use of org.jikesrvm.classloader.NormalMethod in project JikesRVM by JikesRVM.
the class StackTrace method buildStackTrace.
private Element[] buildStackTrace(int first, int last) {
Element[] elements = new Element[countFrames(first, last)];
if (!VM.BuildForOptCompiler) {
int element = 0;
for (int i = first; i <= last; i++) {
elements[element] = createStandardStackTraceElement(getCompiledMethod(i), instructionOffsets[i]);
element++;
}
} else {
int element = 0;
for (int i = first; i <= last; i++) {
CompiledMethod compiledMethod = getCompiledMethod(i);
if ((compiledMethod == null) || (compiledMethod.getCompilerType() != CompiledMethod.OPT)) {
// Invisible or non-opt compiled method
elements[element] = createStandardStackTraceElement(compiledMethod, instructionOffsets[i]);
element++;
} else {
Offset instructionOffset = Offset.fromIntSignExtend(instructionOffsets[i]);
OptCompiledMethod optInfo = (OptCompiledMethod) compiledMethod;
OptMachineCodeMap map = optInfo.getMCMap();
int iei = map.getInlineEncodingForMCOffset(instructionOffset);
if (iei < 0) {
elements[element] = createStandardStackTraceElement(compiledMethod, instructionOffsets[i]);
element++;
} else {
int[] inlineEncoding = map.inlineEncoding;
int bci = map.getBytecodeIndexForMCOffset(instructionOffset);
for (; iei >= 0; iei = OptEncodedCallSiteTree.getParent(iei, inlineEncoding)) {
int mid = OptEncodedCallSiteTree.getMethodID(iei, inlineEncoding);
RVMMethod method = MemberReference.getMethodRef(mid).getResolvedMember();
int lineNumber = ((NormalMethod) method).getLineNumberForBCIndex(bci);
elements[element] = createOptStackTraceElement(method, lineNumber, instructionOffset, bci);
element++;
if (iei > 0) {
bci = OptEncodedCallSiteTree.getByteCodeOffset(iei, inlineEncoding);
}
}
}
}
}
}
return elements;
}
use of org.jikesrvm.classloader.NormalMethod 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.classloader.NormalMethod 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;
}
use of org.jikesrvm.classloader.NormalMethod in project JikesRVM by JikesRVM.
the class SpecialCompiler method baselineCompile.
/**
* Compiles the method with the baseline compiler.
* <ol>
* <li>generate prologue (PSEUDO_bytecode) from the state.
* <li>make up new byte code with prologue.
* <li>set method's bytecode to the specilizaed byte code.
* <li>call BaselineCompilerImpl.compile,
* the 'compile' method is customized to process pseudo instructions,
* and it will reset the byte code to the original one, and adjust
* the map from bytecode to the generated machine code. then the
* reference map can be generated corrected relying on the original
* bytecode.
* </ol>
* <p>
* NOTE: this is different from optCompile which resets the
* bytecode after compilation. I believe this minimizes the
* work to change both compilers.
* @param state the execution state for the compilation
* @return the compiled method produced by the baseline compiler
*/
public static CompiledMethod baselineCompile(ExecutionState state) {
NormalMethod method = state.getMethod();
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("BASE : starts compiling " + method);
}
/* generate prologue bytes */
byte[] prologue = state.generatePrologue();
if (VM.TraceOnStackReplacement) {
VM.sysWriteln("prologue length " + prologue.length);
}
// the compiler will call setForOsrSpecialization after generating the reference map
/* set a flag for specialization, compiler will see it, and
* know how to do it properly.
*/
method.setForOsrSpecialization(prologue, state.getMaxStackHeight());
/* for baseline compilation, we do not adjust the exception table and line table
* because the compiler will generate maps after compilation.
* Any necessary adjustment should be made during the compilation
*/
CompiledMethod newCompiledMethod;
if (VM.BuildForIA32) {
newCompiledMethod = org.jikesrvm.compilers.baseline.ia32.BaselineCompilerImpl.compile(method);
} else {
if (VM.VerifyAssertions)
VM._assert(VM.BuildForPowerPC);
newCompiledMethod = org.jikesrvm.compilers.baseline.ppc.BaselineCompilerImpl.compile(method);
}
// compiled method was already set by BaselineCompilerImpl.compile
// the call here does nothing
// method.finalizeOsrSpecialization();
// mark the method is a specialized one
newCompiledMethod.setSpecialForOSR();
if (VM.TraceOnStackReplacement) {
// ((BaselineCompiledMethod)newCompiledMethod).printCodeMapEntries();
VM.sysWriteln("BASE : done, CMID 0x" + Integer.toHexString(newCompiledMethod.getId()) + "(" + newCompiledMethod.getId() + ") JTOC offset " + Services.addressAsHexString(newCompiledMethod.getOsrJTOCoffset().toWord().toAddress()));
}
return newCompiledMethod;
}
use of org.jikesrvm.classloader.NormalMethod in project JikesRVM by JikesRVM.
the class BaselineCompiledMethod method encodeMappingInfo.
/**
* Encode/compress the bytecode map, reference (GC) map and exception table
*
* @param referenceMaps to encode
* @param bcMap unencoded bytecode to code array offset map
*/
public void encodeMappingInfo(ReferenceMaps referenceMaps, int[] bcMap) {
int count = 0;
int lastBC = 0, lastIns = 0;
for (int i = 0; i < bcMap.length; i++) {
if (bcMap[i] != 0) {
int deltaBC = i - lastBC;
int deltaIns = bcMap[i] - lastIns;
if (VM.VerifyAssertions) {
VM._assert(deltaBC >= 0 && deltaIns >= 0);
}
if (deltaBC <= 6 && deltaIns <= 31) {
count++;
} else {
if (deltaBC > 65535 || deltaIns > 65535) {
VM.sysFail("BaselineCompiledMethod: a fancier encoding is needed");
}
count += 5;
}
lastBC = i;
lastIns = bcMap[i];
}
}
bytecodeMap = new byte[count];
count = lastBC = lastIns = 0;
for (int i = 0; i < bcMap.length; i++) {
if (bcMap[i] != 0) {
int deltaBC = i - lastBC;
int deltaIns = bcMap[i] - lastIns;
if (VM.VerifyAssertions) {
VM._assert(deltaBC >= 0 && deltaIns >= 0);
}
if (deltaBC <= 6 && deltaIns <= 31) {
bytecodeMap[count++] = (byte) ((deltaBC << 5) | deltaIns);
} else {
// From before, we know that deltaBC <= 65535 and deltaIns <= 65535
bytecodeMap[count++] = (byte) 255;
bytecodeMap[count++] = (byte) (deltaBC >> 8);
bytecodeMap[count++] = (byte) (deltaBC & 255);
bytecodeMap[count++] = (byte) (deltaIns >> 8);
bytecodeMap[count++] = (byte) (deltaIns & 255);
}
lastBC = i;
lastIns = bcMap[i];
}
}
// TODO: it's likely for short methods we can share the bytecodeMap
referenceMaps.translateByte2Machine(bcMap);
this.referenceMaps = referenceMaps;
ExceptionHandlerMap emap = ((NormalMethod) method).getExceptionHandlerMap();
if (emap != null) {
eTable = BaselineExceptionTable.encode(emap, bcMap);
}
}
Aggregations