/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * 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/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.baseline.ia32; import static org.jikesrvm.ia32.BaselineConstants.BRIDGE_FRAME_EXTRA_SIZE; import static org.jikesrvm.ia32.BaselineConstants.EBP_SAVE_OFFSET; import static org.jikesrvm.ia32.BaselineConstants.EBX_SAVE_OFFSET; import static org.jikesrvm.ia32.BaselineConstants.EDI_SAVE_OFFSET; import static org.jikesrvm.ia32.BaselineConstants.STACKFRAME_FIRST_PARAMETER_OFFSET; import static org.jikesrvm.ia32.BaselineConstants.T0; import static org.jikesrvm.ia32.BaselineConstants.T0_SAVE_OFFSET; import static org.jikesrvm.ia32.BaselineConstants.T1; import static org.jikesrvm.ia32.BaselineConstants.T1_SAVE_OFFSET; import static org.jikesrvm.ia32.RegisterConstants.EBP; import static org.jikesrvm.ia32.RegisterConstants.EBX; import static org.jikesrvm.ia32.RegisterConstants.EDI; import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS; import org.jikesrvm.VM; import org.jikesrvm.classloader.NormalMethod; import org.jikesrvm.compilers.baseline.AbstractBaselineGCMapIterator; import org.jikesrvm.compilers.common.CompiledMethod; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.AddressArray; import org.vmmagic.unboxed.Offset; /** * Iterator for stack frame built by the Baseline compiler. * <p> * An Instance of this class will iterate through a particular * reference map of a method returning the offsets of any references * that are part of the input parameters, local variables, and * java stack for the stack frame. */ @Uninterruptible public final class BaselineGCMapIterator extends AbstractBaselineGCMapIterator { /** Compiled method for the frame */ protected ArchBaselineCompiledMethod currentCompiledMethod; /** have we reported the base ptr of the edge counter array? */ private boolean counterArrayBase; public BaselineGCMapIterator(AddressArray registerLocations) { super(registerLocations); bridgeData = new ArchBridgeDataExtractor(); } /* * Interface */ /** * Set the iterator to scan the map at the machine instruction offset * provided. The iterator is positioned to the beginning of the map. NOTE: An * iterator may be reused to scan a different method and map. * * @param compiledMethod * identifies the method and class * @param instructionOffset * identifies the map to be scanned. * @param fp * identifies a specific occurrence of this method and allows for * processing instance specific information i.e JSR return address * values */ @Override public void setupIterator(CompiledMethod compiledMethod, Offset instructionOffset, Address fp) { currentCompiledMethod = (ArchBaselineCompiledMethod) compiledMethod; currentMethod = (NormalMethod) currentCompiledMethod.getMethod(); currentNumLocals = currentMethod.getLocalWords(); // setup superclass // framePtr = fp; // setup stackframe mapping // mapReader.setMethod(currentMethod, compiledMethod); mapReader.locateGCPoint(instructionOffset); if (mapReader.currentMapIsForJSR()) { mapReader.acquireLockForJSRProcessing(); int JSRindex = mapReader.setupJSRSubroutineMap(); while (JSRindex != 0) { Address nextCallerAddress = framePtr.plus(convertIndexToOffset(JSRindex)).loadAddress(); Offset nextMachineCodeOffset = compiledMethod.getInstructionOffset(nextCallerAddress); if (VM.TraceStkMaps) { traceSetupJSRsubroutineMap(JSRindex, nextCallerAddress, nextMachineCodeOffset); } JSRindex = mapReader.getNextJSRAddressIndex(nextMachineCodeOffset); } } if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWrite("BaselineGCMapIterator setupIterator mapId = "); VM.sysWrite(mapReader.getMapId()); VM.sysWrite(" for "); VM.sysWrite(compiledMethod.getMethod()); VM.sysWriteln("."); } bridgeData.setupDynamicBridgeMapping(currentMethod, fp); reset(); } @Override protected void resetOtherState() { // setup map to report EBX if this method is holding the base of counter array in it. counterArrayBase = currentCompiledMethod.hasCounterArray(); } @Override protected void resetArchitectureSpecificBridgeSState() { if (bridgeData.hasBridgeInfo()) { bridgeData.resetBridgeRegisterIndex(); bridgeData.setBridgeRegisterLocation(framePtr.plus(STACKFRAME_FIRST_PARAMETER_OFFSET)); // top of frame bridgeData.resetBridgeSpilledParamLocation(framePtr); } } /** * Converts a biased index from a local area into an offset in the stack. * * @param index index in the local area (biased : local0 has index 1) * @return corresponding offset in the stack */ public short 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 = BaselineCompilerImpl.locationToOffset(convertIndexToLocation(index)) - BYTES_IN_ADDRESS; // no jsrbit here if (VM.TraceStkMaps) { VM.sysWriteln("convertIndexToOffset- input index = ", index, " offset = ", offset); } return offset; } @Override public Address getNextReferenceAddress() { if (!mapReader.isFinishedWithRegularMap()) { if (counterArrayBase) { counterArrayBase = false; return registerLocations.get(EBX.value()); } mapReader.updateMapIndex(); if (mapReader.currentMapHasMorePointers()) { int mapOffset = convertIndexToOffset(mapReader.getMapIndex()); if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWrite("BaselineGCMapIterator getNextReferenceOffset = "); VM.sysWriteHex(mapOffset); VM.sysWrite(" (= "); VM.sysWrite(mapOffset); VM.sysWrite(")"); VM.sysWriteln("."); VM.sysWrite("Reference is "); } if (bridgeData.isBridgeParameterMappingRequired()) { if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWriteHex(framePtr.plus(mapOffset - BRIDGE_FRAME_EXTRA_SIZE).loadAddress()); VM.sysWriteln("."); if (mapReader.currentMapIsForJSR()) { VM.sysWriteln("Offset is a JSR return address ie internal pointer."); } } // TODO clean this return (framePtr.plus(mapOffset - BRIDGE_FRAME_EXTRA_SIZE)); } else { if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWriteHex(framePtr.plus(mapOffset).loadAddress()); VM.sysWriteln("."); if (mapReader.currentMapIsForJSR()) { VM.sysWriteln("Offset is a JSR return address ie internal pointer."); } } return (framePtr.plus(mapOffset)); } } else { // remember that we are done with the map for future calls, and then // drop down to the code below mapReader.setFinishedWithRegularMap(); } } if (bridgeData.isBridgeParameterMappingRequired()) { if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) { ((ArchBridgeDataExtractor) bridgeData).traceBridgeTarget(); } if (bridgeData.needsBridgeRegisterLocationsUpdate()) { // point registerLocations[] to our callers stackframe // registerLocations.set(EDI.value(), framePtr.plus(EDI_SAVE_OFFSET)); registerLocations.set(T0.value(), framePtr.plus(T0_SAVE_OFFSET)); registerLocations.set(T1.value(), framePtr.plus(T1_SAVE_OFFSET)); registerLocations.set(EBX.value(), framePtr.plus(EBX_SAVE_OFFSET)); bridgeData.setBridgeRegistersLocationUpdated(); } if (bridgeData.hasUnprocessedImplicitThis()) { return bridgeData.getImplicitThisAddress(); } // now the remaining parameters while (bridgeData.hasMoreBridgeParameters()) { return bridgeData.getNextBridgeParameterAddress(); } } else { // point registerLocations[] to our callers stackframe // registerLocations.set(EDI.value(), framePtr.plus(EDI_SAVE_OFFSET)); registerLocations.set(EBX.value(), framePtr.plus(EBX_SAVE_OFFSET)); if (currentMethod.hasBaselineSaveLSRegistersAnnotation()) { registerLocations.set(EBP.value(), framePtr.plus(EBP_SAVE_OFFSET)); } } if (VM.TraceStkMaps || TRACE_ALL || TRACE_DL) { VM.sysWriteln("BaselineGCMapIterator getNextReferenceOffset: all references processed."); } return Address.zero(); } @Override public Address getNextReturnAddressAddress() { if (!mapReader.currentMapIsForJSR()) { if (VM.TraceStkMaps || TRACE_ALL) { traceMapIdForGetNextReturnAddressAddress(); } return Address.zero(); } mapReader.updateMapIndexWithJSRReturnAddrIndex(); if (VM.TraceStkMaps || TRACE_ALL) { VM.sysWrite("BaselineGCMapIterator getNextReturnAddressOffset = "); VM.sysWrite(convertIndexToOffset(mapReader.getMapIndex())); VM.sysWriteln("."); } return (!mapReader.currentMapHasMorePointers()) ? Address.zero() : framePtr.plus(convertIndexToOffset(mapReader.getMapIndex())); } }