/* * 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.osr.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.BaselineConstants.FP; import static org.jikesrvm.ppc.BaselineConstants.S0; import static org.jikesrvm.ppc.RegisterConstants.LAST_NONVOLATILE_FPR; import static org.jikesrvm.ppc.RegisterConstants.LAST_NONVOLATILE_GPR; import static org.jikesrvm.ppc.RegisterConstants.LG_INSTRUCTION_WIDTH; import static org.jikesrvm.ppc.StackframeLayoutConstants.BYTES_IN_STACKSLOT; import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_METHOD_ID_OFFSET; import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_RETURN_ADDRESS_OFFSET; import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_DOUBLE; import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS; import org.jikesrvm.VM; import org.jikesrvm.adaptive.util.AOSLogging; import org.jikesrvm.compilers.baseline.ppc.ArchBaselineCompiledMethod; import org.jikesrvm.compilers.common.CompiledMethod; import org.jikesrvm.compilers.common.CompiledMethods; import org.jikesrvm.compilers.common.assembler.ppc.Assembler; import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod; import org.jikesrvm.osr.ExecutionState; import org.jikesrvm.ppc.RegisterConstants.FPR; import org.jikesrvm.ppc.RegisterConstants.GPR; import org.jikesrvm.runtime.Magic; import org.jikesrvm.runtime.Memory; import org.jikesrvm.runtime.Statics; import org.jikesrvm.scheduler.RVMThread; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; /** * CodeInstaller adjusts registers and return address to make a * specialized thread as a normal thread get scheduled. The method * prologue ( machine code ) is adjusted to cooperate with the code * installer. */ public abstract class CodeInstaller { /* 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); ///////////////////////////////////// ////// recover saved registers. ///////////////////////////////////// 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; } }