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.baseline.ia32;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.classloader.MethodReference;
017    import org.jikesrvm.classloader.NormalMethod;
018    import org.jikesrvm.classloader.TypeReference;
019    import org.jikesrvm.compilers.baseline.BaselineCompiledMethod;
020    import org.jikesrvm.compilers.baseline.ReferenceMaps;
021    import org.jikesrvm.compilers.common.CompiledMethod;
022    import org.jikesrvm.compilers.common.CompiledMethods;
023    import org.jikesrvm.ia32.BaselineConstants;
024    import org.jikesrvm.mm.mminterface.GCMapIterator;
025    import org.jikesrvm.runtime.DynamicLink;
026    import org.jikesrvm.runtime.Magic;
027    import org.vmmagic.pragma.Uninterruptible;
028    import org.vmmagic.unboxed.Address;
029    import org.vmmagic.unboxed.Offset;
030    import org.vmmagic.unboxed.WordArray;
031    
032    /**
033     * Iterator for stack frame  built by the Baseline compiler
034     * An Instance of this class will iterate through a particular
035     * reference map of a method returning the offsets of any refereces
036     * that are part of the input parameters, local variables, and
037     * java stack for the stack frame.
038     */
039    @Uninterruptible
040    public abstract class BaselineGCMapIterator extends GCMapIterator implements BaselineConstants {
041      private static final boolean TRACE_ALL = false;
042      private static final boolean TRACE_DL = false; // dynamic link frames
043    
044      /*
045       * Iterator state for mapping any stackframe.
046       */
047      /** Compiled method for the frame */
048      private NormalMethod currentMethod;
049      /** Compiled method for the frame */
050      private BaselineCompiledMethod currentCompiledMethod;
051      private int currentNumLocals;
052      /** Current index in current map */
053      private int mapIndex;
054      /** id of current map out of all maps */
055      private int mapId;
056      /** set of maps for this method */
057      private ReferenceMaps maps;
058      /** have we reported the base ptr of the edge counter array? */
059      private boolean counterArrayBase;
060    
061      /*
062       *  Additional iterator state for mapping dynamic bridge stackframes.
063       */
064      /** place to keep info returned by CompiledMethod.getDynamicLink */
065      private final DynamicLink dynamicLink;
066      /** method to be invoked via dynamic bridge (null: current frame is not a dynamic bridge) */
067      private MethodReference bridgeTarget;
068      /** parameter types passed by that method */
069      private TypeReference[] bridgeParameterTypes;
070      /** have all bridge parameters been mapped yet? */
071      private boolean bridgeParameterMappingRequired;
072      /** do we need to map spilled params (baseline compiler = no, opt = yes) */
073      private boolean bridgeSpilledParameterMappingRequired;
074      /** have the register location been updated */
075      private boolean bridgeRegistersLocationUpdated;
076      /** have we processed all the values in the regular map yet? */
077      private boolean finishedWithRegularMap;
078      /** first parameter to be mapped (-1 == "this") */
079      private int bridgeParameterInitialIndex;
080      /** current parameter being mapped (-1 == "this") */
081      private int bridgeParameterIndex;
082      /** gpr register it lives in */
083      private int bridgeRegisterIndex;
084      /** memory address at which that register was saved */
085      private Address bridgeRegisterLocation;
086      /** current spilled param location */
087      private Address bridgeSpilledParamLocation;
088      /** starting offset to stack location for param0 */
089      private int bridgeSpilledParamInitialOffset;
090    
091      /**
092       * Constructor. Remember the location array for registers. This array needs to
093       * be updated with the location of any saved registers. This information is
094       * not used by this iterator but must be updated for the other types of
095       * iterators (ones for the opt compiler built frames) The locations are kept
096       * as addresses within the stack.
097       */
098      public BaselineGCMapIterator(WordArray registerLocations) {
099        this.registerLocations = registerLocations; // (in superclass)
100        dynamicLink = new DynamicLink();
101      }
102    
103      /*
104       * Interface
105       */
106    
107      /**
108       * Set the iterator to scan the map at the machine instruction offset
109       * provided. The iterator is positioned to the beginning of the map. NOTE: An
110       * iterator may be reused to scan a different method and map.
111       *
112       * @param compiledMethod
113       *          identifies the method and class
114       * @param instructionOffset
115       *          identifies the map to be scanned.
116       * @param fp
117       *          identifies a specific occurrance of this method and allows for
118       *          processing instance specific information i.e JSR return address
119       *          values
120       */
121      public void setupIterator(CompiledMethod compiledMethod, Offset instructionOffset, Address fp) {
122        currentCompiledMethod = (BaselineCompiledMethod) compiledMethod;
123        currentMethod = (NormalMethod) currentCompiledMethod.getMethod();
124        currentNumLocals = currentMethod.getLocalWords();
125    
126        // setup superclass
127        //
128        framePtr = fp;
129    
130        // setup stackframe mapping
131        //
132        maps = ((BaselineCompiledMethod) compiledMethod).referenceMaps;
133        mapId = maps.locateGCPoint(instructionOffset, currentMethod);
134        mapIndex = 0;
135        if (mapId < 0) {
136          // lock the jsr lock to serialize jsr processing
137          ReferenceMaps.jsrLock.lock();
138          int JSRindex = maps.setupJSRSubroutineMap(mapId);
139          while (JSRindex != 0) {
140            Address nextCallerAddress = framePtr.plus(convertIndexToOffset(JSRindex)).loadAddress();
141            Offset nextMachineCodeOffset = compiledMethod.getInstructionOffset(nextCallerAddress);
142            if (VM.TraceStkMaps) {
143              VM.sysWriteln("     setupJSRsubroutineMap- nested jsrs end of loop- = ");
144              VM.sysWriteln("      next jsraddress offset = ", JSRindex);
145              VM.sysWriteln("      next callers address = ", nextCallerAddress);
146              VM.sysWriteln("      next machinecodeoffset = ", nextMachineCodeOffset);
147              if (nextMachineCodeOffset.sLT(Offset.zero())) {
148                VM.sysWriteln("BAD MACHINE CODE OFFSET");
149              }
150            }
151            JSRindex = maps.getNextJSRAddressIndex(nextMachineCodeOffset, currentMethod);
152          }
153        }
154        if (VM.TraceStkMaps || TRACE_ALL) {
155          VM.sysWrite("BaselineGCMapIterator setupIterator mapId = ");
156          VM.sysWrite(mapId);
157          VM.sysWrite(" for ");
158          VM.sysWrite(compiledMethod.getMethod());
159          VM.sysWrite(".\n");
160        }
161    
162        // setup dynamic bridge mapping
163        //
164        bridgeTarget = null;
165        bridgeParameterTypes = null;
166        bridgeParameterMappingRequired = false;
167        bridgeRegistersLocationUpdated = false;
168        bridgeParameterIndex = 0;
169        bridgeRegisterIndex = 0;
170        bridgeRegisterLocation = Address.zero();
171        bridgeSpilledParamLocation = Address.zero();
172    
173        if (currentMethod.getDeclaringClass().hasDynamicBridgeAnnotation()) {
174          Address ip = Magic.getReturnAddress(fp);
175          fp = Magic.getCallerFramePointer(fp);
176          int callingCompiledMethodId = Magic.getCompiledMethodID(fp);
177          CompiledMethod callingCompiledMethod = CompiledMethods.getCompiledMethod(callingCompiledMethodId);
178          Offset callingInstructionOffset = callingCompiledMethod.getInstructionOffset(ip);
179    
180          callingCompiledMethod.getDynamicLink(dynamicLink, callingInstructionOffset);
181          bridgeTarget = dynamicLink.methodRef();
182          bridgeParameterTypes = bridgeTarget.getParameterTypes();
183          if (dynamicLink.isInvokedWithImplicitThisParameter()) {
184            bridgeParameterInitialIndex = -1;
185            bridgeSpilledParamInitialOffset = 2*WORDSIZE; // this + return addr
186          } else {
187            bridgeParameterInitialIndex = 0;
188            bridgeSpilledParamInitialOffset = WORDSIZE; // return addr
189          }
190          bridgeSpilledParamInitialOffset += (bridgeTarget.getParameterWords() << LG_WORDSIZE);
191          bridgeSpilledParameterMappingRequired = callingCompiledMethod.getCompilerType() != CompiledMethod.BASELINE;
192        }
193    
194        reset();
195      }
196    
197      /**
198       * Reset iteration to initial state. This allows a map to be scanned multiple
199       * times.
200       */
201      public void reset() {
202        mapIndex = 0;
203        finishedWithRegularMap = false;
204    
205        // setup map to report EBX if this method is holding the base of counter array in it.
206        counterArrayBase = currentCompiledMethod.hasCounterArray();
207    
208        if (bridgeTarget != null) {
209          bridgeParameterMappingRequired = true;
210          bridgeParameterIndex = bridgeParameterInitialIndex;
211          bridgeRegisterIndex = 0;
212          bridgeRegisterLocation = framePtr.plus(STACKFRAME_FIRST_PARAMETER_OFFSET); // top of frame
213          bridgeSpilledParamLocation = framePtr.plus(bridgeSpilledParamInitialOffset);
214        }
215      }
216    
217      /**
218       * given a index in the local area (biased : local0 has index 1)
219       *   this routine determines the correspondig offset in the stack
220       */
221      public short convertIndexToLocation(int index) {
222        if (index == 0) return 0;
223        if (index <= currentNumLocals) { //index is biased by 1;
224          return currentCompiledMethod.getGeneralLocalLocation(index - 1);
225        } else {
226          return currentCompiledMethod.getGeneralStackLocation(index - 1 - currentNumLocals);
227        }
228      }
229    
230      private int convertIndexToOffset(int index) {
231        //for ia32: always offset, never registers
232        if (index == 0) return 0; //invalid
233    
234        // index is biased by 1, index 1 means local 0, this is at offset -BYTES_IN_ADDRESS from startLocalOffset
235        int offset = BaselineCompilerImpl.locationToOffset(convertIndexToLocation(index)) - BYTES_IN_ADDRESS; // no jsrbit here
236        if (VM.TraceStkMaps) {
237          VM.sysWriteln("convertIndexToOffset- input index = ", index, "  offset = ", offset);
238        }
239        return offset;
240      }
241    
242      /**
243       * Get location of next reference. A zero return indicates that no more
244       * references exist.
245       */
246      public Address getNextReferenceAddress() {
247        if (!finishedWithRegularMap) {
248          if (counterArrayBase) {
249            counterArrayBase = false;
250            return registerLocations.get(EBX.value()).toAddress();
251          }
252          if (mapId < 0) {
253            mapIndex = maps.getNextJSRRefIndex(mapIndex);
254          } else {
255            mapIndex = maps.getNextRefIndex(mapIndex, mapId);
256          }
257    
258          if (mapIndex != 0) {
259            int mapOffset = convertIndexToOffset(mapIndex);
260            if (VM.TraceStkMaps || TRACE_ALL) {
261              VM.sysWrite("BaselineGCMapIterator getNextReferenceOffset = ");
262              VM.sysWriteHex(mapOffset);
263              VM.sysWrite(".\n");
264              VM.sysWrite("Reference is ");
265            }
266            if (bridgeParameterMappingRequired) {
267              if (VM.TraceStkMaps || TRACE_ALL) {
268                VM.sysWriteHex(framePtr.plus(mapOffset - BRIDGE_FRAME_EXTRA_SIZE).loadAddress());
269                VM.sysWrite(".\n");
270                if (mapId < 0) {
271                  VM.sysWrite("Offset is a JSR return address ie internal pointer.\n");
272                }
273              }
274    
275              // TODO  clean this
276              return (framePtr.plus(mapOffset - BRIDGE_FRAME_EXTRA_SIZE));
277            } else {
278              if (VM.TraceStkMaps || TRACE_ALL) {
279                VM.sysWriteHex(framePtr.plus(mapOffset).loadAddress());
280                VM.sysWrite(".\n");
281                if (mapId < 0) {
282                  VM.sysWrite("Offset is a JSR return address ie internal pointer.\n");
283                }
284              }
285              return (framePtr.plus(mapOffset));
286            }
287          } else {
288            // remember that we are done with the map for future calls, and then
289            //   drop down to the code below
290            finishedWithRegularMap = true;
291          }
292        }
293    
294        if (bridgeParameterMappingRequired) {
295          if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) {
296            VM.sysWrite("getNextReferenceAddress: bridgeTarget=");
297            VM.sysWrite(bridgeTarget);
298            VM.sysWrite("\n");
299          }
300    
301          if (!bridgeRegistersLocationUpdated) {
302            // point registerLocations[] to our callers stackframe
303            //
304            registerLocations.set(EDI.value(), framePtr.plus(EDI_SAVE_OFFSET).toWord());
305            registerLocations.set(T0.value(), framePtr.plus(T0_SAVE_OFFSET).toWord());
306            registerLocations.set(T1.value(), framePtr.plus(T1_SAVE_OFFSET).toWord());
307            registerLocations.set(EBX.value(), framePtr.plus(EBX_SAVE_OFFSET).toWord());
308    
309            bridgeRegistersLocationUpdated = true;
310          }
311    
312          // handle implicit "this" parameter, if any
313          //
314          if (bridgeParameterIndex == -1) {
315            bridgeParameterIndex += 1;
316            bridgeRegisterIndex += 1;
317            bridgeRegisterLocation = bridgeRegisterLocation.minus(WORDSIZE);
318            bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(WORDSIZE);
319    
320            if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) {
321              VM.sysWrite("BaselineGCMapIterator getNextReferenceOffset = dynamic link GPR this ");
322              VM.sysWrite(bridgeRegisterLocation.plus(WORDSIZE));
323              VM.sysWrite(".\n");
324            }
325            return bridgeRegisterLocation.plus(WORDSIZE);
326          }
327    
328          // now the remaining parameters
329          //
330          while (bridgeParameterIndex < bridgeParameterTypes.length) {
331            TypeReference bridgeParameterType = bridgeParameterTypes[bridgeParameterIndex++];
332    
333            if (bridgeParameterType.isReferenceType()) {
334              bridgeRegisterIndex += 1;
335              bridgeRegisterLocation = bridgeRegisterLocation.minus(WORDSIZE);
336              bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(WORDSIZE);
337    
338              if (bridgeRegisterIndex <= NUM_PARAMETER_GPRS) {
339                if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) {
340                  VM.sysWrite("BaselineGCMapIterator getNextReferenceOffset = dynamic link GPR parameter ");
341                  VM.sysWrite(bridgeRegisterLocation.plus(WORDSIZE));
342                  VM.sysWrite(".\n");
343                }
344                return bridgeRegisterLocation.plus(WORDSIZE);
345              } else {
346                if (bridgeSpilledParameterMappingRequired) {
347                  if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) {
348                    VM.sysWrite("BaselineGCMapIterator getNextReferenceOffset = dynamic link spilled parameter ");
349                    VM.sysWrite(bridgeSpilledParamLocation.plus(WORDSIZE));
350                    VM.sysWrite(".\n");
351                  }
352                  return bridgeSpilledParamLocation.plus(WORDSIZE);
353                } else {
354                  break;
355                }
356              }
357            } else if (bridgeParameterType.isLongType()) {
358              bridgeRegisterIndex += VM.BuildFor32Addr ? 2 : 1;
359              bridgeRegisterLocation = bridgeRegisterLocation.minus(2*WORDSIZE);
360              bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(2*WORDSIZE);
361            } else if (bridgeParameterType.isDoubleType()) {
362              bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(2*WORDSIZE);
363            } else if (bridgeParameterType.isFloatType()) {
364              bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(WORDSIZE);
365            } else {
366              // boolean, byte, char, short, int
367              bridgeRegisterIndex += 1;
368              bridgeRegisterLocation = bridgeRegisterLocation.minus(WORDSIZE);
369              bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(WORDSIZE);
370            }
371          }
372        } else {
373          // point registerLocations[] to our callers stackframe
374          //
375          registerLocations.set(EDI.value(), framePtr.plus(EDI_SAVE_OFFSET).toWord());
376          registerLocations.set(EBX.value(), framePtr.plus(EBX_SAVE_OFFSET).toWord());
377          if (currentMethod.hasBaselineSaveLSRegistersAnnotation()) {
378            registerLocations.set(EBP.value(), framePtr.plus(EBP_SAVE_OFFSET).toWord());
379          }
380        }
381    
382        return Address.zero();
383      }
384    
385      /**
386       * Gets the location of the next return address after the current position. A
387       * zero return indicates that no more references exist
388       */
389      public Address getNextReturnAddressAddress() {
390        if (mapId >= 0) {
391          if (VM.TraceStkMaps || TRACE_ALL) {
392            VM.sysWrite("BaselineGCMapIterator getNextReturnAddressOffset mapId = ");
393            VM.sysWrite(mapId);
394            VM.sysWrite(".\n");
395          }
396          return Address.zero();
397        }
398        mapIndex = maps.getNextJSRReturnAddrIndex(mapIndex);
399        if (VM.TraceStkMaps || TRACE_ALL) {
400          VM.sysWrite("BaselineGCMapIterator getNextReturnAddressOffset = ");
401          VM.sysWrite(convertIndexToOffset(mapIndex));
402          VM.sysWrite(".\n");
403        }
404        return (mapIndex == 0) ? Address.zero() : framePtr.plus(convertIndexToOffset(mapIndex));
405      }
406    
407      /**
408       * Cleanup pointers - used with method maps to release data structures early
409       * ... they may be in temporary storage ie storage only used during garbage
410       * collection
411       */
412      public void cleanupPointers() {
413        maps.cleanupPointers();
414        maps = null;
415        if (mapId < 0) {
416          ReferenceMaps.jsrLock.unlock();
417        }
418        bridgeTarget = null;
419        bridgeParameterTypes = null;
420      }
421    
422      public int getType() {
423        return CompiledMethod.BASELINE;
424      }
425    
426      /**
427       * For debugging (used with checkRefMap)
428       */
429      public int getStackDepth() {
430        return maps.getStackDepth(mapId);
431      }
432    }
433