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