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