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