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.ia32; 014 015 import org.jikesrvm.ArchitectureSpecific; 016 import org.jikesrvm.VM; 017 import org.jikesrvm.classloader.RVMField; 018 import org.jikesrvm.compilers.common.assembler.ForwardReference; 019 import org.jikesrvm.compilers.common.assembler.ia32.Assembler; 020 import org.jikesrvm.objectmodel.ObjectModel; 021 import org.jikesrvm.objectmodel.JavaHeaderConstants; 022 import org.jikesrvm.runtime.ArchEntrypoints; 023 import org.jikesrvm.runtime.EntrypointHelper; 024 import org.jikesrvm.runtime.Entrypoints; 025 import org.jikesrvm.runtime.Magic; 026 import org.jikesrvm.scheduler.RVMThread; 027 import org.vmmagic.unboxed.Offset; 028 029 /** 030 * A place to put hand written machine code typically invoked by Magic 031 * methods. 032 * 033 * <p>Hand coding of small inline instruction sequences is typically handled by 034 * each compiler's implementation of Magic methods. 035 * A few Magic methods are so complex that their implementations require 036 * many instructions. But our compilers do not inline 037 * arbitrary amounts of machine code. We therefore write such code blocks 038 * here, out of line. 039 * 040 * <p>These code blocks can be shared by all compilers. They can be branched to 041 * via a jtoc offset (obtained from Entrypoints.XXXInstructionsField). 042 */ 043 public abstract class OutOfLineMachineCode implements BaselineConstants { 044 //-----------// 045 // interface // 046 //-----------// 047 048 public static void init() { 049 generatePcThunkInstructions(); 050 reflectiveMethodInvokerInstructions = generateReflectiveMethodInvokerInstructions(); 051 saveThreadStateInstructions = generateSaveThreadStateInstructions(); 052 threadSwitchInstructions = generateThreadSwitchInstructions(); 053 RVMThread.stackTrampolineBridgeInstructions = generateStackTrampolineBridgeInstructions(); 054 restoreHardwareExceptionStateInstructions = generateRestoreHardwareExceptionStateInstructions(); 055 } 056 057 //----------------// 058 // implementation // 059 //----------------// 060 061 public static final RVMField[] pcThunkInstructionsField = new RVMField[8]; 062 063 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 064 // Accessed via field array above 065 private static ArchitectureSpecific.CodeArray pcThunkEAXInstructions; 066 067 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 068 // Accessed via field array above 069 private static ArchitectureSpecific.CodeArray pcThunkEBXInstructions; 070 071 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 072 // Accessed via field array above 073 private static ArchitectureSpecific.CodeArray pcThunkECXInstructions; 074 075 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 076 // Accessed via field array above 077 private static ArchitectureSpecific.CodeArray pcThunkEDXInstructions; 078 079 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 080 // Accessed via field array above 081 private static ArchitectureSpecific.CodeArray pcThunkEBPInstructions; 082 083 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 084 // Accessed via field array above 085 private static ArchitectureSpecific.CodeArray pcThunkESIInstructions; 086 087 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 088 // Accessed via field array above 089 private static ArchitectureSpecific.CodeArray pcThunkEDIInstructions; 090 091 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 092 // Accessed via EntryPoints 093 private static ArchitectureSpecific.CodeArray reflectiveMethodInvokerInstructions; 094 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 095 // Accessed via EntryPoints 096 private static ArchitectureSpecific.CodeArray saveThreadStateInstructions; 097 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 098 // Accessed via EntryPoints 099 private static ArchitectureSpecific.CodeArray threadSwitchInstructions; 100 @SuppressWarnings({"unused", "UnusedDeclaration", "FieldCanBeLocal"}) 101 // Accessed via EntryPoints 102 private static ArchitectureSpecific.CodeArray restoreHardwareExceptionStateInstructions; 103 104 private static final Offset PARAMS_FP_OFFSET = Offset.fromIntSignExtend(WORDSIZE * 2); 105 private static final Offset FPRMETA_FP_OFFSET = Offset.fromIntSignExtend(WORDSIZE * 3); 106 private static final Offset FPRS_FP_OFFSET = Offset.fromIntSignExtend(WORDSIZE * 4); 107 private static final Offset GPRS_FP_OFFSET = Offset.fromIntSignExtend(WORDSIZE * 5); 108 private static final Offset CODE_FP_OFFSET = Offset.fromIntSignExtend(WORDSIZE * 6); 109 110 /** 111 * Machine code to get the address of the instruction after the call to this 112 * method 113 */ 114 private static void generatePcThunkInstructions() { 115 Assembler asm = new ArchitectureSpecific.Assembler(0); 116 asm.emitMOV_Reg_RegInd(EAX, SP); 117 asm.emitRET(); 118 pcThunkEAXInstructions = asm.getMachineCodes(); 119 pcThunkInstructionsField[EAX.value()] = 120 EntrypointHelper.getField(OutOfLineMachineCode.class, 121 "pcThunkEAXInstructions", ArchitectureSpecific.CodeArray.class); 122 123 asm = new ArchitectureSpecific.Assembler(0); 124 asm.emitMOV_Reg_RegInd(EBX, SP); 125 asm.emitRET(); 126 pcThunkEBXInstructions = asm.getMachineCodes(); 127 pcThunkInstructionsField[EBX.value()] = 128 EntrypointHelper.getField(OutOfLineMachineCode.class, 129 "pcThunkEBXInstructions", ArchitectureSpecific.CodeArray.class); 130 131 asm = new ArchitectureSpecific.Assembler(0); 132 asm.emitMOV_Reg_RegInd(ECX, SP); 133 asm.emitRET(); 134 pcThunkECXInstructions = asm.getMachineCodes(); 135 pcThunkInstructionsField[ECX.value()] = 136 EntrypointHelper.getField(OutOfLineMachineCode.class, 137 "pcThunkECXInstructions", ArchitectureSpecific.CodeArray.class); 138 139 asm = new ArchitectureSpecific.Assembler(0); 140 asm.emitMOV_Reg_RegInd(EDX, SP); 141 asm.emitRET(); 142 pcThunkEDXInstructions = asm.getMachineCodes(); 143 pcThunkInstructionsField[EDX.value()] = 144 EntrypointHelper.getField(OutOfLineMachineCode.class, 145 "pcThunkEDXInstructions", ArchitectureSpecific.CodeArray.class); 146 147 // NB a PC thunk into ESP isn't allowed 148 149 asm = new ArchitectureSpecific.Assembler(0); 150 asm.emitMOV_Reg_RegInd(EBP, SP); 151 asm.emitRET(); 152 pcThunkEBPInstructions = asm.getMachineCodes(); 153 pcThunkInstructionsField[EBP.value()] = 154 EntrypointHelper.getField(OutOfLineMachineCode.class, 155 "pcThunkEBPInstructions", ArchitectureSpecific.CodeArray.class); 156 157 asm = new ArchitectureSpecific.Assembler(0); 158 asm.emitMOV_Reg_RegInd(ESI, SP); 159 asm.emitRET(); 160 pcThunkESIInstructions = asm.getMachineCodes(); 161 pcThunkInstructionsField[ESI.value()] = 162 EntrypointHelper.getField(OutOfLineMachineCode.class, 163 "pcThunkESIInstructions", ArchitectureSpecific.CodeArray.class); 164 165 asm = new ArchitectureSpecific.Assembler(0); 166 asm.emitMOV_Reg_RegInd(EDI, SP); 167 asm.emitRET(); 168 pcThunkEDIInstructions = asm.getMachineCodes(); 169 pcThunkInstructionsField[EDI.value()] = 170 EntrypointHelper.getField(OutOfLineMachineCode.class, 171 "pcThunkEDIInstructions", ArchitectureSpecific.CodeArray.class); 172 } 173 174 /** 175 * Machine code for reflective method invocation. 176 * <pre> 177 * VM compiled with NUM_PARAMETERS_GPRS == 0 178 * Registers taken at runtime: 179 * none 180 * Stack taken at runtime: 181 * hi-mem 182 * address of method entrypoint to be called 183 * address of gpr registers to be loaded 184 * address of fpr registers to be loaded 185 * address of parameters area in calling frame 186 * return address 187 * low-mem 188 * 189 * VM compiled with NUM_PARAMETERS_GPRS == 1 190 * T0 == address of method entrypoint to be called 191 * Stack taken at runtime: 192 * hi-mem 193 * space ??? 194 * address of gpr registers to be loaded 195 * address of fpr registers to be loaded 196 * address of parameters area in calling frame 197 * return address 198 * low-mem 199 * 200 * VM compiled with NUM_PARAMETERS_GPRS == 2 201 * T0 == address of method entrypoint to be called 202 * T1 == address of gpr registers to be loaded 203 * Stack taken at runtime: 204 * hi-mem 205 * space ??? 206 * space ??? 207 * address of fpr registers to be loaded 208 * address of parameters area in calling frame 209 * return address 210 * low-mem 211 * 212 * Registers returned at runtime: 213 * standard return value conventions used 214 * 215 * Side effects at runtime: 216 * artificial stackframe created and destroyed 217 * volatile, and scratch registers destroyed 218 * </pre> 219 */ 220 private static ArchitectureSpecific.CodeArray generateReflectiveMethodInvokerInstructions() { 221 Assembler asm = new ArchitectureSpecific.Assembler(100); 222 int gprs; 223 Offset fpOffset = ArchEntrypoints.framePointerField.getOffset(); 224 GPR T = T0; 225 gprs = NUM_PARAMETER_GPRS; 226 // we have exactly 5 paramaters, offset 0 from SP is the return address the 227 // parameters are at offsets 5 to 1 228 Offset offset = Offset.fromIntZeroExtend(5 << LG_WORDSIZE); 229 // Write at most 2 parameters from registers in the stack. This is 230 // logically equivalent to ParamaterRegisterUnload in the compiler 231 if (gprs > 0) { 232 gprs--; 233 if (VM.BuildFor32Addr) { 234 asm.emitMOV_RegDisp_Reg(SP, offset, T); 235 } else { 236 asm.emitMOV_RegDisp_Reg_Quad(SP, offset, T); 237 } 238 T = T1; 239 offset = offset.minus(WORDSIZE); 240 } 241 if (gprs > 0) { 242 if (VM.BuildFor32Addr) { 243 asm.emitMOV_RegDisp_Reg(SP, offset, T); 244 } else { 245 asm.emitMOV_RegDisp_Reg_Quad(SP, offset, T); 246 } 247 } 248 249 /* available registers S0, T0, T1 */ 250 251 /* push a new frame */ 252 asm.emitPUSH_RegDisp(TR, fpOffset); // link this frame with next 253 ThreadLocalState.emitMoveRegToField(asm, fpOffset, SP); // establish base of new frame 254 asm.emitPUSH_Imm(INVISIBLE_METHOD_ID); 255 asm.emitADD_Reg_Imm(SP, STACKFRAME_BODY_OFFSET); 256 257 /* write parameters on stack 258 * move data from memory addressed by Paramaters array, the fourth 259 * parameter to this, into the stack. 260 * SP target address 261 * S0 source address 262 * T1 length 263 * T0 scratch 264 */ 265 ThreadLocalState.emitMoveFieldToReg(asm, S0, fpOffset); 266 if (VM.BuildFor32Addr) { 267 asm.emitMOV_Reg_RegDisp(S0, S0, PARAMS_FP_OFFSET); // S0 <- Parameters 268 asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset()); // T1 <- Parameters.length() 269 asm.emitCMP_Reg_Imm(T1, 0); // length == 0 ? 270 } else { 271 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, PARAMS_FP_OFFSET);// S0 <- Parameters 272 if (JavaHeaderConstants.ARRAY_LENGTH_BYTES == 4) { 273 asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset()); // T1 <- Parameters.length() 274 asm.emitCMP_Reg_Imm(T1, 0); // length == 0 ? 275 } else { 276 asm.emitMOV_Reg_RegDisp_Quad(T1, S0, ObjectModel.getArrayLengthOffset()); // T1 <- Parameters.length() 277 asm.emitCMP_Reg_Imm_Quad(T1, 0); // length == 0 ? 278 } 279 } 280 281 int parameterLoopLabel = asm.getMachineCodeIndex(); 282 ForwardReference fr1 = asm.forwardJcc(Assembler.EQ); // done? --> branch to end 283 if (VM.BuildFor32Addr) { 284 asm.emitMOV_Reg_RegInd(T0, S0); // T0 <- Paramaters[i] 285 } else { 286 asm.emitMOV_Reg_RegInd_Quad(T0, S0); // T0 <- Paramaters[i] 287 } 288 asm.emitPUSH_Reg(T0); // mem[j++] <- Parameters[i] 289 if (VM.BuildFor32Addr) { 290 asm.emitADD_Reg_Imm(S0, WORDSIZE); // i++ 291 } else { 292 asm.emitADD_Reg_Imm_Quad(S0, WORDSIZE); // i++ 293 } 294 if (JavaHeaderConstants.ARRAY_LENGTH_BYTES == 4) { 295 asm.emitADD_Reg_Imm(T1, -1); // length-- 296 } else { 297 asm.emitADD_Reg_Imm_Quad(T1, -1); // length-- 298 } 299 asm.emitJMP_Imm(parameterLoopLabel); 300 301 fr1.resolve(asm); // end of the loop 302 303 if (SSE2_FULL) { 304 /* write fprs onto fprs registers */ 305 ThreadLocalState.emitMoveFieldToReg(asm, S0, fpOffset); 306 if (VM.BuildFor32Addr) { 307 asm.emitMOV_Reg_RegDisp(T0, S0, FPRS_FP_OFFSET); // T0 <- FPRs 308 asm.emitMOV_Reg_RegDisp(T1, T0, ObjectModel.getArrayLengthOffset()); // T1 <- FPRs.length() 309 asm.emitMOV_Reg_RegDisp(S0, S0, FPRMETA_FP_OFFSET); // S0 <- FPRmeta 310 } else { 311 asm.emitMOV_Reg_RegDisp_Quad(T0, S0, FPRS_FP_OFFSET); // T0 <- FPRs 312 if (JavaHeaderConstants.ARRAY_LENGTH_BYTES == 4) { 313 asm.emitMOV_Reg_RegDisp(T1, T0, ObjectModel.getArrayLengthOffset()); // T1 <- FPRs.length() 314 } else { 315 asm.emitMOV_Reg_RegDisp_Quad(T1, T0, ObjectModel.getArrayLengthOffset()); // T1 <- FPRs.length() 316 } 317 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, FPRMETA_FP_OFFSET); // S0 <- FPRmeta 318 } 319 320 if (VM.VerifyAssertions) VM._assert(NUM_PARAMETER_FPRS <= 4); 321 322 ForwardReference fr_next; 323 324 asm.emitCMP_Reg_Imm(T1, 0); // length == 0 ? 325 ForwardReference fpr_r1 = asm.forwardJcc(Assembler.EQ); 326 asm.emitMOVSD_Reg_RegInd(XMM0, T0); 327 asm.emitCMP_RegInd_Imm_Byte(S0, 0); 328 fr_next = asm.forwardJcc(Assembler.NE); 329 asm.emitCVTSD2SS_Reg_Reg(XMM0, XMM0); 330 fr_next.resolve(asm); 331 332 asm.emitSUB_Reg_Imm(T1, 1); // length == 0 ? 333 ForwardReference fpr_r2 = asm.forwardJcc(Assembler.EQ); 334 asm.emitMOVSD_Reg_RegDisp(XMM1, T0, Offset.fromIntZeroExtend(WORDSIZE*2)); 335 asm.emitCMP_RegDisp_Imm_Byte(S0, Offset.fromIntZeroExtend(1), 0); 336 fr_next = asm.forwardJcc(Assembler.NE); 337 asm.emitCVTSD2SS_Reg_Reg(XMM1, XMM1); 338 fr_next.resolve(asm); 339 340 asm.emitSUB_Reg_Imm(T1, 1); // length == 0 ? 341 ForwardReference fpr_r3 = asm.forwardJcc(Assembler.EQ); 342 asm.emitMOVSD_Reg_RegDisp(XMM2, T0, Offset.fromIntZeroExtend(WORDSIZE*4)); 343 asm.emitCMP_RegDisp_Imm_Byte(S0, Offset.fromIntZeroExtend(2), 0); 344 fr_next = asm.forwardJcc(Assembler.NE); 345 asm.emitCVTSD2SS_Reg_Reg(XMM2, XMM2); 346 fr_next.resolve(asm); 347 348 asm.emitSUB_Reg_Imm(T1, 1); // length == 0 ? 349 ForwardReference fpr_r4 = asm.forwardJcc(Assembler.EQ); 350 asm.emitMOVSD_Reg_RegDisp(XMM3, T0, Offset.fromIntZeroExtend(WORDSIZE*6)); 351 asm.emitCMP_RegDisp_Imm_Byte(S0, Offset.fromIntZeroExtend(3), 0); 352 fr_next = asm.forwardJcc(Assembler.NE); 353 asm.emitCVTSD2SS_Reg_Reg(XMM3, XMM3); 354 fr_next.resolve(asm); 355 356 fpr_r1.resolve(asm); 357 fpr_r2.resolve(asm); 358 fpr_r3.resolve(asm); 359 fpr_r4.resolve(asm); 360 361 } else { 362 if (VM.VerifyAssertions) VM._assert(VM.BuildFor32Addr); 363 /* write fprs onto fprs registers */ 364 ThreadLocalState.emitMoveFieldToReg(asm, S0, fpOffset); 365 asm.emitMOV_Reg_RegDisp(S0, S0, FPRS_FP_OFFSET); // S0 <- FPRs 366 asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset()); // T1 <- FPRs.length() 367 asm.emitSHL_Reg_Imm(T1, LG_WORDSIZE + 1); // length in bytes 368 asm.emitADD_Reg_Reg(S0, T1); // S0 <- last FPR + 8 369 asm.emitCMP_Reg_Imm(T1, 0); // length == 0 ? 370 371 int fprsLoopLabel = asm.getMachineCodeIndex(); 372 ForwardReference fr2 = asm.forwardJcc(Assembler.EQ); // done? --> branch to end 373 asm.emitSUB_Reg_Imm(S0, 2 * WORDSIZE); // i-- 374 asm.emitFLD_Reg_RegInd_Quad(FP0, S0); // frp[fpr_sp++] <-FPRs[i] 375 asm.emitSUB_Reg_Imm(T1, 2 * WORDSIZE); // length-- 376 asm.emitJMP_Imm(fprsLoopLabel); 377 378 fr2.resolve(asm); // end of the loop 379 } 380 381 /* write gprs: S0 = Base address of GPRs[], T1 = GPRs.length */ 382 ThreadLocalState.emitMoveFieldToReg(asm, S0, fpOffset); 383 if (VM.BuildFor32Addr) { 384 asm.emitMOV_Reg_RegDisp(S0, S0, GPRS_FP_OFFSET); // S0 <- GPRs 385 asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset()); // T1 <- GPRs.length() 386 asm.emitCMP_Reg_Imm(T1, 0); // length == 0 ? 387 } else { 388 asm.emitMOV_Reg_RegDisp(S0, S0, GPRS_FP_OFFSET); // S0 <- GPRs 389 if (JavaHeaderConstants.ARRAY_LENGTH_BYTES == 4) { 390 asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset()); // T1 <- GPRs.length() 391 asm.emitCMP_Reg_Imm(T1, 0); // length == 0 ? 392 } else { 393 asm.emitMOV_Reg_RegDisp_Quad(T1, S0, ObjectModel.getArrayLengthOffset()); // T1 <- GPRs.length() 394 asm.emitCMP_Reg_Imm_Quad(T1, 0); // length == 0 ? 395 } 396 } 397 ForwardReference fr3 = asm.forwardJcc(Assembler.EQ); // result 0 --> branch to end 398 if (VM.BuildFor32Addr) { 399 asm.emitMOV_Reg_RegInd(T0, S0); // T0 <- GPRs[0] 400 } else { 401 asm.emitMOV_Reg_RegInd_Quad(T0, S0); // T0 <- GPRs[0] 402 } 403 asm.emitADD_Reg_Imm(S0, WORDSIZE); // S0 += WORDSIZE 404 asm.emitADD_Reg_Imm(T1, -1); // T1-- 405 ForwardReference fr4 = asm.forwardJcc(Assembler.EQ); // result 0 --> branch to end 406 if (VM.BuildFor32Addr) { 407 asm.emitMOV_Reg_RegInd(T1, S0); // T1 <- GPRs[1] 408 } else { 409 asm.emitMOV_Reg_RegInd_Quad(T1, S0); // T1 <- GPRs[1] 410 } 411 fr3.resolve(asm); 412 fr4.resolve(asm); 413 414 /* branch to method. On a good day we might even be back */ 415 ThreadLocalState.emitMoveFieldToReg(asm, S0, fpOffset); 416 if (VM.BuildFor32Addr) { 417 asm.emitMOV_Reg_RegDisp(S0, S0, CODE_FP_OFFSET); // S0 <- code 418 } else { 419 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, CODE_FP_OFFSET); // S0 <- code 420 } 421 asm.emitCALL_Reg(S0); // go there 422 // T0/T1 have returned value 423 424 /* and get out */ 425 // NOTE: RVM callee has popped the params, so we can simply 426 // add back in the initial SP to FP delta to get SP to be a framepointer again! 427 if (VM.BuildFor32Addr) { 428 asm.emitADD_Reg_Imm(SP, -STACKFRAME_BODY_OFFSET + WORDSIZE); 429 } else { 430 asm.emitADD_Reg_Imm_Quad(SP, -STACKFRAME_BODY_OFFSET + WORDSIZE); 431 } 432 asm.emitPOP_RegDisp(TR, fpOffset); 433 434 asm.emitRET_Imm(5 << LG_WORDSIZE); // again, exactly 5 parameters 435 436 return asm.getMachineCodes(); 437 } 438 439 /** 440 * Machine code to implement "Magic.saveThreadState()". 441 * <pre> 442 * Registers taken at runtime: 443 * T0 == address of Registers object 444 * 445 * Registers returned at runtime: 446 * none 447 * 448 * Side effects at runtime: 449 * S0, T1 destroyed 450 * Thread state stored into Registers object 451 * </pre> 452 */ 453 private static ArchitectureSpecific.CodeArray generateSaveThreadStateInstructions() { 454 if (VM.VerifyAssertions) { 455 VM._assert(NUM_NONVOLATILE_FPRS == 0); // assuming no NV FPRs (otherwise would have to save them here) 456 } 457 Assembler asm = new ArchitectureSpecific.Assembler(0); 458 Offset ipOffset = ArchEntrypoints.registersIPField.getOffset(); 459 Offset fpOffset = ArchEntrypoints.registersFPField.getOffset(); 460 Offset gprsOffset = ArchEntrypoints.registersGPRsField.getOffset(); 461 if (VM.BuildFor32Addr) { 462 asm.emitMOV_Reg_RegDisp(S0, TR, ArchEntrypoints.framePointerField.getOffset()); 463 asm.emitMOV_RegDisp_Reg(T0, fpOffset, S0); // registers.fp := pr.framePointer 464 } else { 465 asm.emitMOV_Reg_RegDisp_Quad(S0, TR, ArchEntrypoints.framePointerField.getOffset()); 466 asm.emitMOV_RegDisp_Reg_Quad(T0, fpOffset, S0); // registers.fp := pr.framePointer 467 } 468 asm.emitPOP_Reg(T1); // T1 := return address (target of final jmp) 469 asm.emitMOV_RegDisp_Reg(T0, ipOffset, T1); // registers.ip := return address 470 asm.emitPOP_Reg(S0); // throw away space for registers parameter (in T0) 471 if (VM.BuildFor32Addr) { 472 asm.emitMOV_Reg_RegDisp(S0, T0, gprsOffset); // S0 := registers.gprs[] 473 asm.emitMOV_RegDisp_Reg(S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE), SP); // registers.gprs[#SP] := SP 474 for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) { 475 asm.emitMOV_RegDisp_Reg(S0, 476 Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE), 477 NONVOLATILE_GPRS[i]); // registers.gprs[i] := i'th register 478 } 479 } else { 480 asm.emitMOV_Reg_RegDisp_Quad(S0, T0, gprsOffset); // S0 := registers.gprs[] 481 asm.emitMOV_RegDisp_Reg_Quad(S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE), SP); // registers.gprs[#SP] := SP 482 for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) { 483 asm.emitMOV_RegDisp_Reg_Quad(S0, 484 Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE), 485 NONVOLATILE_GPRS[i]); // registers.gprs[i] := i'th register 486 } 487 } 488 asm.emitJMP_Reg(T1); // return to return address 489 return asm.getMachineCodes(); 490 } 491 492 /** 493 * Machine code to perform a stack trampoline bridge for 494 * implementing a return barrier. 495 * <p> 496 * This code is used to hijack a return and bridge to some 497 * other method (which implements the return barrier) before 498 * falling back to the intended return address. 499 * <p> 500 * The key here is to preserve register and stack state so that 501 * the caller is oblivious of the detour that occurred during 502 * the return. 503 */ 504 private static ArchitectureSpecific.CodeArray generateStackTrampolineBridgeInstructions() { 505 if (VM.VerifyAssertions) { 506 VM._assert(NUM_NONVOLATILE_FPRS == 0); // assuming no NV FPRs (otherwise would have to save them here) 507 VM._assert(VM.BuildFor32Addr); 508 } 509 Assembler asm = new ArchitectureSpecific.Assembler(0); 510 511 /* push the hijacked return address (which is held in thread-local state) */ 512 asm.emitPUSH_RegDisp(TR, ArchEntrypoints.hijackedReturnAddressField.getOffset()); 513 514 /* push the GPRs and fp */ 515 for (int i = 0; i < NUM_GPRS; i++) { 516 asm.emitPUSH_Reg(ALL_GPRS[i]); 517 } 518 asm.emitPUSH_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset()); 519 520 /* call the handler */ 521 asm.emitCALL_Abs(Magic.getTocPointer().plus(Entrypoints.returnBarrierMethod.getOffset())); 522 523 /* pop the fp and GPRs */ 524 asm.emitPOP_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset()); 525 for (int i = NUM_GPRS - 1; i >= 0; i--) { 526 asm.emitPOP_Reg(ALL_GPRS[i]); 527 } 528 529 /* pop the hijacked return address and return */ 530 asm.emitRET(); 531 532 return asm.getMachineCodes(); 533 } 534 535 536 /** 537 * Machine code to implement "Magic.threadSwitch()". 538 * <pre> 539 * NOTE: Currently not functional for PNT: left as a guide for possible reimplementation. 540 * 541 * Parameters taken at runtime: 542 * T0 == address of Thread object for the current thread 543 * T1 == address of Registers object for the new thread 544 * 545 * Registers returned at runtime: 546 * none 547 * 548 * Side effects at runtime: 549 * sets current Thread's beingDispatched field to false 550 * saves current Thread's nonvolatile hardware state in its Registers object 551 * restores new thread's Registers nonvolatile hardware state. 552 * execution resumes at address specificed by restored thread's Registers ip field 553 * </pre> 554 */ 555 private static ArchitectureSpecific.CodeArray generateThreadSwitchInstructions() { 556 if (VM.VerifyAssertions) { 557 VM._assert(NUM_NONVOLATILE_FPRS == 0); // assuming no NV FPRs (otherwise would have to save them here) 558 } 559 Assembler asm = new ArchitectureSpecific.Assembler(0); 560 Offset ipOffset = ArchEntrypoints.registersIPField.getOffset(); 561 Offset fpOffset = ArchEntrypoints.registersFPField.getOffset(); 562 Offset gprsOffset = ArchEntrypoints.registersGPRsField.getOffset(); 563 Offset regsOffset = Entrypoints.threadContextRegistersField.getOffset(); 564 565 // (1) Save hardware state of thread we are switching off of. 566 if (VM.BuildFor32Addr) { 567 asm.emitMOV_Reg_RegDisp(S0, T0, regsOffset); // S0 = T0.contextRegisters 568 } else { 569 asm.emitMOV_Reg_RegDisp_Quad(S0, T0, regsOffset); // S0 = T0.contextRegisters 570 } 571 asm.emitPOP_RegDisp(S0, ipOffset); // T0.contextRegisters.ip = returnAddress 572 asm.emitPUSH_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset()); // push TR.framePointer 573 asm.emitPOP_RegDisp(S0, fpOffset); // T0.contextRegisters.fp = pushed framepointer 574 asm.emitADD_Reg_Imm(SP, 2*WORDSIZE); // discard 2 words of parameters (T0, T1) 575 if (VM.BuildFor32Addr) { 576 asm.emitMOV_Reg_RegDisp(S0, S0, gprsOffset); // S0 = T0.contextRegisters.gprs; 577 asm.emitMOV_RegDisp_Reg(S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE), SP); // T0.contextRegisters.gprs[#SP] := SP 578 for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) { 579 // T0.contextRegisters.gprs[i] := i'th register 580 asm.emitMOV_RegDisp_Reg(S0, 581 Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE), 582 NONVOLATILE_GPRS[i]); 583 } 584 } else { 585 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, gprsOffset); // S0 = T0.contextRegisters.gprs; 586 asm.emitMOV_RegDisp_Reg_Quad(S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE), SP); // T0.contextRegisters.gprs[#SP] := SP 587 for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) { 588 // T0.contextRegisters.gprs[i] := i'th register 589 asm.emitMOV_RegDisp_Reg_Quad(S0, 590 Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE), 591 NONVOLATILE_GPRS[i]); 592 } 593 } 594 595 // (2) Set currentThread.beingDispatched to false 596 // PNT: don't have this field anymore 597 //asm.emitMOV_RegDisp_Imm_Byte(T0, 598 // Entrypoints.beingDispatchedField.getOffset(), 599 // 0); // previous thread's stack is nolonger in use, so it can now be dispatched on any virtual processor 600 601 // (3) Restore hardware state of thread we are switching to. 602 if (VM.BuildFor32Addr) { 603 asm.emitMOV_Reg_RegDisp(S0, T1, fpOffset); // S0 := restoreRegs.fp 604 } else { 605 asm.emitMOV_Reg_RegDisp_Quad(S0, T1, fpOffset); // S0 := restoreRegs.fp 606 } 607 // TR.framePointer = restoreRegs.fp 608 ThreadLocalState.emitMoveRegToField(asm, 609 ArchEntrypoints.framePointerField.getOffset(), 610 S0); 611 if (VM.BuildFor32Addr) { 612 asm.emitMOV_Reg_RegDisp(S0, T1, gprsOffset); // S0 := restoreRegs.gprs[] 613 asm.emitMOV_Reg_RegDisp(SP, S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE)); // SP := restoreRegs.gprs[#SP] 614 for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) { 615 // i'th register := restoreRegs.gprs[i] 616 asm.emitMOV_Reg_RegDisp(NONVOLATILE_GPRS[i], 617 S0, 618 Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << 619 LG_WORDSIZE)); 620 } 621 } else { 622 asm.emitMOV_Reg_RegDisp_Quad(S0, T1, gprsOffset); // S0 := restoreRegs.gprs[] 623 asm.emitMOV_Reg_RegDisp_Quad(SP, S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE)); // SP := restoreRegs.gprs[#SP] 624 for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) { 625 // i'th register := restoreRegs.gprs[i] 626 asm.emitMOV_Reg_RegDisp_Quad(NONVOLATILE_GPRS[i], 627 S0, 628 Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE)); 629 } 630 } 631 asm.emitJMP_RegDisp(T1, ipOffset); // return to (save) return address 632 return asm.getMachineCodes(); 633 } 634 635 /** 636 * Machine code to implement "Magic.restoreHardwareExceptionState()". 637 * <pre> 638 * Registers taken at runtime: 639 * T0 == address of Registers object 640 * 641 * Registers returned at runtime: 642 * none 643 * 644 * Side effects at runtime: 645 * all registers are restored except THREAD_REGISTER and EFLAGS; 646 * execution resumes at "registers.ip" 647 * </pre> 648 */ 649 private static ArchitectureSpecific.CodeArray generateRestoreHardwareExceptionStateInstructions() { 650 Assembler asm = new ArchitectureSpecific.Assembler(0); 651 652 // Set TR.framePointer to be registers.fp 653 if (VM.BuildFor32Addr) { 654 asm.emitMOV_Reg_RegDisp(S0, T0, ArchEntrypoints.registersFPField.getOffset()); 655 } else { 656 asm.emitMOV_Reg_RegDisp_Quad(S0, T0, ArchEntrypoints.registersFPField.getOffset()); 657 } 658 ThreadLocalState.emitMoveRegToField(asm, ArchEntrypoints.framePointerField.getOffset(), S0); 659 660 // Restore SP 661 if (VM.BuildFor32Addr) { 662 asm.emitMOV_Reg_RegDisp(S0, T0, ArchEntrypoints.registersGPRsField.getOffset()); 663 asm.emitMOV_Reg_RegDisp(SP, S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE)); 664 } else { 665 asm.emitMOV_Reg_RegDisp_Quad(S0, T0, ArchEntrypoints.registersGPRsField.getOffset()); 666 asm.emitMOV_Reg_RegDisp_Quad(SP, S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE)); 667 } 668 669 // Push registers.ip to stack (now that SP has been restored) 670 asm.emitPUSH_RegDisp(T0, ArchEntrypoints.registersIPField.getOffset()); 671 672 // Restore the GPRs except for S0, TR, and SP 673 // (restored above and then modified by pushing registers.ip!) 674 Offset off = Offset.zero(); 675 for (byte i = 0; i < NUM_GPRS; i++, off = off.plus(WORDSIZE)) { 676 if (i != S0.value() && i != ESI.value() && i != SP.value()) { 677 if (VM.BuildFor32Addr) { 678 asm.emitMOV_Reg_RegDisp(GPR.lookup(i), S0, off); 679 } else { 680 asm.emitMOV_Reg_RegDisp_Quad(GPR.lookup(i), S0, off); 681 } 682 } 683 } 684 685 // Restore S0 686 if (VM.BuildFor32Addr) { 687 asm.emitMOV_Reg_RegDisp(S0, S0, Offset.fromIntZeroExtend(S0.value() << LG_WORDSIZE)); 688 } else { 689 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, Offset.fromIntZeroExtend(S0.value() << LG_WORDSIZE)); 690 } 691 692 // Return to registers.ip (popping stack) 693 asm.emitRET(); 694 return asm.getMachineCodes(); 695 } 696 }