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