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