/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.baseline.ia32; import org.jikesrvm.VM; import org.jikesrvm.classloader.VM_MethodReference; import org.jikesrvm.classloader.VM_NormalMethod; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.baseline.VM_BaselineCompiledMethod; import org.jikesrvm.compilers.baseline.VM_ReferenceMaps; import org.jikesrvm.compilers.common.VM_CompiledMethod; import org.jikesrvm.compilers.common.VM_CompiledMethods; import org.jikesrvm.ia32.VM_BaselineConstants; import org.jikesrvm.memorymanagers.mminterface.VM_GCMapIterator; import org.jikesrvm.runtime.VM_DynamicLink; import org.jikesrvm.runtime.VM_Magic; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.LocalAddress; import org.vmmagic.unboxed.Offset; import org.vmmagic.unboxed.WordArray; /** * Iterator for stack frame built by the Baseline compiler * An Instance of this class will iterate through a particular * reference map of a method returning the offsets of any refereces * that are part of the input parameters, local variables, and * java stack for the stack frame. */ @Uninterruptible public abstract class VM_BaselineGCMapIterator extends VM_GCMapIterator implements VM_BaselineConstants { private static final boolean TRACE_ALL = false; private static final boolean TRACE_DL = false; // dynamic link frames //-------------// // Constructor // //-------------// // // Remember the location array for registers. This array needs to be updated // with the location of any saved registers. // This information is not used by this iterator but must be updated for the // other types of iterators (ones for the opt compiler built frames) // The locations are kept as addresses within the stack. // public VM_BaselineGCMapIterator(WordArray registerLocations) { this.registerLocations = registerLocations; // (in superclass) dynamicLink = new VM_DynamicLink(); } //-----------// // Interface // //-----------// // // Set the iterator to scan the map at the machine instruction offset provided. // The iterator is positioned to the beginning of the map // // method - identifies the method and class // instruction offset - identifies the map to be scanned. // fp - identifies a specific occurrance of this method and // allows for processing instance specific information // i.e JSR return address values // // NOTE: An iterator may be reused to scan a different method and map. // public void setupIterator(VM_CompiledMethod compiledMethod, Offset instructionOffset, LocalAddress fp) { currentCompiledMethod = (VM_BaselineCompiledMethod) compiledMethod; currentMethod = (VM_NormalMethod) currentCompiledMethod.getMethod(); currentNumLocals = currentMethod.getLocalWords(); // setup superclass // framePtr = fp; // setup stackframe mapping // maps = ((VM_BaselineCompiledMethod) compiledMethod).referenceMaps; mapId = maps.locateGCPoint(instructionOffset, currentMethod); mapIndex = 0; if (mapId < 0) { // lock the jsr lock to serialize jsr processing VM_ReferenceMaps.jsrLock.lock("jsr lock"); int JSRindex = maps.setupJSRSubroutineMap(mapId); while (JSRindex != 0) { LocalAddress nextCallerAddress = framePtr.plus(convertIndexToOffset(JSRindex)).loadLocalAddress(); Offset nextMachineCodeOffset = compiledMethod.getInstructionOffset(nextCallerAddress); if (VM.TraceStkMaps) { VM.sysWriteln(" setupJSRsubroutineMap- nested jsrs end of loop- = "); VM.sysWriteln(" next jsraddress offset = ", JSRindex); VM.sysWriteln(" next callers address = ", nextCallerAddress); VM.sysWriteln(" next machinecodeoffset = ", nextMachineCodeOffset); if (nextMachineCodeOffset.sLT(Offset.zero())) { VM.sysWriteln("BAD MACHINE CODE OFFSET"); } } JSRindex = maps.getNextJSRAddressIndex(nextMachineCodeOffset, currentMethod); } } if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWrite("VM_BaselineGCMapIterator setupIterator mapId = "); VM.sysWrite(mapId); VM.sysWrite(" for "); VM.sysWrite(compiledMethod.getMethod()); VM.sysWrite(".\n"); } // setup dynamic bridge mapping // bridgeTarget = null; bridgeParameterTypes = null; bridgeParameterMappingRequired = false; bridgeRegistersLocationUpdated = false; bridgeParameterIndex = 0; bridgeRegisterIndex = 0; bridgeRegisterLocation = LocalAddress.zero(); bridgeSpilledParamLocation = LocalAddress.zero(); if (currentMethod.getDeclaringClass().hasDynamicBridgeAnnotation()) { LocalAddress ip = VM_Magic.getReturnAddress(fp); fp = VM_Magic.getCallerFramePointer(fp); int callingCompiledMethodId = VM_Magic.getCompiledMethodID(fp); VM_CompiledMethod callingCompiledMethod = VM_CompiledMethods.getCompiledMethod(callingCompiledMethodId); Offset callingInstructionOffset = callingCompiledMethod.getInstructionOffset(ip); callingCompiledMethod.getDynamicLink(dynamicLink, callingInstructionOffset); bridgeTarget = dynamicLink.methodRef(); bridgeParameterTypes = bridgeTarget.getParameterTypes(); if (dynamicLink.isInvokedWithImplicitThisParameter()) { bridgeParameterInitialIndex = -1; bridgeSpilledParamInitialOffset = 8; // this + return addr } else { bridgeParameterInitialIndex = 0; bridgeSpilledParamInitialOffset = 4; // return addr } bridgeSpilledParamInitialOffset += (4 * bridgeTarget.getParameterWords()); bridgeSpilledParameterMappingRequired = callingCompiledMethod.getCompilerType() != VM_CompiledMethod.BASELINE; } reset(); } // Reset iteration to initial state. // This allows a map to be scanned multiple times // public void reset() { mapIndex = 0; finishedWithRegularMap = false; // setup map to report EBX if this method is holding the base of counter array in it. counterArrayBase = currentCompiledMethod.hasCounterArray(); if (bridgeTarget != null) { bridgeParameterMappingRequired = true; bridgeParameterIndex = bridgeParameterInitialIndex; bridgeRegisterIndex = 0; bridgeRegisterLocation = framePtr.plus(STACKFRAME_FIRST_PARAMETER_OFFSET); // top of frame bridgeSpilledParamLocation = framePtr.plus(bridgeSpilledParamInitialOffset); } } /** * given a index in the local area (biased : local0 has index 1) * this routine determines the correspondig offset in the stack */ public int convertIndexToLocation(int index) { if (index == 0) return 0; if (index <= currentNumLocals) { //index is biased by 1; return currentCompiledMethod.getGeneralLocalLocation(index - 1); } else { return currentCompiledMethod.getGeneralStackLocation(index - 1 - currentNumLocals); } } private int convertIndexToOffset(int index) { //for ia32: always offset, never registers if (index == 0) return 0; //invalid // index is biased by 1, index 1 means local 0, this is at offset -BYTES_IN_ADDRESS from startLocalOffset int offset = VM_Compiler.locationToOffset(convertIndexToLocation(index)) - BYTES_IN_ADDRESS; // no jsrbit here if (VM.TraceStkMaps) { VM.sysWriteln("convertIndexToOffset- input index = ", index, " offset = ", offset); } return offset; } // Get location of next reference. // A zero return indicates that no more references exist. // public LocalAddress getNextReferenceAddress() { if (!finishedWithRegularMap) { if (counterArrayBase) { counterArrayBase = false; return registerLocations.get(EBX).toLocalAddress(); } if (mapId < 0) { mapIndex = maps.getNextJSRRefIndex(mapIndex); } else { mapIndex = maps.getNextRefIndex(mapIndex, mapId); } if (mapIndex != 0) { int mapOffset = convertIndexToOffset(mapIndex); if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWrite("VM_BaselineGCMapIterator getNextReferenceOffset = "); VM.sysWriteHex(mapOffset); VM.sysWrite(".\n"); VM.sysWrite("Reference is "); } if (bridgeParameterMappingRequired) { if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWriteHex(framePtr.plus(mapOffset - BRIDGE_FRAME_EXTRA_SIZE).loadInt()); VM.sysWrite(".\n"); if (mapId < 0) { VM.sysWrite("Offset is a JSR return address ie internal pointer.\n"); } } // TODO clean this return (framePtr.plus(mapOffset - BRIDGE_FRAME_EXTRA_SIZE)); } else { if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWriteHex(framePtr.plus(mapOffset).loadInt()); VM.sysWrite(".\n"); if (mapId < 0) { VM.sysWrite("Offset is a JSR return address ie internal pointer.\n"); } } return (framePtr.plus(mapOffset)); } } else { // remember that we are done with the map for future calls, and then // drop down to the code below finishedWithRegularMap = true; } } if (bridgeParameterMappingRequired) { if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) { VM.sysWrite("getNextReferenceAddress: bridgeTarget="); VM.sysWrite(bridgeTarget); VM.sysWrite("\n"); } if (!bridgeRegistersLocationUpdated) { // point registerLocations[] to our callers stackframe // registerLocations.set(JTOC, framePtr.plus(JTOC_SAVE_OFFSET).toWord()); registerLocations.set(T0, framePtr.plus(T0_SAVE_OFFSET).toWord()); registerLocations.set(T1, framePtr.plus(T1_SAVE_OFFSET).toWord()); registerLocations.set(EBX, framePtr.plus(EBX_SAVE_OFFSET).toWord()); bridgeRegistersLocationUpdated = true; } // handle implicit "this" parameter, if any // if (bridgeParameterIndex == -1) { bridgeParameterIndex += 1; bridgeRegisterIndex += 1; bridgeRegisterLocation = bridgeRegisterLocation.minus(4); bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(4); if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) { VM.sysWrite("VM_BaselineGCMapIterator getNextReferenceOffset = dynamic link GPR this "); VM.sysWrite(bridgeRegisterLocation.plus(4)); VM.sysWrite(".\n"); } return bridgeRegisterLocation.plus(4); } // now the remaining parameters // while (bridgeParameterIndex < bridgeParameterTypes.length) { VM_TypeReference bridgeParameterType = bridgeParameterTypes[bridgeParameterIndex++]; if (bridgeParameterType.isReferenceType()) { bridgeRegisterIndex += 1; bridgeRegisterLocation = bridgeRegisterLocation.minus(4); bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(4); if (bridgeRegisterIndex <= NUM_PARAMETER_GPRS) { if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) { VM.sysWrite("VM_BaselineGCMapIterator getNextReferenceOffset = dynamic link GPR parameter "); VM.sysWrite(bridgeRegisterLocation.plus(4)); VM.sysWrite(".\n"); } return bridgeRegisterLocation.plus(4); } else { if (bridgeSpilledParameterMappingRequired) { if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) { VM.sysWrite("VM_BaselineGCMapIterator getNextReferenceOffset = dynamic link spilled parameter "); VM.sysWrite(bridgeSpilledParamLocation.plus(4)); VM.sysWrite(".\n"); } return bridgeSpilledParamLocation.plus(4); } else { break; } } } else if (bridgeParameterType.isLongType()) { bridgeRegisterIndex += 2; bridgeRegisterLocation = bridgeRegisterLocation.minus(8); bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(8); } else if (bridgeParameterType.isDoubleType()) { bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(8); } else if (bridgeParameterType.isFloatType()) { bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(4); } else { // boolean, byte, char, short, int bridgeRegisterIndex += 1; bridgeRegisterLocation = bridgeRegisterLocation.minus(4); bridgeSpilledParamLocation = bridgeSpilledParamLocation.minus(4); } } } else { // point registerLocations[] to our callers stackframe // registerLocations.set(JTOC, framePtr.plus(JTOC_SAVE_OFFSET).toWord()); registerLocations.set(EBX, framePtr.plus(EBX_SAVE_OFFSET).toWord()); } return LocalAddress.zero(); } // // Gets the location of the next return address // after the current position. // a zero return indicates that no more references exist // public LocalAddress getNextReturnAddressAddress() { if (mapId >= 0) { if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWrite("VM_BaselineGCMapIterator getNextReturnAddressOffset mapId = "); VM.sysWrite(mapId); VM.sysWrite(".\n"); } return LocalAddress.zero(); } mapIndex = maps.getNextJSRReturnAddrIndex(mapIndex); if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWrite("VM_BaselineGCMapIterator getNextReturnAddressOffset = "); VM.sysWrite(convertIndexToOffset(mapIndex)); VM.sysWrite(".\n"); } return (mapIndex == 0) ? LocalAddress.zero() : framePtr.plus(convertIndexToOffset(mapIndex)); } // cleanup pointers - used with method maps to release data structures // early ... they may be in temporary storage ie storage only used // during garbage collection // public void cleanupPointers() { maps.cleanupPointers(); maps = null; if (mapId < 0) { VM_ReferenceMaps.jsrLock.unlock(); } bridgeTarget = null; bridgeParameterTypes = null; } public int getType() { return VM_CompiledMethod.BASELINE; } // For debugging (used with checkRefMap) // public int getStackDepth() { return maps.getStackDepth(mapId); } // Iterator state for mapping any stackframe. // private VM_NormalMethod currentMethod; // compiled method for the frame private VM_BaselineCompiledMethod currentCompiledMethod; // compiled method for the frame private int currentNumLocals; private int mapIndex; // current index in current map private int mapId; // id of current map out of all maps private VM_ReferenceMaps maps; // set of maps for this method private boolean counterArrayBase; // have we reported the base ptr of the edge counter array? // Additional iterator state for mapping dynamic bridge stackframes. // private VM_DynamicLink dynamicLink; // place to keep info returned by VM_CompiledMethod.getDynamicLink private VM_MethodReference bridgeTarget; // method to be invoked via dynamic bridge (null: current frame is not a dynamic bridge) private VM_TypeReference[] bridgeParameterTypes; // parameter types passed by that method private boolean bridgeParameterMappingRequired; // have all bridge parameters been mapped yet? private boolean bridgeSpilledParameterMappingRequired; // do we need to map spilled params (baseline compiler = no, opt = yes) private boolean bridgeRegistersLocationUpdated; // have the register location been updated private boolean finishedWithRegularMap; // have we processed all the values in the regular map yet? private int bridgeParameterInitialIndex; // first parameter to be mapped (-1 == "this") private int bridgeParameterIndex; // current parameter being mapped (-1 == "this") private int bridgeRegisterIndex; // gpr register it lives in private LocalAddress bridgeRegisterLocation; // memory address at which that register was saved private LocalAddress bridgeSpilledParamLocation; // current spilled param location private int bridgeSpilledParamInitialOffset;// starting offset to stack location for param0 }