use of org.jikesrvm.compilers.common.CompiledMethod in project JikesRVM by JikesRVM.
the class OptExecutionStateExtractor method extractState.
@Override
public ExecutionState extractState(RVMThread thread, Offset osrFPoff, Offset methFPoff, int cmid) {
/* perform machine and compiler dependent operations here
* osrFPoff is the fp offset of
* OptSaveVolatile.threadSwithFrom<...>
*
* (stack grows downward)
* foo
* |-> <-- methFPoff
* |
* | <tsfrom>
* |-- <-- osrFPoff
*
*
* The threadSwitchFrom method saves all volatiles, nonvolatiles, and
* scratch registers. All register values for 'foo' can be obtained
* from the register save area of '<tsfrom>' method.
*/
byte[] stack = thread.getStack();
// get registers for the caller ( real method )
TempRegisters registers = new TempRegisters(thread.getContextRegisters());
if (VM.VerifyAssertions) {
int foocmid = Magic.getIntAtOffset(stack, methFPoff.plus(STACKFRAME_METHOD_ID_OFFSET));
if (foocmid != cmid) {
CompiledMethod cm = CompiledMethods.getCompiledMethod(cmid);
VM.sysWriteln("unmatch method, it should be " + cm.getMethod());
CompiledMethod foo = CompiledMethods.getCompiledMethod(foocmid);
VM.sysWriteln("but now it is " + foo.getMethod());
walkOnStack(stack, osrFPoff);
}
VM._assert(foocmid == cmid);
}
OptCompiledMethod fooCM = (OptCompiledMethod) CompiledMethods.getCompiledMethod(cmid);
/* Following code get the machine code offset to the
* next instruction. All operation of the stack frame
* are kept in GC critical section.
* All code in the section should not cause any GC
* activities, and avoid lazy compilation.
*/
/* Following code is architecture dependent. In IA32, the return address
* saved in caller stack frames, so use osrFP to get the next instruction
* address of foo
*/
// get the next machine code offset of the real method
VM.disableGC();
Address osrFP = Magic.objectAsAddress(stack).plus(osrFPoff);
Address nextIP = Magic.getReturnAddressUnchecked(osrFP);
Offset ipOffset = fooCM.getInstructionOffset(nextIP);
VM.enableGC();
EncodedOSRMap fooOSRMap = fooCM.getOSRMap();
/* get register reference map from OSR map
* we are using this map to convert addresses to objects,
* thus we can operate objects out of GC section.
*/
int regmap = fooOSRMap.getRegisterMapForMCOffset(ipOffset);
{
int bufCMID = Magic.getIntAtOffset(stack, osrFPoff.plus(STACKFRAME_METHOD_ID_OFFSET));
CompiledMethod bufCM = CompiledMethods.getCompiledMethod(bufCMID);
// SaveVolatile can only be compiled by OPT compiler
if (VM.VerifyAssertions)
VM._assert(bufCM instanceof OptCompiledMethod);
restoreValuesFromOptSaveVolatile(stack, osrFPoff, registers, regmap, bufCM);
}
// return a list of states: from caller to callee
// if the osr happens in an inlined method, the state is
// a chain of recoverd methods.
ExecutionState state = getExecStateSequence(thread, stack, ipOffset, methFPoff, cmid, osrFPoff, registers, fooOSRMap);
// reverse callerState points, it becomes callee -> caller
ExecutionState prevState = null;
ExecutionState nextState = state;
while (nextState != null) {
// 1. current node
state = nextState;
// 1. hold the next state first
nextState = nextState.callerState;
// 2. redirect pointer
state.callerState = prevState;
// 3. move prev to current
prevState = state;
}
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("OptExecState : recovered states " + thread.toString());
ExecutionState temp = state;
do {
VM.sysWriteln(temp.toString());
temp = temp.callerState;
} while (temp != null);
}
return state;
}
use of org.jikesrvm.compilers.common.CompiledMethod in project JikesRVM by JikesRVM.
the class BaselineExecutionStateExtractor method extractState.
@Override
public ExecutionState extractState(RVMThread thread, Offset tsFromFPoff, Offset methFPoff, int cmid) {
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("BASE execStateExtractor starting ...");
}
AbstractRegisters contextRegisters = thread.getContextRegisters();
byte[] stack = thread.getStack();
if (VM.VerifyAssertions) {
int fooCmid = Magic.getIntAtOffset(stack, methFPoff.plus(STACKFRAME_METHOD_ID_OFFSET));
VM._assert(fooCmid == cmid);
}
ArchBaselineCompiledMethod fooCM = (ArchBaselineCompiledMethod) CompiledMethods.getCompiledMethod(cmid);
NormalMethod fooM = (NormalMethod) fooCM.getMethod();
// get the next bc index
VM.disableGC();
Address rowIP = Magic.objectAsAddress(stack).loadAddress(methFPoff.plus(STACKFRAME_RETURN_ADDRESS_OFFSET));
Offset ipOffset = fooCM.getInstructionOffset(rowIP);
VM.enableGC();
// CAUTION: IP Offset should point to next instruction
int bcIndex = fooCM.findBytecodeIndexForInstruction(ipOffset.plus(INSTRUCTION_WIDTH));
// assertions
if (VM.VerifyAssertions)
VM._assert(bcIndex != -1);
// create execution state object
ExecutionState state = new ExecutionState(thread, methFPoff, cmid, bcIndex, tsFromFPoff);
/* extract values for local and stack, but first of all
* we need to get type information for current PC.
*/
BytecodeTraverser typer = new BytecodeTraverser();
typer.computeLocalStackTypes(fooM, bcIndex);
byte[] localTypes = typer.getLocalTypes();
byte[] stackTypes = typer.getStackTypes();
// type. We should remove non-reference type
for (int i = 0, n = localTypes.length; i < n; i++) {
// if typer reports a local is reference type, but the GC map says no
// then set the localType to uninitialized, see VM spec, bytecode verifier
// CAUTION: gc map uses mc offset in bytes!!!
boolean gcref = fooCM.referenceMaps.isLocalRefType(fooM, ipOffset.plus(INSTRUCTION_WIDTH), i);
if (!gcref && (localTypes[i] == ClassTypeCode)) {
// use gc map as reference
localTypes[i] = VoidTypeCode;
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("GC maps disgrees with type matcher at " + i + "th local");
VM.sysWriteln();
}
}
}
if (VM.TraceOnStackReplacement) {
Offset ipIndex = ipOffset.toWord().rsha(LG_INSTRUCTION_WIDTH).toOffset();
VM.sysWriteln("BC Index : " + bcIndex);
VM.sysWriteln("IP Index : ", ipIndex.plus(1));
VM.sysWriteln("MC Offset : ", ipOffset.plus(INSTRUCTION_WIDTH));
VM.sysWrite("Local Types :");
for (byte localType : localTypes) {
VM.sysWrite(" " + (char) localType);
}
VM.sysWriteln();
VM.sysWrite("Stack Types :");
for (byte stackType : stackTypes) {
VM.sysWrite(" " + (char) stackType);
}
VM.sysWriteln();
}
// go through the stack frame and extract values
// In the variable value list, we keep the order as follows:
// L0, L1, ..., S0, S1, ....
// adjust local offset and stack offset
// NOTE: donot call BaselineCompilerImpl.getFirstLocalOffset(method)
int bufCMID = Magic.getIntAtOffset(stack, tsFromFPoff.plus(STACKFRAME_METHOD_ID_OFFSET));
CompiledMethod bufCM = CompiledMethods.getCompiledMethod(bufCMID);
int cType = bufCM.getCompilerType();
// restore non-volatile registers that could contain locals; saved by yieldpointfrom methods
// for the moment disabled OPT compilation of yieldpointfrom, because here we assume baselinecompilation !! TODO
TempRegisters registers = new TempRegisters(contextRegisters);
WordArray gprs = registers.gprs;
double[] fprs = registers.fprs;
Object[] objs = registers.objs;
VM.disableGC();
// the threadswitchfrom... method on the other hand can be baseline or opt!
if (cType == CompiledMethod.BASELINE) {
if (VM.VerifyAssertions) {
VM._assert(bufCM.getMethod().hasBaselineSaveLSRegistersAnnotation());
VM._assert(methFPoff.EQ(tsFromFPoff.plus(((ArchBaselineCompiledMethod) bufCM).getFrameSize())));
}
Offset currentRegisterLocation = tsFromFPoff.plus(((ArchBaselineCompiledMethod) bufCM).getFrameSize());
for (int i = LAST_FLOAT_STACK_REGISTER.value(); i >= FIRST_FLOAT_LOCAL_REGISTER.value(); --i) {
currentRegisterLocation = currentRegisterLocation.minus(BYTES_IN_DOUBLE);
long lbits = Magic.getLongAtOffset(stack, currentRegisterLocation);
fprs[i] = Magic.longBitsAsDouble(lbits);
}
for (int i = LAST_FIXED_STACK_REGISTER.value(); i >= FIRST_FIXED_LOCAL_REGISTER.value(); --i) {
currentRegisterLocation = currentRegisterLocation.minus(BYTES_IN_ADDRESS);
Word w = Magic.objectAsAddress(stack).loadWord(currentRegisterLocation);
gprs.set(i, w);
}
} else {
// (cType == CompiledMethod.OPT)
// KV: this code needs to be modified. We need the tsFrom methods to save all NON-VOLATILES in their prolog (as is the case for baseline)
// This is because we don't know at compile time which registers might be in use and wich not by the caller method at runtime!!
// For now we disallow tsFrom methods to be opt compiled when the caller is baseline compiled
// todo: fix this together with the SaveVolatile rewrite
OptCompiledMethod fooOpt = (OptCompiledMethod) bufCM;
// foo definitely not save volatile.
if (VM.VerifyAssertions) {
boolean saveVolatile = fooOpt.isSaveVolatile();
VM._assert(!saveVolatile);
}
Offset offset = tsFromFPoff.plus(fooOpt.getUnsignedNonVolatileOffset());
// recover nonvolatile GPRs
int firstGPR = fooOpt.getFirstNonVolatileGPR();
if (firstGPR != -1) {
for (int i = firstGPR; i <= LAST_NONVOLATILE_GPR.value(); i++) {
Word w = Magic.objectAsAddress(stack).loadWord(offset);
gprs.set(i, w);
offset = offset.plus(BYTES_IN_ADDRESS);
}
}
// recover nonvolatile FPRs
int firstFPR = fooOpt.getFirstNonVolatileFPR();
if (firstFPR != -1) {
for (int i = firstFPR; i <= LAST_NONVOLATILE_FPR.value(); i++) {
long lbits = Magic.getLongAtOffset(stack, offset);
fprs[i] = Magic.longBitsAsDouble(lbits);
offset = offset.plus(BYTES_IN_DOUBLE);
}
}
}
// save objects in registers in register object array
int size = localTypes.length;
for (int i = 0; i < size; i++) {
if ((localTypes[i] == ClassTypeCode) || (localTypes[i] == ArrayTypeCode)) {
short loc = fooCM.getGeneralLocalLocation(i);
if (BaselineCompilerImpl.isRegister(loc)) {
objs[loc] = Magic.addressAsObject(gprs.get(loc).toAddress());
}
}
}
VM.enableGC();
// for locals
getVariableValueFromLocations(stack, methFPoff, localTypes, fooCM, LOCAL, registers, state);
// for stacks
Offset stackOffset = methFPoff.plus(fooCM.getEmptyStackOffset());
getVariableValue(stack, stackOffset, stackTypes, fooCM, STACK, state);
if (VM.TraceOnStackReplacement) {
state.printState();
}
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("BASE executionStateExtractor done ");
}
return state;
}
use of org.jikesrvm.compilers.common.CompiledMethod in project JikesRVM by JikesRVM.
the class CodeInstaller method install.
/* install the newly compiled instructions. */
public static boolean install(ExecutionState state, CompiledMethod cm) {
RVMThread thread = state.getThread();
byte[] stack = thread.getStack();
Offset fooFPOffset = state.getFPOffset();
// we are going to dynamically generate some code recover
// register values from the stack frame.
int foomid = Magic.getIntAtOffset(stack, fooFPOffset.plus(STACKFRAME_METHOD_ID_OFFSET));
CompiledMethod foo = CompiledMethods.getCompiledMethod(foomid);
int cType = foo.getCompilerType();
Assembler asm = new Assembler(0, VM.TraceOnStackReplacement);
// ///////////////////////////////////
if (cType == CompiledMethod.BASELINE) {
ArchBaselineCompiledMethod bcm = (ArchBaselineCompiledMethod) foo;
int offset = bcm.getFrameSize();
for (int i = bcm.getLastFloatStackRegister(); i >= FIRST_FLOAT_LOCAL_REGISTER.value(); --i) {
offset -= BYTES_IN_DOUBLE;
asm.emitLFD(FPR.lookup(i), offset, FP);
}
for (int i = bcm.getLastFixedStackRegister(); i >= FIRST_FIXED_LOCAL_REGISTER.value(); --i) {
offset -= BYTES_IN_ADDRESS;
asm.emitLAddr(GPR.lookup(i), offset, FP);
}
} else if (cType == CompiledMethod.OPT) {
OptCompiledMethod fooOpt = (OptCompiledMethod) foo;
// foo definitely not save volatile.
boolean saveVolatile = fooOpt.isSaveVolatile();
if (VM.VerifyAssertions) {
VM._assert(!saveVolatile);
}
int offset = fooOpt.getUnsignedNonVolatileOffset();
// recover nonvolatile GPRs
int firstGPR = fooOpt.getFirstNonVolatileGPR();
if (firstGPR != -1) {
for (int i = firstGPR; i <= LAST_NONVOLATILE_GPR.value(); i++) {
asm.emitLAddr(GPR.lookup(i), offset, FP);
offset += BYTES_IN_STACKSLOT;
}
}
// recover nonvolatile FPRs
int firstFPR = fooOpt.getFirstNonVolatileFPR();
if (firstFPR != -1) {
for (int i = firstFPR; i <= LAST_NONVOLATILE_FPR.value(); i++) {
asm.emitLFD(FPR.lookup(i), offset, FP);
offset += BYTES_IN_DOUBLE;
}
}
}
if (VM.VerifyAssertions) {
Object jtocContent = Statics.getSlotContentsAsObject(cm.getOsrJTOCoffset());
VM._assert(jtocContent == cm.getEntryCodeArray());
}
// load address of newInstructions from JTOC
asm.emitLAddrToc(S0, cm.getOsrJTOCoffset());
// mov CTR addr
asm.emitMTCTR(S0);
// lwz FP, 0(FP)
asm.emitLAddr(FP, 0, FP);
// lwz T0, NEXT_INSTR(FP)
asm.emitLAddr(S0, STACKFRAME_RETURN_ADDRESS_OFFSET.toInt(), FP);
// mov LR, addr
asm.emitMTLR(S0);
// bctr
asm.emitBCCTR();
// mark the thread as waiting for on stack replacement.
thread.isWaitingForOsr = true;
thread.bridgeInstructions = asm.getMachineCodes();
thread.fooFPOffset = fooFPOffset;
Address bridgeaddr = Magic.objectAsAddress(thread.bridgeInstructions);
Memory.sync(bridgeaddr, thread.bridgeInstructions.length() << LG_INSTRUCTION_WIDTH);
AOSLogging.logger.logOsrEvent("OSR code installation succeeded");
return true;
}
use of org.jikesrvm.compilers.common.CompiledMethod in project JikesRVM by JikesRVM.
the class OSRProfiler method invalidateState.
// invalidate an execution state
private static synchronized void invalidateState(ExecutionState state) {
// step 1: invalidate the compiled method with this OSR assumption
// how does this affect the performance?
CompiledMethod mostRecentlyCompiledMethod = CompiledMethods.getCompiledMethod(state.cmid);
if (VM.VerifyAssertions) {
VM._assert(mostRecentlyCompiledMethod.getMethod() == state.meth);
}
// be invalidated in more than one thread at the same time
if (mostRecentlyCompiledMethod != state.meth.getCurrentCompiledMethod()) {
return;
}
// make sure the compiled method is an opt one
if (!(mostRecentlyCompiledMethod instanceof OptCompiledMethod)) {
return;
}
// reset the compiled method to null first, if other thread invokes
// this method before following opt recompilation, it can avoid OSR
state.meth.invalidateCompiledMethod(mostRecentlyCompiledMethod);
// a list of state from callee -> caller
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("OSR " + OSRProfiler.invalidations + " : " + state.bcIndex + "@" + state.meth);
}
// simply reset the compiled method to null is not good
// for long run loops, because invalidate may cause
// the method falls back to the baseline again...
// NOW, we look for the previous compilation plan, and reuse
// the compilation plan.
boolean recmplsucc = false;
if (Controller.enabled) {
CompilationPlan cmplplan = null;
if (Controller.options.ENABLE_PRECOMPILE && CompilerAdviceAttribute.hasAdvice()) {
CompilerAdviceAttribute attr = CompilerAdviceAttribute.getCompilerAdviceInfo(state.meth);
if (VM.VerifyAssertions) {
VM._assert(attr.getCompiler() == CompiledMethod.OPT);
}
if (Controller.options.counters()) {
// for invocation counter, we only use one optimization level
cmplplan = InvocationCounts.createCompilationPlan(state.meth);
} else {
// for now there is not two options for sampling, so
// we don't have to use: if (Controller.options.sampling())
cmplplan = Controller.recompilationStrategy.createCompilationPlan(state.meth, attr.getOptLevel(), null);
}
} else {
ControllerPlan ctrlplan = ControllerMemory.findMatchingPlan(mostRecentlyCompiledMethod);
if (ctrlplan != null) {
cmplplan = ctrlplan.getCompPlan();
}
}
if (cmplplan != null) {
if (VM.VerifyAssertions) {
VM._assert(cmplplan.getMethod() == state.meth);
}
// for invalidated method, we do not perform OSR guarded inlining anymore.
// the Options object may be shared by several methods,
// we have to reset it back
boolean savedOsr = cmplplan.options.OSR_GUARDED_INLINING;
cmplplan.options.OSR_GUARDED_INLINING = false;
int newcmid = RuntimeCompiler.recompileWithOpt(cmplplan);
cmplplan.options.OSR_GUARDED_INLINING = savedOsr;
if (newcmid != -1) {
AOSLogging.logger.debug("recompiling state with opt succeeded " + state.cmid);
AOSLogging.logger.debug("new cmid " + newcmid);
// transfer hotness to the new cmid
double oldSamples = Controller.methodSamples.getData(state.cmid);
Controller.methodSamples.reset(state.cmid);
Controller.methodSamples.augmentData(newcmid, oldSamples);
recmplsucc = true;
if (VM.TraceOnStackReplacement) {
VM.sysWriteln(" recompile " + state.meth + " at -O" + cmplplan.options.getOptLevel());
}
}
}
}
if (!recmplsucc) {
int newcmid = RuntimeCompiler.recompileWithOpt(state.meth);
if (newcmid == -1) {
if (VM.TraceOnStackReplacement) {
VM.sysWriteln(" opt recompilation failed!");
}
state.meth.invalidateCompiledMethod(mostRecentlyCompiledMethod);
}
}
if (VM.TraceOnStackReplacement) {
VM.sysWriteln(" opt recompilation done!");
}
}
use of org.jikesrvm.compilers.common.CompiledMethod in project JikesRVM by JikesRVM.
the class SpecialCompiler method optCompile.
/**
* <ol>
* <li>generate prologue PSEUDO_bytecode from the state.
* <li>make new bytecodes with prologue.
* <li>set method's bytecode to specialized one.
* <li>adjust exception map, line number map.
* <li>compile the method.
* <li>restore bytecode, exception, linenumber map to the original one.
* </ol>
*
* @param state the execution state for the compilation
* @return the compiled method produced by the optimizing compiler
*/
public static CompiledMethod optCompile(ExecutionState state) {
NormalMethod method = state.getMethod();
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("OPT : starts compiling " + method);
}
ControllerPlan latestPlan = ControllerMemory.findLatestPlan(method);
OptOptions _options = null;
if (latestPlan != null) {
_options = latestPlan.getCompPlan().options.dup();
} else {
// no previous compilation plan, a long run loop promoted from baseline.
// this only happens when testing, not in real code
_options = new OptOptions();
_options.setOptLevel(0);
}
// disable OSR points in specialized method
_options.OSR_GUARDED_INLINING = false;
CompilationPlan compPlan = new CompilationPlan(method, (OptimizationPlanElement[]) RuntimeCompiler.optimizationPlan, null, _options);
// it is also necessary to recompile the current method
// without OSR.
/* generate prologue bytes */
byte[] prologue = state.generatePrologue();
int prosize = prologue.length;
method.setForOsrSpecialization(prologue, state.getMaxStackHeight());
int[] oldStartPCs = null;
int[] oldEndPCs = null;
int[] oldHandlerPCs = null;
/* adjust exception table. */
{
// if (VM.TraceOnStackReplacement) {
// VM.sysWriteln("OPT adjust exception table.");
// }
ExceptionHandlerMap exceptionHandlerMap = method.getExceptionHandlerMap();
if (exceptionHandlerMap != null) {
oldStartPCs = exceptionHandlerMap.getStartPC();
oldEndPCs = exceptionHandlerMap.getEndPC();
oldHandlerPCs = exceptionHandlerMap.getHandlerPC();
int n = oldStartPCs.length;
int[] newStartPCs = new int[n];
System.arraycopy(oldStartPCs, 0, newStartPCs, 0, n);
exceptionHandlerMap.setStartPC(newStartPCs);
int[] newEndPCs = new int[n];
System.arraycopy(oldEndPCs, 0, newEndPCs, 0, n);
exceptionHandlerMap.setEndPC(newEndPCs);
int[] newHandlerPCs = new int[n];
System.arraycopy(oldHandlerPCs, 0, newHandlerPCs, 0, n);
exceptionHandlerMap.setHandlerPC(newHandlerPCs);
for (int i = 0; i < n; i++) {
newStartPCs[i] += prosize;
newEndPCs[i] += prosize;
newHandlerPCs[i] += prosize;
}
}
}
CompiledMethod newCompiledMethod = RuntimeCompiler.recompileWithOptOnStackSpecialization(compPlan);
// restore original bytecode, exception table, and line number table
method.finalizeOsrSpecialization();
{
ExceptionHandlerMap exceptionHandlerMap = method.getExceptionHandlerMap();
if (exceptionHandlerMap != null) {
exceptionHandlerMap.setStartPC(oldStartPCs);
exceptionHandlerMap.setEndPC(oldEndPCs);
exceptionHandlerMap.setHandlerPC(oldHandlerPCs);
}
}
// reverse back to the baseline
if (newCompiledMethod == null) {
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("OPT : fialed, because compilation in progress, " + "fall back to baseline");
}
return baselineCompile(state);
}
// mark the method is a specialized one
newCompiledMethod.setSpecialForOSR();
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("OPT : done");
VM.sysWriteln();
}
return newCompiledMethod;
}
Aggregations