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