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