001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.runtimesupport.ia32;
014
015import static org.jikesrvm.ia32.RegisterConstants.NONVOLATILE_GPRS;
016import static org.jikesrvm.ia32.RegisterConstants.NUM_NONVOLATILE_GPRS;
017import static org.jikesrvm.ia32.RegisterConstants.NUM_VOLATILE_GPRS;
018import static org.jikesrvm.ia32.RegisterConstants.VOLATILE_GPRS;
019import static org.jikesrvm.ia32.StackframeLayoutConstants.FPU_STATE_SIZE;
020import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_BODY_OFFSET;
021import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS;
022
023import org.jikesrvm.VM;
024import org.jikesrvm.compilers.opt.runtimesupport.OptGenericGCMapIterator;
025import org.vmmagic.pragma.Uninterruptible;
026import org.vmmagic.unboxed.Address;
027import org.vmmagic.unboxed.AddressArray;
028
029/**
030 * An instance of this class provides iteration across the references
031 * represented by a frame built by the OPT compiler.
032 * <p>
033 * The architecture-specific version of the GC Map iterator.  It inherits
034 * its architecture-independent code from OptGenericGCMapIterator.
035 * This version is for IA32.
036 */
037@Uninterruptible
038public final class OptGCMapIterator extends OptGenericGCMapIterator {
039
040  private static final boolean DEBUG = false;
041
042  public OptGCMapIterator(AddressArray registerLocations) {
043    super(registerLocations);
044  }
045
046  /**
047   * If any non-volatile GPRs were saved by the method being processed
048   * then update the registerLocations array with the locations where the
049   * registers were saved.  Also, check for special methods that also
050   * save the volatile GPRs.
051   */
052  @Override
053  protected void updateLocateRegisters() {
054
055    //           HIGH MEMORY
056    //
057    //       +---------------+                                           |
058    //  FP-> |   saved FP    |  <-- this frame's caller's frame          |
059    //       +---------------+                                           |
060    //       |    cmid       |  <-- this frame's compiledmethod id       |
061    //       +---------------+                                           |
062    //       |               |                                           |
063    //       |  Spill Area   |  <-- spills and other method-specific     |
064    //       |     ...       |      compiler-managed storage             |
065    //       +---------------+                                           |
066    //       |   Saved FP    |     only SaveVolatile Frames              |
067    //       |    State      |                                           |
068    //       +---------------+                                           |
069    //       |  VolGPR[0]    |
070    //       |     ...       |     only SaveVolatile Frames
071    //       |  VolGPR[n]    |
072    //       +---------------+
073    //       |  NVolGPR[k]   |  <-- cm.getUnsignedNonVolatileOffset()
074    //       |     ...       |   k == cm.getFirstNonVolatileGPR()
075    //       |  NVolGPR[n]   |
076    //       +---------------+
077    //
078    //           LOW MEMORY
079
080    int frameOffset = compiledMethod.getUnsignedNonVolatileOffset();
081    if (frameOffset >= 0) {
082      // get to the non vol area
083      Address nonVolArea = framePtr.minus(frameOffset);
084
085      // update non-volatiles
086      int first = compiledMethod.getFirstNonVolatileGPR();
087      if (first >= 0) {
088        // move to the beginning of the nonVol area
089        Address location = nonVolArea;
090
091        for (int i = first; i < NUM_NONVOLATILE_GPRS; i++) {
092          // determine what register index corresponds to this location
093          int registerIndex = NONVOLATILE_GPRS[i].value();
094          registerLocations.set(registerIndex, location);
095          if (DEBUG) {
096            VM.sysWrite("UpdateRegisterLocations: Register ");
097            VM.sysWrite(registerIndex);
098            VM.sysWrite(" to Location ");
099            VM.sysWrite(location);
100            VM.sysWrite("\n");
101          }
102          location = location.minus(BYTES_IN_ADDRESS);
103        }
104      }
105
106      // update volatiles if needed
107      if (compiledMethod.isSaveVolatile()) {
108        // move to the beginning of the nonVol area
109        Address location = nonVolArea.plus(BYTES_IN_ADDRESS * NUM_VOLATILE_GPRS);
110
111        for (int i = 0; i < NUM_VOLATILE_GPRS; i++) {
112          // determine what register index corresponds to this location
113          int registerIndex = VOLATILE_GPRS[i].value();
114          registerLocations.set(registerIndex, location);
115          if (DEBUG) {
116            VM.sysWrite("UpdateRegisterLocations: Register ");
117            VM.sysWrite(registerIndex);
118            VM.sysWrite(" to Location ");
119            VM.sysWrite(location);
120            VM.sysWrite("\n");
121          }
122          location = location.minus(BYTES_IN_ADDRESS);
123        }
124      }
125    }
126  }
127
128  @Override
129  public Address getStackLocation(Address framePtr, int offset) {
130    return framePtr.minus(offset);
131  }
132
133  /**
134   *  Get address of the first spill location for the given frame ptr
135   *  @return the first spill location
136   */
137  @Override
138  public Address getFirstSpillLoc() {
139    return framePtr.plus(STACKFRAME_BODY_OFFSET);
140  }
141
142  /**
143   *  Get address of the last spill location for the given frame ptr
144   *  @return the last spill location
145   */
146  @Override
147  public Address getLastSpillLoc() {
148    if (compiledMethod.isSaveVolatile()) {
149      return framePtr.minus(compiledMethod.getUnsignedNonVolatileOffset() - BYTES_IN_ADDRESS - SAVE_VOL_SIZE);
150    } else {
151      return framePtr.minus(compiledMethod.getUnsignedNonVolatileOffset() - BYTES_IN_ADDRESS);
152    }
153  }
154
155  static final int VOL_SIZE = BYTES_IN_ADDRESS * NUM_VOLATILE_GPRS;
156  static final int SAVE_VOL_SIZE = VOL_SIZE + FPU_STATE_SIZE;
157}