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.compilers.baseline.ia32; 014 015import static org.jikesrvm.classloader.ClassLoaderConstants.CP_CLASS; 016import static org.jikesrvm.classloader.ClassLoaderConstants.CP_STRING; 017import static org.jikesrvm.compilers.common.assembler.ia32.AssemblerConstants.*; 018import static org.jikesrvm.ia32.ArchConstants.SSE2_BASE; 019import static org.jikesrvm.ia32.ArchConstants.SSE2_FULL; 020import static org.jikesrvm.ia32.BaselineConstants.EBP_SAVE_OFFSET; 021import static org.jikesrvm.ia32.BaselineConstants.EBX_SAVE_OFFSET; 022import static org.jikesrvm.ia32.BaselineConstants.EDI_SAVE_OFFSET; 023import static org.jikesrvm.ia32.BaselineConstants.FPU_SAVE_OFFSET; 024import static org.jikesrvm.ia32.BaselineConstants.LG_WORDSIZE; 025import static org.jikesrvm.ia32.BaselineConstants.S0; 026import static org.jikesrvm.ia32.BaselineConstants.S1; 027import static org.jikesrvm.ia32.BaselineConstants.SAVED_GPRS; 028import static org.jikesrvm.ia32.BaselineConstants.SAVED_GPRS_FOR_SAVE_LS_REGISTERS; 029import static org.jikesrvm.ia32.BaselineConstants.SP; 030import static org.jikesrvm.ia32.BaselineConstants.T0; 031import static org.jikesrvm.ia32.BaselineConstants.T0_SAVE_OFFSET; 032import static org.jikesrvm.ia32.BaselineConstants.T1; 033import static org.jikesrvm.ia32.BaselineConstants.T1_SAVE_OFFSET; 034import static org.jikesrvm.ia32.BaselineConstants.TR; 035import static org.jikesrvm.ia32.BaselineConstants.WORDSIZE; 036import static org.jikesrvm.ia32.BaselineConstants.XMM_SAVE_OFFSET; 037import static org.jikesrvm.ia32.RegisterConstants.EAX; 038import static org.jikesrvm.ia32.RegisterConstants.EBP; 039import static org.jikesrvm.ia32.RegisterConstants.EBX; 040import static org.jikesrvm.ia32.RegisterConstants.ECX; 041import static org.jikesrvm.ia32.RegisterConstants.EDI; 042import static org.jikesrvm.ia32.RegisterConstants.EDX; 043import static org.jikesrvm.ia32.RegisterConstants.ESI; 044import static org.jikesrvm.ia32.RegisterConstants.ESP; 045import static org.jikesrvm.ia32.RegisterConstants.FP0; 046import static org.jikesrvm.ia32.RegisterConstants.FP1; 047import static org.jikesrvm.ia32.RegisterConstants.NATIVE_PARAMETER_FPRS; 048import static org.jikesrvm.ia32.RegisterConstants.NATIVE_PARAMETER_GPRS; 049import static org.jikesrvm.ia32.RegisterConstants.NONVOLATILE_GPRS; 050import static org.jikesrvm.ia32.RegisterConstants.NUM_PARAMETER_FPRS; 051import static org.jikesrvm.ia32.RegisterConstants.NUM_PARAMETER_GPRS; 052import static org.jikesrvm.ia32.RegisterConstants.THREAD_REGISTER; 053import static org.jikesrvm.ia32.RegisterConstants.XMM0; 054import static org.jikesrvm.ia32.RegisterConstants.XMM1; 055import static org.jikesrvm.ia32.RegisterConstants.XMM2; 056import static org.jikesrvm.ia32.RegisterConstants.XMM3; 057import static org.jikesrvm.ia32.StackframeLayoutConstants.FPU_STATE_SIZE; 058import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_BODY_OFFSET; 059import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_HEADER_SIZE; 060import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_METHOD_ID_OFFSET; 061import static org.jikesrvm.ia32.StackframeLayoutConstants.XMM_STATE_SIZE; 062import static org.jikesrvm.ia32.TrapConstants.RVM_TRAP_BASE; 063import static org.jikesrvm.mm.mminterface.Barriers.*; 064import static org.jikesrvm.objectmodel.JavaHeaderConstants.ARRAY_LENGTH_BYTES; 065import static org.jikesrvm.objectmodel.TIBLayoutConstants.NEEDS_DYNAMIC_LINK; 066import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_DOES_IMPLEMENT_INDEX; 067import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_INTERFACE_DISPATCH_TABLE_INDEX; 068import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_SUPERCLASS_IDS_INDEX; 069import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_BYTE; 070import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_INT; 071import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_LONG; 072import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_SHORT; 073import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_INT; 074import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_SHORT; 075import static org.jikesrvm.runtime.RuntimeEntrypoints.TRAP_UNREACHABLE_BYTECODE; 076import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS; 077 078import org.jikesrvm.VM; 079import org.jikesrvm.adaptive.AosEntrypoints; 080import org.jikesrvm.adaptive.recompilation.InvocationCounts; 081import org.jikesrvm.classloader.DynamicTypeCheck; 082import org.jikesrvm.classloader.FieldReference; 083import org.jikesrvm.classloader.InterfaceInvocation; 084import org.jikesrvm.classloader.InterfaceMethodSignature; 085import org.jikesrvm.classloader.MemberReference; 086import org.jikesrvm.classloader.MethodReference; 087import org.jikesrvm.classloader.NormalMethod; 088import org.jikesrvm.classloader.RVMArray; 089import org.jikesrvm.classloader.RVMClass; 090import org.jikesrvm.classloader.RVMField; 091import org.jikesrvm.classloader.RVMMethod; 092import org.jikesrvm.classloader.RVMType; 093import org.jikesrvm.classloader.TypeReference; 094import org.jikesrvm.compilers.baseline.BaselineCompiledMethod; 095import org.jikesrvm.compilers.baseline.BaselineCompiler; 096import org.jikesrvm.compilers.baseline.EdgeCounts; 097import org.jikesrvm.compilers.baseline.TemplateCompilerFramework; 098import org.jikesrvm.compilers.common.CompiledMethod; 099import org.jikesrvm.compilers.common.assembler.AbstractAssembler; 100import org.jikesrvm.compilers.common.assembler.ForwardReference; 101import org.jikesrvm.compilers.common.assembler.ia32.Assembler; 102import org.jikesrvm.ia32.RegisterConstants.GPR; 103import org.jikesrvm.ia32.RegisterConstants.XMM; 104import org.jikesrvm.jni.ia32.JNICompiler; 105import org.jikesrvm.mm.mminterface.MemoryManager; 106import org.jikesrvm.objectmodel.ObjectModel; 107import org.jikesrvm.runtime.ArchEntrypoints; 108import org.jikesrvm.runtime.Entrypoints; 109import org.jikesrvm.runtime.Magic; 110import org.jikesrvm.runtime.RuntimeEntrypoints; 111import org.jikesrvm.runtime.Statics; 112import org.jikesrvm.scheduler.RVMThread; 113import org.vmmagic.pragma.Inline; 114import org.vmmagic.pragma.Pure; 115import org.vmmagic.pragma.Uninterruptible; 116import org.vmmagic.unboxed.Offset; 117 118/** 119 * BaselineCompilerImpl is the baseline compiler implementation for the IA32 architecture. 120 */ 121public final class BaselineCompilerImpl extends BaselineCompiler { 122 123 private final Assembler asm; 124 125 static { 126 // Force resolution of BaselineMagic before using in genMagic 127 Object x = BaselineMagic.generateMagic(null, null, null, Offset.zero()); 128 } 129 130 private final int parameterWords; 131 private Offset firstLocalOffset; 132 133 static final Offset NO_SLOT = Offset.zero(); 134 static final Offset ONE_SLOT = NO_SLOT.plus(WORDSIZE); 135 static final Offset TWO_SLOTS = ONE_SLOT.plus(WORDSIZE); 136 static final Offset THREE_SLOTS = TWO_SLOTS.plus(WORDSIZE); 137 static final Offset FOUR_SLOTS = THREE_SLOTS.plus(WORDSIZE); 138 static final Offset FIVE_SLOTS = FOUR_SLOTS.plus(WORDSIZE); 139 private static final Offset MINUS_ONE_SLOT = NO_SLOT.minus(WORDSIZE); 140 141 /** 142 * Create a BaselineCompilerImpl object for the compilation of method. 143 * 144 * @param cm the method that will be associated with this compilation 145 * @param localFixedLocations unused on IA32 146 * @param localFloatLocations unused on IA32 147 */ 148 public BaselineCompilerImpl(BaselineCompiledMethod cm, short[] localFixedLocations, short[] localFloatLocations) { 149 super(cm); 150 stackHeights = new int[bcodes.length()]; 151 parameterWords = method.getParameterWords() + (method.isStatic() ? 0 : 1); // add 1 for this pointer 152 asm = new Assembler(bcodes.length(),shouldPrint, this); 153 } 154 155 @Override 156 protected AbstractAssembler getAssembler() { 157 return asm; 158 } 159 160 /** 161 * Have we encountered a bytecode without valid stack heights? if so throw this exception 162 */ 163 private static final class UnreachableBytecodeException extends Exception { 164 private static final long serialVersionUID = 8300835844142105706L; 165 UnreachableBytecodeException() {} 166 } 167 168 169 @Override 170 protected void initializeCompiler() { 171 //nothing to do for Intel 172 } 173 174 @Override 175 public byte getLastFixedStackRegister() { 176 return -1; //doesn't dedicate registers to stack; 177 } 178 179 @Override 180 public byte getLastFloatStackRegister() { 181 return -1; //doesn't dedicate registers to stack; 182 } 183 184 @Uninterruptible 185 public static short getGeneralLocalLocation(int index, short[] localloc, NormalMethod m) { 186 // we currently do not use location arrays on Intel 187 return offsetToLocation(getStartLocalOffset(m).minus(index << LOG_BYTES_IN_ADDRESS)); 188 } 189 190 @Uninterruptible 191 public static short getFloatLocalLocation(int index, short[] localloc, NormalMethod m) { 192 // we currently do not use location arrays on Intel 193 return offsetToLocation(getStartLocalOffset(m).minus(index << LOG_BYTES_IN_ADDRESS)); 194 } 195 196 @Uninterruptible 197 public static int locationToOffset(short location) { 198 return -location; 199 } 200 201 @Uninterruptible 202 public static short offsetToLocation(Offset offset) { 203 return (short)-offset.toInt(); 204 } 205 206 207 @Uninterruptible 208 public static short offsetToLocation(int offset) { 209 return (short)-offset; 210 } 211 212 @Uninterruptible 213 public static short getEmptyStackOffset(NormalMethod m) { 214 return (short)getFirstLocalOffset(m).minus(m.getLocalWords() << LG_WORDSIZE).plus(WORDSIZE).toInt(); 215 } 216 217 /** 218 * This is misnamed. It should be getFirstParameterOffset. 219 * It will not work as a base to access true locals. 220 * TODO!! make sure it is not being used incorrectly 221 * 222 * @param method the method in question 223 * 224 * @return offset of first parameter 225 */ 226 @Uninterruptible 227 private static Offset getFirstLocalOffset(NormalMethod method) { 228 if (method.getDeclaringClass().hasBridgeFromNativeAnnotation()) { 229 return STACKFRAME_BODY_OFFSET.minus(JNICompiler.SAVED_GPRS_FOR_JNI << LG_WORDSIZE); 230 } else if (method.hasBaselineSaveLSRegistersAnnotation()) { 231 return STACKFRAME_BODY_OFFSET.minus(SAVED_GPRS_FOR_SAVE_LS_REGISTERS << LG_WORDSIZE); 232 } else { 233 return STACKFRAME_BODY_OFFSET.minus(SAVED_GPRS << LG_WORDSIZE); 234 } 235 } 236 237 @Uninterruptible 238 private static Offset getStartLocalOffset(NormalMethod method) { 239 return getFirstLocalOffset(method).plus(WORDSIZE); 240 } 241 242 /** 243 * Adjust the value of ESP/RSP 244 * 245 * @param size amount to change ESP/RSP by 246 * @param mayClobber can the value in S0 or memory be destroyed? 247 * (i.e. can we use a destructive short push/pop opcode) 248 */ 249 private void adjustStack(int size, boolean mayClobber) { 250 final boolean debug = false; 251 if (size != 0) { 252 if (mayClobber) { 253 // first try short opcodes 254 switch(size >> LG_WORDSIZE) { 255 case -2: 256 if (debug) { 257 asm.emitPUSH_Imm(0xFA1FACE); 258 asm.emitPUSH_Imm(0xFA2FACE); 259 } else { 260 asm.emitPUSH_Reg(EAX); 261 asm.emitPUSH_Reg(EAX); 262 } 263 return; 264 case -1: 265 if (debug) { 266 asm.emitPUSH_Imm(0xFA3FACE); 267 } else { 268 asm.emitPUSH_Reg(EAX); 269 } 270 return; 271 case 1: 272 asm.emitPOP_Reg(S1); 273 if (debug) { 274 asm.emitMOV_Reg_Imm(S1, 0xFA4FACE); 275 } 276 return; 277 case 2: 278 asm.emitPOP_Reg(S1); 279 asm.emitPOP_Reg(S1); 280 if (debug) { 281 asm.emitMOV_Reg_Imm(S1, 0xFA5FACE); 282 } 283 return; 284 } 285 } 286 if (VM.BuildFor32Addr) { 287 asm.emitADD_Reg_Imm(SP, size); 288 } else { 289 asm.emitADD_Reg_Imm_Quad(SP, size); 290 } 291 } 292 } 293 294 /** 295 * Move a value from the stack into a register using the shortest encoding and 296 * the appropriate width for 32/64 297 * 298 * @param dest register to load into 299 * @param off offset on stack 300 */ 301 private void stackMoveHelper(GPR dest, Offset off) { 302 stackMoveHelper(asm, dest, off); 303 } 304 305 /** 306 * Move a value from the stack into a register using the shortest encoding and 307 * the appropriate width for 32/64 308 * 309 * @param asm the assembler instance 310 * @param dest register to load into 311 * @param off offset on stack 312 */ 313 private static void stackMoveHelper(Assembler asm, GPR dest, Offset off) { 314 if (WORDSIZE == 4) { 315 if (off.isZero()) { 316 asm.emitMOV_Reg_RegInd(dest, SP); 317 } else { 318 asm.emitMOV_Reg_RegDisp(dest, SP, off); 319 } 320 } else { 321 if (off.isZero()) { 322 asm.emitMOV_Reg_RegInd_Quad(dest, SP); 323 } else { 324 asm.emitMOV_Reg_RegDisp_Quad(dest, SP, off); 325 } 326 } 327 } 328 329 /* 330 * implementation of abstract methods of BaselineCompiler 331 */ 332 333 /** 334 * Nothing to do on IA32. 335 */ 336 @Override 337 protected void starting_bytecode() {} 338 339 @Override 340 protected void emit_prologue() { 341 genPrologue(); 342 } 343 344 @Override 345 protected void emit_threadSwitchTest(int whereFrom) { 346 genThreadSwitchTest(whereFrom); 347 } 348 349 @Override 350 protected boolean emit_Magic(MethodReference magicMethod) { 351 return genMagic(magicMethod); 352 } 353 354 /* 355 * Loading constants 356 */ 357 358 @Override 359 protected void emit_aconst_null() { 360 asm.emitPUSH_Imm(0); 361 } 362 363 @Override 364 protected void emit_iconst(int val) { 365 asm.emitPUSH_Imm(val); 366 } 367 368 @Override 369 protected void emit_lconst(int val) { 370 asm.emitPUSH_Imm(0); // high part 371 asm.emitPUSH_Imm(val); // low part 372 } 373 374 @Override 375 protected void emit_fconst_0() { 376 asm.emitPUSH_Imm(0); 377 } 378 379 @Override 380 protected void emit_fconst_1() { 381 asm.emitPUSH_Imm(0x3f800000); 382 } 383 384 @Override 385 protected void emit_fconst_2() { 386 asm.emitPUSH_Imm(0x40000000); 387 } 388 389 @Override 390 protected void emit_dconst_0() { 391 if (VM.BuildFor32Addr) { 392 asm.emitPUSH_Imm(0x00000000); 393 asm.emitPUSH_Imm(0x00000000); 394 } else { 395 adjustStack(-WORDSIZE, true); 396 asm.emitPUSH_Imm(0x00000000); 397 } 398 } 399 400 @Override 401 protected void emit_dconst_1() { 402 if (VM.BuildFor32Addr) { 403 asm.emitPUSH_Imm(0x3ff00000); 404 asm.emitPUSH_Imm(0x00000000); 405 } else { 406 adjustStack(-WORDSIZE, true); 407 asm.generateJTOCpush(Entrypoints.oneDoubleField.getOffset()); 408 } 409 } 410 411 @Override 412 protected void emit_ldc(Offset offset, byte type) { 413 if (VM.BuildFor32Addr || (type == CP_CLASS) || (type == CP_STRING)) { 414 asm.generateJTOCpush(offset); 415 } else { 416 asm.generateJTOCloadInt(T0, offset); 417 asm.emitPUSH_Reg(T0); 418 } 419 } 420 421 @Override 422 protected void emit_ldc2(Offset offset, byte type) { 423 if (VM.BuildFor32Addr) { 424 asm.emitPUSH_Abs(Magic.getTocPointer().plus(offset).plus(WORDSIZE)); // high 32 bits 425 asm.emitPUSH_Abs(Magic.getTocPointer().plus(offset)); // low 32 bits 426 } else { 427 adjustStack(-WORDSIZE, true); 428 asm.generateJTOCpush(offset); 429 } 430 } 431 432 /* 433 * loading local variables 434 */ 435 436 @Override 437 protected void emit_regular_iload(int index) { 438 try { 439 Offset offset = localOffset(index); 440 if (offset.EQ(Offset.zero())) { 441 asm.emitPUSH_RegInd(ESP); 442 } else { 443 asm.emitPUSH_RegDisp(ESP, offset); 444 } 445 } catch (UnreachableBytecodeException e) { 446 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 447 } 448 } 449 450 @Override 451 protected void emit_fload(int index) { 452 // identical to iload 453 emit_regular_iload(index); 454 } 455 456 @Override 457 protected void emit_regular_aload(int index) { 458 // identical to iload 459 emit_regular_iload(index); 460 } 461 462 @Override 463 protected void emit_lload(int index) { 464 try { 465 Offset offset = localOffset(index); 466 if (VM.BuildFor32Addr) { 467 asm.emitPUSH_RegDisp(ESP, offset); // high part 468 asm.emitPUSH_RegDisp(ESP, offset); // low part (ESP has moved by 4!!) 469 } else { 470 adjustStack(-WORDSIZE, true); 471 asm.emitPUSH_RegDisp(ESP, offset); 472 } 473 } catch (UnreachableBytecodeException e) { 474 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 475 } 476 } 477 478 @Override 479 protected void emit_dload(int index) { 480 // identical to lload 481 emit_lload(index); 482 } 483 484 /* 485 * storing local variables 486 */ 487 488 @Override 489 protected void emit_istore(int index) { 490 try { 491 Offset offset = localOffset(index).minus(WORDSIZE); // pop computes EA after ESP has moved by WORDSIZE! 492 if (offset.EQ(Offset.zero())) { 493 asm.emitPOP_RegInd(ESP); 494 } else { 495 asm.emitPOP_RegDisp(ESP, offset); 496 } 497 } catch (UnreachableBytecodeException e) { 498 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 499 } 500 } 501 502 @Override 503 protected void emit_fstore(int index) { 504 // identical to istore 505 emit_istore(index); 506 } 507 508 @Override 509 protected void emit_astore(int index) { 510 // identical to istore 511 emit_istore(index); 512 } 513 514 @Override 515 protected void emit_lstore(int index) { 516 try { 517 if (VM.BuildFor32Addr) { 518 // pop computes EA after ESP has moved by 4! 519 Offset offset = localOffset(index + 1).minus(WORDSIZE); 520 asm.emitPOP_RegDisp(ESP, offset); // high part 521 asm.emitPOP_RegDisp(ESP, offset); // low part (ESP has moved by 4!!) 522 } else { 523 Offset offset = localOffset(index + 1).minus(WORDSIZE); 524 asm.emitPOP_RegDisp(ESP, offset); 525 adjustStack(WORDSIZE, true); // throw away top word 526 } 527 } catch (UnreachableBytecodeException e) { 528 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 529 } 530 } 531 532 @Override 533 protected void emit_dstore(int index) { 534 // identical to lstore 535 emit_lstore(index); 536 } 537 538 /* 539 * array loads 540 */ 541 542 @Override 543 protected void emit_iaload() { 544 asm.emitPOP_Reg(T0); // T0 is array index 545 asm.emitPOP_Reg(S0); // S0 is array ref 546 if (VM.BuildFor64Addr) { 547 asm.emitAND_Reg_Reg(T0, T0); // clear MSBs 548 } 549 genBoundsCheck(asm, T0, S0); // T0 is index, S0 is address of array 550 // push [S0+T0<<2] 551 asm.emitPUSH_RegIdx(S0, T0, WORD, NO_SLOT); 552 } 553 554 @Override 555 protected void emit_faload() { 556 // identical to iaload 557 emit_iaload(); 558 } 559 560 @Override 561 protected void emit_aaload() { 562 asm.emitPOP_Reg(T0); // T0 is array index 563 asm.emitPOP_Reg(T1); // T1 is array ref 564 if (VM.BuildFor64Addr) { 565 asm.emitAND_Reg_Reg(T0, T0); // clear MSBs 566 } 567 genBoundsCheck(asm, T0, T1); // T0 is index, T1 is address of array 568 if (NEEDS_OBJECT_ALOAD_BARRIER) { 569 // rewind 2 args on stack 570 asm.emitPUSH_Reg(T1); // T1 is array ref 571 asm.emitPUSH_Reg(T0); // T0 is array index 572 Barriers.compileArrayLoadBarrier(asm, true); 573 } else { 574 asm.emitPUSH_RegIdx(T1, T0, (short)LG_WORDSIZE, NO_SLOT); // push [S0+T0*WORDSIZE] 575 } 576 } 577 578 @Override 579 protected void emit_caload() { 580 asm.emitPOP_Reg(T0); // T0 is array index 581 asm.emitPOP_Reg(S0); // S0 is array ref 582 if (VM.BuildFor64Addr) { 583 asm.emitAND_Reg_Reg(T0, T0); // clear MSBs 584 } 585 genBoundsCheck(asm, T0, S0); // T0 is index, S0 is address of array 586 // T1 = (int)[S0+T0<<1] 587 if (VM.BuildFor32Addr) { 588 asm.emitMOVZX_Reg_RegIdx_Word(T1, S0, T0, SHORT, NO_SLOT); 589 } else { 590 asm.emitMOVZXQ_Reg_RegIdx_Word(T1, S0, T0, SHORT, NO_SLOT); 591 } 592 asm.emitPUSH_Reg(T1); // push short onto stack 593 } 594 595 /** 596 * Emits code to load an int local variable and then load from a character array 597 * @param index the local index to load 598 */ 599 @Override 600 protected void emit_iload_caload(int index) { 601 try { 602 Offset offset = localOffset(index); 603 if (offset.EQ(Offset.zero())) { 604 asm.emitMOV_Reg_RegInd(T0, SP); // T0 is array index 605 } else { 606 asm.emitMOV_Reg_RegDisp(T0, SP, offset); // T0 is array index 607 } 608 // NB MSBs of T0 are already clear in 64bit 609 asm.emitPOP_Reg(S0); // S0 is array ref 610 genBoundsCheck(asm, T0, S0); // T0 is index, S0 is address of array 611 // T1 = (int)[S0+T0<<1] 612 if (VM.BuildFor32Addr) { 613 asm.emitMOVZX_Reg_RegIdx_Word(T1, S0, T0, SHORT, NO_SLOT); 614 } else { 615 asm.emitMOVZXQ_Reg_RegIdx_Word(T1, S0, T0, SHORT, NO_SLOT); 616 } 617 asm.emitPUSH_Reg(T1); // push short onto stack 618 } catch (UnreachableBytecodeException e) { 619 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 620 } 621 } 622 623 @Override 624 protected void emit_saload() { 625 asm.emitPOP_Reg(T0); // T0 is array index 626 asm.emitPOP_Reg(S0); // S0 is array ref 627 if (VM.BuildFor64Addr) { 628 asm.emitAND_Reg_Reg(T0, T0); // clear MSBs 629 } 630 genBoundsCheck(asm, T0, S0); // T0 is index, S0 is address of array 631 // T1 = (int)[S0+T0<<1] 632 if (VM.BuildFor32Addr) { 633 asm.emitMOVSX_Reg_RegIdx_Word(T1, S0, T0, SHORT, NO_SLOT); 634 } else { 635 asm.emitMOVSXQ_Reg_RegIdx_Word(T1, S0, T0, SHORT, NO_SLOT); 636 } 637 asm.emitPUSH_Reg(T1); // push short onto stack 638 } 639 640 @Override 641 protected void emit_baload() { 642 asm.emitPOP_Reg(T0); // T0 is array index 643 asm.emitPOP_Reg(S0); // S0 is array ref 644 if (VM.BuildFor64Addr) { 645 asm.emitAND_Reg_Reg(T0, T0); // clear MSBs 646 } 647 genBoundsCheck(asm, T0, S0); // T0 is index, S0 is address of array 648 // T1 = (int)[S0+T0<<1] 649 if (VM.BuildFor32Addr) { 650 asm.emitMOVSX_Reg_RegIdx_Byte(T1, S0, T0, BYTE, NO_SLOT); 651 } else { 652 asm.emitMOVSXQ_Reg_RegIdx_Byte(T1, S0, T0, BYTE, NO_SLOT); 653 } 654 asm.emitPUSH_Reg(T1); // push byte onto stack 655 } 656 657 @Override 658 protected void emit_laload() { 659 asm.emitPOP_Reg(T0); // T0 is array index 660 asm.emitPOP_Reg(T1); // T1 is array ref 661 if (VM.BuildFor64Addr) { 662 asm.emitAND_Reg_Reg(T0, T0); // clear MSBs 663 } 664 genBoundsCheck(asm, T0, T1); // T0 is index, T1 is address of array 665 if (VM.BuildFor32Addr) { 666 asm.emitPUSH_RegIdx(T1, T0, LONG, ONE_SLOT); // load high part of desired long array element 667 asm.emitPUSH_RegIdx(T1, T0, LONG, NO_SLOT); // load low part of desired long array element 668 } else { 669 adjustStack(-WORDSIZE, true); 670 asm.emitPUSH_RegIdx(T1, T0, LONG, NO_SLOT); // load desired long array element 671 } 672 } 673 674 @Override 675 protected void emit_daload() { 676 // identical to laload 677 emit_laload(); 678 } 679 680 /* 681 * array stores 682 */ 683 684 /** 685 * Generates a primitive array store for the given size. 686 * 687 * @param size in bytes of the array store to generate 688 */ 689 private void primitiveArrayStoreHelper(int size) { 690 Barriers.compileModifyCheck(asm, (size == 8) ? 3 * WORDSIZE : 2 * WORDSIZE); 691 if (VM.BuildFor32Addr) { 692 if (size == 8) { 693 asm.emitPOP_Reg(S1); // S1 is the low value 694 } 695 asm.emitPOP_Reg(T1); // T1 is the value/high value 696 asm.emitPOP_Reg(T0); // T0 is array index 697 asm.emitPOP_Reg(S0); // S0 is array ref 698 } else { 699 asm.emitPOP_Reg(T1); // T1 is the value 700 if (size == 8) { 701 adjustStack(WORDSIZE, true); // throw away slot 702 } 703 asm.emitPOP_Reg(T0); // T0 is array index 704 asm.emitPOP_Reg(S0); // S0 is array ref 705 asm.emitAND_Reg_Reg(T0, T0); // clear MSBs 706 } 707 genBoundsCheck(asm, T0, S0); // T0 is index, S0 is address of array 708 switch (size) { 709 case 8: 710 if (VM.BuildFor32Addr) { 711 asm.emitMOV_RegIdx_Reg(S0, T0, LONG, NO_SLOT, S1); // [S0+T0<<<3] <- S1 712 asm.emitMOV_RegIdx_Reg(S0, T0, LONG, ONE_SLOT, T1); // [4+S0+T0<<<3] <- T1 713 } else { 714 asm.emitMOV_RegIdx_Reg_Quad(S0, T0, LONG, NO_SLOT, T1); // [S0+T0<<<3] <- T1 715 } 716 break; 717 case 4: 718 asm.emitMOV_RegIdx_Reg(S0, T0, WORD, NO_SLOT, T1); // [S0 + T0<<2] <- T1 719 break; 720 case 2: 721 // store halfword element into array i.e. [S0 +T0] <- T1 (halfword) 722 asm.emitMOV_RegIdx_Reg_Word(S0, T0, SHORT, NO_SLOT, T1); 723 break; 724 case 1: 725 asm.emitMOV_RegIdx_Reg_Byte(S0, T0, BYTE, NO_SLOT, T1); // [S0 + T0<<2] <- T1 726 break; 727 default: 728 if (VM.VerifyAssertions) { 729 VM._assert(VM.NOT_REACHED, "Unhandled byte size!"); 730 } else { 731 VM.sysFail("Unhandled byte size"); 732 } 733 } 734 } 735 736 /** 737 * Private helper to perform an array bounds check 738 * @param index offset from current SP to the array index 739 * @param arrayRef offset from current SP to the array reference 740 */ 741 private void boundsCheckHelper(Offset index, Offset arrayRef) { 742 stackMoveHelper(T0, index); // T0 is array index 743 if (VM.BuildFor64Addr) { 744 asm.emitAND_Reg_Reg(T0, T0); // clear MSBs 745 } 746 stackMoveHelper(S0, arrayRef); // S0 is array ref 747 genBoundsCheck(asm, T0, S0); // T0 is index, S0 is address of array 748 } 749 750 @Override 751 protected void emit_iastore() { 752 Barriers.compileModifyCheck(asm, 2 * WORDSIZE); 753 if (NEEDS_INT_ASTORE_BARRIER) { 754 boundsCheckHelper(ONE_SLOT, TWO_SLOTS); 755 Barriers.compileArrayStoreBarrierInt(asm, this); 756 } else { 757 primitiveArrayStoreHelper(4); 758 } 759 } 760 761 @Override 762 protected void emit_fastore() { 763 Barriers.compileModifyCheck(asm, 2 * WORDSIZE); 764 if (NEEDS_FLOAT_ASTORE_BARRIER) { 765 boundsCheckHelper(ONE_SLOT, TWO_SLOTS); 766 Barriers.compileArrayStoreBarrierFloat(asm, this); 767 } else { 768 primitiveArrayStoreHelper(4); 769 } 770 } 771 772 773 @Override 774 protected void emit_aastore() { 775 Barriers.compileModifyCheck(asm, 2 * WORDSIZE); 776 if (doesCheckStore) { 777 genParameterRegisterLoad(asm, 3); 778 asm.generateJTOCcall(Entrypoints.aastoreMethod.getOffset()); 779 } else { 780 genParameterRegisterLoad(asm, 3); 781 asm.generateJTOCcall(Entrypoints.aastoreUninterruptibleMethod.getOffset()); 782 } 783 } 784 785 @Override 786 protected void emit_castore() { 787 Barriers.compileModifyCheck(asm, 2 * WORDSIZE); 788 if (NEEDS_CHAR_ASTORE_BARRIER) { 789 boundsCheckHelper(ONE_SLOT, TWO_SLOTS); 790 Barriers.compileArrayStoreBarrierChar(asm, this); 791 } else { 792 primitiveArrayStoreHelper(2); 793 } 794 } 795 796 @Override 797 protected void emit_sastore() { 798 Barriers.compileModifyCheck(asm, 2 * WORDSIZE); 799 if (NEEDS_SHORT_ASTORE_BARRIER) { 800 boundsCheckHelper(ONE_SLOT, TWO_SLOTS); 801 Barriers.compileArrayStoreBarrierShort(asm, this); 802 } else { 803 primitiveArrayStoreHelper(2); 804 } 805 } 806 807 @Override 808 protected void emit_bastore() { 809 Barriers.compileModifyCheck(asm, 2 * WORDSIZE); 810 if (NEEDS_BYTE_ASTORE_BARRIER) { 811 boundsCheckHelper(ONE_SLOT, TWO_SLOTS); 812 Barriers.compileArrayStoreBarrierByte(asm, this); 813 } else { 814 primitiveArrayStoreHelper(1); 815 } 816 } 817 818 @Override 819 protected void emit_lastore() { 820 Barriers.compileModifyCheck(asm, 3 * WORDSIZE); 821 if (NEEDS_LONG_ASTORE_BARRIER) { 822 boundsCheckHelper(TWO_SLOTS, THREE_SLOTS); 823 Barriers.compileArrayStoreBarrierLong(asm, this); 824 } else { 825 primitiveArrayStoreHelper(8); 826 } 827 } 828 829 @Override 830 protected void emit_dastore() { 831 Barriers.compileModifyCheck(asm, 3 * WORDSIZE); 832 if (NEEDS_DOUBLE_ASTORE_BARRIER) { 833 boundsCheckHelper(TWO_SLOTS, THREE_SLOTS); 834 Barriers.compileArrayStoreBarrierDouble(asm, this); 835 } else { 836 primitiveArrayStoreHelper(8); 837 } 838 } 839 840 /* 841 * expression stack manipulation 842 */ 843 844 @Override 845 protected void emit_pop() { 846 adjustStack(WORDSIZE, true); 847 } 848 849 @Override 850 protected void emit_pop2() { 851 // This could be encoded as the single 3 byte instruction 852 // asm.emitADD_Reg_Imm(SP, 8); 853 // or as the following 2 1 byte instructions. There doesn't appear to be any 854 // performance difference. 855 adjustStack(WORDSIZE * 2, true); 856 } 857 858 @Override 859 protected void emit_dup() { 860 // This could be encoded as the 2 instructions totalling 4 bytes: 861 // asm.emitMOV_Reg_RegInd(T0, SP); 862 // asm.emitPUSH_Reg(T0); 863 // However, there doesn't seem to be any performance difference to: 864 asm.emitPUSH_RegInd(SP); 865 } 866 867 @Override 868 protected void emit_dup_x1() { 869 asm.emitPOP_Reg(T0); 870 asm.emitPOP_Reg(S0); 871 asm.emitPUSH_Reg(T0); 872 asm.emitPUSH_Reg(S0); 873 asm.emitPUSH_Reg(T0); 874 } 875 876 @Override 877 protected void emit_dup_x2() { 878 asm.emitPOP_Reg(T0); 879 asm.emitPOP_Reg(S0); 880 asm.emitPOP_Reg(T1); 881 asm.emitPUSH_Reg(T0); 882 asm.emitPUSH_Reg(T1); 883 asm.emitPUSH_Reg(S0); 884 asm.emitPUSH_Reg(T0); 885 } 886 887 @Override 888 protected void emit_dup2() { 889 asm.emitPOP_Reg(T0); 890 asm.emitPOP_Reg(S0); 891 asm.emitPUSH_Reg(S0); 892 asm.emitPUSH_Reg(T0); 893 asm.emitPUSH_Reg(S0); 894 asm.emitPUSH_Reg(T0); 895 } 896 897 @Override 898 protected void emit_dup2_x1() { 899 asm.emitPOP_Reg(T0); 900 asm.emitPOP_Reg(S0); 901 asm.emitPOP_Reg(T1); 902 asm.emitPUSH_Reg(S0); 903 asm.emitPUSH_Reg(T0); 904 asm.emitPUSH_Reg(T1); 905 asm.emitPUSH_Reg(S0); 906 asm.emitPUSH_Reg(T0); 907 } 908 909 @Override 910 protected void emit_dup2_x2() { 911 asm.emitPOP_Reg(T0); 912 asm.emitPOP_Reg(S0); 913 asm.emitPOP_Reg(T1); 914 asm.emitPOP_Reg(S1); 915 asm.emitPUSH_Reg(S0); 916 asm.emitPUSH_Reg(T0); 917 asm.emitPUSH_Reg(S1); 918 asm.emitPUSH_Reg(T1); 919 asm.emitPUSH_Reg(S0); 920 asm.emitPUSH_Reg(T0); 921 } 922 923 @Override 924 protected void emit_swap() { 925 // This could be encoded as the 4 instructions totalling 14 bytes: 926 // asm.emitMOV_Reg_RegInd(T0, SP); 927 // asm.emitMOV_Reg_RegDisp(S0, SP, ONE_SLOT); 928 // asm.emitMOV_RegDisp_Reg(SP, ONE_SLOT, T0); 929 // asm.emitMOV_RegInd_Reg(SP, S0); 930 // But the following is 4bytes: 931 asm.emitPOP_Reg(T0); 932 asm.emitPOP_Reg(S0); 933 asm.emitPUSH_Reg(T0); 934 asm.emitPUSH_Reg(S0); 935 } 936 937 /* 938 * int ALU 939 */ 940 941 @Override 942 protected void emit_iadd() { 943 asm.emitPOP_Reg(T0); 944 asm.emitADD_RegInd_Reg(SP, T0); 945 } 946 947 @Override 948 protected void emit_isub() { 949 asm.emitPOP_Reg(T0); 950 asm.emitSUB_RegInd_Reg(SP, T0); 951 } 952 953 @Override 954 protected void emit_imul() { 955 asm.emitPOP_Reg(T0); 956 asm.emitPOP_Reg(T1); 957 asm.emitIMUL2_Reg_Reg(T0, T1); 958 asm.emitPUSH_Reg(T0); 959 } 960 961 @Override 962 protected void emit_idiv() { 963 asm.emitPOP_Reg(ECX); // ECX is divisor; NOTE: can't use symbolic registers because of intel hardware requirements 964 asm.emitPOP_Reg(EAX); // EAX is dividend 965 asm.emitCDQ(); // sign extend EAX into EDX 966 asm.emitIDIV_Reg_Reg(EAX, ECX); 967 asm.emitPUSH_Reg(EAX); // push result 968 } 969 970 @Override 971 protected void emit_irem() { 972 asm.emitPOP_Reg(ECX); // ECX is divisor; NOTE: can't use symbolic registers because of intel hardware requirements 973 asm.emitPOP_Reg(EAX); // EAX is dividend 974 asm.emitCDQ(); // sign extend EAX into EDX 975 asm.emitIDIV_Reg_Reg(EAX, ECX); 976 asm.emitPUSH_Reg(EDX); // push remainder 977 } 978 979 @Override 980 protected void emit_ineg() { 981 asm.emitNEG_RegInd(SP); // [SP] <- -[SP] 982 } 983 984 @Override 985 protected void emit_ishl() { 986 asm.emitPOP_Reg(ECX); 987 asm.emitSHL_RegInd_Reg(SP, ECX); 988 } 989 990 @Override 991 protected void emit_ishr() { 992 asm.emitPOP_Reg(ECX); 993 asm.emitSAR_RegInd_Reg(SP, ECX); 994 } 995 996 @Override 997 protected void emit_iushr() { 998 asm.emitPOP_Reg(ECX); 999 asm.emitSHR_RegInd_Reg(SP, ECX); 1000 } 1001 1002 @Override 1003 protected void emit_iand() { 1004 asm.emitPOP_Reg(T0); 1005 asm.emitAND_RegInd_Reg(SP, T0); 1006 } 1007 1008 @Override 1009 protected void emit_ior() { 1010 asm.emitPOP_Reg(T0); 1011 asm.emitOR_RegInd_Reg(SP, T0); 1012 } 1013 1014 @Override 1015 protected void emit_ixor() { 1016 asm.emitPOP_Reg(T0); 1017 asm.emitXOR_RegInd_Reg(SP, T0); 1018 } 1019 1020 @Override 1021 protected void emit_iinc(int index, int val) { 1022 try { 1023 Offset offset = localOffset(index); 1024 asm.emitADD_RegDisp_Imm(ESP, offset, val); 1025 } catch (UnreachableBytecodeException e) { 1026 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 1027 } 1028 } 1029 1030 /* 1031 * long ALU 1032 */ 1033 1034 @Override 1035 protected void emit_ladd() { 1036 if (VM.BuildFor32Addr) { 1037 asm.emitPOP_Reg(T0); // the low half of one long 1038 asm.emitPOP_Reg(S0); // the high half 1039 asm.emitADD_RegInd_Reg(SP, T0); // add low halves 1040 asm.emitADC_RegDisp_Reg(SP, ONE_SLOT, S0); // add high halves with carry 1041 } else { 1042 asm.emitPOP_Reg(T0); // the long value 1043 asm.emitPOP_Reg(S0); // throw away slot 1044 asm.emitADD_RegInd_Reg_Quad(SP, T0); // add values 1045 } 1046 } 1047 1048 @Override 1049 protected void emit_lsub() { 1050 if (VM.BuildFor32Addr) { 1051 asm.emitPOP_Reg(T0); // the low half of one long 1052 asm.emitPOP_Reg(S0); // the high half 1053 asm.emitSUB_RegInd_Reg(SP, T0); // subtract low halves 1054 asm.emitSBB_RegDisp_Reg(SP, ONE_SLOT, S0); // subtract high halves with borrow 1055 } else { 1056 asm.emitPOP_Reg(T0); // the long value 1057 adjustStack(WORDSIZE, true); // throw away slot 1058 asm.emitSUB_RegInd_Reg_Quad(SP, T0); // sub values 1059 } 1060 } 1061 1062 @Override 1063 protected void emit_lmul() { 1064 if (VM.BuildFor64Addr) { 1065 asm.emitPOP_Reg(T0); // the long value 1066 asm.emitPOP_Reg(S0); // throw away slot 1067 asm.emitIMUL2_Reg_RegInd_Quad(T0, SP); 1068 asm.emitMOV_RegInd_Reg_Quad(SP, T0); 1069 } else { 1070 // stack: value1.high = mulitplier 1071 // value1.low 1072 // value2.high = multiplicand 1073 // value2.low <-- ESP 1074 if (VM.VerifyAssertions) VM._assert(S0 != EAX); 1075 if (VM.VerifyAssertions) VM._assert(S0 != EDX); 1076 // EAX = multiplicand low; SP changed! 1077 asm.emitPOP_Reg(EAX); 1078 // EDX = multiplicand high 1079 asm.emitPOP_Reg(EDX); 1080 // stack: value1.high = mulitplier 1081 // value1.low <-- ESP 1082 // value2.high = multiplicand 1083 // value2.low 1084 // S0 = multiplier high 1085 asm.emitMOV_Reg_RegDisp(S0, SP, ONE_SLOT); 1086 // is one operand > 2^32 ? 1087 asm.emitOR_Reg_Reg(EDX, S0); 1088 // EDX = multiplier low 1089 asm.emitMOV_Reg_RegInd(EDX, SP); 1090 // Jump if we need a 64bit multiply 1091 ForwardReference fr1 = asm.forwardJcc(NE); 1092 // EDX:EAX = 32bit multiply of multiplier and multiplicand low 1093 asm.emitMUL_Reg_Reg(EAX, EDX); 1094 // Jump over 64bit multiply 1095 ForwardReference fr2 = asm.forwardJMP(); 1096 // Start of 64bit multiply 1097 fr1.resolve(asm); 1098 // EDX = multiplicand high * multiplier low 1099 asm.emitIMUL2_Reg_RegDisp(EDX, SP, MINUS_ONE_SLOT); 1100 // S0 = multiplier high * multiplicand low 1101 asm.emitIMUL2_Reg_Reg(S0, EAX); 1102 // S0 = S0 + EDX 1103 asm.emitADD_Reg_Reg(S0, EDX); 1104 // EDX:EAX = 32bit multiply of multiplier and multiplicand low 1105 asm.emitMUL_Reg_RegInd(EAX, SP); 1106 // EDX = EDX + S0 1107 asm.emitADD_Reg_Reg(EDX, S0); 1108 // Finish up 1109 fr2.resolve(asm); 1110 // store EDX:EAX to stack 1111 asm.emitMOV_RegDisp_Reg(SP, ONE_SLOT, EDX); 1112 asm.emitMOV_RegInd_Reg(SP, EAX); 1113 } 1114 } 1115 1116 @Override 1117 protected void emit_ldiv() { 1118 if (VM.BuildFor64Addr) { 1119 asm.emitPOP_Reg(ECX); // ECX is divisor; NOTE: can't use symbolic registers because of intel hardware requirements 1120 asm.emitPOP_Reg(EAX); // throw away slot 1121 asm.emitPOP_Reg(EAX); // EAX is dividend 1122 asm.emitCDO(); // sign extend EAX into EDX 1123 asm.emitIDIV_Reg_Reg_Quad(EAX, ECX); 1124 asm.emitPUSH_Reg(EAX); // push result 1125 } else { 1126 // (1) zero check 1127 asm.emitMOV_Reg_RegInd(T0, SP); 1128 asm.emitOR_Reg_RegDisp(T0, SP, ONE_SLOT); 1129 asm.emitBranchLikelyNextInstruction(); 1130 ForwardReference fr1 = asm.forwardJcc(NE); 1131 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO + RVM_TRAP_BASE); // trap if divisor is 0 1132 fr1.resolve(asm); 1133 // (2) save RVM nonvolatiles 1134 int numNonVols = NONVOLATILE_GPRS.length; 1135 Offset off = Offset.fromIntSignExtend(numNonVols * WORDSIZE); 1136 for (int i = 0; i < numNonVols; i++) { 1137 asm.emitPUSH_Reg(NONVOLATILE_GPRS[i]); 1138 } 1139 // (3) Push args to C function (reversed) 1140 asm.emitPUSH_RegDisp(SP, off.plus(4)); 1141 asm.emitPUSH_RegDisp(SP, off.plus(4)); 1142 asm.emitPUSH_RegDisp(SP, off.plus(20)); 1143 asm.emitPUSH_RegDisp(SP, off.plus(20)); 1144 // (4) invoke C function through bootrecord 1145 asm.emitMOV_Reg_Abs(S0, Magic.getTocPointer().plus(Entrypoints.the_boot_recordField.getOffset())); 1146 asm.emitCALL_RegDisp(S0, Entrypoints.sysLongDivideIPField.getOffset()); 1147 // (5) pop space for arguments 1148 adjustStack(4 * WORDSIZE, true); 1149 // (6) restore RVM nonvolatiles 1150 for (int i = numNonVols - 1; i >= 0; i--) { 1151 asm.emitPOP_Reg(NONVOLATILE_GPRS[i]); 1152 } 1153 // (7) pop expression stack 1154 adjustStack(WORDSIZE * 4, true); 1155 // (8) push results 1156 asm.emitPUSH_Reg(T1); 1157 asm.emitPUSH_Reg(T0); 1158 } 1159 } 1160 1161 @Override 1162 protected void emit_lrem() { 1163 if (VM.BuildFor64Addr) { 1164 asm.emitPOP_Reg(ECX); // ECX is divisor; NOTE: can't use symbolic registers because of intel hardware requirements 1165 asm.emitPOP_Reg(EAX); // throw away slot 1166 asm.emitPOP_Reg(EAX); // EAX is dividend 1167 asm.emitCDO(); // sign extend EAX into EDX 1168 asm.emitIDIV_Reg_Reg_Quad(EAX, ECX); 1169 asm.emitPUSH_Reg(EDX); // push result 1170 } else { 1171 // (1) zero check 1172 asm.emitMOV_Reg_RegInd(T0, SP); 1173 asm.emitOR_Reg_RegDisp(T0, SP, ONE_SLOT); 1174 asm.emitBranchLikelyNextInstruction(); 1175 ForwardReference fr1 = asm.forwardJcc(NE); 1176 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO + RVM_TRAP_BASE); // trap if divisor is 0 1177 fr1.resolve(asm); 1178 // (2) save RVM nonvolatiles 1179 int numNonVols = NONVOLATILE_GPRS.length; 1180 Offset off = Offset.fromIntSignExtend(numNonVols * WORDSIZE); 1181 for (int i = 0; i < numNonVols; i++) { 1182 asm.emitPUSH_Reg(NONVOLATILE_GPRS[i]); 1183 } 1184 // (3) Push args to C function (reversed) 1185 asm.emitPUSH_RegDisp(SP, off.plus(4)); 1186 asm.emitPUSH_RegDisp(SP, off.plus(4)); 1187 asm.emitPUSH_RegDisp(SP, off.plus(20)); 1188 asm.emitPUSH_RegDisp(SP, off.plus(20)); 1189 // (4) invoke C function through bootrecord 1190 asm.emitMOV_Reg_Abs(S0, Magic.getTocPointer().plus(Entrypoints.the_boot_recordField.getOffset())); 1191 asm.emitCALL_RegDisp(S0, Entrypoints.sysLongRemainderIPField.getOffset()); 1192 // (5) pop space for arguments 1193 adjustStack(4 * WORDSIZE, true); 1194 // (6) restore RVM nonvolatiles 1195 for (int i = numNonVols - 1; i >= 0; i--) { 1196 asm.emitPOP_Reg(NONVOLATILE_GPRS[i]); 1197 } 1198 // (7) pop expression stack 1199 adjustStack(WORDSIZE * 4, true); 1200 // (8) push results 1201 asm.emitPUSH_Reg(T1); 1202 asm.emitPUSH_Reg(T0); 1203 } 1204 } 1205 1206 @Override 1207 protected void emit_lneg() { 1208 if (VM.BuildFor32Addr) { 1209 // The following is fewer instructions, but larger code 1210 // asm.emitNOT_RegDisp(SP, ONE_SLOT); 1211 // asm.emitNEG_RegInd(SP); 1212 // asm.emitSBB_RegDisp_Imm(SP, ONE_SLOT, -1); 1213 // this implementation is shorter and promotes ESP folding 1214 asm.emitPOP_Reg(T0); // T0 = low 1215 asm.emitNEG_Reg(T0); // T0 = -low 1216 asm.emitPOP_Reg(T1); // T1 = high 1217 asm.emitNOT_Reg(T1); // T1 = ~T1 (doesn't effect flags) 1218 asm.emitSBB_Reg_Imm(T1, -1); // T1 = high + 1 - CF 1219 asm.emitPUSH_Reg(T1); 1220 asm.emitPUSH_Reg(T0); 1221 } else { 1222 asm.emitNEG_RegInd_Quad(SP); 1223 } 1224 } 1225 1226 @Override 1227 protected void emit_lshl() { 1228 if (VM.BuildFor32Addr) { 1229 if (SSE2_BASE) { 1230 asm.emitPOP_Reg(T0); // shift amount (6 bits) 1231 asm.emitMOVQ_Reg_RegInd(XMM1, SP); // XMM1 <- [SP] 1232 asm.emitAND_Reg_Imm(T0, 0x3F); // mask to 6bits 1233 asm.emitMOVD_Reg_Reg(XMM0, T0); // XMM0 <- T0 1234 asm.emitPSLLQ_Reg_Reg(XMM1, XMM0); // XMM1 <<= XMM0 1235 asm.emitMOVQ_RegInd_Reg(SP, XMM1); // [SP] <- XMM1 1236 } else { 1237 if (VM.VerifyAssertions) VM._assert(ECX != T0); // ECX is constrained to be the shift count 1238 if (VM.VerifyAssertions) VM._assert(ECX != T1); 1239 asm.emitPOP_Reg(ECX); // shift amount (6 bits) 1240 asm.emitPOP_Reg(T0); // pop low half 1241 asm.emitPOP_Reg(T1); // pop high half 1242 asm.emitAND_Reg_Imm(ECX, 0x3F); 1243 asm.emitCMP_Reg_Imm(ECX, 32); 1244 ForwardReference fr1 = asm.forwardJcc(LT); 1245 asm.emitMOV_Reg_Reg(T1, T0); // high half = low half 1246 asm.emitXOR_Reg_Reg(T0, T0); // low half = 0 1247 fr1.resolve(asm); 1248 asm.emitSHLD_Reg_Reg_Reg(T1, T0, ECX); // shift high half, filling from low 1249 asm.emitSHL_Reg_Reg(T0, ECX); // shift low half 1250 asm.emitPUSH_Reg(T1); // push high half 1251 asm.emitPUSH_Reg(T0); // push low half 1252 } 1253 } else { 1254 asm.emitPOP_Reg(ECX); 1255 asm.emitSHL_RegInd_Reg_Quad(SP, ECX); 1256 } 1257 } 1258 1259 @Override 1260 protected void emit_lshr() { 1261 if (VM.BuildFor32Addr) { 1262 if (VM.VerifyAssertions) VM._assert(ECX != T0); // ECX is constrained to be the shift count 1263 if (VM.VerifyAssertions) VM._assert(ECX != T1); 1264 asm.emitPOP_Reg(ECX); // shift amount (6 bits) 1265 asm.emitPOP_Reg(T0); // pop low half 1266 asm.emitPOP_Reg(T1); // pop high half 1267 asm.emitAND_Reg_Imm(ECX, 0x3F); 1268 asm.emitCMP_Reg_Imm(ECX, 32); 1269 ForwardReference fr1 = asm.forwardJcc(LT); 1270 asm.emitMOV_Reg_Reg(T0, T1); // low half = high half 1271 asm.emitSAR_Reg_Imm(T1, 31); // high half = sign extension of low half 1272 fr1.resolve(asm); 1273 asm.emitSHRD_Reg_Reg_Reg(T0, T1, ECX); // shift low half, filling from high 1274 asm.emitSAR_Reg_Reg(T1, ECX); // shift high half 1275 asm.emitPUSH_Reg(T1); // push high half 1276 asm.emitPUSH_Reg(T0); // push low half 1277 } else { 1278 asm.emitPOP_Reg(ECX); 1279 asm.emitSAR_RegInd_Reg_Quad(SP, ECX); 1280 } 1281 } 1282 1283 @Override 1284 protected void emit_lushr() { 1285 if (VM.BuildFor32Addr) { 1286 if (SSE2_BASE) { 1287 asm.emitPOP_Reg(T0); // shift amount (6 bits) 1288 asm.emitMOVQ_Reg_RegInd(XMM1, SP); // XMM1 <- [SP] 1289 asm.emitAND_Reg_Imm(T0, 0x3F); // mask to 6bits 1290 asm.emitMOVD_Reg_Reg(XMM0, T0); // XMM0 <- T0 1291 asm.emitPSRLQ_Reg_Reg(XMM1, XMM0); // XMM1 >>>= XMM0 1292 asm.emitMOVQ_RegInd_Reg(SP, XMM1); // [SP] <- XMM1 1293 } else { 1294 if (VM.VerifyAssertions) VM._assert(ECX != T0); // ECX is constrained to be the shift count 1295 if (VM.VerifyAssertions) VM._assert(ECX != T1); 1296 asm.emitPOP_Reg(ECX); // shift amount (6 bits) 1297 asm.emitPOP_Reg(T0); // pop low half 1298 asm.emitPOP_Reg(T1); // pop high half 1299 asm.emitAND_Reg_Imm(ECX, 0x3F); 1300 asm.emitCMP_Reg_Imm(ECX, 32); 1301 ForwardReference fr1 = asm.forwardJcc(LT); 1302 asm.emitMOV_Reg_Reg(T0, T1); // low half = high half 1303 asm.emitXOR_Reg_Reg(T1, T1); // high half = 0 1304 fr1.resolve(asm); 1305 asm.emitSHRD_Reg_Reg_Reg(T0, T1, ECX); // shift low half, filling from high 1306 asm.emitSHR_Reg_Reg(T1, ECX); // shift high half 1307 asm.emitPUSH_Reg(T1); // push high half 1308 asm.emitPUSH_Reg(T0); // push low half 1309 } 1310 } else { 1311 asm.emitPOP_Reg(ECX); 1312 asm.emitSHR_RegInd_Reg_Quad(SP, ECX); 1313 } 1314 } 1315 1316 @Override 1317 protected void emit_land() { 1318 if (VM.BuildFor32Addr) { 1319 asm.emitPOP_Reg(T0); // low 1320 asm.emitPOP_Reg(S0); // high 1321 asm.emitAND_RegInd_Reg(SP, T0); 1322 asm.emitAND_RegDisp_Reg(SP, ONE_SLOT, S0); 1323 } else { 1324 asm.emitPOP_Reg(T0); // long value 1325 asm.emitPOP_Reg(S0); // throw away slot 1326 asm.emitAND_RegInd_Reg_Quad(SP, T0); 1327 } 1328 } 1329 1330 @Override 1331 protected void emit_lor() { 1332 if (VM.BuildFor32Addr) { 1333 asm.emitPOP_Reg(T0); // low 1334 asm.emitPOP_Reg(S0); // high 1335 asm.emitOR_RegInd_Reg(SP, T0); 1336 asm.emitOR_RegDisp_Reg(SP, ONE_SLOT, S0); 1337 } else { 1338 asm.emitPOP_Reg(T0); // long value 1339 asm.emitPOP_Reg(S0); // throw away slot 1340 asm.emitOR_RegInd_Reg_Quad(SP, T0); 1341 } 1342 } 1343 1344 /** 1345 * Emit code to implement the lxor bytecode 1346 */ 1347 @Override 1348 protected void emit_lxor() { 1349 if (VM.BuildFor32Addr) { 1350 asm.emitPOP_Reg(T0); // low 1351 asm.emitPOP_Reg(S0); // high 1352 asm.emitXOR_RegInd_Reg(SP, T0); 1353 asm.emitXOR_RegDisp_Reg(SP, ONE_SLOT, S0); 1354 } else { 1355 asm.emitPOP_Reg(T0); // long value 1356 asm.emitPOP_Reg(S0); // throw away slot 1357 asm.emitXOR_RegInd_Reg_Quad(SP, T0); 1358 } 1359 } 1360 1361 /* 1362 * float ALU 1363 */ 1364 1365 @Override 1366 protected void emit_fadd() { 1367 if (SSE2_BASE) { 1368 asm.emitMOVSS_Reg_RegInd(XMM0, SP); // XMM0 = value2 1369 adjustStack(WORDSIZE, true); // throw away slot 1370 asm.emitADDSS_Reg_RegInd(XMM0, SP); // XMM0 += value1 1371 asm.emitMOVSS_RegInd_Reg(SP, XMM0); // set result on stack 1372 } else { 1373 asm.emitFLD_Reg_RegInd(FP0, SP); // FPU reg. stack <- value2 1374 adjustStack(WORDSIZE, true); // throw away slot 1375 asm.emitFADD_Reg_RegInd(FP0, SP); // FPU reg. stack += value1 1376 asm.emitFSTP_RegInd_Reg(SP, FP0); // POP FPU reg. stack onto stack 1377 } 1378 } 1379 1380 @Override 1381 protected void emit_fsub() { 1382 if (SSE2_BASE) { 1383 asm.emitMOVSS_Reg_RegDisp(XMM0, SP, ONE_SLOT); // XMM0 = value1 1384 asm.emitSUBSS_Reg_RegInd(XMM0, SP); // XMM0 -= value2 1385 adjustStack(WORDSIZE, true); // throw away slot 1386 asm.emitMOVSS_RegInd_Reg(SP, XMM0); // set result on stack 1387 } else { 1388 asm.emitFLD_Reg_RegDisp(FP0, SP, ONE_SLOT); // FPU reg. stack <- value1 1389 asm.emitFSUB_Reg_RegInd(FP0, SP); // FPU reg. stack -= value2 1390 adjustStack(WORDSIZE, true); // throw away slot 1391 asm.emitFSTP_RegInd_Reg(SP, FP0); // POP FPU reg. stack onto stack 1392 } 1393 } 1394 1395 @Override 1396 protected void emit_fmul() { 1397 if (SSE2_BASE) { 1398 asm.emitMOVSS_Reg_RegInd(XMM0, SP); // XMM0 = value2 1399 adjustStack(WORDSIZE, true); // throw away slot 1400 asm.emitMULSS_Reg_RegInd(XMM0, SP); // XMM0 *= value1 1401 asm.emitMOVSS_RegInd_Reg(SP, XMM0); // set result on stack 1402 } else { 1403 asm.emitFLD_Reg_RegInd(FP0, SP); // FPU reg. stack <- value2 1404 adjustStack(WORDSIZE, true); // throw away slot 1405 asm.emitFMUL_Reg_RegInd(FP0, SP); // FPU reg. stack *= value1 1406 asm.emitFSTP_RegInd_Reg(SP, FP0); // POP FPU reg. stack onto stack 1407 } 1408 } 1409 1410 /** 1411 * Emit code to implement the fdiv bytecode 1412 */ 1413 @Override 1414 protected void emit_fdiv() { 1415 if (SSE2_BASE) { 1416 asm.emitMOVSS_Reg_RegDisp(XMM0, SP, ONE_SLOT); // XMM0 = value1 1417 asm.emitDIVSS_Reg_RegInd(XMM0, SP); // XMM0 /= value2 1418 adjustStack(WORDSIZE, true); // throw away slot 1419 asm.emitMOVSS_RegInd_Reg(SP, XMM0); // set result on stack 1420 } else { 1421 asm.emitFLD_Reg_RegDisp(FP0, SP, ONE_SLOT); // FPU reg. stack <- value1 1422 asm.emitFDIV_Reg_RegInd(FP0, SP); // FPU reg. stack /= value2 1423 adjustStack(WORDSIZE, true); // throw away slot 1424 asm.emitFSTP_RegInd_Reg(SP, FP0); // POP FPU reg. stack onto stack 1425 } 1426 } 1427 1428 @Override 1429 protected void emit_frem() { 1430 asm.emitFLD_Reg_RegInd(FP0, SP); // FPU reg. stack <- value2, or a 1431 adjustStack(WORDSIZE, true); // throw away slot 1432 asm.emitFLD_Reg_RegInd(FP0, SP); // FPU reg. stack <- value1, or b 1433 int retryLabel = asm.getMachineCodeIndex(); // come here if partial remainder not complete 1434 asm.emitFPREM(); // FPU reg. stack <- a%b 1435 asm.emitFSTSW_Reg(EAX); // AX = fpsw 1436 asm.emitAND_Reg_Imm(EAX, 0x400); // is C2 set? 1437 asm.emitJCC_Cond_Imm(NE, retryLabel); // if yes then goto retryLabel and continue to compute remainder 1438 asm.emitFSTP_RegInd_Reg(SP, FP0); // POP FPU reg. stack (results) onto java stack 1439 asm.emitFFREEP_Reg(FP0); 1440 } 1441 1442 @Override 1443 protected void emit_fneg() { 1444 // flip sign bit 1445 asm.emitXOR_RegInd_Imm(SP, 0x80000000); 1446 } 1447 1448 /* 1449 * double ALU 1450 */ 1451 1452 @Override 1453 protected void emit_dadd() { 1454 if (SSE2_BASE) { 1455 asm.emitMOVSD_Reg_RegInd(XMM0, SP); // XMM0 = value2 1456 adjustStack(WORDSIZE * 2, true); // throw away long slot 1457 asm.emitADDSD_Reg_RegInd(XMM0, SP); // XMM0 += value1 1458 asm.emitMOVSD_RegInd_Reg(SP, XMM0); // set result on stack 1459 } else { 1460 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); // FPU reg. stack <- value2 1461 adjustStack(WORDSIZE * 2, true); // throw away long slot 1462 asm.emitFADD_Reg_RegInd_Quad(FP0, SP); // FPU reg. stack += value1 1463 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); // POP FPU reg. stack onto stack 1464 } 1465 } 1466 1467 @Override 1468 protected void emit_dsub() { 1469 if (SSE2_BASE) { 1470 asm.emitMOVSD_Reg_RegDisp(XMM0, SP, TWO_SLOTS); // XMM0 = value1 1471 asm.emitSUBSD_Reg_RegInd(XMM0, SP); // XMM0 -= value2 1472 adjustStack(WORDSIZE * 2, true); // throw away long slot 1473 asm.emitMOVSD_RegInd_Reg(SP, XMM0); // set result on stack 1474 } else { 1475 asm.emitFLD_Reg_RegDisp_Quad(FP0, SP, TWO_SLOTS); // FPU reg. stack <- value1 1476 asm.emitFSUB_Reg_RegInd_Quad(FP0, SP); // FPU reg. stack -= value2 1477 adjustStack(WORDSIZE * 2, true); // throw away long slot 1478 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); // POP FPU reg. stack onto stack 1479 } 1480 } 1481 1482 @Override 1483 protected void emit_dmul() { 1484 if (SSE2_BASE) { 1485 asm.emitMOVSD_Reg_RegInd(XMM0, SP); // XMM0 = value2 1486 adjustStack(WORDSIZE * 2, true); // throw away long slot 1487 asm.emitMULSD_Reg_RegInd(XMM0, SP); // XMM0 *= value1 1488 asm.emitMOVSD_RegInd_Reg(SP, XMM0); // set result on stack 1489 } else { 1490 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); // FPU reg. stack <- value2 1491 adjustStack(WORDSIZE * 2, true); // throw away long slot 1492 asm.emitFMUL_Reg_RegInd_Quad(FP0, SP); // FPU reg. stack *= value1 1493 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); // POP FPU reg. stack onto stack 1494 } 1495 } 1496 1497 @Override 1498 protected void emit_ddiv() { 1499 if (SSE2_BASE) { 1500 asm.emitMOVSD_Reg_RegDisp(XMM0, SP, TWO_SLOTS); // XMM0 = value1 1501 asm.emitDIVSD_Reg_RegInd(XMM0, SP); // XMM0 /= value2 1502 adjustStack(WORDSIZE * 2, true); // throw away long slot 1503 asm.emitMOVSD_RegInd_Reg(SP, XMM0); // set result on stack 1504 } else { 1505 asm.emitFLD_Reg_RegDisp_Quad(FP0, SP, TWO_SLOTS); // FPU reg. stack <- value1 1506 asm.emitFDIV_Reg_RegInd_Quad(FP0, SP); // FPU reg. stack /= value2 1507 adjustStack(WORDSIZE * 2, true); // throw away long slot 1508 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); // POP FPU reg. stack onto stack 1509 } 1510 } 1511 1512 @Override 1513 protected void emit_drem() { 1514 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); // FPU reg. stack <- value2, or a 1515 adjustStack(WORDSIZE * 2, true); // throw away slot 1516 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); // FPU reg. stack <- value1, or b 1517 int retryLabel = asm.getMachineCodeIndex(); // come here if partial remainder not complete 1518 asm.emitFPREM(); // FPU reg. stack <- a%b 1519 asm.emitFSTSW_Reg(EAX); // AX = fpsw 1520 asm.emitAND_Reg_Imm(EAX, 0x400); // is C2 set? 1521 asm.emitJCC_Cond_Imm(NE, retryLabel); // if yes then goto retryLabel and continue to compute remainder 1522 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); // POP FPU reg. stack (results) onto java stack 1523 asm.emitFFREEP_Reg(FP0); // throw away top of stack 1524 } 1525 1526 @Override 1527 protected void emit_dneg() { 1528 // flip sign bit 1529 asm.emitXOR_RegDisp_Imm_Byte(SP, Offset.fromIntZeroExtend(7), 0x80); 1530 } 1531 1532 /* 1533 * conversion ops 1534 */ 1535 1536 @Override 1537 protected void emit_i2l() { 1538 if (VM.BuildFor32Addr) { 1539 asm.emitPUSH_RegInd(SP); // duplicate int on stack 1540 asm.emitSAR_RegDisp_Imm(SP, ONE_SLOT, 31); // sign extend as high word of long 1541 } else { 1542 asm.emitPOP_Reg(EAX); 1543 asm.emitCDQE(); 1544 adjustStack(-WORDSIZE, true); 1545 asm.emitPUSH_Reg(EAX); 1546 } 1547 } 1548 1549 @Override 1550 protected void emit_l2i() { 1551 asm.emitPOP_Reg(T0); // long value 1552 adjustStack(WORDSIZE, true); // throw away slot 1553 asm.emitPUSH_Reg(T0); 1554 } 1555 1556 @Override 1557 protected void emit_i2f() { 1558 if (SSE2_BASE) { 1559 asm.emitCVTSI2SS_Reg_RegInd(XMM0, SP); 1560 asm.emitMOVSS_RegInd_Reg(SP, XMM0); 1561 } else { 1562 asm.emitFILD_Reg_RegInd(FP0, SP); 1563 asm.emitFSTP_RegInd_Reg(SP, FP0); 1564 } 1565 } 1566 1567 @Override 1568 protected void emit_i2d() { 1569 if (SSE2_BASE) { 1570 asm.emitCVTSI2SD_Reg_RegInd(XMM0, SP); 1571 adjustStack(-WORDSIZE, true); // grow the stack 1572 asm.emitMOVSD_RegInd_Reg(SP, XMM0); 1573 } else { 1574 asm.emitFILD_Reg_RegInd(FP0, SP); 1575 adjustStack(-WORDSIZE, true); // grow the stack 1576 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); 1577 } 1578 } 1579 1580 @Override 1581 protected void emit_l2f() { 1582 asm.emitFILD_Reg_RegInd_Quad(FP0, SP); 1583 adjustStack(WORDSIZE, true); // shrink the stack 1584 asm.emitFSTP_RegInd_Reg(SP, FP0); 1585 } 1586 1587 @Override 1588 protected void emit_l2d() { 1589 asm.emitFILD_Reg_RegInd_Quad(FP0, SP); 1590 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); 1591 } 1592 1593 @Override 1594 protected void emit_f2d() { 1595 if (SSE2_BASE) { 1596 asm.emitCVTSS2SD_Reg_RegInd(XMM0, SP); 1597 adjustStack(-WORDSIZE, true); // throw away slot 1598 asm.emitMOVSD_RegInd_Reg(SP, XMM0); 1599 } else { 1600 asm.emitFLD_Reg_RegInd(FP0, SP); 1601 adjustStack(-WORDSIZE, true); // throw away slot 1602 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); 1603 } 1604 } 1605 1606 @Override 1607 protected void emit_d2f() { 1608 if (SSE2_BASE) { 1609 asm.emitCVTSD2SS_Reg_RegInd(XMM0, SP); 1610 adjustStack(WORDSIZE, true); // throw away slot 1611 asm.emitMOVSS_RegInd_Reg(SP, XMM0); 1612 } else { 1613 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); 1614 adjustStack(WORDSIZE, true); // throw away slot 1615 asm.emitFSTP_RegInd_Reg(SP, FP0); 1616 } 1617 } 1618 1619 @Override 1620 protected void emit_f2i() { 1621 if (SSE2_BASE) { 1622 // Set up value in XMM0 1623 asm.emitMOVSS_Reg_RegInd(XMM0, SP); 1624 asm.emitXOR_Reg_Reg(T1, T1); // adjust = 0 1625 asm.emitXOR_Reg_Reg(T0, T0); // result = 0 1626 // value cmp maxint 1627 asm.generateJTOCcmpFloat(XMM0, Entrypoints.maxintFloatField.getOffset()); 1628 ForwardReference fr1 = asm.forwardJcc(PE); // if NaN goto fr1 1629 asm.emitSET_Cond_Reg_Byte(LGE, T1); // T1 = (value >= maxint) ? 1 : 0; 1630 asm.emitCVTTSS2SI_Reg_Reg(T0, XMM0); // T0 = (int)value, or 0x80000000 if value > maxint 1631 asm.emitSUB_Reg_Reg(T0, T1); // T0 = T0 - T1, ie fix max int case 1632 fr1.resolve(asm); 1633 asm.emitMOV_RegInd_Reg(SP,T0); // push result 1634 } else { 1635 // TODO: use x87 operations to do this conversion inline taking care of 1636 // the boundary cases that differ between x87 and Java 1637 1638 // (1) save RVM nonvolatiles 1639 int numNonVols = NONVOLATILE_GPRS.length; 1640 Offset off = Offset.fromIntSignExtend(numNonVols * WORDSIZE); 1641 for (int i = 0; i < numNonVols; i++) { 1642 asm.emitPUSH_Reg(NONVOLATILE_GPRS[i]); 1643 } 1644 // (2) Push arg to C function 1645 asm.emitPUSH_RegDisp(SP, off); 1646 // (3) invoke C function through bootrecord 1647 asm.emitMOV_Reg_Abs(S0, Magic.getTocPointer().plus(Entrypoints.the_boot_recordField.getOffset())); 1648 asm.emitCALL_RegDisp(S0, Entrypoints.sysFloatToIntIPField.getOffset()); 1649 // (4) pop argument; 1650 asm.emitPOP_Reg(S0); 1651 // (5) restore RVM nonvolatiles 1652 for (int i = numNonVols - 1; i >= 0; i--) { 1653 asm.emitPOP_Reg(NONVOLATILE_GPRS[i]); 1654 } 1655 // (6) put result on expression stack 1656 asm.emitMOV_RegInd_Reg(SP, T0); 1657 } 1658 } 1659 1660 @Override 1661 protected void emit_f2l() { 1662 if (VM.BuildFor32Addr) { 1663 // TODO: SSE3 has a FISTTP instruction that stores the value with truncation 1664 // meaning the FPSCW can be left alone 1665 1666 // Setup value into FP1 1667 asm.emitFLD_Reg_RegInd(FP0, SP); 1668 // Setup maxlong into FP0 1669 asm.emitFLD_Reg_Abs(FP0, Magic.getTocPointer().plus(Entrypoints.maxlongFloatField.getOffset())); 1670 // if value > maxlong or NaN goto fr1; FP0 = value 1671 asm.emitFUCOMIP_Reg_Reg(FP0, FP1); 1672 ForwardReference fr1 = asm.forwardJcc(LLE); 1673 // Normally the status and control word rounds numbers, but for conversion 1674 // to an integer/long value we want truncation. We therefore save the FPSCW, 1675 // set it to truncation perform operation then restore 1676 adjustStack(-WORDSIZE, true); // Grow the stack 1677 asm.emitFNSTCW_RegDisp(SP, MINUS_ONE_SLOT); // [SP-4] = fpscw 1678 asm.emitMOVZX_Reg_RegDisp_Word(T0, SP, MINUS_ONE_SLOT); // EAX = fpscw 1679 asm.emitOR_Reg_Imm(T0, 0xC00); // EAX = FPSCW in truncate mode 1680 asm.emitMOV_RegInd_Reg(SP, T0); // [SP] = new fpscw value 1681 asm.emitFLDCW_RegInd(SP); // Set FPSCW 1682 asm.emitFISTP_RegInd_Reg_Quad(SP, FP0); // Store 64bit long 1683 asm.emitFLDCW_RegDisp(SP, MINUS_ONE_SLOT); // Restore FPSCW 1684 ForwardReference fr2 = asm.forwardJMP(); 1685 fr1.resolve(asm); 1686 asm.emitFSTP_Reg_Reg(FP0, FP0); // pop FPU*1 1687 ForwardReference fr3 = asm.forwardJcc(PE); // if value == NaN goto fr3 1688 asm.emitMOV_RegInd_Imm(SP, 0x7FFFFFFF); 1689 asm.emitPUSH_Imm(-1); 1690 ForwardReference fr4 = asm.forwardJMP(); 1691 fr3.resolve(asm); 1692 asm.emitMOV_RegInd_Imm(SP, 0); 1693 asm.emitPUSH_Imm(0); 1694 fr2.resolve(asm); 1695 fr4.resolve(asm); 1696 } else { 1697 // Set up value in XMM0 1698 asm.emitMOVSS_Reg_RegInd(XMM0, SP); 1699 asm.emitXOR_Reg_Reg(T1, T1); // adjust = 0 1700 asm.emitXOR_Reg_Reg(T0, T0); // result = 0 1701 // value cmp maxlong 1702 asm.generateJTOCcmpFloat(XMM0, Entrypoints.maxlongFloatField.getOffset()); 1703 ForwardReference fr1 = asm.forwardJcc(PE); // if NaN goto fr1 1704 asm.emitSET_Cond_Reg_Byte(LGE, T1); // T1 = (value >= maxint) ? 1 : 0; 1705 asm.emitCVTTSS2SI_Reg_Reg_Quad(T0, XMM0); // T0 = (int)value, or 0x80000000 if value > maxint 1706 asm.emitSUB_Reg_Reg_Quad(T0, T1); // T0 = T0 - T1, ie fix max long case 1707 fr1.resolve(asm); 1708 asm.emitPUSH_Reg(T0); // push result 1709 } 1710 } 1711 1712 @Override 1713 protected void emit_d2i() { 1714 if (SSE2_BASE) { 1715 // Set up value in XMM0 1716 asm.emitMOVSD_Reg_RegInd(XMM0, SP); 1717 adjustStack(2 * WORDSIZE, true); // throw away slots 1718 asm.emitXOR_Reg_Reg(T1, T1); // adjust = 0 1719 asm.emitXOR_Reg_Reg(T0, T0); // result = 0 1720 // value cmp maxint 1721 asm.generateJTOCcmpDouble(XMM0, Entrypoints.maxintField.getOffset()); 1722 ForwardReference fr1 = asm.forwardJcc(PE); // if NaN goto fr1 1723 asm.emitSET_Cond_Reg_Byte(LGE, T1); // T1 = (value >= maxint) ? 1 : 0; 1724 asm.emitCVTTSD2SI_Reg_Reg(T0, XMM0); // T0 = (int)value, or 0x80000000 if value > maxint 1725 asm.emitSUB_Reg_Reg(T0, T1); // T0 = T0 - T1, ie fix max int case 1726 fr1.resolve(asm); 1727 asm.emitPUSH_Reg(T0); // push result 1728 } else { 1729 // TODO: use x87 operations to do this conversion inline taking care of 1730 // the boundary cases that differ between x87 and Java 1731 // (1) save RVM nonvolatiles 1732 int numNonVols = NONVOLATILE_GPRS.length; 1733 Offset off = Offset.fromIntSignExtend(numNonVols * WORDSIZE); 1734 for (int i = 0; i < numNonVols; i++) { 1735 asm.emitPUSH_Reg(NONVOLATILE_GPRS[i]); 1736 } 1737 // (2) Push args to C function (reversed) 1738 asm.emitPUSH_RegDisp(SP, off.plus(4)); 1739 asm.emitPUSH_RegDisp(SP, off.plus(4)); 1740 // (3) invoke C function through bootrecord 1741 asm.emitMOV_Reg_Abs(S0, Magic.getTocPointer().plus(Entrypoints.the_boot_recordField.getOffset())); 1742 asm.emitCALL_RegDisp(S0, Entrypoints.sysDoubleToIntIPField.getOffset()); 1743 // (4) pop arguments 1744 asm.emitPOP_Reg(S0); 1745 asm.emitPOP_Reg(S0); 1746 // (5) restore RVM nonvolatiles 1747 for (int i = numNonVols - 1; i >= 0; i--) { 1748 asm.emitPOP_Reg(NONVOLATILE_GPRS[i]); 1749 } 1750 // (6) put result on expression stack 1751 adjustStack(WORDSIZE, true); // throw away slot 1752 asm.emitMOV_RegInd_Reg(SP, T0); 1753 } 1754 } 1755 1756 @Override 1757 protected void emit_d2l() { 1758 if (VM.BuildFor32Addr) { 1759 // TODO: SSE3 has a FISTTP instruction that stores the value with truncation 1760 // meaning the FPSCW can be left alone 1761 1762 // Setup value into FP1 1763 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); 1764 // Setup maxlong into FP0 1765 asm.emitFLD_Reg_Abs_Quad(FP0, Magic.getTocPointer().plus(Entrypoints.maxlongField.getOffset())); 1766 // if value > maxlong or NaN goto fr1; FP0 = value 1767 asm.emitFUCOMIP_Reg_Reg(FP0, FP1); 1768 ForwardReference fr1 = asm.forwardJcc(LLE); 1769 // Normally the status and control word rounds numbers, but for conversion 1770 // to an integer/long value we want truncation. We therefore save the FPSCW, 1771 // set it to truncation perform operation then restore 1772 asm.emitFNSTCW_RegDisp(SP, MINUS_ONE_SLOT); // [SP-4] = fpscw 1773 asm.emitMOVZX_Reg_RegDisp_Word(T0, SP, MINUS_ONE_SLOT); // EAX = fpscw 1774 asm.emitOR_Reg_Imm(T0, 0xC00); // EAX = FPSCW in truncate mode 1775 asm.emitMOV_RegInd_Reg(SP, T0); // [SP] = new fpscw value 1776 asm.emitFLDCW_RegInd(SP); // Set FPSCW 1777 asm.emitFISTP_RegInd_Reg_Quad(SP, FP0); // Store 64bit long 1778 asm.emitFLDCW_RegDisp(SP, MINUS_ONE_SLOT); // Restore FPSCW 1779 ForwardReference fr2 = asm.forwardJMP(); 1780 fr1.resolve(asm); 1781 asm.emitFSTP_Reg_Reg(FP0, FP0); // pop FPU*1 1782 ForwardReference fr3 = asm.forwardJcc(PE); // if value == NaN goto fr3 1783 asm.emitMOV_RegDisp_Imm(SP, ONE_SLOT, 0x7FFFFFFF); 1784 asm.emitMOV_RegInd_Imm(SP, -1); 1785 ForwardReference fr4 = asm.forwardJMP(); 1786 fr3.resolve(asm); 1787 asm.emitMOV_RegDisp_Imm(SP, ONE_SLOT, 0); 1788 asm.emitMOV_RegInd_Imm(SP, 0); 1789 fr2.resolve(asm); 1790 fr4.resolve(asm); 1791 } else { 1792 // Set up value in XMM0 1793 asm.emitMOVSD_Reg_RegInd(XMM0, SP); 1794 asm.emitXOR_Reg_Reg(T1, T1); // adjust = 0 1795 asm.emitXOR_Reg_Reg(T0, T0); // result = 0 1796 // value cmp maxlong 1797 asm.generateJTOCcmpDouble(XMM0, Entrypoints.maxlongField.getOffset()); 1798 ForwardReference fr1 = asm.forwardJcc(PE); // if NaN goto fr1 1799 asm.emitSET_Cond_Reg_Byte(LGE, T1); // T1 = (value >= maxlong) ? 1 : 0; 1800 asm.emitCVTTSD2SIQ_Reg_Reg_Quad(T0, XMM0); // T0 = (int)value, or 0x80...00 if value > maxlong 1801 asm.emitSUB_Reg_Reg_Quad(T0, T1); // T0 = T0 - T1, ie fix max long case 1802 fr1.resolve(asm); 1803 asm.emitMOV_RegInd_Reg_Quad(SP, T0); // push result 1804 } 1805 } 1806 1807 @Override 1808 protected void emit_i2b() { 1809 // This could be coded as 2 instructions as follows: 1810 // asm.emitMOVSX_Reg_RegInd_Byte(T0, SP); 1811 // asm.emitMOV_RegInd_Reg(SP, T0); 1812 // Indirection via ESP requires an extra byte for the indirection, so the 1813 // total code size is 6 bytes. The 3 instruction version below is only 4 1814 // bytes long and faster on Pentium 4 benchmarks. 1815 asm.emitPOP_Reg(T0); 1816 asm.emitMOVSX_Reg_Reg_Byte(T0, T0); 1817 asm.emitPUSH_Reg(T0); 1818 } 1819 1820 @Override 1821 protected void emit_i2c() { 1822 // This could be coded as zeroing the high 16bits on stack: 1823 // asm.emitMOV_RegDisp_Imm_Word(SP, Offset.fromIntSignExtend(2), 0); 1824 // or as 2 instructions: 1825 // asm.emitMOVZX_Reg_RegInd_Word(T0, SP); 1826 // asm.emitMOV_RegInd_Reg(SP, T0); 1827 // Benchmarks show the following sequence to be more optimal on a Pentium 4 1828 asm.emitPOP_Reg(T0); 1829 asm.emitMOVZX_Reg_Reg_Word(T0, T0); 1830 asm.emitPUSH_Reg(T0); 1831 } 1832 1833 @Override 1834 protected void emit_i2s() { 1835 // This could be coded as 2 instructions as follows: 1836 // asm.emitMOVSX_Reg_RegInd_Word(T0, SP); 1837 // asm.emitMOV_RegInd_Reg(SP, T0); 1838 // Indirection via ESP requires an extra byte for the indirection, so the 1839 // total code size is 6 bytes. The 3 instruction version below is only 4 1840 // bytes long and faster on Pentium 4 benchmarks. 1841 asm.emitPOP_Reg(T0); 1842 asm.emitMOVSX_Reg_Reg_Word(T0, T0); 1843 asm.emitPUSH_Reg(T0); 1844 } 1845 1846 /* 1847 * comparision ops 1848 */ 1849 1850 @Override 1851 protected void emit_regular_lcmp() { 1852 if (VM.BuildFor32Addr) { 1853 asm.emitPOP_Reg(T0); // (S0:T0) = (high half value2: low half value2) 1854 asm.emitPOP_Reg(S0); 1855 asm.emitPOP_Reg(T1); // (..:T1) = (.. : low half of value1) 1856 asm.emitSUB_Reg_Reg(T1, T0); // T1 = T1 - T0 1857 asm.emitPOP_Reg(T0); // (T0:..) = (high half of value1 : ..) 1858 // NB pop does not alter the carry register 1859 asm.emitSBB_Reg_Reg(T0, S0); // T0 = T0 - S0 - CF 1860 asm.emitOR_Reg_Reg(T1, T0); // T1 = T1 | T0 updating ZF 1861 asm.emitSET_Cond_Reg_Byte(NE, T1); 1862 asm.emitMOVZX_Reg_Reg_Byte(T1, T1); // T1 = (value1 != value2) ? 1 : 0 1863 asm.emitSAR_Reg_Imm(T0, 31); // T0 = (value1 < value2) ? -1 : 0 1864 asm.emitOR_Reg_Reg(T1, T0); // T1 = T1 | T0 1865 asm.emitPUSH_Reg(T1); // push result on stack 1866 } else { 1867 // using a shift in 64bits costs an extra byte in the opcode 1868 asm.emitPOP_Reg(T0); // T0 is long value2 1869 adjustStack(WORDSIZE, true); // throw away slot 1870 asm.emitPOP_Reg(T1); // T1 is long value1 1871 adjustStack(WORDSIZE, true); // throw away slot 1872 asm.emitCMP_Reg_Reg_Quad(T1, T0); // 64bit compare 1873 asm.emitSET_Cond_Reg_Byte(LT, T0); // T0 = value1 < value2 ? 1 : 0 1874 asm.emitSET_Cond_Reg_Byte(GT, T1); // T1 = value1 > value2 ? 1 : 0 1875 asm.emitSUB_Reg_Reg_Byte(T1, T0); // T1 = (value1 > value2 ? 1 : 0) - (value1 < value2 ? 1 : 0) 1876 asm.emitMOVSX_Reg_Reg_Byte(T1, T1); // Fix sign extension 1877 asm.emitPUSH_Reg(T1); // push result on stack 1878 } 1879 } 1880 1881 @Override 1882 protected void emit_regular_DFcmpGL(boolean single, boolean unorderedGT) { 1883 if (SSE2_BASE) { 1884 if (single) { 1885 asm.emitMOVSS_Reg_RegInd(XMM0, SP); // XMM0 = value2 1886 asm.emitMOVSS_Reg_RegDisp(XMM1, SP, ONE_SLOT); // XMM1 = value1 1887 adjustStack(WORDSIZE * 2, true); // throw away slots 1888 } else { 1889 asm.emitMOVSD_Reg_RegInd(XMM0, SP); // XMM0 = value2 1890 asm.emitMOVSD_Reg_RegDisp(XMM1, SP, TWO_SLOTS); // XMM1 = value1 1891 adjustStack(WORDSIZE * 4, true); // throw away slots 1892 } 1893 } else { 1894 if (single) { 1895 asm.emitFLD_Reg_RegInd(FP0, SP); // Setup value2 into FP1, 1896 asm.emitFLD_Reg_RegDisp(FP0, SP, ONE_SLOT); // value1 into FP0 1897 adjustStack(WORDSIZE * 2, true); // throw away slots 1898 } else { 1899 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); // Setup value2 into FP1, 1900 asm.emitFLD_Reg_RegDisp_Quad(FP0, SP, TWO_SLOTS); // value1 into FP0 1901 adjustStack(WORDSIZE * 4, true); // throw away slots 1902 } 1903 } 1904 if (unorderedGT) { 1905 asm.emitMOV_Reg_Imm(T0, 1); // result/T0 = 1 (high bits are 0) 1906 } else { 1907 asm.emitXOR_Reg_Reg(T0, T0); // clear high bits of result 1908 } 1909 if (SSE2_BASE) { 1910 if (single) { 1911 asm.emitUCOMISS_Reg_Reg(XMM1, XMM0); // compare value1 and value2 1912 } else { 1913 asm.emitUCOMISD_Reg_Reg(XMM1, XMM0); // compare value1 and value2 1914 } 1915 } else { 1916 asm.emitFUCOMIP_Reg_Reg(FP0, FP1); // compare and pop FPU *1 1917 } 1918 ForwardReference fr1 = null; 1919 if (unorderedGT) { 1920 fr1 = asm.forwardJcc(PE); // if unordered goto push result (1) 1921 } 1922 asm.emitSET_Cond_Reg_Byte(LGT, T0); // T0 = XMM0 > XMM1 ? 1 : 0 1923 asm.emitSBB_Reg_Imm(T0, 0); // T0 -= XMM0 < or unordered XMM1 ? 1 : 0 1924 if (unorderedGT) { 1925 fr1.resolve(asm); 1926 } 1927 asm.emitPUSH_Reg(T0); // push result on stack 1928 if (!SSE2_BASE) { 1929 asm.emitFSTP_Reg_Reg(FP0, FP0); // pop FPU*1 1930 } 1931 } 1932 1933 /* 1934 * branching 1935 */ 1936 1937 /** 1938 * @param bc the branch condition 1939 * @return assembler constant equivalent for the branch condition 1940 */ 1941 @Pure 1942 private byte mapCondition(BranchCondition bc) { 1943 switch (bc) { 1944 case EQ: return EQ; 1945 case NE: return NE; 1946 case LT: return LT; 1947 case GE: return GE; 1948 case GT: return GT; 1949 case LE: return LE; 1950 default: if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); return -1; 1951 } 1952 } 1953 1954 @Override 1955 @Inline(value = Inline.When.ArgumentsAreConstant, arguments = {2}) 1956 protected void emit_lcmp_if(int bTarget, BranchCondition bc) { 1957 if (VM.BuildFor32Addr) { 1958 if (bc == BranchCondition.LE || bc == BranchCondition.GT) { 1959 // flip operands in these cases 1960 if (bc == BranchCondition.LE) { 1961 bc = BranchCondition.GE; 1962 } else { 1963 bc = BranchCondition.LT; 1964 } 1965 asm.emitPOP_Reg(T1); // (T0:T1) = (high half value2: low half value2) 1966 asm.emitPOP_Reg(T0); 1967 asm.emitPOP_Reg(S0); // (..:S0) = (.. : low half of value1) 1968 asm.emitSUB_Reg_Reg(T1, S0); // T1 = T1 - S0 1969 asm.emitPOP_Reg(S0); // (S0:..) = (high half of value1 : ..) 1970 // NB pop does not alter the carry register 1971 asm.emitSBB_Reg_Reg(T0, S0); // T0 = T0 - S0 - CF 1972 } else { 1973 asm.emitPOP_Reg(T0); // (S0:T0) = (high half value2: low half value2) 1974 asm.emitPOP_Reg(S0); 1975 asm.emitPOP_Reg(T1); // (..:T1) = (.. : low half of value1) 1976 asm.emitSUB_Reg_Reg(T1, T0); // T1 = T1 - T0 1977 asm.emitPOP_Reg(T0); // (T0:..) = (high half of value1 : ..) 1978 // NB pop does not alter the carry register 1979 asm.emitSBB_Reg_Reg(T0, S0); // T0 = T0 - S0 - CF 1980 if (bc == BranchCondition.EQ || bc == BranchCondition.NE) { 1981 asm.emitOR_Reg_Reg(T1, T0); // T1 = T1 | T0 updating ZF 1982 } 1983 } 1984 } else { 1985 asm.emitPOP_Reg(T0); // T0 is long value2 1986 adjustStack(WORDSIZE, true); // throw away slot 1987 asm.emitPOP_Reg(T1); // T1 is long value1 1988 adjustStack(WORDSIZE, true); // throw away slot 1989 asm.emitCMP_Reg_Reg_Quad(T1, T0); // 64bit compare 1990 } 1991 genCondBranch(mapCondition(bc), bTarget); 1992 } 1993 1994 @Override 1995 protected void emit_DFcmpGL_if(boolean single, boolean unorderedGT, int bTarget, BranchCondition bc) { 1996 if (SSE2_BASE) { 1997 if (single) { 1998 asm.emitMOVSS_Reg_RegInd(XMM0, SP); // XMM0 = value2 1999 asm.emitMOVSS_Reg_RegDisp(XMM1, SP, ONE_SLOT); // XMM1 = value1 2000 adjustStack(WORDSIZE * 2, true); // throw away slots 2001 } else { 2002 asm.emitMOVSD_Reg_RegInd(XMM0, SP); // XMM0 = value2 2003 asm.emitMOVSD_Reg_RegDisp(XMM1, SP, TWO_SLOTS); // XMM1 = value1 2004 adjustStack(WORDSIZE * 4, true); // throw away slots 2005 } 2006 } else { 2007 if (single) { 2008 asm.emitFLD_Reg_RegInd(FP0, SP); // Setup value2 into FP1, 2009 asm.emitFLD_Reg_RegDisp(FP0, SP, ONE_SLOT); // value1 into FP0 2010 adjustStack(WORDSIZE * 2, true); // throw away slots 2011 } else { 2012 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); // Setup value2 into FP1, 2013 asm.emitFLD_Reg_RegDisp_Quad(FP0, SP, TWO_SLOTS); // value1 into FP0 2014 adjustStack(WORDSIZE * 4, true); // throw away slots 2015 } 2016 } 2017 if (SSE2_BASE) { 2018 if (single) { 2019 asm.emitUCOMISS_Reg_Reg(XMM1, XMM0); // compare value1 and value2 2020 } else { 2021 asm.emitUCOMISD_Reg_Reg(XMM1, XMM0); // compare value1 and value2 2022 } 2023 } else { 2024 asm.emitFUCOMIP_Reg_Reg(FP0, FP1); // compare and pop FPU *1 2025 asm.emitFSTP_Reg_Reg(FP0, FP0); // pop FPU*1 2026 } 2027 byte asm_bc = -1; 2028 boolean unordered_taken = false; 2029 switch (bc) { 2030 case EQ: 2031 asm_bc = EQ; 2032 unordered_taken = false; 2033 break; 2034 case NE: 2035 asm_bc = NE; 2036 unordered_taken = true; 2037 break; 2038 case LT: 2039 asm_bc = LLT; 2040 unordered_taken = !unorderedGT; 2041 break; 2042 case GE: 2043 asm_bc = LGE; 2044 unordered_taken = unorderedGT; 2045 break; 2046 case GT: 2047 asm_bc = LGT; 2048 unordered_taken = unorderedGT; 2049 break; 2050 case LE: 2051 asm_bc = LLE; 2052 unordered_taken = !unorderedGT; 2053 break; 2054 default: 2055 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 2056 } 2057 int mTarget = bytecodeMap[bTarget]; 2058 if (!VM.runningTool && ((BaselineCompiledMethod) compiledMethod).hasCounterArray()) { 2059 // Allocate two counters: taken and not taken 2060 int entry = edgeCounterIdx; 2061 edgeCounterIdx += 2; 2062 if (!unordered_taken) { 2063 ForwardReference notTaken1 = asm.forwardJcc(PE); 2064 ForwardReference notTaken2 = asm.forwardJcc(asm.flipCode(asm_bc)); 2065 // Increment taken counter & jump to target 2066 incEdgeCounter(T1, null, entry + EdgeCounts.TAKEN); 2067 asm.emitJMP_ImmOrLabel(mTarget, bTarget); 2068 // Increment not taken counter 2069 notTaken1.resolve(asm); 2070 notTaken2.resolve(asm); 2071 incEdgeCounter(T1, null, entry + EdgeCounts.NOT_TAKEN); 2072 } else { 2073 ForwardReference taken1 = asm.forwardJcc(PE); 2074 ForwardReference taken2 = asm.forwardJcc(asm_bc); 2075 // Increment taken counter & jump to target 2076 incEdgeCounter(T1, null, entry + EdgeCounts.NOT_TAKEN); 2077 ForwardReference notTaken = asm.forwardJMP(); 2078 // Increment taken counter 2079 taken1.resolve(asm); 2080 taken2.resolve(asm); 2081 incEdgeCounter(T1, null, entry + EdgeCounts.TAKEN); 2082 asm.emitJMP_ImmOrLabel(mTarget, bTarget); 2083 notTaken.resolve(asm); 2084 } 2085 } else { 2086 if (unordered_taken) { 2087 asm.emitJCC_Cond_ImmOrLabel(PE, mTarget, bTarget); 2088 asm.emitJCC_Cond_ImmOrLabel(asm_bc, mTarget, bTarget); 2089 } else { 2090 ForwardReference notTaken = asm.forwardJcc(PE); 2091 asm.emitJCC_Cond_ImmOrLabel(asm_bc, mTarget, bTarget); 2092 notTaken.resolve(asm); 2093 } 2094 } 2095 } 2096 2097 @Override 2098 @Inline(value = Inline.When.ArgumentsAreConstant, arguments = {2}) 2099 protected void emit_if(int bTarget, BranchCondition bc) { 2100 asm.emitPOP_Reg(T0); 2101 asm.emitTEST_Reg_Reg(T0, T0); 2102 genCondBranch(mapCondition(bc), bTarget); 2103 } 2104 2105 @Override 2106 @Inline(value = Inline.When.ArgumentsAreConstant, arguments = {2}) 2107 protected void emit_if_icmp(int bTarget, BranchCondition bc) { 2108 asm.emitPOP_Reg(T1); 2109 asm.emitPOP_Reg(T0); 2110 asm.emitCMP_Reg_Reg(T0, T1); 2111 genCondBranch(mapCondition(bc), bTarget); 2112 } 2113 2114 @Override 2115 protected void emit_if_acmpeq(int bTarget) { 2116 asm.emitPOP_Reg(S0); 2117 asm.emitPOP_Reg(T0); 2118 if (VM.BuildFor32Addr) { 2119 asm.emitCMP_Reg_Reg(T0, S0); 2120 } else { 2121 asm.emitCMP_Reg_Reg_Quad(T0, S0); 2122 } 2123 genCondBranch(EQ, bTarget); 2124 } 2125 2126 @Override 2127 protected void emit_if_acmpne(int bTarget) { 2128 asm.emitPOP_Reg(S0); 2129 asm.emitPOP_Reg(T0); 2130 if (VM.BuildFor32Addr) { 2131 asm.emitCMP_Reg_Reg(T0, S0); 2132 } else { 2133 asm.emitCMP_Reg_Reg_Quad(T0, S0); 2134 } 2135 genCondBranch(NE, bTarget); 2136 } 2137 2138 @Override 2139 protected void emit_ifnull(int bTarget) { 2140 asm.emitPOP_Reg(T0); 2141 if (VM.BuildFor32Addr) { 2142 asm.emitTEST_Reg_Reg(T0, T0); 2143 } else { 2144 asm.emitTEST_Reg_Reg_Quad(T0, T0); 2145 } 2146 genCondBranch(EQ, bTarget); 2147 } 2148 2149 @Override 2150 protected void emit_ifnonnull(int bTarget) { 2151 asm.emitPOP_Reg(T0); 2152 if (VM.BuildFor32Addr) { 2153 asm.emitTEST_Reg_Reg(T0, T0); 2154 } else { 2155 asm.emitTEST_Reg_Reg_Quad(T0, T0); 2156 } 2157 genCondBranch(NE, bTarget); 2158 } 2159 2160 @Override 2161 protected void emit_goto(int bTarget) { 2162 int mTarget = bytecodeMap[bTarget]; 2163 asm.emitJMP_ImmOrLabel(mTarget, bTarget); 2164 } 2165 2166 @Override 2167 protected void emit_jsr(int bTarget) { 2168 int mTarget = bytecodeMap[bTarget]; 2169 asm.emitCALL_ImmOrLabel(mTarget, bTarget); 2170 } 2171 2172 @Override 2173 protected void emit_ret(int index) { 2174 try { 2175 Offset offset = localOffset(index); 2176 // Can be: 2177 // asm.emitJMP_RegDisp(ESP, offset); 2178 // but this will cause call-return branch prediction pairing to fail 2179 asm.emitPUSH_RegDisp(ESP, offset); 2180 asm.emitRET(); 2181 } catch (UnreachableBytecodeException e) { 2182 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 2183 } 2184 } 2185 2186 @Override 2187 protected void emit_tableswitch(int defaultval, int low, int high) { 2188 int bTarget = biStart + defaultval; 2189 int mTarget = bytecodeMap[bTarget]; 2190 int n = high - low + 1; // n = number of normal cases (0..n-1) 2191 asm.emitPOP_Reg(T1); // T1 is index of desired case 2192 asm.emitSUB_Reg_Imm(T1, low); // relativize T1 2193 asm.emitCMP_Reg_Imm(T1, n); // 0 <= relative index < n 2194 2195 if (!VM.runningTool && ((BaselineCompiledMethod) compiledMethod).hasCounterArray()) { 2196 int firstCounter = edgeCounterIdx; 2197 edgeCounterIdx += (n + 1); 2198 2199 // Jump around code for default case 2200 ForwardReference fr = asm.forwardJcc(LLT); 2201 incEdgeCounter(S0, null, firstCounter + n); 2202 asm.emitJMP_ImmOrLabel(mTarget, bTarget); 2203 fr.resolve(asm); 2204 2205 // Increment counter for the appropriate case 2206 incEdgeCounter(S0, T1, firstCounter); 2207 } else { 2208 asm.emitJCC_Cond_ImmOrLabel(LGE, mTarget, bTarget); // if not, goto default case 2209 } 2210 2211 // T0 = EIP at start of method 2212 asm.emitMETHODSTART_Reg(T0); 2213 // T0 += [T0 + T1<<2 + ??] - we will patch ?? when we know the placement of the table 2214 int toPatchAddress = asm.getMachineCodeIndex(); 2215 if (VM.buildFor32Addr()) { 2216 asm.emitMOV_Reg_RegIdx(T1, T0, T1, WORD, Offset.fromIntZeroExtend(Integer.MAX_VALUE)); 2217 asm.emitADD_Reg_Reg(T0, T1); 2218 } else { 2219 asm.emitMOV_Reg_RegIdx(T1, T0, T1, WORD, Offset.fromIntZeroExtend(Integer.MAX_VALUE)); 2220 asm.emitADD_Reg_Reg_Quad(T0, T1); 2221 } 2222 // JMP T0 2223 asm.emitJMP_Reg(T0); 2224 asm.emitNOP((4 - asm.getMachineCodeIndex()) & 3); // align table 2225 // create table of offsets from start of method 2226 asm.patchSwitchTableDisplacement(toPatchAddress); 2227 for (int i = 0; i < n; i++) { 2228 int offset = bcodes.getTableSwitchOffset(i); 2229 bTarget = biStart + offset; 2230 mTarget = bytecodeMap[bTarget]; 2231 asm.emitOFFSET_Imm_ImmOrLabel(i, mTarget, bTarget); 2232 } 2233 bcodes.skipTableSwitchOffsets(n); 2234 } 2235 2236 /** 2237 * Emit code to implement the lookupswitch bytecode. 2238 * Uses linear search, one could use a binary search tree instead, 2239 * but this is the baseline compiler, so don't worry about it. 2240 * 2241 * @param defaultval bcIndex of the default target 2242 * @param npairs number of pairs in the lookup switch 2243 */ 2244 @Override 2245 protected void emit_lookupswitch(int defaultval, int npairs) { 2246 asm.emitPOP_Reg(T0); 2247 for (int i = 0; i < npairs; i++) { 2248 int match = bcodes.getLookupSwitchValue(i); 2249 asm.emitCMP_Reg_Imm(T0, match); 2250 int offset = bcodes.getLookupSwitchOffset(i); 2251 int bTarget = biStart + offset; 2252 int mTarget = bytecodeMap[bTarget]; 2253 if (!VM.runningTool && ((BaselineCompiledMethod) compiledMethod).hasCounterArray()) { 2254 // Flip conditions so we can jump over the increment of the taken counter. 2255 ForwardReference fr = asm.forwardJcc(NE); 2256 incEdgeCounter(S0, null, edgeCounterIdx++); 2257 asm.emitJMP_ImmOrLabel(mTarget, bTarget); 2258 fr.resolve(asm); 2259 } else { 2260 asm.emitJCC_Cond_ImmOrLabel(EQ, mTarget, bTarget); 2261 } 2262 } 2263 bcodes.skipLookupSwitchPairs(npairs); 2264 int bTarget = biStart + defaultval; 2265 int mTarget = bytecodeMap[bTarget]; 2266 if (!VM.runningTool && ((BaselineCompiledMethod) compiledMethod).hasCounterArray()) { 2267 incEdgeCounter(S0, null, edgeCounterIdx++); // increment default counter 2268 } 2269 asm.emitJMP_ImmOrLabel(mTarget, bTarget); 2270 } 2271 2272 /* 2273 * returns (from function; NOT ret) 2274 */ 2275 2276 @Override 2277 protected void emit_ireturn() { 2278 if (method.isSynchronized()) genMonitorExit(); 2279 asm.emitPOP_Reg(T0); 2280 genEpilogue(WORDSIZE, WORDSIZE); 2281 } 2282 2283 @Override 2284 protected void emit_lreturn() { 2285 if (method.isSynchronized()) genMonitorExit(); 2286 if (VM.BuildFor32Addr) { 2287 asm.emitPOP_Reg(T1); // low half 2288 asm.emitPOP_Reg(T0); // high half 2289 genEpilogue(2 * WORDSIZE, 2 * WORDSIZE); 2290 } else { 2291 asm.emitPOP_Reg(T0); 2292 genEpilogue(2 * WORDSIZE, WORDSIZE); 2293 } 2294 } 2295 2296 @Override 2297 protected void emit_freturn() { 2298 if (method.isSynchronized()) genMonitorExit(); 2299 if (SSE2_FULL) { 2300 asm.emitMOVSS_Reg_RegInd(XMM0, SP); 2301 } else { 2302 asm.emitFLD_Reg_RegInd(FP0, SP); 2303 } 2304 genEpilogue(WORDSIZE, 0); 2305 } 2306 2307 @Override 2308 protected void emit_dreturn() { 2309 if (method.isSynchronized()) genMonitorExit(); 2310 if (SSE2_FULL) { 2311 asm.emitMOVSD_Reg_RegInd(XMM0, SP); 2312 } else { 2313 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); 2314 } 2315 genEpilogue(2 * WORDSIZE, 0); 2316 } 2317 2318 @Override 2319 protected void emit_areturn() { 2320 if (method.isSynchronized()) genMonitorExit(); 2321 asm.emitPOP_Reg(T0); 2322 genEpilogue(WORDSIZE, WORDSIZE); 2323 } 2324 2325 @Override 2326 protected void emit_return() { 2327 if (method.isSynchronized()) genMonitorExit(); 2328 genEpilogue(0, 0); 2329 } 2330 2331 /* 2332 * field access 2333 */ 2334 2335 @Override 2336 protected void emit_unresolved_getstatic(FieldReference fieldRef) { 2337 emitDynamicLinkingSequence(asm, T0, fieldRef, true); 2338 if (NEEDS_OBJECT_GETSTATIC_BARRIER && !fieldRef.getFieldContentsType().isPrimitiveType()) { 2339 Barriers.compileGetstaticBarrier(asm, T0, fieldRef.getId()); 2340 return; 2341 } 2342 if (fieldRef.getSize() <= BYTES_IN_INT) { 2343 // get static field - [SP--] = [T0<<0+JTOC] 2344 if (VM.BuildFor32Addr) { 2345 asm.emitPUSH_RegDisp(T0, Magic.getTocPointer().toWord().toOffset()); 2346 } else { 2347 asm.generateJTOCloadInt(T0, T0); 2348 asm.emitPUSH_Reg(T0); 2349 } 2350 } else { // field is two words (double or long) 2351 if (VM.VerifyAssertions) VM._assert(fieldRef.getSize() == BYTES_IN_LONG); 2352 if (VM.BuildFor32Addr) { 2353 asm.emitPUSH_RegDisp(T0, Magic.getTocPointer().toWord().toOffset().plus(WORDSIZE)); // get high part 2354 asm.emitPUSH_RegDisp(T0, Magic.getTocPointer().toWord().toOffset()); // get low part 2355 } else { 2356 if (fieldRef.getNumberOfStackSlots() != 1) { 2357 adjustStack(-WORDSIZE, true); 2358 } 2359 asm.generateJTOCpush(T0); 2360 } 2361 } 2362 } 2363 2364 @Override 2365 protected void emit_resolved_getstatic(FieldReference fieldRef) { 2366 RVMField field = fieldRef.peekResolvedField(); 2367 Offset fieldOffset = field.getOffset(); 2368 if (NEEDS_OBJECT_GETSTATIC_BARRIER && !fieldRef.getFieldContentsType().isPrimitiveType() && !field.isUntraced()) { 2369 Barriers.compileGetstaticBarrierImm(asm, fieldOffset, fieldRef.getId()); 2370 return; 2371 } 2372 if (fieldRef.getSize() <= BYTES_IN_INT) { // field is one word 2373 if (VM.BuildFor32Addr) { 2374 asm.emitPUSH_Abs(Magic.getTocPointer().plus(fieldOffset)); 2375 } else { 2376 asm.generateJTOCloadInt(T0, fieldOffset); 2377 asm.emitPUSH_Reg(T0); 2378 } 2379 } else { // field is two words (double or long) 2380 if (VM.VerifyAssertions) VM._assert(fieldRef.getSize() == BYTES_IN_LONG); 2381 if (VM.BuildFor32Addr) { 2382 asm.emitPUSH_Abs(Magic.getTocPointer().plus(fieldOffset).plus(WORDSIZE)); // get high part 2383 asm.emitPUSH_Abs(Magic.getTocPointer().plus(fieldOffset)); // get low part 2384 } else { 2385 if (fieldRef.getNumberOfStackSlots() != 1) { 2386 adjustStack(-WORDSIZE, true); 2387 } 2388 asm.generateJTOCpush(fieldOffset); 2389 } 2390 } 2391 } 2392 2393 @Override 2394 protected void emit_unresolved_putstatic(FieldReference fieldRef) { 2395 emitDynamicLinkingSequence(asm, T0, fieldRef, true); 2396 if (NEEDS_OBJECT_PUTSTATIC_BARRIER && fieldRef.getFieldContentsType().isReferenceType()) { 2397 Barriers.compilePutstaticBarrier(asm, T0, fieldRef.getId()); 2398 } else { 2399 if (fieldRef.getSize() <= BYTES_IN_INT) { // field is one word 2400 if (VM.BuildFor32Addr) { 2401 asm.emitPOP_RegDisp(T0, Magic.getTocPointer().toWord().toOffset()); 2402 } else { 2403 asm.emitPOP_Reg(T1); 2404 asm.generateJTOCstoreInt(T0, T1); 2405 } 2406 } else { // field is two words (double or long) 2407 if (VM.VerifyAssertions) VM._assert(fieldRef.getSize() == BYTES_IN_LONG); 2408 if (VM.BuildFor32Addr) { 2409 asm.emitPOP_RegDisp(T0, Magic.getTocPointer().toWord().toOffset()); // store low part 2410 asm.emitPOP_RegDisp(T0, Magic.getTocPointer().toWord().toOffset().plus(WORDSIZE)); // store high part 2411 } else { 2412 asm.generateJTOCpop(T0); 2413 if (fieldRef.getNumberOfStackSlots() != 1) { 2414 adjustStack(WORDSIZE, true); 2415 } 2416 } 2417 } 2418 } 2419 // The field may be volatile 2420 asm.emitMFENCE(); 2421 } 2422 2423 @Override 2424 protected void emit_resolved_putstatic(FieldReference fieldRef) { 2425 RVMField field = fieldRef.peekResolvedField(); 2426 Offset fieldOffset = field.getOffset(); 2427 if (NEEDS_OBJECT_PUTSTATIC_BARRIER && field.isReferenceType() && !field.isUntraced()) { 2428 Barriers.compilePutstaticBarrierImm(asm, fieldOffset, fieldRef.getId()); 2429 } else { 2430 if (field.getSize() <= BYTES_IN_INT) { // field is one word 2431 if (VM.BuildFor32Addr) { 2432 asm.emitPOP_Abs(Magic.getTocPointer().plus(fieldOffset)); 2433 } else { 2434 asm.emitPOP_Reg(T1); 2435 asm.generateJTOCstoreInt(fieldOffset, T1); 2436 } 2437 } else { // field is two words (double or long) 2438 if (VM.VerifyAssertions) VM._assert(fieldRef.getSize() == BYTES_IN_LONG); 2439 if (VM.BuildFor32Addr) { 2440 asm.generateJTOCpop(fieldOffset); // store low part 2441 asm.generateJTOCpop(fieldOffset.plus(WORDSIZE)); // store high part 2442 } else { 2443 asm.generateJTOCpop(fieldOffset); 2444 if (fieldRef.getNumberOfStackSlots() != 1) { 2445 adjustStack(WORDSIZE, true); 2446 } 2447 } 2448 } 2449 } 2450 if (field.isVolatile()) { 2451 asm.emitMFENCE(); 2452 } 2453 } 2454 2455 @Override 2456 protected void emit_unresolved_getfield(FieldReference fieldRef) { 2457 TypeReference fieldType = fieldRef.getFieldContentsType(); 2458 emitDynamicLinkingSequence(asm, T0, fieldRef, true); 2459 if (fieldType.isReferenceType()) { 2460 // 32/64bit reference load 2461 if (NEEDS_OBJECT_GETFIELD_BARRIER) { 2462 Barriers.compileGetfieldBarrier(asm, T0, fieldRef.getId()); 2463 } else { 2464 asm.emitPOP_Reg(S0); // S0 is object reference 2465 asm.emitPUSH_RegIdx(S0, T0, BYTE, NO_SLOT); // place field value on stack 2466 } 2467 } else if (fieldType.isBooleanType()) { 2468 // 8bit unsigned load 2469 asm.emitPOP_Reg(S0); // S0 is object reference 2470 asm.emitMOVZX_Reg_RegIdx_Byte(T1, S0, T0, BYTE, NO_SLOT); // T1 is field value 2471 asm.emitPUSH_Reg(T1); // place value on stack 2472 } else if (fieldType.isByteType()) { 2473 // 8bit signed load 2474 asm.emitPOP_Reg(S0); // S0 is object reference 2475 asm.emitMOVSX_Reg_RegIdx_Byte(T1, S0, T0, BYTE, NO_SLOT); // T1 is field value 2476 asm.emitPUSH_Reg(T1); // place value on stack 2477 } else if (fieldType.isShortType()) { 2478 // 16bit signed load 2479 asm.emitPOP_Reg(S0); // S0 is object reference 2480 asm.emitMOVSX_Reg_RegIdx_Word(T1, S0, T0, BYTE, NO_SLOT); // T1 is field value 2481 asm.emitPUSH_Reg(T1); // place value on stack 2482 } else if (fieldType.isCharType()) { 2483 // 16bit unsigned load 2484 asm.emitPOP_Reg(S0); // S0 is object reference 2485 asm.emitMOVZX_Reg_RegIdx_Word(T1, S0, T0, BYTE, NO_SLOT); // T1 is field value 2486 asm.emitPUSH_Reg(T1); // place value on stack 2487 } else if (fieldType.isIntType() || fieldType.isFloatType() || 2488 (VM.BuildFor32Addr && fieldType.isWordLikeType())) { 2489 // 32bit load 2490 asm.emitPOP_Reg(S0); // S0 is object reference 2491 if (VM.BuildFor32Addr) { 2492 asm.emitPUSH_RegIdx(S0, T0, BYTE, NO_SLOT); // place field value on stack 2493 } else { 2494 asm.emitMOV_Reg_RegIdx(T1, S0, T0, BYTE, NO_SLOT); // T1 is field value 2495 asm.emitPUSH_Reg(T1); // place value on stack 2496 } 2497 } else { 2498 // 64bit load 2499 if (VM.VerifyAssertions) { 2500 VM._assert(fieldType.isLongType() || fieldType.isDoubleType() || 2501 (VM.BuildFor64Addr && fieldType.isWordLikeType())); 2502 } 2503 asm.emitPOP_Reg(T1); // T1 is object reference 2504 // NB it's unknown whether the field is volatile, so it is necessary to 2505 // emit instruction sequences that provide atomic access. 2506 if (VM.BuildFor32Addr) { 2507 // NB this is a 64bit copy from memory to the stack so implement 2508 // as a slightly optimized Intel memory copy using the FPU 2509 adjustStack(-2 * WORDSIZE, true); // adjust stack down to hold 64bit value 2510 if (SSE2_BASE) { 2511 asm.emitMOVQ_Reg_RegIdx(XMM0, T1, T0, BYTE, NO_SLOT); // XMM0 is field value 2512 asm.emitMOVQ_RegInd_Reg(SP, XMM0); // place value on stack 2513 } else { 2514 asm.emitFLD_Reg_RegIdx_Quad(FP0, T1, T0, BYTE, NO_SLOT); // FP0 is field value 2515 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); // place value on stack 2516 } 2517 } else { 2518 if (!fieldType.isWordLikeType()) { 2519 adjustStack(-WORDSIZE, true); // add empty slot 2520 } 2521 asm.emitPUSH_RegIdx(T1, T0, BYTE, NO_SLOT); // place value on stack 2522 } 2523 } 2524 } 2525 2526 @Override 2527 protected void emit_resolved_getfield(FieldReference fieldRef) { 2528 TypeReference fieldType = fieldRef.getFieldContentsType(); 2529 RVMField field = fieldRef.peekResolvedField(); 2530 Offset fieldOffset = field.getOffset(); 2531 if (field.isReferenceType()) { 2532 // 32/64bit reference load 2533 if (NEEDS_OBJECT_GETFIELD_BARRIER && !field.isUntraced()) { 2534 Barriers.compileGetfieldBarrierImm(asm, fieldOffset, fieldRef.getId()); 2535 } else { 2536 asm.emitPOP_Reg(T0); // T0 is object reference 2537 asm.emitPUSH_RegDisp(T0, fieldOffset); // place field value on stack 2538 } 2539 } else if (fieldType.isBooleanType()) { 2540 // 8bit unsigned load 2541 asm.emitPOP_Reg(S0); // S0 is object reference 2542 asm.emitMOVZX_Reg_RegDisp_Byte(T0, S0, fieldOffset); // T0 is field value 2543 asm.emitPUSH_Reg(T0); // place value on stack 2544 } else if (fieldType.isByteType()) { 2545 // 8bit signed load 2546 asm.emitPOP_Reg(S0); // S0 is object reference 2547 asm.emitMOVSX_Reg_RegDisp_Byte(T0, S0, fieldOffset); // T0 is field value 2548 asm.emitPUSH_Reg(T0); // place value on stack 2549 } else if (fieldType.isShortType()) { 2550 // 16bit signed load 2551 asm.emitPOP_Reg(S0); // S0 is object reference 2552 asm.emitMOVSX_Reg_RegDisp_Word(T0, S0, fieldOffset); // T0 is field value 2553 asm.emitPUSH_Reg(T0); // place value on stack 2554 } else if (fieldType.isCharType()) { 2555 // 16bit unsigned load 2556 asm.emitPOP_Reg(S0); // S0 is object reference 2557 asm.emitMOVZX_Reg_RegDisp_Word(T0, S0, fieldOffset); // T0 is field value 2558 asm.emitPUSH_Reg(T0); // place value on stack 2559 } else if (fieldType.isIntType() || fieldType.isFloatType() || 2560 (VM.BuildFor32Addr && fieldType.isWordLikeType())) { 2561 // 32bit load 2562 asm.emitPOP_Reg(S0); // S0 is object reference 2563 if (VM.BuildFor32Addr) { 2564 asm.emitPUSH_RegDisp(S0, fieldOffset); // place value on stack 2565 } else { 2566 asm.emitMOV_Reg_RegDisp(T0, S0, fieldOffset); // T0 is field value 2567 asm.emitPUSH_Reg(T0); // place value on stack 2568 } 2569 } else { 2570 // 64bit load 2571 if (VM.VerifyAssertions) { 2572 VM._assert(fieldType.isLongType() || fieldType.isDoubleType() || 2573 (VM.BuildFor64Addr && fieldType.isWordLikeType())); 2574 } 2575 asm.emitPOP_Reg(T0); // T0 is object reference 2576 if (VM.BuildFor32Addr && field.isVolatile()) { 2577 // NB this is a 64bit copy from memory to the stack so implement 2578 // as a slightly optimized Intel memory copy using the FPU 2579 adjustStack(-2 * WORDSIZE, true); // adjust stack down to hold 64bit value 2580 if (SSE2_BASE) { 2581 asm.emitMOVQ_Reg_RegDisp(XMM0, T0, fieldOffset); // XMM0 is field value 2582 asm.emitMOVQ_RegInd_Reg(SP, XMM0); // replace reference with value on stack 2583 } else { 2584 asm.emitFLD_Reg_RegDisp_Quad(FP0, T0, fieldOffset); // FP0 is field value 2585 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); // replace reference with value on stack 2586 } 2587 } else if (VM.BuildFor32Addr && !field.isVolatile()) { 2588 asm.emitPUSH_RegDisp(T0, fieldOffset.plus(ONE_SLOT)); // place high half on stack 2589 asm.emitPUSH_RegDisp(T0, fieldOffset); // place low half on stack 2590 } else { 2591 if (!fieldType.isWordLikeType()) { 2592 adjustStack(-WORDSIZE, true); // add empty slot 2593 } 2594 asm.emitPUSH_RegDisp(T0, fieldOffset); // place value on stack 2595 } 2596 } 2597 } 2598 2599 /** 2600 * Emits code to load a reference local variable and then perform a field load 2601 * @param index the local index to load 2602 * @param fieldRef the referenced field 2603 */ 2604 @Override 2605 protected void emit_aload_resolved_getfield(int index, FieldReference fieldRef) { 2606 try { 2607 Offset offset = localOffset(index); 2608 TypeReference fieldType = fieldRef.getFieldContentsType(); 2609 RVMField field = fieldRef.peekResolvedField(); 2610 Offset fieldOffset = field.getOffset(); 2611 if (field.isReferenceType()) { 2612 // 32/64bit reference load 2613 if (NEEDS_OBJECT_GETFIELD_BARRIER && !field.isUntraced()) { 2614 emit_regular_aload(index); 2615 Barriers.compileGetfieldBarrierImm(asm, fieldOffset, fieldRef.getId()); 2616 } else { 2617 stackMoveHelper(S0, offset); // S0 is object reference 2618 asm.emitPUSH_RegDisp(S0, fieldOffset); // place field value on stack 2619 } 2620 } else if (fieldType.isBooleanType()) { 2621 // 8bit unsigned load 2622 stackMoveHelper(S0, offset); // S0 is object reference 2623 asm.emitMOVZX_Reg_RegDisp_Byte(T0, S0, fieldOffset); // T0 is field value 2624 asm.emitPUSH_Reg(T0); // place value on stack 2625 } else if (fieldType.isByteType()) { 2626 // 8bit signed load 2627 stackMoveHelper(S0, offset); // S0 is object reference 2628 asm.emitMOVSX_Reg_RegDisp_Byte(T0, S0, fieldOffset); // T0 is field value 2629 asm.emitPUSH_Reg(T0); // place value on stack 2630 } else if (fieldType.isShortType()) { 2631 // 16bit signed load 2632 stackMoveHelper(S0, offset); // S0 is object reference 2633 asm.emitMOVSX_Reg_RegDisp_Word(T0, S0, fieldOffset); // T0 is field value 2634 asm.emitPUSH_Reg(T0); // place value on stack 2635 } else if (fieldType.isCharType()) { 2636 // 16bit unsigned load 2637 stackMoveHelper(S0, offset); // S0 is object reference 2638 asm.emitMOVZX_Reg_RegDisp_Word(T0, S0, fieldOffset); // T0 is field value 2639 asm.emitPUSH_Reg(T0); // place value on stack 2640 } else if (fieldType.isIntType() || fieldType.isFloatType() || 2641 (VM.BuildFor32Addr && fieldType.isWordType())) { 2642 // 32bit load 2643 stackMoveHelper(S0, offset); // S0 is object reference 2644 if (VM.BuildFor32Addr) { 2645 asm.emitPUSH_RegDisp(S0, fieldOffset); // place value on stack 2646 } else { 2647 asm.emitMOV_Reg_RegDisp(T0, S0, fieldOffset); // T0 is field value 2648 asm.emitPUSH_Reg(T0); // place value on stack 2649 } 2650 } else { 2651 // 64bit load 2652 if (VM.VerifyAssertions) { 2653 VM._assert(fieldType.isLongType() || fieldType.isDoubleType() || 2654 (VM.BuildFor64Addr && fieldType.isWordType())); 2655 } 2656 stackMoveHelper(S0, offset); // S0 is object reference 2657 if (VM.BuildFor32Addr && field.isVolatile()) { 2658 // NB this is a 64bit copy from memory to the stack so implement 2659 // as a slightly optimized Intel memory copy using the FPU 2660 adjustStack(-2 * WORDSIZE, true); // adjust stack down to hold 64bit value 2661 if (SSE2_BASE) { 2662 asm.emitMOVQ_Reg_RegDisp(XMM0, S0, fieldOffset); // XMM0 is field value 2663 asm.emitMOVQ_RegInd_Reg(SP, XMM0); // replace reference with value on stack 2664 } else { 2665 asm.emitFLD_Reg_RegDisp_Quad(FP0, S0, fieldOffset); // FP0 is field value 2666 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); // replace reference with value on stack 2667 } 2668 } else if (VM.BuildFor32Addr && !field.isVolatile()) { 2669 asm.emitPUSH_RegDisp(S0, fieldOffset.plus(ONE_SLOT)); // place high half on stack 2670 asm.emitPUSH_RegDisp(S0, fieldOffset); // place low half on stack 2671 } else { 2672 if (!fieldType.isWordType()) { 2673 adjustStack(-WORDSIZE, true); // add empty slot 2674 } 2675 asm.emitPUSH_RegDisp(S0, fieldOffset); // place value on stack 2676 } 2677 } 2678 } catch (UnreachableBytecodeException e) { 2679 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 2680 } 2681 } 2682 2683 @Override 2684 protected void emit_unresolved_putfield(FieldReference fieldRef) { 2685 Barriers.compileModifyCheck(asm, fieldRef.getNumberOfStackSlots() * WORDSIZE); 2686 TypeReference fieldType = fieldRef.getFieldContentsType(); 2687 emitDynamicLinkingSequence(asm, T0, fieldRef, true); 2688 if (fieldType.isReferenceType()) { 2689 // 32/64bit reference store 2690 if (NEEDS_OBJECT_PUTFIELD_BARRIER) { 2691 Barriers.compilePutfieldBarrier(asm, T0, fieldRef.getId()); 2692 } else { 2693 asm.emitPOP_Reg(T1); // T1 is the value to be stored 2694 asm.emitPOP_Reg(S0); // S0 is the object reference 2695 if (VM.BuildFor32Addr) { 2696 asm.emitMOV_RegIdx_Reg(S0, T0, BYTE, NO_SLOT, T1); // [S0+T0] <- T1 2697 } else { 2698 asm.emitMOV_RegIdx_Reg_Quad(S0, T0, BYTE, NO_SLOT, T1); // [S0+T0] <- T1 2699 } 2700 } 2701 } else if (NEEDS_BOOLEAN_PUTFIELD_BARRIER && fieldType.isBooleanType()) { 2702 Barriers.compilePutfieldBarrierBoolean(asm, T0, fieldRef.getId(), this); 2703 } else if (NEEDS_BYTE_PUTFIELD_BARRIER && fieldType.isByteType()) { 2704 Barriers.compilePutfieldBarrierByte(asm, T0, fieldRef.getId(), this); 2705 } else if (NEEDS_CHAR_PUTFIELD_BARRIER && fieldType.isCharType()) { 2706 Barriers.compilePutfieldBarrierChar(asm, T0, fieldRef.getId(), this); 2707 } else if (NEEDS_DOUBLE_PUTFIELD_BARRIER && fieldType.isDoubleType()) { 2708 Barriers.compilePutfieldBarrierDouble(asm, T0, fieldRef.getId(), this); 2709 } else if (NEEDS_FLOAT_PUTFIELD_BARRIER && fieldType.isFloatType()) { 2710 Barriers.compilePutfieldBarrierFloat(asm, T0, fieldRef.getId(), this); 2711 } else if (NEEDS_INT_PUTFIELD_BARRIER && fieldType.isIntType()) { 2712 Barriers.compilePutfieldBarrierInt(asm, T0, fieldRef.getId(), this); 2713 } else if (NEEDS_LONG_PUTFIELD_BARRIER && fieldType.isLongType()) { 2714 Barriers.compilePutfieldBarrierLong(asm, T0, fieldRef.getId(), this); 2715 } else if (NEEDS_SHORT_PUTFIELD_BARRIER && fieldType.isShortType()) { 2716 Barriers.compilePutfieldBarrierShort(asm, T0, fieldRef.getId(), this); 2717 } else if (NEEDS_WORD_PUTFIELD_BARRIER && fieldType.isWordType()) { 2718 Barriers.compilePutfieldBarrierWord(asm, T0, fieldRef.getId(), this); 2719 } else if (NEEDS_ADDRESS_PUTFIELD_BARRIER && fieldType.isAddressType()) { 2720 Barriers.compilePutfieldBarrierAddress(asm, T0, fieldRef.getId(), this); 2721 } else if (NEEDS_OFFSET_PUTFIELD_BARRIER && fieldType.isOffsetType()) { 2722 Barriers.compilePutfieldBarrierOffset(asm, T0, fieldRef.getId(), this); 2723 } else if (NEEDS_EXTENT_PUTFIELD_BARRIER && fieldType.isExtentType()) { 2724 Barriers.compilePutfieldBarrierExtent(asm, T0, fieldRef.getId(), this); 2725 } else if (fieldType.isBooleanType() || fieldType.isByteType()) { // no need for primitive write barriers 2726 // 8bit store 2727 asm.emitPOP_Reg(T1); // T1 is the value to be stored 2728 asm.emitPOP_Reg(S0); // S0 is the object reference 2729 asm.emitMOV_RegIdx_Reg_Byte(S0, T0, BYTE, NO_SLOT, T1); // [S0+T0] <- T1 2730 } else if (fieldType.isShortType() || fieldType.isCharType()) { 2731 // 16bit store 2732 asm.emitPOP_Reg(T1); // T1 is the value to be stored 2733 asm.emitPOP_Reg(S0); // S0 is the object reference 2734 asm.emitMOV_RegIdx_Reg_Word(S0, T0, BYTE, NO_SLOT, T1); // [S0+T0] <- T1 2735 } else if (fieldType.isIntType() || fieldType.isFloatType() || 2736 (VM.BuildFor32Addr && fieldType.isWordLikeType())) { 2737 // 32bit store 2738 asm.emitPOP_Reg(T1); // T1 is the value to be stored 2739 asm.emitPOP_Reg(S0); // S0 is the object reference 2740 asm.emitMOV_RegIdx_Reg(S0, T0, BYTE, NO_SLOT, T1); // [S0+T0] <- T1 2741 } else { 2742 // 64bit store 2743 if (VM.VerifyAssertions) { 2744 VM._assert(fieldType.isLongType() || fieldType.isDoubleType() || 2745 (VM.BuildFor64Addr && fieldType.isWordLikeType())); 2746 } 2747 if (VM.BuildFor32Addr) { 2748 // NB this is a 64bit copy from the stack to memory so implement 2749 // as a slightly optimized Intel memory copy using the FPU 2750 asm.emitMOV_Reg_RegDisp(S0, SP, TWO_SLOTS); // S0 is the object reference 2751 if (SSE2_BASE) { 2752 asm.emitMOVQ_Reg_RegInd(XMM0, SP); // XMM0 is the value to be stored 2753 asm.emitMOVQ_RegIdx_Reg(S0, T0, BYTE, NO_SLOT, XMM0); // [S0+T0] <- XMM0 2754 } else { 2755 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); // FP0 is the value to be stored 2756 asm.emitFSTP_RegIdx_Reg_Quad(S0, T0, BYTE, NO_SLOT, FP0); // [S0+T0] <- FP0 2757 } 2758 if (!fieldType.isWordLikeType()) { 2759 adjustStack(WORDSIZE * 3, true); // complete popping the values and reference 2760 } else { 2761 adjustStack(WORDSIZE * 2, true); // complete popping the values and reference 2762 } 2763 } else { 2764 asm.emitPOP_Reg(T1); // T1 is the value to be stored 2765 if (!fieldType.isWordLikeType()) { 2766 adjustStack(WORDSIZE, true); // throw away slot 2767 } 2768 asm.emitPOP_Reg(S0); // S0 is the object reference 2769 asm.emitMOV_RegIdx_Reg_Quad(S0, T0, BYTE, NO_SLOT, T1); // [S0+T0] <- T1 2770 } 2771 } 2772 // The field may be volatile. 2773 asm.emitMFENCE(); 2774 } 2775 2776 @Override 2777 protected void emit_resolved_putfield(FieldReference fieldRef) { 2778 Barriers.compileModifyCheck(asm, fieldRef.getNumberOfStackSlots() * WORDSIZE); 2779 RVMField field = fieldRef.peekResolvedField(); 2780 TypeReference fieldType = fieldRef.getFieldContentsType(); 2781 Offset fieldOffset = field.getOffset(); 2782 if (field.isReferenceType()) { 2783 // 32/64bit reference store 2784 if (NEEDS_OBJECT_PUTFIELD_BARRIER && !field.isUntraced()) { 2785 Barriers.compilePutfieldBarrierImm(asm, fieldOffset, fieldRef.getId()); 2786 } else { 2787 asm.emitPOP_Reg(T0); // T0 is the value to be stored 2788 asm.emitPOP_Reg(S0); // S0 is the object reference 2789 // [S0+fieldOffset] <- T0 2790 if (VM.BuildFor32Addr) { 2791 asm.emitMOV_RegDisp_Reg(S0, fieldOffset, T0); 2792 } else { 2793 asm.emitMOV_RegDisp_Reg_Quad(S0, fieldOffset, T0); 2794 } 2795 } 2796 } else if (NEEDS_BOOLEAN_PUTFIELD_BARRIER && fieldType.isBooleanType()) { 2797 Barriers.compilePutfieldBarrierBooleanImm(asm, fieldOffset, fieldRef.getId(), this); 2798 } else if (NEEDS_BYTE_PUTFIELD_BARRIER && fieldType.isByteType()) { 2799 Barriers.compilePutfieldBarrierByteImm(asm, fieldOffset, fieldRef.getId(), this); 2800 } else if (NEEDS_CHAR_PUTFIELD_BARRIER && fieldType.isCharType()) { 2801 Barriers.compilePutfieldBarrierCharImm(asm, fieldOffset, fieldRef.getId(), this); 2802 } else if (NEEDS_DOUBLE_PUTFIELD_BARRIER && fieldType.isDoubleType()) { 2803 Barriers.compilePutfieldBarrierDoubleImm(asm, fieldOffset, fieldRef.getId(), this); 2804 } else if (NEEDS_FLOAT_PUTFIELD_BARRIER && fieldType.isFloatType()) { 2805 Barriers.compilePutfieldBarrierFloatImm(asm, fieldOffset, fieldRef.getId(), this); 2806 } else if (NEEDS_INT_PUTFIELD_BARRIER && fieldType.isIntType()) { 2807 Barriers.compilePutfieldBarrierIntImm(asm, fieldOffset, fieldRef.getId(), this); 2808 } else if (NEEDS_LONG_PUTFIELD_BARRIER && fieldType.isLongType()) { 2809 Barriers.compilePutfieldBarrierLongImm(asm, fieldOffset, fieldRef.getId(), this); 2810 } else if (NEEDS_SHORT_PUTFIELD_BARRIER && fieldType.isShortType()) { 2811 Barriers.compilePutfieldBarrierShortImm(asm, fieldOffset, fieldRef.getId(), this); 2812 } else if (NEEDS_WORD_PUTFIELD_BARRIER && fieldType.isWordType()) { 2813 Barriers.compilePutfieldBarrierWordImm(asm, fieldOffset, fieldRef.getId(), this); 2814 } else if (NEEDS_ADDRESS_PUTFIELD_BARRIER && fieldType.isAddressType()) { 2815 Barriers.compilePutfieldBarrierAddressImm(asm, fieldOffset, fieldRef.getId(), this); 2816 } else if (NEEDS_OFFSET_PUTFIELD_BARRIER && fieldType.isOffsetType()) { 2817 Barriers.compilePutfieldBarrierOffsetImm(asm, fieldOffset, fieldRef.getId(), this); 2818 } else if (NEEDS_EXTENT_PUTFIELD_BARRIER && fieldType.isExtentType()) { 2819 Barriers.compilePutfieldBarrierExtentImm(asm, fieldOffset, fieldRef.getId(), this); 2820 } else if (field.getSize() == BYTES_IN_BYTE) { // no need for primitive write barriers 2821 // 8bit store 2822 asm.emitPOP_Reg(T0); // T0 is the value to be stored 2823 asm.emitPOP_Reg(S0); // S0 is the object reference 2824 // [S0+fieldOffset] <- T0 2825 asm.emitMOV_RegDisp_Reg_Byte(S0, fieldOffset, T0); 2826 } else if (field.getSize() == BYTES_IN_SHORT) { 2827 // 16bit store 2828 asm.emitPOP_Reg(T0); // T0 is the value to be stored 2829 asm.emitPOP_Reg(S0); // S0 is the object reference 2830 // [S0+fieldOffset] <- T0 2831 asm.emitMOV_RegDisp_Reg_Word(S0, fieldOffset, T0); 2832 } else if (field.getSize() == BYTES_IN_INT) { 2833 // 32bit store 2834 asm.emitPOP_Reg(T0); // T0 is the value to be stored 2835 asm.emitPOP_Reg(S0); // S0 is the object reference 2836 // [S0+fieldOffset] <- T0 2837 asm.emitMOV_RegDisp_Reg(S0, fieldOffset, T0); 2838 } else { 2839 // 64bit store 2840 if (VM.VerifyAssertions) { 2841 VM._assert(field.getSize() == BYTES_IN_LONG); 2842 } 2843 if (VM.BuildFor32Addr) { 2844 // NB this is a 64bit copy from the stack to memory so implement 2845 // as a slightly optimized Intel memory copy using the FPU 2846 asm.emitMOV_Reg_RegDisp(S0, SP, TWO_SLOTS); // S0 is the object reference 2847 if (SSE2_BASE) { 2848 asm.emitMOVQ_Reg_RegInd(XMM0, SP); // XMM0 is the value to be stored 2849 asm.emitMOVQ_RegDisp_Reg(S0, fieldOffset, XMM0); // [S0+fieldOffset] <- XMM0 2850 } else { 2851 asm.emitFLD_Reg_RegInd_Quad(FP0, SP); // FP0 is the value to be stored 2852 asm.emitFSTP_RegDisp_Reg_Quad(S0, fieldOffset, FP0); 2853 } 2854 adjustStack(WORDSIZE * 3, true); // complete popping the values and reference 2855 } else { 2856 asm.emitPOP_Reg(T1); // T1 is the value to be stored 2857 if (!field.getType().isWordLikeType()) { 2858 adjustStack(WORDSIZE, true); // throw away slot 2859 } 2860 asm.emitPOP_Reg(S0); // S0 is the object reference 2861 asm.emitMOV_RegDisp_Reg_Quad(S0, fieldOffset, T1); // [S0+fieldOffset] <- T1 2862 } 2863 } 2864 if (field.isVolatile()) { 2865 asm.emitMFENCE(); 2866 } 2867 } 2868 2869 /* 2870 * method invocation 2871 */ 2872 2873 @Override 2874 protected void emit_unresolved_invokevirtual(MethodReference methodRef) { 2875 emitDynamicLinkingSequence(asm, T0, methodRef, true); // T0 has offset of method 2876 int methodRefparameterWords = methodRef.getParameterWords() + 1; // +1 for "this" parameter 2877 Offset objectOffset = 2878 Offset.fromIntZeroExtend(methodRefparameterWords << LG_WORDSIZE).minus(WORDSIZE); // object offset into stack 2879 stackMoveHelper(T1, objectOffset); // T1 has "this" parameter 2880 asm.baselineEmitLoadTIB(S0, T1); // S0 has TIB 2881 if (VM.BuildFor32Addr) { 2882 asm.emitMOV_Reg_RegIdx(S0, S0, T0, BYTE, NO_SLOT); // S0 has address of virtual method 2883 } else { 2884 asm.emitMOV_Reg_RegIdx_Quad(S0, S0, T0, BYTE, NO_SLOT); // S0 has address of virtual method 2885 } 2886 genParameterRegisterLoad(methodRef, true); 2887 asm.emitCALL_Reg(S0); // call virtual method 2888 genResultRegisterUnload(methodRef); // push return value, if any 2889 } 2890 2891 @Override 2892 protected void emit_resolved_invokevirtual(MethodReference methodRef) { 2893 int methodRefparameterWords = methodRef.getParameterWords() + 1; // +1 for "this" parameter 2894 Offset methodRefOffset = methodRef.peekResolvedMethod().getOffset(); 2895 Offset objectOffset = 2896 Offset.fromIntZeroExtend(methodRefparameterWords << LG_WORDSIZE).minus(WORDSIZE); // object offset into stack 2897 stackMoveHelper(T1, objectOffset); // T1 has "this" parameter 2898 asm.baselineEmitLoadTIB(S0, T1); // S0 has TIB 2899 genParameterRegisterLoad(methodRef, true); 2900 asm.emitCALL_RegDisp(S0, methodRefOffset); // call virtual method 2901 genResultRegisterUnload(methodRef); // push return value, if any 2902 } 2903 2904 @Override 2905 protected void emit_resolved_invokespecial(MethodReference methodRef, RVMMethod target) { 2906 if (target.isObjectInitializer()) { 2907 genParameterRegisterLoad(methodRef, true); 2908 asm.generateJTOCcall(target.getOffset()); 2909 genResultRegisterUnload(target.getMemberRef().asMethodReference()); 2910 } else { 2911 if (VM.VerifyAssertions) VM._assert(!target.isStatic()); 2912 // invoke via class's tib slot 2913 Offset methodRefOffset = target.getOffset(); 2914 if (VM.BuildFor32Addr) { 2915 asm.emitMOV_Reg_Abs(S0, Magic.getTocPointer().plus(target.getDeclaringClass().getTibOffset())); 2916 } else { 2917 asm.generateJTOCloadLong(S0, target.getDeclaringClass().getTibOffset()); 2918 } 2919 genParameterRegisterLoad(methodRef, true); 2920 asm.emitCALL_RegDisp(S0, methodRefOffset); 2921 genResultRegisterUnload(methodRef); 2922 } 2923 } 2924 2925 @Override 2926 protected void emit_unresolved_invokespecial(MethodReference methodRef) { 2927 emitDynamicLinkingSequence(asm, S0, methodRef, true); 2928 genParameterRegisterLoad(methodRef, true); 2929 asm.generateJTOCcall(S0); 2930 genResultRegisterUnload(methodRef); 2931 } 2932 2933 @Override 2934 protected void emit_unresolved_invokestatic(MethodReference methodRef) { 2935 emitDynamicLinkingSequence(asm, S0, methodRef, true); 2936 genParameterRegisterLoad(methodRef, false); 2937 asm.generateJTOCcall(S0); 2938 genResultRegisterUnload(methodRef); 2939 } 2940 2941 @Override 2942 protected void emit_resolved_invokestatic(MethodReference methodRef) { 2943 Offset methodOffset = methodRef.peekResolvedMethod().getOffset(); 2944 genParameterRegisterLoad(methodRef, false); 2945 asm.generateJTOCcall(methodOffset); 2946 genResultRegisterUnload(methodRef); 2947 } 2948 2949 @Override 2950 protected void emit_invokeinterface(MethodReference methodRef) { 2951 final int count = methodRef.getParameterWords() + 1; // +1 for "this" parameter 2952 2953 RVMMethod resolvedMethod = null; 2954 resolvedMethod = methodRef.peekInterfaceMethod(); 2955 2956 // (1) Emit dynamic type checking sequence if required to do so inline. 2957 if (VM.BuildForIMTInterfaceInvocation) { 2958 if (methodRef.isMiranda()) { 2959 // TODO: It's not entirely clear that we can just assume that 2960 // the class actually implements the interface. 2961 // However, we don't know what interface we need to be checking 2962 // so there doesn't appear to be much else we can do here. 2963 } else { 2964 if (resolvedMethod == null) { 2965 // Can't successfully resolve it at compile time. 2966 // Call uncommon case typechecking routine to do the right thing when this code actually executes. 2967 // T1 = "this" object 2968 stackMoveHelper(T1, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE)); 2969 asm.emitPUSH_Imm(methodRef.getId()); // push dict id of target 2970 asm.emitPUSH_Reg(T1); // push "this" 2971 genParameterRegisterLoad(asm, 2); // pass 2 parameter word 2972 // check that "this" class implements the interface 2973 asm.generateJTOCcall(Entrypoints.unresolvedInvokeinterfaceImplementsTestMethod.getOffset()); 2974 } else { 2975 RVMClass interfaceClass = resolvedMethod.getDeclaringClass(); 2976 int interfaceIndex = interfaceClass.getDoesImplementIndex(); 2977 int interfaceMask = interfaceClass.getDoesImplementBitMask(); 2978 // T1 = "this" object 2979 stackMoveHelper(T1, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE)); 2980 asm.baselineEmitLoadTIB(S0, T1); // S0 = tib of "this" object 2981 if (VM.BuildFor32Addr) { 2982 asm.emitMOV_Reg_RegDisp(S0, S0, Offset.fromIntZeroExtend(TIB_DOES_IMPLEMENT_INDEX << LG_WORDSIZE)); // implements bit vector 2983 } else { 2984 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, Offset.fromIntZeroExtend(TIB_DOES_IMPLEMENT_INDEX << LG_WORDSIZE)); // implements bit vector 2985 } 2986 2987 if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) { 2988 // must do arraybounds check of implements bit vector 2989 if (ARRAY_LENGTH_BYTES == 4) { 2990 asm.emitCMP_RegDisp_Imm(S0, ObjectModel.getArrayLengthOffset(), interfaceIndex); 2991 } else { 2992 asm.emitCMP_RegDisp_Imm_Quad(S0, ObjectModel.getArrayLengthOffset(), interfaceIndex); 2993 } 2994 asm.emitBranchLikelyNextInstruction(); 2995 ForwardReference fr = asm.forwardJcc(LGT); 2996 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_MUST_IMPLEMENT + RVM_TRAP_BASE); 2997 fr.resolve(asm); 2998 } 2999 3000 // Test the appropriate bit and if set, branch around another trap imm 3001 if (interfaceIndex == 0) { 3002 asm.emitTEST_RegInd_Imm(S0, interfaceMask); 3003 } else { 3004 asm.emitTEST_RegDisp_Imm(S0, Offset.fromIntZeroExtend(interfaceIndex << LOG_BYTES_IN_INT), interfaceMask); 3005 } 3006 asm.emitBranchLikelyNextInstruction(); 3007 ForwardReference fr = asm.forwardJcc(NE); 3008 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_MUST_IMPLEMENT + RVM_TRAP_BASE); 3009 fr.resolve(asm); 3010 } 3011 } 3012 } 3013 3014 // (2) Emit interface invocation sequence. 3015 if (VM.BuildForIMTInterfaceInvocation) { 3016 InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(methodRef); 3017 // squirrel away signature ID 3018 Offset offset = ArchEntrypoints.hiddenSignatureIdField.getOffset(); 3019 asm.emitMOV_RegDisp_Imm(THREAD_REGISTER, offset, sig.getId()); 3020 // T1 = "this" object 3021 stackMoveHelper(T1, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE)); 3022 asm.baselineEmitLoadTIB(S0, T1); 3023 // Load the IMT Base into S0 3024 if (VM.BuildFor32Addr) { 3025 asm.emitMOV_Reg_RegDisp(S0, S0, Offset.fromIntZeroExtend(TIB_INTERFACE_DISPATCH_TABLE_INDEX << LG_WORDSIZE)); 3026 } else { 3027 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, Offset.fromIntZeroExtend(TIB_INTERFACE_DISPATCH_TABLE_INDEX << LG_WORDSIZE)); 3028 } 3029 genParameterRegisterLoad(methodRef, true); 3030 asm.emitCALL_RegDisp(S0, sig.getIMTOffset()); // the interface call 3031 } else { 3032 int itableIndex = -1; 3033 if (VM.BuildForITableInterfaceInvocation && resolvedMethod != null) { 3034 // get the index of the method in the Itable 3035 itableIndex = 3036 InterfaceInvocation.getITableIndex(resolvedMethod.getDeclaringClass(), 3037 methodRef.getName(), 3038 methodRef.getDescriptor()); 3039 } 3040 if (itableIndex == -1) { 3041 // itable index is not known at compile-time. 3042 // call "invokeInterface" to resolve object + method id into 3043 // method address 3044 int methodRefId = methodRef.getId(); 3045 // "this" parameter is obj 3046 if (count == 1) { 3047 asm.emitPUSH_RegInd(SP); 3048 } else { 3049 asm.emitPUSH_RegDisp(SP, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE)); 3050 } 3051 asm.emitPUSH_Imm(methodRefId); // id of method to call 3052 genParameterRegisterLoad(asm, 2); // pass 2 parameter words 3053 // invokeinterface(obj, id) returns address to call 3054 asm.generateJTOCcall(Entrypoints.invokeInterfaceMethod.getOffset()); 3055 if (VM.BuildFor32Addr) { 3056 asm.emitMOV_Reg_Reg(S0, T0); // S0 has address of method 3057 } else { 3058 asm.emitMOV_Reg_Reg_Quad(S0, T0); // S0 has address of method 3059 } 3060 genParameterRegisterLoad(methodRef, true); 3061 asm.emitCALL_Reg(S0); // the interface method (its parameters are on stack) 3062 } else { 3063 // itable index is known at compile-time. 3064 // call "findITable" to resolve object + interface id into 3065 // itable address 3066 // T0 = "this" object 3067 stackMoveHelper(T0, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE)); 3068 asm.baselineEmitLoadTIB(S0, T0); 3069 asm.emitPUSH_Reg(S0); 3070 asm.emitPUSH_Imm(resolvedMethod.getDeclaringClass().getInterfaceId()); // interface id 3071 genParameterRegisterLoad(asm, 2); // pass 2 parameter words 3072 asm.generateJTOCcall(Entrypoints.findItableMethod.getOffset()); // findItableOffset(tib, id) returns iTable 3073 if (VM.BuildFor32Addr) { 3074 asm.emitMOV_Reg_Reg(S0, T0); // S0 has iTable 3075 } else { 3076 asm.emitMOV_Reg_Reg_Quad(S0, T0); // S0 has iTable 3077 } 3078 genParameterRegisterLoad(methodRef, true); 3079 // the interface call 3080 asm.emitCALL_RegDisp(S0, Offset.fromIntZeroExtend(itableIndex << LG_WORDSIZE)); 3081 } 3082 } 3083 genResultRegisterUnload(methodRef); 3084 } 3085 3086 /* 3087 * other object model functions 3088 */ 3089 3090 @Override 3091 protected void emit_resolved_new(RVMClass typeRef) { 3092 int instanceSize = typeRef.getInstanceSize(); 3093 Offset tibOffset = typeRef.getTibOffset(); 3094 int whichAllocator = MemoryManager.pickAllocator(typeRef, method); 3095 int align = ObjectModel.getAlignment(typeRef); 3096 int offset = ObjectModel.getOffsetForAlignment(typeRef, false); 3097 int site = MemoryManager.getAllocationSite(true); 3098 asm.emitPUSH_Imm(instanceSize); 3099 asm.generateJTOCpush(tibOffset); // put tib on stack 3100 asm.emitPUSH_Imm(typeRef.hasFinalizer() ? 1 : 0); // does the class have a finalizer? 3101 asm.emitPUSH_Imm(whichAllocator); 3102 asm.emitPUSH_Imm(align); 3103 asm.emitPUSH_Imm(offset); 3104 asm.emitPUSH_Imm(site); 3105 genParameterRegisterLoad(asm, 7); // pass 7 parameter words 3106 asm.generateJTOCcall(Entrypoints.resolvedNewScalarMethod.getOffset()); 3107 asm.emitPUSH_Reg(T0); 3108 } 3109 3110 @Override 3111 protected void emit_unresolved_new(TypeReference typeRef) { 3112 int site = MemoryManager.getAllocationSite(true); 3113 asm.emitPUSH_Imm(typeRef.getId()); 3114 asm.emitPUSH_Imm(site); // site 3115 genParameterRegisterLoad(asm, 2); // pass 2 parameter words 3116 asm.generateJTOCcall(Entrypoints.unresolvedNewScalarMethod.getOffset()); 3117 asm.emitPUSH_Reg(T0); 3118 } 3119 3120 @Override 3121 protected void emit_resolved_newarray(RVMArray array) { 3122 int width = array.getLogElementSize(); 3123 Offset tibOffset = array.getTibOffset(); 3124 int headerSize = ObjectModel.computeHeaderSize(array); 3125 int whichAllocator = MemoryManager.pickAllocator(array, method); 3126 int site = MemoryManager.getAllocationSite(true); 3127 int align = ObjectModel.getAlignment(array); 3128 int offset = ObjectModel.getOffsetForAlignment(array, false); 3129 // count is already on stack- nothing required 3130 asm.emitPUSH_Imm(width); // logElementSize 3131 asm.emitPUSH_Imm(headerSize); // headerSize 3132 asm.generateJTOCpush(tibOffset); // tib 3133 asm.emitPUSH_Imm(whichAllocator); // allocator 3134 asm.emitPUSH_Imm(align); 3135 asm.emitPUSH_Imm(offset); 3136 asm.emitPUSH_Imm(site); 3137 genParameterRegisterLoad(asm, 8); // pass 8 parameter words 3138 asm.generateJTOCcall(Entrypoints.resolvedNewArrayMethod.getOffset()); 3139 asm.emitPUSH_Reg(T0); 3140 } 3141 3142 @Override 3143 protected void emit_unresolved_newarray(TypeReference tRef) { 3144 int site = MemoryManager.getAllocationSite(true); 3145 // count is already on stack- nothing required 3146 asm.emitPUSH_Imm(tRef.getId()); 3147 asm.emitPUSH_Imm(site); // site 3148 genParameterRegisterLoad(asm, 3); // pass 3 parameter words 3149 asm.generateJTOCcall(Entrypoints.unresolvedNewArrayMethod.getOffset()); 3150 asm.emitPUSH_Reg(T0); 3151 } 3152 3153 @Override 3154 protected void emit_multianewarray(TypeReference typeRef, int dimensions) { 3155 // TODO: implement direct call to RuntimeEntrypoints.buildTwoDimensionalArray 3156 // Calculate the offset from FP on entry to newarray: 3157 // 1 word for each parameter, plus 1 for return address on 3158 // stack and 1 for code technique in Linker 3159 final int PARAMETERS = 4; 3160 final int OFFSET_WORDS = PARAMETERS + 2; 3161 3162 // setup parameters for newarrayarray routine 3163 asm.emitPUSH_Imm(method.getId()); // caller 3164 asm.emitPUSH_Imm(dimensions); // dimension of arrays 3165 asm.emitPUSH_Imm(typeRef.getId()); // type of array elements 3166 asm.emitPUSH_Imm((dimensions + OFFSET_WORDS) << LG_WORDSIZE); // offset to dimensions from FP on entry to newarray 3167 3168 genParameterRegisterLoad(asm, PARAMETERS); 3169 asm.generateJTOCcall(ArchEntrypoints.newArrayArrayMethod.getOffset()); 3170 adjustStack(dimensions * WORDSIZE, true); // clear stack of dimensions 3171 asm.emitPUSH_Reg(T0); // push array ref on stack 3172 } 3173 3174 @Override 3175 protected void emit_arraylength() { 3176 asm.emitPOP_Reg(T0); // T0 is array reference 3177 if (ARRAY_LENGTH_BYTES == 4) { 3178 if (VM.BuildFor32Addr) { 3179 asm.emitPUSH_RegDisp(T0, ObjectModel.getArrayLengthOffset()); 3180 } else { 3181 asm.emitMOV_Reg_RegDisp(T0, T0, ObjectModel.getArrayLengthOffset()); 3182 asm.emitPUSH_Reg(T0); 3183 } 3184 } else { 3185 asm.emitPUSH_RegDisp(T0, ObjectModel.getArrayLengthOffset()); 3186 } 3187 } 3188 3189 @Override 3190 protected void emit_athrow() { 3191 genParameterRegisterLoad(asm, 1); // pass 1 parameter word 3192 asm.generateJTOCcall(Entrypoints.athrowMethod.getOffset()); 3193 } 3194 3195 @Override 3196 protected void emit_checkcast(TypeReference typeRef) { 3197 asm.emitPUSH_RegInd(SP); // duplicate the object ref on the stack 3198 asm.emitPUSH_Imm(typeRef.getId()); // TypeReference id. 3199 genParameterRegisterLoad(asm, 2); // pass 2 parameter words 3200 asm.generateJTOCcall(Entrypoints.checkcastMethod.getOffset()); // checkcast(obj, type reference id); 3201 } 3202 3203 @Override 3204 protected void emit_checkcast_resolvedInterface(RVMClass type) { 3205 int interfaceIndex = type.getDoesImplementIndex(); 3206 int interfaceMask = type.getDoesImplementBitMask(); 3207 3208 if (VM.BuildFor32Addr) { 3209 asm.emitMOV_Reg_RegInd(ECX, SP); // load object from stack into ECX 3210 } else { 3211 asm.emitMOV_Reg_RegInd_Quad(ECX, SP); // load object from stack into ECX 3212 } 3213 ForwardReference isNull = asm.forwardJECXZ(); // forward branch if ECX == 0 3214 3215 asm.baselineEmitLoadTIB(S0, ECX); // S0 = TIB of object 3216 // S0 = implements bit vector 3217 if (VM.BuildFor32Addr) { 3218 asm.emitMOV_Reg_RegDisp(S0, S0, Offset.fromIntZeroExtend(TIB_DOES_IMPLEMENT_INDEX << LG_WORDSIZE)); 3219 } else { 3220 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, Offset.fromIntZeroExtend(TIB_DOES_IMPLEMENT_INDEX << LG_WORDSIZE)); 3221 } 3222 3223 if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) { 3224 // must do arraybounds check of implements bit vector 3225 if (ARRAY_LENGTH_BYTES == 4) { 3226 asm.emitCMP_RegDisp_Imm(S0, ObjectModel.getArrayLengthOffset(), interfaceIndex); 3227 } else { 3228 asm.emitCMP_RegDisp_Imm_Quad(S0, ObjectModel.getArrayLengthOffset(), interfaceIndex); 3229 } 3230 asm.emitBranchLikelyNextInstruction(); 3231 ForwardReference fr = asm.forwardJcc(LGT); 3232 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_CHECKCAST + RVM_TRAP_BASE); 3233 fr.resolve(asm); 3234 } 3235 3236 // Test the appropriate bit and if set, branch around another trap imm 3237 asm.emitTEST_RegDisp_Imm(S0, Offset.fromIntZeroExtend(interfaceIndex << LOG_BYTES_IN_INT), interfaceMask); 3238 asm.emitBranchLikelyNextInstruction(); 3239 ForwardReference fr = asm.forwardJcc(NE); 3240 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_CHECKCAST + RVM_TRAP_BASE); 3241 fr.resolve(asm); 3242 isNull.resolve(asm); 3243 } 3244 3245 @Override 3246 protected void emit_checkcast_resolvedClass(RVMClass type) { 3247 int LHSDepth = type.getTypeDepth(); 3248 int LHSId = type.getId(); 3249 3250 if (VM.BuildFor32Addr) { 3251 asm.emitMOV_Reg_RegInd(ECX, SP); // load object from stack 3252 } else { 3253 asm.emitMOV_Reg_RegInd_Quad(ECX, SP); // load object from stack 3254 } 3255 ForwardReference isNull = asm.forwardJECXZ(); // jump forward if ECX == 0 3256 3257 asm.baselineEmitLoadTIB(S0, ECX); // S0 = TIB of object 3258 // S0 = superclass IDs 3259 if (VM.BuildFor32Addr) { 3260 asm.emitMOV_Reg_RegDisp(S0, S0, Offset.fromIntZeroExtend(TIB_SUPERCLASS_IDS_INDEX << LG_WORDSIZE)); 3261 } else { 3262 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, Offset.fromIntZeroExtend(TIB_SUPERCLASS_IDS_INDEX << LG_WORDSIZE)); 3263 } 3264 if (DynamicTypeCheck.MIN_SUPERCLASS_IDS_SIZE <= LHSDepth) { 3265 // must do arraybounds check of superclass display 3266 if (ARRAY_LENGTH_BYTES == 4) { 3267 asm.emitCMP_RegDisp_Imm(S0, ObjectModel.getArrayLengthOffset(), LHSDepth); 3268 } else { 3269 asm.emitCMP_RegDisp_Imm_Quad(S0, ObjectModel.getArrayLengthOffset(), LHSDepth); 3270 } 3271 asm.emitBranchLikelyNextInstruction(); 3272 ForwardReference fr = asm.forwardJcc(LGT); 3273 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_CHECKCAST + RVM_TRAP_BASE); 3274 fr.resolve(asm); 3275 } 3276 3277 // Load id from display at required depth and compare against target id. 3278 asm.emitMOVZX_Reg_RegDisp_Word(S0, S0, Offset.fromIntZeroExtend(LHSDepth << LOG_BYTES_IN_SHORT)); 3279 asm.emitCMP_Reg_Imm(S0, LHSId); 3280 asm.emitBranchLikelyNextInstruction(); 3281 ForwardReference fr = asm.forwardJcc(EQ); 3282 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_CHECKCAST + RVM_TRAP_BASE); 3283 fr.resolve(asm); 3284 isNull.resolve(asm); 3285 } 3286 3287 @Override 3288 protected void emit_checkcast_final(RVMType type) { 3289 if (VM.BuildFor32Addr) { 3290 asm.emitMOV_Reg_RegInd(ECX, SP); // load object from stack 3291 } else { 3292 asm.emitMOV_Reg_RegInd_Quad(ECX, SP); // load object from stack 3293 } 3294 ForwardReference isNull = asm.forwardJECXZ(); // jump forward if ECX == 0 3295 3296 asm.baselineEmitLoadTIB(S0, ECX); // TIB of object 3297 asm.generateJTOCcmpWord(S0, type.getTibOffset()); 3298 asm.emitBranchLikelyNextInstruction(); 3299 ForwardReference fr = asm.forwardJcc(EQ); 3300 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_CHECKCAST + RVM_TRAP_BASE); 3301 fr.resolve(asm); 3302 isNull.resolve(asm); 3303 } 3304 3305 @Override 3306 protected void emit_instanceof(TypeReference typeRef) { 3307 asm.emitPUSH_Imm(typeRef.getId()); 3308 genParameterRegisterLoad(asm, 2); // pass 2 parameter words 3309 asm.generateJTOCcall(Entrypoints.instanceOfMethod.getOffset()); 3310 asm.emitPUSH_Reg(T0); 3311 } 3312 3313 @Override 3314 protected void emit_instanceof_resolvedInterface(RVMClass type) { 3315 int interfaceIndex = type.getDoesImplementIndex(); 3316 int interfaceMask = type.getDoesImplementBitMask(); 3317 3318 asm.emitPOP_Reg(ECX); // load object from stack 3319 ForwardReference isNull = asm.forwardJECXZ(); // test for null 3320 3321 asm.baselineEmitLoadTIB(S0, ECX); // S0 = TIB of object 3322 // S0 = implements bit vector 3323 if (VM.BuildFor32Addr) { 3324 asm.emitMOV_Reg_RegDisp(S0, S0, Offset.fromIntZeroExtend(TIB_DOES_IMPLEMENT_INDEX << LG_WORDSIZE)); 3325 } else { 3326 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, Offset.fromIntZeroExtend(TIB_DOES_IMPLEMENT_INDEX << LG_WORDSIZE)); 3327 } 3328 ForwardReference outOfBounds = null; 3329 if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) { 3330 // must do arraybounds check of implements bit vector 3331 if (ARRAY_LENGTH_BYTES == 4) { 3332 asm.emitCMP_RegDisp_Imm(S0, ObjectModel.getArrayLengthOffset(), interfaceIndex); 3333 } else { 3334 asm.emitCMP_RegDisp_Imm_Quad(S0, ObjectModel.getArrayLengthOffset(), interfaceIndex); 3335 } 3336 outOfBounds = asm.forwardJcc(LLE); 3337 } 3338 3339 // Test the implements bit and push true if it is set 3340 asm.emitTEST_RegDisp_Imm(S0, Offset.fromIntZeroExtend(interfaceIndex << LOG_BYTES_IN_INT), interfaceMask); 3341 ForwardReference notMatched = asm.forwardJcc(EQ); 3342 asm.emitPUSH_Imm(1); 3343 ForwardReference done = asm.forwardJMP(); 3344 3345 // push false 3346 isNull.resolve(asm); 3347 if (outOfBounds != null) outOfBounds.resolve(asm); 3348 notMatched.resolve(asm); 3349 asm.emitPUSH_Imm(0); 3350 3351 done.resolve(asm); 3352 } 3353 3354 @Override 3355 protected void emit_instanceof_resolvedClass(RVMClass type) { 3356 int LHSDepth = type.getTypeDepth(); 3357 int LHSId = type.getId(); 3358 3359 asm.emitPOP_Reg(ECX); // load object from stack 3360 ForwardReference isNull = asm.forwardJECXZ(); // test for null 3361 3362 // get superclass display from object's TIB 3363 asm.baselineEmitLoadTIB(S0, ECX); 3364 if (VM.BuildFor32Addr) { 3365 asm.emitMOV_Reg_RegDisp(S0, S0, Offset.fromIntZeroExtend(TIB_SUPERCLASS_IDS_INDEX << LG_WORDSIZE)); 3366 } else { 3367 asm.emitMOV_Reg_RegDisp_Quad(S0, S0, Offset.fromIntZeroExtend(TIB_SUPERCLASS_IDS_INDEX << LG_WORDSIZE)); 3368 } 3369 ForwardReference outOfBounds = null; 3370 if (DynamicTypeCheck.MIN_SUPERCLASS_IDS_SIZE <= LHSDepth) { 3371 // must do arraybounds check of superclass display 3372 if (ARRAY_LENGTH_BYTES == 4) { 3373 asm.emitCMP_RegDisp_Imm(S0, ObjectModel.getArrayLengthOffset(), LHSDepth); 3374 } else { 3375 asm.emitCMP_RegDisp_Imm_Quad(S0, ObjectModel.getArrayLengthOffset(), LHSDepth); 3376 } 3377 outOfBounds = asm.forwardJcc(LLE); 3378 } 3379 3380 // Load id from display at required depth and compare against target id; push true if matched 3381 asm.emitMOVZX_Reg_RegDisp_Word(S0, S0, Offset.fromIntZeroExtend(LHSDepth << LOG_BYTES_IN_SHORT)); 3382 asm.emitCMP_Reg_Imm(S0, LHSId); 3383 ForwardReference notMatched = asm.forwardJcc(NE); 3384 asm.emitPUSH_Imm(1); 3385 ForwardReference done = asm.forwardJMP(); 3386 3387 // push false 3388 isNull.resolve(asm); 3389 if (outOfBounds != null) outOfBounds.resolve(asm); 3390 notMatched.resolve(asm); 3391 asm.emitPUSH_Imm(0); 3392 3393 done.resolve(asm); 3394 } 3395 3396 @Override 3397 protected void emit_instanceof_final(RVMType type) { 3398 asm.emitPOP_Reg(ECX); // load object from stack 3399 ForwardReference isNull = asm.forwardJECXZ(); // test for null 3400 3401 // compare TIB of object to desired TIB and push true if equal 3402 asm.baselineEmitLoadTIB(S0, ECX); 3403 asm.generateJTOCcmpWord(S0, type.getTibOffset()); 3404 ForwardReference notMatched = asm.forwardJcc(NE); 3405 asm.emitPUSH_Imm(1); 3406 ForwardReference done = asm.forwardJMP(); 3407 3408 // push false 3409 isNull.resolve(asm); 3410 notMatched.resolve(asm); 3411 asm.emitPUSH_Imm(0); 3412 3413 done.resolve(asm); 3414 } 3415 3416 @Override 3417 protected void emit_monitorenter() { 3418 if (VM.BuildFor32Addr) { 3419 asm.emitMOV_Reg_RegInd(T0, SP); // T0 is object reference 3420 } else { 3421 asm.emitMOV_Reg_RegInd_Quad(T0, SP); // T0 is object reference 3422 } 3423 genNullCheck(asm, T0); 3424 genParameterRegisterLoad(asm, 1); // pass 1 parameter word 3425 asm.generateJTOCcall(Entrypoints.lockMethod.getOffset()); 3426 } 3427 3428 @Override 3429 protected void emit_monitorexit() { 3430 genParameterRegisterLoad(asm, 1); // pass 1 parameter word 3431 asm.generateJTOCcall(Entrypoints.unlockMethod.getOffset()); 3432 } 3433 3434 //----------------// 3435 // implementation // 3436 //----------------// 3437 3438 private void genPrologue() { 3439 if (shouldPrint) asm.comment("prologue for " + method); 3440 if (klass.hasBridgeFromNativeAnnotation()) { 3441 // replace the normal prologue with a special prolog 3442 JNICompiler.generateGlueCodeForJNIMethod(asm, method, compiledMethod.getId()); 3443 // set some constants for the code generation of the rest of the method 3444 // firstLocalOffset is shifted down because more registers are saved 3445 firstLocalOffset = STACKFRAME_BODY_OFFSET.minus(JNICompiler.SAVED_GPRS_FOR_JNI << LG_WORDSIZE); 3446 } else { 3447 /* paramaters are on the stack and/or in registers; There is space 3448 * on the stack for all the paramaters; Parameter slots in the 3449 * stack are such that the first paramater has the higher address, 3450 * i.e., it pushed below all the other paramaters; The return 3451 * address is the topmost entry on the stack. The frame pointer 3452 * still addresses the previous frame. 3453 * The first word of the header, currently addressed by the stack 3454 * pointer, contains the return address. 3455 */ 3456 3457 /* establish a new frame: 3458 * push the caller's frame pointer in the stack, and 3459 * reset the frame pointer to the current stack top, 3460 * ie, the frame pointer addresses directly the word 3461 * that contains the previous frame pointer. 3462 * The second word of the header contains the frame 3463 * point of the caller. 3464 * The third word of the header contains the compiled method id of the called method. 3465 */ 3466 // store caller's frame pointer 3467 asm.emitPUSH_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset()); 3468 // establish new frame 3469 if (VM.BuildFor32Addr) { 3470 asm.emitMOV_RegDisp_Reg(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset(), SP); 3471 } else { 3472 asm.emitMOV_RegDisp_Reg_Quad(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset(), SP); 3473 } 3474 /* 3475 * NOTE: until the end of the prologue SP holds the framepointer. 3476 */ 3477 if (VM.VerifyAssertions) VM._assert(STACKFRAME_METHOD_ID_OFFSET.toInt() == -WORDSIZE); 3478 asm.emitPUSH_Imm(compiledMethod.getId()); 3479 3480 /* 3481 * save registers 3482 */ 3483 if (VM.VerifyAssertions) VM._assert(EDI_SAVE_OFFSET.toInt() == -2 * WORDSIZE); 3484 asm.emitPUSH_Reg(EDI); // save nonvolatile EDI register 3485 if (VM.VerifyAssertions) VM._assert(EBX_SAVE_OFFSET.toInt() == -3 * WORDSIZE); 3486 asm.emitPUSH_Reg(EBX); // save nonvolatile EBX register 3487 3488 int savedRegistersSize; 3489 3490 if (method.hasBaselineSaveLSRegistersAnnotation()) { 3491 if (VM.VerifyAssertions) VM._assert(EBP_SAVE_OFFSET.toInt() == -4 * WORDSIZE); 3492 asm.emitPUSH_Reg(EBP); 3493 savedRegistersSize = SAVED_GPRS_FOR_SAVE_LS_REGISTERS << LG_WORDSIZE; 3494 } else { 3495 savedRegistersSize = SAVED_GPRS << LG_WORDSIZE; // default 3496 } 3497 3498 /* handle "dynamic brige" methods: 3499 * save all registers except FP, SP, TR, S0 (scratch), and 3500 * EDI and EBX saved above. 3501 */ 3502 // TODO: (SJF): When I try to reclaim ESI, I may have to save it here? 3503 if (klass.hasDynamicBridgeAnnotation()) { 3504 savedRegistersSize += 2 << LG_WORDSIZE; 3505 if (VM.VerifyAssertions) VM._assert(T0_SAVE_OFFSET.toInt() == -4 * WORDSIZE); 3506 asm.emitPUSH_Reg(T0); 3507 if (VM.VerifyAssertions) VM._assert(T1_SAVE_OFFSET.toInt() == -5 * WORDSIZE); 3508 asm.emitPUSH_Reg(T1); 3509 if (SSE2_FULL) { 3510 // TODO: Store SSE2 Control word? 3511 adjustStack(-XMM_STATE_SIZE, true); // adjust stack to bottom of saved area 3512 if (VM.VerifyAssertions) VM._assert(XMM_SAVE_OFFSET.toInt() == (-5 * WORDSIZE) - XMM_STATE_SIZE); 3513 asm.emitMOVQ_RegDisp_Reg(SP, Offset.fromIntSignExtend(24), XMM3); 3514 asm.emitMOVQ_RegDisp_Reg(SP, Offset.fromIntSignExtend(16), XMM2); 3515 asm.emitMOVQ_RegDisp_Reg(SP, Offset.fromIntSignExtend(8), XMM1); 3516 asm.emitMOVQ_RegInd_Reg(SP, XMM0); 3517 savedRegistersSize += XMM_STATE_SIZE; 3518 } else { 3519 if (VM.VerifyAssertions) VM._assert(FPU_SAVE_OFFSET.toInt() == (-5 * WORDSIZE) - FPU_STATE_SIZE); 3520 adjustStack(-FPU_STATE_SIZE, true); // adjust stack to bottom of saved area 3521 asm.emitFNSAVE_RegInd(SP); 3522 savedRegistersSize += FPU_STATE_SIZE; 3523 } 3524 } 3525 3526 // copy registers to callee's stackframe 3527 firstLocalOffset = STACKFRAME_BODY_OFFSET.minus(savedRegistersSize); 3528 Offset firstParameterOffset = Offset.fromIntSignExtend(savedRegistersSize + STACKFRAME_HEADER_SIZE + (parameterWords << LG_WORDSIZE) - WORDSIZE); 3529 genParameterCopy(firstParameterOffset); 3530 int emptyStackOffset = (method.getLocalWords() << LG_WORDSIZE) - (parameterWords << LG_WORDSIZE); 3531 if (emptyStackOffset != 0) { 3532 adjustStack(-emptyStackOffset, true); // set aside room for non parameter locals 3533 } 3534 /* defer generating code which may cause GC until 3535 * locals were initialized. see emit_deferred_prologue 3536 */ 3537 if (method.isForOsrSpecialization()) { 3538 return; 3539 } 3540 3541 /* 3542 * generate stacklimit check 3543 */ 3544 if (isInterruptible) { 3545 // S0<-limit 3546 if (VM.BuildFor32Addr) { 3547 asm.emitCMP_Reg_RegDisp(SP, TR, Entrypoints.stackLimitField.getOffset()); 3548 } else { 3549 asm.emitCMP_Reg_RegDisp_Quad(SP, TR, Entrypoints.stackLimitField.getOffset()); 3550 } 3551 asm.emitBranchLikelyNextInstruction(); 3552 ForwardReference fr = asm.forwardJcc(LGT); // Jmp around trap if OK 3553 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_STACK_OVERFLOW + RVM_TRAP_BASE); // trap 3554 fr.resolve(asm); 3555 } else { 3556 // TODO!! make sure stackframe of uninterruptible method doesn't overflow guard page 3557 } 3558 3559 if (!VM.runningTool && ((BaselineCompiledMethod) compiledMethod).hasCounterArray()) { 3560 // use (nonvolatile) EBX to hold base of this method's counter array 3561 if (NEEDS_OBJECT_ALOAD_BARRIER) { 3562 asm.emitPUSH_Abs(Magic.getTocPointer().plus(Entrypoints.edgeCountersField.getOffset())); 3563 asm.emitPUSH_Imm(getEdgeCounterIndex()); 3564 Barriers.compileArrayLoadBarrier(asm, false); 3565 if (VM.BuildFor32Addr) { 3566 asm.emitMOV_Reg_Reg(EBX, T0); 3567 } else { 3568 asm.emitMOV_Reg_Reg_Quad(EBX, T0); 3569 } 3570 } else { 3571 asm.emitMOV_Reg_Abs(EBX, Magic.getTocPointer().plus(Entrypoints.edgeCountersField.getOffset())); 3572 asm.emitMOV_Reg_RegDisp(EBX, EBX, getEdgeCounterOffset()); 3573 } 3574 } 3575 3576 if (method.isSynchronized()) genMonitorEnter(); 3577 3578 genThreadSwitchTest(RVMThread.PROLOGUE); 3579 } 3580 } 3581 3582 /** 3583 * Emit deferred prologue 3584 */ 3585 @Override 3586 protected void emit_deferred_prologue() { 3587 3588 if (VM.VerifyAssertions) VM._assert(method.isForOsrSpecialization()); 3589 3590 if (isInterruptible) { 3591 Offset offset = Entrypoints.stackLimitField.getOffset(); 3592 if (VM.BuildFor32Addr) { 3593 // S0<-limit 3594 asm.emitMOV_Reg_RegDisp(S0, THREAD_REGISTER, offset); 3595 asm.emitSUB_Reg_Reg(S0, SP); 3596 asm.emitADD_Reg_Imm(S0, method.getOperandWords() << LG_WORDSIZE); 3597 } else { 3598 // S0<-limit 3599 asm.emitMOV_Reg_RegDisp_Quad(S0, THREAD_REGISTER, offset); 3600 asm.emitSUB_Reg_Reg_Quad(S0, SP); 3601 asm.emitADD_Reg_Imm_Quad(S0, method.getOperandWords() << LG_WORDSIZE); 3602 } 3603 asm.emitBranchLikelyNextInstruction(); 3604 ForwardReference fr = asm.forwardJcc(LT); // Jmp around trap 3605 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_STACK_OVERFLOW + RVM_TRAP_BASE); // trap 3606 fr.resolve(asm); 3607 } else { 3608 // TODO!! make sure stackframe of uninterruptible method doesn't overflow 3609 } 3610 3611 /* never do monitor enter for synced method since the specialized 3612 * code starts after original monitor enter. 3613 */ 3614 3615 genThreadSwitchTest(RVMThread.PROLOGUE); 3616 } 3617 3618 /** 3619 * Generate method epilogue, releasing values from stack and returning 3620 * @param returnSize the size in bytes of the returned value 3621 * @param bytesPopped number of paramter bytes already released 3622 */ 3623 private void genEpilogue(int returnSize, int bytesPopped) { 3624 if (klass.hasBridgeFromNativeAnnotation()) { 3625 // pop locals and parameters, get to saved GPR's 3626 adjustStack((method.getLocalWords() << LG_WORDSIZE) + (returnSize - bytesPopped), true); 3627 JNICompiler.generateEpilogForJNIMethod(asm, this.method); 3628 } else if (klass.hasDynamicBridgeAnnotation()) { 3629 // we never return from a DynamicBridge frame 3630 asm.emitINT_Imm(0xFF); 3631 } else { 3632 // normal method 3633 if (method.hasBaselineSaveLSRegistersAnnotation()) { 3634 // There is one more word out of the total that is for callee-saves, hense 4 * WORDSIZE here rather than 3 * WORDSIZE below. 3635 int spaceToRelease = fp2spOffset(NO_SLOT).toInt() - bytesPopped - (4 * WORDSIZE); 3636 adjustStack(spaceToRelease, true); 3637 if (VM.VerifyAssertions) VM._assert(EBP_SAVE_OFFSET.toInt() == -(4 * WORDSIZE)); 3638 asm.emitPOP_Reg(EBP); // restore nonvolatile EBP register 3639 } else { 3640 int spaceToRelease = fp2spOffset(NO_SLOT).toInt() - bytesPopped - (3 * WORDSIZE); 3641 adjustStack(spaceToRelease, true); 3642 } 3643 if (VM.VerifyAssertions) VM._assert(EBX_SAVE_OFFSET.toInt() == -(3 * WORDSIZE)); 3644 asm.emitPOP_Reg(EBX); // restore non-volatile EBX register 3645 if (VM.VerifyAssertions) VM._assert(EDI_SAVE_OFFSET.toInt() == -(2 * WORDSIZE)); 3646 asm.emitPOP_Reg(EDI); // restore non-volatile EDI register 3647 asm.emitPOP_Reg(ECX); // throw away CMID 3648 // SP == frame pointer 3649 asm.emitPOP_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset()); // discard frame 3650 // return to caller, pop parameters from stack 3651 if (parameterWords == 0) { 3652 asm.emitRET(); 3653 } else { 3654 asm.emitRET_Imm(parameterWords << LG_WORDSIZE); 3655 } 3656 } 3657 } 3658 3659 /** 3660 * Generate instructions to acquire lock on entry to a method 3661 */ 3662 private void genMonitorEnter() { 3663 try { 3664 if (method.isStatic()) { 3665 Offset klassOffset = Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(klass.getClassForType())); 3666 // push java.lang.Class object for klass 3667 asm.generateJTOCpush(klassOffset); 3668 } else { 3669 // push "this" object 3670 asm.emitPUSH_RegDisp(ESP, localOffset(0)); 3671 } 3672 // pass 1 parameter 3673 genParameterRegisterLoad(asm, 1); 3674 asm.generateJTOCcall(Entrypoints.lockMethod.getOffset()); 3675 // after this instruction, the method has the monitor 3676 lockOffset = asm.getMachineCodeIndex(); 3677 } catch (UnreachableBytecodeException e) { 3678 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 3679 } 3680 } 3681 3682 /** 3683 * Generate instructions to release lock on exit from a method 3684 */ 3685 private void genMonitorExit() { 3686 try { 3687 if (method.isStatic()) { 3688 Offset klassOffset = Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(klass.getClassForType())); 3689 // push java.lang.Class object for klass 3690 asm.generateJTOCpush(klassOffset); 3691 } else { 3692 asm.emitPUSH_RegDisp(ESP, localOffset(0)); // push "this" object 3693 } 3694 genParameterRegisterLoad(asm, 1); // pass 1 parameter 3695 asm.generateJTOCcall(Entrypoints.unlockMethod.getOffset()); 3696 } catch (UnreachableBytecodeException e) { 3697 asm.emitINT_Imm(TRAP_UNREACHABLE_BYTECODE + RVM_TRAP_BASE); 3698 } 3699 } 3700 3701 /** 3702 * Generate an explicit null check (compare to zero). 3703 * 3704 * @param asm the assembler to generate into 3705 * @param objRefReg the register containing the reference 3706 */ 3707 @Inline 3708 private static void genNullCheck(Assembler asm, GPR objRefReg) { 3709 // compare to zero 3710 asm.emitTEST_Reg_Reg(objRefReg, objRefReg); 3711 // Jmp around trap if index is OK 3712 asm.emitBranchLikelyNextInstruction(); 3713 ForwardReference fr = asm.forwardJcc(NE); 3714 // trap 3715 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_NULL_POINTER + RVM_TRAP_BASE); 3716 fr.resolve(asm); 3717 } 3718 3719 /** 3720 * Generate an array bounds check trapping if the array bound check fails, 3721 * otherwise falling through. 3722 * @param asm the assembler to generate into 3723 * @param indexReg the register containing the index 3724 * @param arrayRefReg the register containing the array reference 3725 */ 3726 @Inline(value = Inline.When.ArgumentsAreConstant, arguments = {1,2}) 3727 static void genBoundsCheck(Assembler asm, GPR indexReg, GPR arrayRefReg) { 3728 // compare index to array length 3729 if (ARRAY_LENGTH_BYTES == 4) { 3730 asm.emitCMP_RegDisp_Reg(arrayRefReg, ObjectModel.getArrayLengthOffset(), indexReg); 3731 } else { 3732 asm.emitCMP_RegDisp_Reg_Quad(arrayRefReg, ObjectModel.getArrayLengthOffset(), indexReg); 3733 } 3734 // Jmp around trap if index is OK 3735 asm.emitBranchLikelyNextInstruction(); 3736 ForwardReference fr = asm.forwardJcc(LGT); 3737 // "pass" index param to C trap handler 3738 asm.emitMOV_RegDisp_Reg(THREAD_REGISTER, ArchEntrypoints.arrayIndexTrapParamField.getOffset(), indexReg); 3739 // trap 3740 asm.emitINT_Imm(RuntimeEntrypoints.TRAP_ARRAY_BOUNDS + RVM_TRAP_BASE); 3741 fr.resolve(asm); 3742 } 3743 3744 /** 3745 * Emits a conditional branch on the given condition and bytecode target. 3746 * The caller has just emitted the instruction sequence to set the condition codes. 3747 * 3748 * @param cond condition byte 3749 * @param bTarget target bytecode index 3750 */ 3751 private void genCondBranch(byte cond, int bTarget) { 3752 int mTarget = bytecodeMap[bTarget]; 3753 if (!VM.runningTool && ((BaselineCompiledMethod) compiledMethod).hasCounterArray()) { 3754 // Allocate two counters: taken and not taken 3755 int entry = edgeCounterIdx; 3756 edgeCounterIdx += 2; 3757 3758 // Flip conditions so we can jump over the increment of the taken counter. 3759 ForwardReference notTaken = asm.forwardJcc(asm.flipCode(cond)); 3760 3761 // Increment taken counter & jump to target 3762 incEdgeCounter(T1, null, entry + EdgeCounts.TAKEN); 3763 asm.emitJMP_ImmOrLabel(mTarget, bTarget); 3764 3765 // Increment not taken counter 3766 notTaken.resolve(asm); 3767 incEdgeCounter(T1, null, entry + EdgeCounts.NOT_TAKEN); 3768 } else { 3769 asm.emitJCC_Cond_ImmOrLabel(cond, mTarget, bTarget); 3770 } 3771 } 3772 3773 /** 3774 * Generate code to increment edge counter 3775 * @param scratch register to use as scratch 3776 * @param idx optional register holding index value or null 3777 * @param counterIdx index in to counters array 3778 */ 3779 @Inline(value = Inline.When.ArgumentsAreConstant, arguments = {1,2}) 3780 private void incEdgeCounter(GPR scratch, GPR idx, int counterIdx) { 3781 if (VM.VerifyAssertions) VM._assert(((BaselineCompiledMethod) compiledMethod).hasCounterArray()); 3782 if (idx == null) { 3783 asm.emitMOV_Reg_RegDisp(scratch, EBX, Offset.fromIntZeroExtend(counterIdx << LOG_BYTES_IN_INT)); 3784 } else { 3785 asm.emitMOV_Reg_RegIdx(scratch, EBX, idx, WORD, Offset.fromIntZeroExtend(counterIdx << LOG_BYTES_IN_INT)); 3786 } 3787 asm.emitADD_Reg_Imm(scratch, 1); 3788 // Add 1 to scratch, if the add overflows subtract 1 (the carry flag). 3789 // Add saturates at 0xFFFFFFFF 3790 asm.emitSBB_Reg_Imm(scratch, 0); 3791 if (idx == null) { 3792 asm.emitMOV_RegDisp_Reg(EBX, Offset.fromIntSignExtend(counterIdx << LOG_BYTES_IN_INT), scratch); 3793 } else { 3794 asm.emitMOV_RegIdx_Reg(EBX, idx, WORD, Offset.fromIntSignExtend(counterIdx << LOG_BYTES_IN_INT), scratch); 3795 } 3796 } 3797 3798 /** 3799 * Copy parameters from operand stack into registers. 3800 * Assumption: parameters are laid out on the stack in order 3801 * with SP pointing to the last parameter. 3802 * Also, this method is called before the generation of a "helper" method call. 3803 * Assumption: no floating-point parameters. 3804 * @param asm assembler to use for generation 3805 * @param params number of parameter words (including "this" if any). 3806 */ 3807 static void genParameterRegisterLoad(Assembler asm, int params) { 3808 if (VM.VerifyAssertions) VM._assert(0 < params); 3809 if (0 < NUM_PARAMETER_GPRS) { 3810 stackMoveHelper(asm, T0, Offset.fromIntZeroExtend((params - 1) << LG_WORDSIZE)); 3811 } 3812 if (1 < params && 1 < NUM_PARAMETER_GPRS) { 3813 stackMoveHelper(asm, T1, Offset.fromIntZeroExtend((params - 2) << LG_WORDSIZE)); 3814 } 3815 } 3816 3817 /** 3818 * Copy parameters from operand stack into registers. 3819 * Assumption: parameters are layed out on the stack in order 3820 * with SP pointing to the last parameter. 3821 * Also, this method is called before the generation of an explicit method call. 3822 * @param method is the method to be called. 3823 * @param hasThisParam is the method virtual? 3824 */ 3825 protected void genParameterRegisterLoad(MethodReference method, boolean hasThisParam) { 3826 int max = NUM_PARAMETER_GPRS + NUM_PARAMETER_FPRS; 3827 if (max == 0) return; // quit looking when all registers are full 3828 int gpr = 0; // number of general purpose registers filled 3829 int fpr = 0; // number of floating point registers filled 3830 GPR T = T0; // next GPR to get a parameter 3831 int params = method.getParameterWords() + (hasThisParam ? 1 : 0); 3832 Offset offset = Offset.fromIntSignExtend((params - 1) << LG_WORDSIZE); // stack offset of first parameter word 3833 if (hasThisParam) { 3834 if (gpr < NUM_PARAMETER_GPRS) { 3835 stackMoveHelper(T, offset); 3836 T = T1; // at most 2 parameters can be passed in general purpose registers 3837 gpr++; 3838 max--; 3839 } 3840 offset = offset.minus(WORDSIZE); 3841 } 3842 for (TypeReference type : method.getParameterTypes()) { 3843 if (max == 0) return; // quit looking when all registers are full 3844 TypeReference t = type; 3845 if (t.isLongType()) { 3846 if (gpr < NUM_PARAMETER_GPRS) { 3847 if (WORDSIZE == 4) { 3848 stackMoveHelper(T, offset); // lo register := hi mem (== hi order word) 3849 T = T1; // at most 2 parameters can be passed in general purpose registers 3850 gpr++; 3851 max--; 3852 if (gpr < NUM_PARAMETER_GPRS) { 3853 stackMoveHelper(T, offset.minus(WORDSIZE)); // hi register := lo mem (== lo order word) 3854 gpr++; 3855 max--; 3856 } 3857 } else { 3858 // initially offset will point at junk word, move down and over 3859 stackMoveHelper(T, offset.minus(WORDSIZE)); 3860 T = T1; // at most 2 parameters can be passed in general purpose registers 3861 gpr++; 3862 max--; 3863 } 3864 } 3865 offset = offset.minus(2 * WORDSIZE); 3866 } else if (t.isFloatType()) { 3867 if (fpr < NUM_PARAMETER_FPRS) { 3868 if (SSE2_FULL) { 3869 asm.emitMOVSS_Reg_RegDisp(XMM.lookup(fpr), SP, offset); 3870 } else { 3871 asm.emitFLD_Reg_RegDisp(FP0, SP, offset); 3872 } 3873 fpr++; 3874 max--; 3875 } 3876 offset = offset.minus(WORDSIZE); 3877 } else if (t.isDoubleType()) { 3878 if (fpr < NUM_PARAMETER_FPRS) { 3879 if (SSE2_FULL) { 3880 asm.emitMOVSD_Reg_RegDisp(XMM.lookup(fpr), SP, offset.minus(WORDSIZE)); 3881 } else { 3882 asm.emitFLD_Reg_RegDisp_Quad(FP0, SP, offset.minus(WORDSIZE)); 3883 } 3884 fpr++; 3885 max--; 3886 } 3887 offset = offset.minus(2 * WORDSIZE); 3888 } else if (t.isReferenceType() || t.isWordLikeType()) { 3889 if (gpr < NUM_PARAMETER_GPRS) { 3890 stackMoveHelper(T, offset); 3891 T = T1; // at most 2 parameters can be passed in general purpose registers 3892 gpr++; 3893 max--; 3894 } 3895 offset = offset.minus(WORDSIZE); 3896 } else { // t is object, int, short, char, byte, or boolean 3897 if (gpr < NUM_PARAMETER_GPRS) { 3898 if (offset.isZero()) { 3899 asm.emitMOV_Reg_RegInd(T, SP); 3900 } else { 3901 asm.emitMOV_Reg_RegDisp(T, SP, offset); 3902 } 3903 T = T1; // at most 2 parameters can be passed in general purpose registers 3904 gpr++; 3905 max--; 3906 } 3907 offset = offset.minus(WORDSIZE); 3908 } 3909 } 3910 if (VM.VerifyAssertions) VM._assert(offset.EQ(Offset.fromIntSignExtend(-WORDSIZE))); 3911 } 3912 3913 /** 3914 * Stores parameters into local space of the callee's stackframe. 3915 * <p> 3916 * Assumption: although some parameters may be passed in registers, 3917 * space for all parameters is laid out in order on the caller's stackframe. 3918 * 3919 * @param srcOffset offset from frame pointer of first parameter in caller's stackframe. 3920 */ 3921 private void genParameterCopy(Offset srcOffset) { 3922 int gpr = 0; // number of general purpose registers unloaded 3923 int fpr = 0; // number of floating point registers unloaded 3924 GPR T = T0; // next GPR to get a parameter 3925 int dstOffset = 0; // offset from the bottom of the locals for the current parameter 3926 if (!method.isStatic()) { // handle "this" parameter 3927 if (gpr < NUM_PARAMETER_GPRS) { 3928 asm.emitPUSH_Reg(T); 3929 T = T1; // at most 2 parameters can be passed in general purpose registers 3930 gpr++; 3931 } else { // no parameters passed in registers 3932 asm.emitPUSH_RegDisp(SP, srcOffset); 3933 } 3934 dstOffset -= WORDSIZE; 3935 } 3936 int[] fprOffset = new int[NUM_PARAMETER_FPRS]; // to handle floating point parameters in registers 3937 boolean[] is32bit = new boolean[NUM_PARAMETER_FPRS]; // to handle floating point parameters in registers 3938 int spIsOffBy = 0; // in the case of doubles and floats SP may drift from the expected value as we don't use push/pop 3939 for (TypeReference t : method.getParameterTypes()) { 3940 if (t.isLongType()) { 3941 if (spIsOffBy != 0) { 3942 // fix up SP if it drifted 3943 adjustStack(-spIsOffBy, true); 3944 spIsOffBy = 0; 3945 } 3946 if (gpr < NUM_PARAMETER_GPRS) { 3947 if (VM.BuildFor32Addr) { 3948 asm.emitPUSH_Reg(T); // hi mem := lo register (== hi order word) 3949 T = T1; // at most 2 parameters can be passed in general purpose registers 3950 gpr++; 3951 if (gpr < NUM_PARAMETER_GPRS) { 3952 asm.emitPUSH_Reg(T); // lo mem := hi register (== lo order word) 3953 gpr++; 3954 } else { 3955 asm.emitPUSH_RegDisp(SP, srcOffset); // lo mem from caller's stackframe 3956 } 3957 } else { 3958 adjustStack(-WORDSIZE, true); // create empty slot 3959 asm.emitPUSH_Reg(T); // push long 3960 T = T1; // at most 2 parameters can be passed in general purpose registers 3961 gpr++; 3962 } 3963 } else { 3964 if (VM.BuildFor32Addr) { 3965 asm.emitPUSH_RegDisp(SP, srcOffset); // hi mem from caller's stackframe 3966 asm.emitPUSH_RegDisp(SP, srcOffset); // lo mem from caller's stackframe 3967 } else { 3968 adjustStack(-WORDSIZE, true); // create empty slot 3969 asm.emitPUSH_RegDisp(SP, srcOffset); // push long 3970 } 3971 } 3972 dstOffset -= 2 * WORDSIZE; 3973 } else if (t.isFloatType()) { 3974 if (fpr < NUM_PARAMETER_FPRS) { 3975 spIsOffBy += WORDSIZE; 3976 fprOffset[fpr] = dstOffset; 3977 is32bit[fpr] = true; 3978 fpr++; 3979 } else { 3980 if (spIsOffBy != 0) { 3981 // fix up SP if it drifted 3982 adjustStack(-spIsOffBy, true); 3983 spIsOffBy = 0; 3984 } 3985 asm.emitPUSH_RegDisp(SP, srcOffset); 3986 } 3987 dstOffset -= WORDSIZE; 3988 } else if (t.isDoubleType()) { 3989 if (fpr < NUM_PARAMETER_FPRS) { 3990 spIsOffBy += 2 * WORDSIZE; 3991 dstOffset -= WORDSIZE; 3992 fprOffset[fpr] = dstOffset; 3993 dstOffset -= WORDSIZE; 3994 is32bit[fpr] = false; 3995 fpr++; 3996 } else { 3997 if (spIsOffBy != 0) { 3998 // fix up SP if it drifted 3999 adjustStack(-spIsOffBy, true); 4000 spIsOffBy = 0; 4001 } 4002 if (VM.BuildFor32Addr) { 4003 asm.emitPUSH_RegDisp(SP, srcOffset); // hi mem from caller's stackframe 4004 asm.emitPUSH_RegDisp(SP, srcOffset); // lo mem from caller's stackframe 4005 } else { 4006 adjustStack(-WORDSIZE, true); // create empty slot 4007 asm.emitPUSH_RegDisp(SP, srcOffset); // push double 4008 } 4009 dstOffset -= 2 * WORDSIZE; 4010 } 4011 } else { // t is object, int, short, char, byte, or boolean 4012 if (spIsOffBy != 0) { 4013 // fix up SP if it drifted 4014 adjustStack(-spIsOffBy, true); 4015 spIsOffBy = 0; 4016 } 4017 if (gpr < NUM_PARAMETER_GPRS) { 4018 asm.emitPUSH_Reg(T); 4019 T = T1; // at most 2 parameters can be passed in general purpose registers 4020 gpr++; 4021 } else { 4022 asm.emitPUSH_RegDisp(SP, srcOffset); 4023 } 4024 dstOffset -= WORDSIZE; 4025 } 4026 } 4027 if (spIsOffBy != 0) { 4028 // fix up SP if it drifted 4029 adjustStack(-spIsOffBy, true); 4030 } 4031 for (int i = fpr - 1; 0 <= i; i--) { // unload the floating point register stack (backwards) 4032 if (is32bit[i]) { 4033 if (SSE2_BASE) { 4034 asm.emitMOVSS_RegDisp_Reg(SP, Offset.fromIntSignExtend(fprOffset[i] - dstOffset - WORDSIZE), XMM.lookup(i)); 4035 } else { 4036 asm.emitFSTP_RegDisp_Reg(SP, Offset.fromIntSignExtend(fprOffset[i] - dstOffset - WORDSIZE), FP0); 4037 } 4038 } else { 4039 if (SSE2_BASE) { 4040 asm.emitMOVSD_RegDisp_Reg(SP, Offset.fromIntSignExtend(fprOffset[i] - dstOffset - WORDSIZE), XMM.lookup(i)); 4041 } else { 4042 asm.emitFSTP_RegDisp_Reg_Quad(SP, Offset.fromIntSignExtend(fprOffset[i] - dstOffset - WORDSIZE), FP0); 4043 } 4044 } 4045 } 4046 } 4047 4048 /** 4049 * Pushes return value of method from register to operand stack. 4050 * 4051 * @param m the method whose return value is to be pushed 4052 */ 4053 private void genResultRegisterUnload(MethodReference m) { 4054 TypeReference t = m.getReturnType(); 4055 4056 if (t.isVoidType()) { 4057 // nothing to do 4058 } else if (t.isLongType()) { 4059 if (VM.BuildFor32Addr) { 4060 asm.emitPUSH_Reg(T0); // high half 4061 asm.emitPUSH_Reg(T1); // low half 4062 } else { 4063 adjustStack(-WORDSIZE, true); 4064 asm.emitPUSH_Reg(T0); // long value 4065 } 4066 } else if (t.isFloatType()) { 4067 adjustStack(-WORDSIZE, true); 4068 if (SSE2_FULL) { 4069 asm.emitMOVSS_RegInd_Reg(SP, XMM0); 4070 } else { 4071 asm.emitFSTP_RegInd_Reg(SP, FP0); 4072 } 4073 } else if (t.isDoubleType()) { 4074 adjustStack(-2 * WORDSIZE, true); 4075 if (SSE2_FULL) { 4076 asm.emitMOVSD_RegInd_Reg(SP, XMM0); 4077 } else { 4078 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); 4079 } 4080 } else { // t is object, int, short, char, byte, or boolean 4081 asm.emitPUSH_Reg(T0); 4082 } 4083 } 4084 4085 /** 4086 * @param whereFrom is this thread switch from a PROLOGUE, BACKEDGE, or EPILOGUE? 4087 */ 4088 private void genThreadSwitchTest(int whereFrom) { 4089 if (!isInterruptible) { 4090 return; 4091 } 4092 // thread switch requested ?? 4093 asm.emitCMP_RegDisp_Imm(THREAD_REGISTER, Entrypoints.takeYieldpointField.getOffset(), 0); 4094 ForwardReference fr1; 4095 Offset yieldOffset; 4096 if (whereFrom == RVMThread.PROLOGUE) { 4097 // Take yieldpoint if yieldpoint flag is non-zero (either 1 or -1) 4098 fr1 = asm.forwardJcc(EQ); 4099 yieldOffset = Entrypoints.yieldpointFromPrologueMethod.getOffset(); 4100 } else if (whereFrom == RVMThread.BACKEDGE) { 4101 // Take yieldpoint if yieldpoint flag is >0 4102 fr1 = asm.forwardJcc(LE); 4103 yieldOffset = Entrypoints.yieldpointFromBackedgeMethod.getOffset(); 4104 } else { // EPILOGUE 4105 // Take yieldpoint if yieldpoint flag is non-zero (either 1 or -1) 4106 fr1 = asm.forwardJcc(EQ); 4107 yieldOffset = Entrypoints.yieldpointFromEpilogueMethod.getOffset(); 4108 } 4109 asm.generateJTOCcall(yieldOffset); 4110 fr1.resolve(asm); 4111 4112 if (VM.BuildForAdaptiveSystem && options.INVOCATION_COUNTERS) { 4113 int id = compiledMethod.getId(); 4114 InvocationCounts.allocateCounter(id); 4115 asm.emitMOV_Reg_Abs(ECX, Magic.getTocPointer().plus(AosEntrypoints.invocationCountsField.getOffset())); 4116 asm.emitSUB_RegDisp_Imm(ECX, Offset.fromIntZeroExtend(compiledMethod.getId() << 2), 1); 4117 ForwardReference notTaken = asm.forwardJcc(GT); 4118 asm.emitPUSH_Imm(id); 4119 genParameterRegisterLoad(asm, 1); 4120 asm.generateJTOCcall(AosEntrypoints.invocationCounterTrippedMethod.getOffset()); 4121 notTaken.resolve(asm); 4122 } 4123 } 4124 4125 /** 4126 * Generate magic method 4127 * @param m method to generate 4128 * @return true if magic method was generated 4129 */ 4130 private boolean genMagic(MethodReference m) { 4131 if (BaselineMagic.generateMagic(asm, m, method, fp2spOffset(NO_SLOT))) { 4132 return true; 4133 } else if (m.isSysCall()) { 4134 TypeReference[] args = m.getParameterTypes(); 4135 TypeReference rtype = m.getReturnType(); 4136 Offset offsetToLastArg = THREE_SLOTS; // the three regs saved in (1) 4137 Offset offsetToFirstArg = offsetToLastArg.plus((m.getParameterWords() - 1) << LG_WORDSIZE); 4138 boolean[] inRegister = VM.BuildFor32Addr ? null : new boolean[args.length]; 4139 int paramBytes = 0; 4140 4141 // (1) save three RVM nonvolatile/special registers 4142 // we don't have to save EBP: the callee will 4143 // treat it as a framepointer and save/restore 4144 // it for us. 4145 asm.emitPUSH_Reg(EBX); 4146 asm.emitPUSH_Reg(ESI); 4147 asm.emitPUSH_Reg(EDI); 4148 4149 // (2) Pass args in registers passing from left-to-right 4150 // (NB avoid the first argument holding the target function address) 4151 int gpRegistersInUse = 0; 4152 int fpRegistersInUse = 0; 4153 Offset offsetToJavaArg = offsetToFirstArg; 4154 if (VM.BuildFor64Addr) { 4155 for (int i = 1; i < args.length; i++) { 4156 TypeReference arg = args[i]; 4157 if (arg.isFloatType()) { 4158 if (fpRegistersInUse < NATIVE_PARAMETER_FPRS.length) { 4159 inRegister[i] = true; 4160 offsetToJavaArg = offsetToJavaArg.minus(WORDSIZE); 4161 asm.emitMOVSS_Reg_RegDisp((XMM)NATIVE_PARAMETER_FPRS[fpRegistersInUse], SP, offsetToJavaArg); 4162 fpRegistersInUse++; 4163 } 4164 } else if (arg.isDoubleType()) { 4165 if (fpRegistersInUse < NATIVE_PARAMETER_FPRS.length) { 4166 inRegister[i] = true; 4167 offsetToJavaArg = offsetToJavaArg.minus(2 * WORDSIZE); 4168 asm.emitMOVSD_Reg_RegDisp((XMM)NATIVE_PARAMETER_FPRS[fpRegistersInUse], SP, offsetToJavaArg); 4169 fpRegistersInUse++; 4170 } 4171 } else if (arg.isLongType()) { 4172 if (gpRegistersInUse < NATIVE_PARAMETER_GPRS.length) { 4173 inRegister[i] = true; 4174 offsetToJavaArg = offsetToJavaArg.minus(2 * WORDSIZE); 4175 asm.emitMOV_Reg_RegDisp_Quad(NATIVE_PARAMETER_GPRS[gpRegistersInUse], SP, offsetToJavaArg); 4176 gpRegistersInUse++; 4177 } 4178 } else if (arg.isWordLikeType() || arg.isReferenceType()) { 4179 if (gpRegistersInUse < NATIVE_PARAMETER_GPRS.length) { 4180 inRegister[i] = true; 4181 offsetToJavaArg = offsetToJavaArg.minus(WORDSIZE); 4182 asm.emitMOV_Reg_RegDisp_Quad(NATIVE_PARAMETER_GPRS[gpRegistersInUse], SP, offsetToJavaArg); 4183 gpRegistersInUse++; 4184 } 4185 } else { 4186 if (gpRegistersInUse < NATIVE_PARAMETER_GPRS.length) { 4187 inRegister[i] = true; 4188 offsetToJavaArg = offsetToJavaArg.minus(WORDSIZE); 4189 asm.emitMOV_Reg_RegDisp(NATIVE_PARAMETER_GPRS[gpRegistersInUse], SP, offsetToJavaArg); 4190 gpRegistersInUse++; 4191 } 4192 } 4193 } 4194 } 4195 4196 // (3) Stack alignment 4197 ForwardReference dontRealignStack = null; 4198 int argsToPush = 0; 4199 if (VM.BuildFor64Addr) { 4200 for (int i = args.length - 1; i >= 1; i--) { 4201 if (!inRegister[i]) { 4202 TypeReference arg = args[i]; 4203 if (arg.isLongType() || arg.isDoubleType()) { 4204 argsToPush += 2; 4205 } else { 4206 argsToPush ++; 4207 } 4208 } 4209 } 4210 asm.emitTEST_Reg_Imm(SP, 0x8); 4211 if ((argsToPush & 1) != 0) { 4212 dontRealignStack = asm.forwardJcc(NE); 4213 } else { 4214 dontRealignStack = asm.forwardJcc(EQ); 4215 } 4216 } 4217 4218 // Generate argument pushing and call code upto twice, once with realignment 4219 ForwardReference afterCalls = null; 4220 for (int j = VM.BuildFor32Addr ? 1 : 0; j < 2; j++) { 4221 if (j == 0) { 4222 adjustStack(-WORDSIZE, true); 4223 offsetToFirstArg = offsetToFirstArg.plus(WORDSIZE); 4224 offsetToLastArg = offsetToLastArg.plus(WORDSIZE); 4225 } else { 4226 if (dontRealignStack != null) dontRealignStack.resolve(asm); 4227 } 4228 // (4) Stack remaining args to target function from right-to-left 4229 // (NB avoid the first argument holding the target function address) 4230 offsetToJavaArg = offsetToLastArg; 4231 for (int i = args.length - 1; i >= 1; i--) { 4232 TypeReference arg = args[i]; 4233 if (VM.BuildFor32Addr) { 4234 if (arg.isLongType() || arg.isDoubleType()) { 4235 asm.emitPUSH_RegDisp(SP, offsetToJavaArg.plus(WORDSIZE)); 4236 asm.emitPUSH_RegDisp(SP, offsetToJavaArg.plus(WORDSIZE)); 4237 offsetToJavaArg = offsetToJavaArg.plus(4 * WORDSIZE); 4238 offsetToFirstArg = offsetToFirstArg.plus(2 * WORDSIZE); 4239 offsetToLastArg = offsetToLastArg.plus(2 * WORDSIZE); 4240 paramBytes += 2 * WORDSIZE; 4241 } else { 4242 asm.emitPUSH_RegDisp(SP, offsetToJavaArg); 4243 offsetToJavaArg = offsetToJavaArg.plus(2 * WORDSIZE); 4244 offsetToFirstArg = offsetToFirstArg.plus(WORDSIZE); 4245 offsetToLastArg = offsetToLastArg.plus(WORDSIZE); 4246 paramBytes += WORDSIZE; 4247 } 4248 } else { 4249 if (!inRegister[i]) { 4250 if (arg.isLongType() || arg.isDoubleType()) { 4251 adjustStack(-WORDSIZE, true); 4252 asm.emitPUSH_RegDisp(SP, offsetToJavaArg.plus(WORDSIZE)); 4253 offsetToJavaArg = offsetToJavaArg.plus(4 * WORDSIZE); 4254 offsetToFirstArg = offsetToFirstArg.plus(2 * WORDSIZE); 4255 offsetToLastArg = offsetToLastArg.plus(2 * WORDSIZE); 4256 paramBytes += 2 * WORDSIZE; 4257 } else { 4258 asm.emitPUSH_RegDisp(SP, offsetToJavaArg); 4259 offsetToJavaArg = offsetToJavaArg.plus(2 * WORDSIZE); 4260 offsetToFirstArg = offsetToFirstArg.plus(WORDSIZE); 4261 offsetToLastArg = offsetToLastArg.plus(WORDSIZE); 4262 paramBytes += WORDSIZE; 4263 } 4264 } else { 4265 if (arg.isLongType() || arg.isDoubleType()) { 4266 offsetToJavaArg = offsetToJavaArg.plus(2 * WORDSIZE); 4267 } else { 4268 offsetToJavaArg = offsetToJavaArg.plus(WORDSIZE); 4269 } 4270 } 4271 } 4272 } 4273 if (VM.VerifyAssertions) VM._assert(offsetToFirstArg.EQ(offsetToJavaArg)); 4274 4275 // (5) invoke target function with address given by the first argument 4276 if (VM.BuildFor32Addr) { 4277 asm.emitMOV_Reg_RegDisp(S0, SP, offsetToFirstArg); 4278 asm.emitCALL_Reg(S0); 4279 } else { 4280 asm.emitMOV_Reg_RegDisp_Quad(T0, SP, offsetToFirstArg); 4281 asm.emitCALL_Reg(T0); 4282 } 4283 4284 // (6) pop space for arguments 4285 if (j == 0) { 4286 offsetToFirstArg = offsetToFirstArg.minus(WORDSIZE); 4287 offsetToLastArg = offsetToLastArg.minus(WORDSIZE); 4288 adjustStack(paramBytes + WORDSIZE, true); 4289 afterCalls = asm.forwardJMP(); 4290 } else { 4291 adjustStack(paramBytes, true); 4292 } 4293 } 4294 4295 if (afterCalls != null) afterCalls.resolve(asm); 4296 4297 // (7) restore RVM registers 4298 asm.emitPOP_Reg(EDI); 4299 asm.emitPOP_Reg(ESI); 4300 asm.emitPOP_Reg(EBX); 4301 4302 // (8) pop expression stack (including the first parameter) 4303 adjustStack(m.getParameterWords() << LG_WORDSIZE, true); 4304 4305 // (9) push return value 4306 if (rtype.isLongType()) { 4307 if (VM.BuildFor32Addr) { 4308 asm.emitPUSH_Reg(T1); 4309 asm.emitPUSH_Reg(T0); 4310 } else { 4311 adjustStack(-WORDSIZE, true); 4312 asm.emitPUSH_Reg(T0); 4313 } 4314 } else if (rtype.isDoubleType()) { 4315 adjustStack(-2 * WORDSIZE, true); 4316 if (VM.BuildFor32Addr) { 4317 asm.emitFSTP_RegInd_Reg_Quad(SP, FP0); 4318 } else { 4319 asm.emitMOVSD_RegInd_Reg(SP, XMM0); 4320 } 4321 } else if (rtype.isFloatType()) { 4322 adjustStack(-WORDSIZE, true); 4323 if (VM.BuildFor32Addr) { 4324 asm.emitFSTP_RegInd_Reg(SP, FP0); 4325 } else { 4326 asm.emitMOVSS_RegInd_Reg(SP, XMM0); 4327 } 4328 } else if (!rtype.isVoidType()) { 4329 asm.emitPUSH_Reg(T0); 4330 } 4331 return true; 4332 } else { 4333 return false; 4334 } 4335 } 4336 4337 /** 4338 * @param local index of local 4339 * @return offset of Java local variable (off stack pointer) 4340 * assuming ESP is still positioned as it was at the 4341 * start of the current bytecode (biStart) 4342 * @throws UnreachableBytecodeException when the stack heights information for 4343 * the current bytecode is invalid. This can only happen when the bytecode is 4344 * unreachable. 4345 */ 4346 private Offset localOffset(int local) throws UnreachableBytecodeException { 4347 int stackHeight = stackHeights[biStart]; 4348 // Have we computed stack height information? 4349 if (stackHeight < TemplateCompilerFramework.stackHeightForEmptyBasicBlock(method)) { 4350 // If stack heights weren't computed, the bytecode must be unreachable. 4351 throw new UnreachableBytecodeException(); 4352 } 4353 if (VM.VerifyAssertions) VM._assert(method.getLocalWords() > local); 4354 return Offset.fromIntZeroExtend((stackHeights[biStart] - local) << LG_WORDSIZE); 4355 } 4356 4357 /** 4358 * Translates a FP offset into an SP offset 4359 * assuming ESP is still positioned as it was at the 4360 * start of the current bytecode (biStart). 4361 * 4362 * @param offset the FP offset 4363 * @return the SP offset 4364 */ 4365 private Offset fp2spOffset(Offset offset) { 4366 Offset offsetToFrameHead = Offset.fromIntSignExtend(stackHeights[biStart] << LG_WORDSIZE).minus(firstLocalOffset); 4367 return offset.plus(offsetToFrameHead); 4368 } 4369 4370 /** 4371 * Emit dynamic linking sequence placing the offset of the given member in reg 4372 * @param asm assembler to generate code into 4373 * @param reg register to hold offset to method 4374 * @param ref method reference to be resolved 4375 * @param couldBeZero could the value in the offsets table require resolving 4376 */ 4377 static void emitDynamicLinkingSequence(Assembler asm, GPR reg, MemberReference ref, boolean couldBeZero) { 4378 int memberId = ref.getId(); 4379 Offset memberOffset = Offset.fromIntZeroExtend(memberId << 2); 4380 Offset tableOffset = Entrypoints.memberOffsetsField.getOffset(); 4381 if (couldBeZero) { 4382 int retryLabel = asm.getMachineCodeIndex(); // branch here after dynamic class loading 4383 if (VM.BuildFor32Addr) { 4384 asm.emitMOV_Reg_Abs(reg, Magic.getTocPointer().plus(tableOffset)); // reg is offsets table 4385 asm.emitMOV_Reg_RegDisp(reg, reg, memberOffset); // reg is offset of member, or 0 if member's class isn't loaded 4386 } else { 4387 asm.generateJTOCloadLong(reg, tableOffset); // reg is offsets table 4388 asm.emitMOVSXDQ_Reg_RegDisp(reg, reg, memberOffset); // reg is offset of member, or 0 if member's class isn't loaded 4389 } 4390 if (NEEDS_DYNAMIC_LINK == 0) { 4391 asm.emitTEST_Reg_Reg(reg, reg); // reg ?= NEEDS_DYNAMIC_LINK, is field's class loaded? 4392 } else { 4393 asm.emitCMP_Reg_Imm(reg, NEEDS_DYNAMIC_LINK); // reg ?= NEEDS_DYNAMIC_LINK, is field's class loaded? 4394 } 4395 ForwardReference fr = asm.forwardJcc(NE); // if so, skip call instructions 4396 asm.emitPUSH_Imm(memberId); // pass member's dictId 4397 genParameterRegisterLoad(asm, 1); // pass 1 parameter word 4398 Offset resolverOffset = Entrypoints.resolveMemberMethod.getOffset(); 4399 asm.generateJTOCcall(resolverOffset); // does class loading as sideffect 4400 asm.emitJMP_Imm(retryLabel); // reload reg with valid value 4401 fr.resolve(asm); // come from Jcc above. 4402 } else { 4403 if (VM.BuildFor32Addr) { 4404 asm.emitMOV_Reg_Abs(reg, Magic.getTocPointer().plus(tableOffset)); // reg is offsets table 4405 } else { 4406 asm.generateJTOCloadLong(reg, tableOffset); // reg is offsets table 4407 } 4408 asm.emitMOV_Reg_RegDisp(reg, reg, memberOffset); // reg is offset of member 4409 } 4410 } 4411 4412 /** 4413 * OSR routine to emit code to invoke a compiled method (with known jtoc 4414 * offset). Treat it like a resolved invoke static, but take care of 4415 * this object in the case.<p> 4416 * 4417 * I have not thought about GCMaps for invoke_compiledmethod.<p> 4418 * TODO: Figure out what the above GCMaps comment means and fix it! 4419 */ 4420 @Override 4421 protected void emit_invoke_compiledmethod(CompiledMethod cm) { 4422 Offset methodOffset = cm.getOsrJTOCoffset(); 4423 boolean takeThis = !cm.method.isStatic(); 4424 MethodReference ref = cm.method.getMemberRef().asMethodReference(); 4425 genParameterRegisterLoad(ref, takeThis); 4426 asm.generateJTOCcall(methodOffset); 4427 genResultRegisterUnload(ref); 4428 } 4429 4430 /** 4431 * Implementation for OSR load return address bytecode 4432 */ 4433 @Override 4434 protected void emit_loadretaddrconst(int bcIndex) { 4435 asm.generateLoadReturnAddress(bcIndex); 4436 } 4437 4438 /** 4439 * Generate branch for pending goto OSR mechanism 4440 * @param bTarget is optional, it emits a JUMP instruction, but the caller 4441 * is responsible for patching the target address by calling the resolve method 4442 * of the returned forward reference. 4443 */ 4444 @Override 4445 protected ForwardReference emit_pending_goto(int bTarget) { 4446 return asm.generatePendingJMP(bTarget); 4447 } 4448} 4449