/*
* 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.ppc;
import static org.jikesrvm.ppc.BaselineConstants.FIRST_FIXED_LOCAL_REGISTER;
import static org.jikesrvm.ppc.BaselineConstants.FIRST_FLOAT_LOCAL_REGISTER;
import static org.jikesrvm.ppc.RegisterConstants.FIRST_VOLATILE_FPR;
import static org.jikesrvm.ppc.RegisterConstants.FIRST_VOLATILE_GPR;
import static org.jikesrvm.ppc.RegisterConstants.LAST_NONVOLATILE_FPR;
import static org.jikesrvm.ppc.RegisterConstants.LAST_NONVOLATILE_GPR;
import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_DOUBLE;
import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_DOUBLE;
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.jikesrvm.runtime.Magic;
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;
public BaselineGCMapIterator(AddressArray registerLocations) {
super(registerLocations);
bridgeData = new ArchBridgeDataExtractor();
}
/**
* 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 occurrance 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) compiledMethod.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;
short location = convertIndexToLocation(JSRindex);
if (BaselineCompilerImpl.isRegister(location)) {
nextCallerAddress = registerLocations.get(location);
} else {
nextCallerAddress =
framePtr.plus(BaselineCompilerImpl.locationToOffset(location) -
BYTES_IN_ADDRESS); //location offsets are positioned on top of stackslot
}
nextCallerAddress = nextCallerAddress.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(currentMethod);
VM.sysWriteln(".");
}
bridgeData.setupDynamicBridgeMapping(currentMethod, fp);
reset();
}
@Override
protected void resetArchitectureSpecificBridgeSState() {
bridgeData.resetBridgeRegisterIndex();
bridgeData.setBridgeRegisterLocation(framePtr.loadAddress());
// point to first saved gpr
bridgeData.decBrigeRegisterLocation(BYTES_IN_DOUBLE * (LAST_NONVOLATILE_FPR.value() - FIRST_VOLATILE_FPR.value() + 1) +
BYTES_IN_ADDRESS * (LAST_NONVOLATILE_GPR.value() - FIRST_VOLATILE_GPR.value() + 1));
// get to my caller's frameptr and then walk up to the spill area
Address callersFP = Magic.getCallerFramePointer(framePtr);
bridgeData.resetBridgeSpilledParamLocation(callersFP);
}
/**
* given a index in the local area (biased : local0 has index 1)
* this routine determines the correspondig offset in the stack
*/
public short convertIndexToLocation(int index) {
if (index == 0) return 0;
if (index <= currentNumLocals) { //index is biased by 1;
//register (positive value) or stacklocation (negative value)
return currentCompiledMethod.getGeneralLocalLocation(index - 1);
} else {
//locations must point to the top of the slot
return currentCompiledMethod.getGeneralStackLocation(index - 1 - currentNumLocals);
}
}
@Override
public Address getNextReferenceAddress() {
if (!mapReader.isFinishedWithRegularMap()) {
mapReader.updateMapIndex();
if (VM.TraceStkMaps || TRACE_ALL) {
VM.sysWrite("BaselineGCMapIterator getNextReferenceIndex = ");
VM.sysWrite(mapReader.getMapIndex());
VM.sysWriteln(".");
if (mapReader.currentMapIsForJSR()) {
VM.sysWriteln("Index is a JSR return address ie internal pointer.");
}
}
if (mapReader.currentMapHasMorePointers()) {
short location = convertIndexToLocation(mapReader.getMapIndex());
if (VM.TraceStkMaps || TRACE_ALL) {
VM.sysWrite("BaselineGCMapIterator getNextReference location = ");
VM.sysWrite(location);
VM.sysWriteln();
}
if (BaselineCompilerImpl.isRegister(location)) {
return registerLocations.get(location);
} else {
return framePtr.plus(BaselineCompilerImpl.locationToOffset(location) -
BYTES_IN_ADDRESS); //location offsets are positioned on top of stackslot
}
} 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 (bridgeData.needsBridgeRegisterLocationsUpdate()) {
// point registerLocations[] to our callers stackframe
//
Address location = framePtr.plus(currentCompiledMethod.getFrameSize());
location = location.minus((LAST_NONVOLATILE_FPR.value() - FIRST_VOLATILE_FPR.value() + 1) * BYTES_IN_DOUBLE);
// skip non-volatile and volatile fprs
for (int i = LAST_NONVOLATILE_GPR.value(); i >= FIRST_VOLATILE_GPR.value(); --i) {
location = location.minus(BYTES_IN_ADDRESS);
registerLocations.set(i, location);
}
bridgeData.setBridgeRegistersLocationUpdated();
}
if (bridgeData.hasUnprocessedImplicitThis()) {
return bridgeData.getImplicitThisAddress();
}
// now the remaining parameters
//
while (bridgeData.hasMoreBridgeParameters()) {
return bridgeData.getNextBridgeParameterAddress();
}
}
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 getNextReturnAddressIndex = ");
VM.sysWrite(mapReader.getMapIndex());
VM.sysWriteln(".");
}
if (!mapReader.currentMapHasMorePointers()) return Address.zero();
short location = convertIndexToLocation(mapReader.getMapIndex());
if (VM.TraceStkMaps || TRACE_ALL) {
VM.sysWrite("BaselineGCMapIterator getNextReturnAddress location = ");
VM.sysWrite(location);
VM.sysWriteln(".");
}
if (BaselineCompilerImpl.isRegister(location)) {
return registerLocations.get(location);
} else {
return framePtr.plus(BaselineCompilerImpl.locationToOffset(location) -
BYTES_IN_ADDRESS); //location offsets are positioned on top of stackslot
}
}
@Override
public void cleanupPointers() {
// Make sure that the registerLocation array is updated with the
// locations where this method cached its callers registers.
// [[Yuck. I hate having to do this here, but it seems to be the
// only safe way to do this...]]
updateCallerRegisterLocations();
super.cleanupPointers();
}
private void updateCallerRegisterLocations() {
//dynamic bridge's registers already restored by calls to getNextReferenceAddress()
if (!currentMethod.getDeclaringClass().hasDynamicBridgeAnnotation()) {
if (VM.TraceStkMaps || TRACE_ALL) VM.sysWriteln(" Update Caller RegisterLocations");
Address addr = framePtr.plus(currentCompiledMethod.getFrameSize());
addr =
addr.minus((currentCompiledMethod.getLastFloatStackRegister() - FIRST_FLOAT_LOCAL_REGISTER.value() + 1) <<
LOG_BYTES_IN_DOUBLE); //skip float registers
for (int i = currentCompiledMethod.getLastFixedStackRegister(); i >= FIRST_FIXED_LOCAL_REGISTER.value(); --i) {
addr = addr.minus(BYTES_IN_ADDRESS);
registerLocations.set(i, addr);
}
}
}
}