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