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