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