001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.osr.ia32; 014 015import static org.jikesrvm.ia32.BaselineConstants.EBX_SAVE_OFFSET; 016import static org.jikesrvm.ia32.BaselineConstants.EDI_SAVE_OFFSET; 017import static org.jikesrvm.ia32.BaselineConstants.S0; 018import static org.jikesrvm.ia32.BaselineConstants.SP; 019import static org.jikesrvm.ia32.BaselineConstants.TR; 020import static org.jikesrvm.ia32.RegisterConstants.EBX; 021import static org.jikesrvm.ia32.RegisterConstants.EDI; 022import static org.jikesrvm.ia32.RegisterConstants.LG_INSTRUCTION_WIDTH; 023import static org.jikesrvm.ia32.RegisterConstants.NONVOLATILE_GPRS; 024import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_METHOD_ID_OFFSET; 025 026import org.jikesrvm.VM; 027import org.jikesrvm.adaptive.util.AOSLogging; 028import org.jikesrvm.compilers.common.CompiledMethod; 029import org.jikesrvm.compilers.common.CompiledMethods; 030import org.jikesrvm.compilers.common.assembler.ia32.Assembler; 031import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod; 032import org.jikesrvm.osr.ExecutionState; 033import org.jikesrvm.runtime.ArchEntrypoints; 034import org.jikesrvm.runtime.Magic; 035import org.jikesrvm.runtime.Memory; 036import org.jikesrvm.runtime.Statics; 037import org.jikesrvm.scheduler.RVMThread; 038import org.vmmagic.unboxed.Address; 039import org.vmmagic.unboxed.Offset; 040 041/** 042 * CodeInstaller generates a glue code which recovers registers and 043 * from the stack frames and branch to the newly compiled method instructions. 044 * The glue code is installed right before returning to the threading method 045 * by PostThreadSwitch 046 */ 047public abstract class CodeInstaller { 048 049 public static boolean install(ExecutionState state, CompiledMethod cm) { 050 RVMThread thread = state.getThread(); 051 byte[] stack = thread.getStack(); 052 053 Offset tsfromFPOffset = state.getTSFPOffset(); 054 Offset fooFPOffset = state.getFPOffset(); 055 056 int foomid = Magic.getIntAtOffset(stack, fooFPOffset.plus(STACKFRAME_METHOD_ID_OFFSET)); 057 058 CompiledMethod foo = CompiledMethods.getCompiledMethod(foomid); 059 int cType = foo.getCompilerType(); 060 061 int SW_WIDTH = 4; 062 063 // this offset is used to adjust SP to FP right after return 064 // from a call. 4 bytes for return address and 065 // 4 bytes for saved FP of tsfrom. 066 Offset sp2fpOffset = fooFPOffset.minus(tsfromFPOffset).minus(2 * SW_WIDTH); 067 068 // should given an estimated length, and print the instructions 069 // for debugging 070 Assembler asm = new Assembler(50, VM.TraceOnStackReplacement); 071 072 // 1. generate bridge instructions to recover saved registers 073 if (cType == CompiledMethod.BASELINE) { 074 075// asm.emitINT_Imm(3); // break here for debugging 076 077 // unwind stack pointer, SP is FP now 078 asm.emitADD_Reg_Imm(SP, sp2fpOffset.toInt()); 079 080 // TODO is this ok for 64-bit with JTOC in register? 081 asm.emitMOV_Reg_Abs(S0, Magic.getTocPointer().plus(cm.getOsrJTOCoffset())); 082 083 // restore saved EDI 084 asm.emitMOV_Reg_RegDisp(EDI, SP, EDI_SAVE_OFFSET); 085 // restore saved EBX 086 asm.emitMOV_Reg_RegDisp(EBX, SP, EBX_SAVE_OFFSET); 087 // restore frame pointer 088 asm.emitPOP_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset()); 089 // do not pop return address and parameters, 090 // we make a faked call to newly compiled method 091 asm.emitJMP_Reg(S0); 092 } else if (cType == CompiledMethod.OPT) { 093 /////////////////////////////////////////////////// 094 // recover saved registers from foo's stack frame 095 /////////////////////////////////////////////////// 096 OptCompiledMethod fooOpt = (OptCompiledMethod) foo; 097 098 // foo definitely not save volatile 099 boolean saveVolatile = fooOpt.isSaveVolatile(); 100 if (VM.VerifyAssertions) { 101 VM._assert(!saveVolatile); 102 } 103 104 // assume SP is on foo's stack frame, 105 int firstNonVolatile = fooOpt.getFirstNonVolatileGPR(); 106 int nonVolatiles = fooOpt.getNumberOfNonvolatileGPRs(); 107 int nonVolatileOffset = fooOpt.getUnsignedNonVolatileOffset(); 108 109 for (int i = firstNonVolatile; i < firstNonVolatile + nonVolatiles; i++) { 110 asm.emitMOV_Reg_RegDisp(NONVOLATILE_GPRS[i], SP, sp2fpOffset.minus(nonVolatileOffset)); 111 nonVolatileOffset += SW_WIDTH; 112 } 113 // adjust SP to frame pointer 114 asm.emitADD_Reg_Imm(SP, sp2fpOffset.toInt()); 115 // restore frame pointer 116 asm.emitPOP_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset()); 117 118 // branch to the newly compiled instructions 119 asm.emitJMP_Abs(Magic.getTocPointer().plus(cm.getOsrJTOCoffset())); 120 } 121 122 if (VM.TraceOnStackReplacement) { 123 VM.sysWrite("new CM instr addr "); 124 VM.sysWriteHex(Statics.getSlotContentsAsInt(cm.getOsrJTOCoffset())); 125 VM.sysWriteln(); 126 VM.sysWrite("JTOC register "); 127 VM.sysWriteHex(Magic.getTocPointer()); 128 VM.sysWriteln(); 129 VM.sysWrite("Thread register "); 130 VM.sysWriteHex(Magic.objectAsAddress(Magic.getThreadRegister())); 131 VM.sysWriteln(); 132 133 VM.sysWriteln("tsfromFPOffset ", tsfromFPOffset); 134 VM.sysWriteln("fooFPOffset ", fooFPOffset); 135 VM.sysWriteln("SP + ", sp2fpOffset.plus(4)); 136 } 137 138 // 3. set thread flags 139 thread.isWaitingForOsr = true; 140 thread.bridgeInstructions = asm.getMachineCodes(); 141 thread.fooFPOffset = fooFPOffset; 142 thread.tsFPOffset = tsfromFPOffset; 143 144 Address bridgeaddr = Magic.objectAsAddress(thread.bridgeInstructions); 145 146 Memory.sync(bridgeaddr, thread.bridgeInstructions.length() << LG_INSTRUCTION_WIDTH); 147 148 AOSLogging.logger.logOsrEvent("OSR code installation succeeded"); 149 150 return true; 151 } 152}