/*
* 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;
import org.jikesrvm.classloader.MethodReference;
import org.jikesrvm.classloader.NormalMethod;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.common.CompiledMethod;
import org.jikesrvm.runtime.DynamicLink;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Offset;
/**
* This class provides a skeleton for extracting data from dynamic bridge
* frames for the GC map iterators. It contains the common functionality
* required by all currently implemented architectures.
* <p>
* Subclasses must implement the actual extraction of the data. They
* may also provide tracing.
*/
@Uninterruptible
public abstract class AbstractBridgeDataExtractor {
/** the current method */
protected NormalMethod currentMethod;
/** place to keep info returned by CompiledMethod.getDynamicLink */
protected DynamicLink dynamicLink;
/** method to be invoked via dynamic bridge ({@code null}: current frame is not a dynamic bridge) */
protected MethodReference bridgeTarget;
/** parameter types passed by that method */
protected TypeReference[] bridgeParameterTypes;
/** have all bridge parameters been mapped yet? */
protected boolean bridgeParameterMappingRequired;
/** have the register location been updated? */
protected boolean bridgeRegistersLocationUpdated;
/** first parameter to be mapped (-1 == "this") */
protected int bridgeParameterInitialIndex;
/** current parameter being mapped (-1 == "this") */
protected int bridgeParameterIndex;
/** memory address at which that register was saved */
protected Address bridgeRegisterLocation;
/** current spilled param location */
protected Address bridgeSpilledParamLocation;
protected AbstractBridgeDataExtractor() {
dynamicLink = new DynamicLink();
}
protected void initForMethod(NormalMethod nm) {
currentMethod = nm;
bridgeTarget = null;
bridgeParameterTypes = null;
bridgeParameterMappingRequired = false;
bridgeRegistersLocationUpdated = false;
bridgeParameterIndex = 0;
bridgeRegisterLocation = Address.zero();
bridgeSpilledParamLocation = Address.zero();
}
public final void setupDynamicBridgeMapping(NormalMethod method, Address fp) {
initForMethod(method);
setupBridgeRegisterIndex();
if (currentMethod.getDeclaringClass().hasDynamicBridgeAnnotation()) {
setupArchitectureSpecificDynamicBridgeMapping(fp);
}
}
protected abstract void setupArchitectureSpecificDynamicBridgeMapping(Address fp);
protected abstract void setupBridgeRegisterIndex();
public final boolean hasBridgeInfo() {
return bridgeTarget != null;
}
/**
* @return {@code true} if there is still an implicit this
* parameter that needs to be processed, {@code false} otherwise
*
* @see #getImplicitThisAddress()
*/
public final boolean hasUnprocessedImplicitThis() {
return bridgeParameterIndex == -1;
}
public final boolean hasMoreBridgeParameters() {
return bridgeParameterIndex < bridgeParameterTypes.length;
}
public final boolean isBridgeParameterMappingRequired() {
return bridgeParameterMappingRequired;
}
public final boolean needsBridgeRegisterLocationsUpdate() {
return !bridgeRegistersLocationUpdated;
}
public final void setBridgeRegistersLocationUpdated() {
this.bridgeRegistersLocationUpdated = true;
}
public final void setBridgeRegisterLocation(Address bridgeRegisterLocation) {
this.bridgeRegisterLocation = bridgeRegisterLocation;
}
public final void decBrigeRegisterLocation(int bytes) {
bridgeRegisterLocation = bridgeRegisterLocation.minus(bytes);
}
protected final void incBrigeRegisterLocation(int bytes) {
bridgeRegisterLocation = bridgeRegisterLocation.plus(bytes);
}
protected final void cleanupPointers() {
bridgeTarget = null;
bridgeParameterTypes = null;
}
protected final void updateWithInfoForDynamicLink(CompiledMethod callingCompiledMethod, Offset callingInstructionOffset) {
callingCompiledMethod.getDynamicLink(dynamicLink, callingInstructionOffset);
bridgeTarget = dynamicLink.methodRef();
bridgeParameterTypes = bridgeTarget.getParameterTypes();
if (dynamicLink.isInvokedWithImplicitThisParameter()) {
bridgeParameterInitialIndex = -1;
} else {
bridgeParameterInitialIndex = 0;
}
}
public abstract void resetBridgeRegisterIndex();
protected abstract void incBridgeRegisterIndex();
/**
* Checks if any unprocessed bridge <em>registers</em>
* remain. When all bridge registers are processed, there
* may still be spilled values that need to be processed.
* It is the responsibility of the subclasses to handle those.
*
* @return {@code true} if any unprocessed bridge <em>registers</em>
* remain
*/
protected abstract boolean unprocessedBridgeRegistersRemain();
protected final void reset() {
bridgeParameterMappingRequired = true;
bridgeParameterIndex = bridgeParameterInitialIndex;
}
/**
* Resets the spilled param location in an architecture-specific way,
* based on the given address.
*
* @param addr the address to use for the computation
*/
public abstract void resetBridgeSpilledParamLocation(Address addr);
/**
* NOTE: it is the responsibility of the caller to check
* that the method actually has an implicit this parameter
* and that it still needs to be processed.
*
* @return the address of the implicit this parameter
* @see #hasUnprocessedImplicitThis()
*/
public abstract Address getImplicitThisAddress();
/**
* @return the address of the next bridge parameter or
* {@code Address.zero()} if no parameters are left
*/
public abstract Address getNextBridgeParameterAddress();
}