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