/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Common Public License (CPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/cpl1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.jikesrvm.compilers.baseline.ia32;

import org.jikesrvm.ArchitectureSpecific.Assembler;
import org.jikesrvm.ArchitectureSpecific.CodeArray;
import org.jikesrvm.ArchitectureSpecific.Registers;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.Atom;
import org.jikesrvm.classloader.MethodReference;
import org.jikesrvm.classloader.RVMArray;
import org.jikesrvm.classloader.RVMMethod;
import org.jikesrvm.classloader.RVMType;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.common.assembler.ForwardReference;
import org.jikesrvm.ia32.RegisterConstants.GPR;
import org.jikesrvm.jni.FunctionTable;
import org.jikesrvm.mm.mminterface.CollectorThread;
import org.jikesrvm.mm.mminterface.MemoryManager;
import org.jikesrvm.objectmodel.IMT;
import org.jikesrvm.objectmodel.JavaHeader;
import org.jikesrvm.objectmodel.ObjectModel;
import org.jikesrvm.objectmodel.TIB;
import org.jikesrvm.runtime.ArchEntrypoints;
import org.jikesrvm.runtime.EntrypointHelper;
import org.jikesrvm.runtime.Entrypoints;
import org.jikesrvm.runtime.Magic;
import org.jikesrvm.runtime.MagicNames;
import org.jikesrvm.scheduler.Processor;
import org.jikesrvm.scheduler.ProcessorTable;
import org.jikesrvm.scheduler.RVMThread;
import org.jikesrvm.scheduler.greenthreads.GreenProcessor;
import org.jikesrvm.util.ImmutableEntryHashMapRVM;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.AddressArray;
import org.vmmagic.unboxed.Extent;
import org.vmmagic.unboxed.ExtentArray;
import org.vmmagic.unboxed.ObjectReference;
import org.vmmagic.unboxed.ObjectReferenceArray;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.OffsetArray;
import org.vmmagic.unboxed.Word;
import org.vmmagic.unboxed.WordArray;
import org.vmmagic.pragma.Uninterruptible;

import static org.jikesrvm.ia32.ArchConstants.SSE2_BASE;
import static org.jikesrvm.ia32.ArchConstants.SSE2_FULL;
import static org.jikesrvm.ia32.BaselineConstants.LG_WORDSIZE;
import static org.jikesrvm.ia32.BaselineConstants.WORDSIZE;
import static org.jikesrvm.ia32.BaselineConstants.EAX;
import static org.jikesrvm.ia32.BaselineConstants.EBX;
import static org.jikesrvm.ia32.BaselineConstants.ECX;
import static org.jikesrvm.ia32.BaselineConstants.EDX;
import static org.jikesrvm.ia32.BaselineConstants.ESI;
import static org.jikesrvm.ia32.BaselineConstants.EDI;
import static org.jikesrvm.ia32.BaselineConstants.FP0;
import static org.jikesrvm.ia32.BaselineConstants.XMM0;
import static org.jikesrvm.ia32.BaselineConstants.XMM1;
import static org.jikesrvm.ia32.BaselineConstants.XMM2;
import static org.jikesrvm.ia32.BaselineConstants.XMM3;
import static org.jikesrvm.ia32.BaselineConstants.EBX_SAVE_OFFSET;
import static org.jikesrvm.ia32.BaselineConstants.EDI_SAVE_OFFSET;
import static org.jikesrvm.ia32.BaselineConstants.T0_SAVE_OFFSET;
import static org.jikesrvm.ia32.BaselineConstants.T1_SAVE_OFFSET;
import static org.jikesrvm.ia32.BaselineConstants.XMM_SAVE_OFFSET;
import static org.jikesrvm.ia32.BaselineConstants.FPU_SAVE_OFFSET;
import static org.jikesrvm.ia32.BaselineConstants.PR;
import static org.jikesrvm.ia32.BaselineConstants.S0;
import static org.jikesrvm.ia32.BaselineConstants.SP;
import static org.jikesrvm.ia32.BaselineConstants.T0;
import static org.jikesrvm.ia32.BaselineConstants.T1;
import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_FRAME_POINTER_OFFSET;
import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_METHOD_ID_OFFSET;
import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_RETURN_ADDRESS_OFFSET;
import static org.jikesrvm.compilers.baseline.ia32.BaselineCompilerImpl.NO_SLOT;
import static org.jikesrvm.compilers.baseline.ia32.BaselineCompilerImpl.ONE_SLOT;
import static org.jikesrvm.compilers.baseline.ia32.BaselineCompilerImpl.TWO_SLOTS;
import static org.jikesrvm.compilers.baseline.ia32.BaselineCompilerImpl.THREE_SLOTS;
import static org.jikesrvm.compilers.baseline.ia32.BaselineCompilerImpl.FOUR_SLOTS;
import static org.jikesrvm.compilers.baseline.ia32.BaselineCompilerImpl.FIVE_SLOTS;
import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_TYPE_INDEX;
import static org.jikesrvm.runtime.EntrypointHelper.getMethodReference;

/**
 * Create magic code
 */
final class BaselineMagic {
  /**
   * Map of method references to objects that will generate the necessary magic
   */
  private static final ImmutableEntryHashMapRVM<MethodReference,MagicGenerator> generators =
    new ImmutableEntryHashMapRVM<MethodReference,MagicGenerator>();

  /**
   * When casting or loading object references should the reference be checked
   * to see if it is an object reference first?
   */
  private static final boolean VALIDATE_OBJECT_REFERENCES = false;

  /**
   * If a bad reference is encountered should we halt the VM?
   */
  private static final boolean FAIL_ON_BAD_REFERENCES = true;

  /**
   * Entry point to generating magic
   * @param asm assembler to generate magic code into
   * @param m method reference
   * @param cm the method being compiled
   * @param sd the depth of the stack
   * @return true if magic was generated
   */
  static boolean generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
    MagicGenerator g = generators.get(m);
    if (g != null) {
      g.generateMagic(asm, m, cm, sd);
      return true;
    } else {
      return false;
    }
  }

  /**
   * Flag to avoid recursive calls to check
   */
  private static volatile boolean inCheck = false;
  /**
   * Method called to check an object reference is valid
   * @param value
   */
  @SuppressWarnings("unused")
  @Uninterruptible
  private static void check(ObjectReference value) {
    if (!inCheck) {
      inCheck = true;
      if (!MemoryManager.validRef(value) && FAIL_ON_BAD_REFERENCES) {
        VM.sysFail("Bad object reference encountered");
      }
      inCheck = false;
    }
  }

  /**
   * Reference of method that checks a reference
   */
  private static final MethodReference checkMR =
    EntrypointHelper.getMethodReference(BaselineMagic.class,
        Atom.findOrCreateUnicodeAtom("check"), ObjectReference.class, void.class);

  /**
   * Parent of all magic generating classes
   */
  private abstract static class MagicGenerator {
    abstract void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd);
  }

  /**
   * Add a reference check to a magic generator
   */
  private static final class EarlyReferenceCheckDecorator extends MagicGenerator {
    private final Offset offset;
    private final MagicGenerator generator;
    /**
     * Construct decorator that will add reference checks
     * @param offset on stack of reference to check
     * @param generator the magic generator being decorated
     */
    EarlyReferenceCheckDecorator(Offset offset, MagicGenerator generator) {
      this.offset = offset;
      this.generator = generator;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      Class<?> dc = cm.getDeclaringClass().getClassForType();
      if ((dc != JavaHeader.class) &&
          (dc != ObjectModel.class)
      ){
        if (checkMR.needsDynamicLink(cm)) {
          BaselineCompilerImpl.emitDynamicLinkingSequence(asm, S0, checkMR, true);
          if (offset.NE(NO_SLOT)) {
            asm.emitMOV_Reg_RegDisp(T0, SP, offset);
          } else {
            asm.emitMOV_Reg_RegInd(T0, SP);
          }
          asm.emitPUSH_Reg(T0);
          asm.emitCALL_RegDisp(S0, Magic.getTocPointer().toWord().toOffset());
        } else {
          if (offset.NE(NO_SLOT)) {
            asm.emitMOV_Reg_RegDisp(T0, SP, offset);
          } else {
            asm.emitMOV_Reg_RegInd(T0, SP);
          }
          asm.emitPUSH_Reg(T0);
          asm.emitCALL_Abs(Magic.getTocPointer().plus(checkMR.peekResolvedMethod().getOffset()));
        }
      }
      generator.generateMagic(asm, m, cm, sd);
    }
  }

  /**
   * Add a reference check to a magic generator
   */
  private static final class LateReferenceCheckDecorator extends MagicGenerator {
    private final Offset offset;
    private final MagicGenerator generator;
    /**
     * Construct decorator that will add reference checks
     * @param offset on stack of reference to check
     * @param generator the magic generator being decorated
     */
    LateReferenceCheckDecorator(Offset offset, MagicGenerator generator) {
      this.offset = offset;
      this.generator = generator;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      generator.generateMagic(asm, m, cm, sd);
      Class<?> dc = cm.getDeclaringClass().getClassForType();
      if ((dc != JavaHeader.class) &&
          (dc != ObjectModel.class)
      ){
        if (checkMR.needsDynamicLink(cm)) {
          BaselineCompilerImpl.emitDynamicLinkingSequence(asm, S0, checkMR, true);
          if (offset.NE(NO_SLOT)) {
            asm.emitMOV_Reg_RegDisp(T0, SP, offset);
          } else {
            asm.emitMOV_Reg_RegInd(T0, SP);
          }
          asm.emitPUSH_Reg(T0);
          asm.emitCALL_RegDisp(S0, Magic.getTocPointer().toWord().toOffset());
        } else {
          if (offset.NE(NO_SLOT)) {
            asm.emitMOV_Reg_RegDisp(T0, SP, offset);
          } else {
            asm.emitMOV_Reg_RegInd(T0, SP);
          }
          asm.emitPUSH_Reg(T0);
          asm.emitCALL_Abs(Magic.getTocPointer().plus(checkMR.peekResolvedMethod().getOffset()));
        }
      }
    }
  }

  /**
   * Load a 32bit quantity from an address
   */
  private static final class Load32 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // No offset
      asm.emitPOP_Reg(T0);                      // address
      asm.emitPUSH_RegInd(T0);                  // pushes [T0+0]
    }
  }
  static {
    MagicGenerator g = new Load32();
    generators.put(getMethodReference(Address.class, MagicNames.loadAddress, Address.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.prepareAddress, Address.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadWord, Word.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.prepareWord, Word.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadInt, int.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.prepareInt, int.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadFloat, float.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new LateReferenceCheckDecorator(NO_SLOT, g);
    }
    generators.put(getMethodReference(Address.class, MagicNames.prepareObjectReference, ObjectReference.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadObjectReference, ObjectReference.class), g);
  }

  /**
   * Load a 32bit quantity from an address and offset parameter
   */
  private static final class Load32_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Load at offset
      asm.emitPOP_Reg(S0);                  // offset
      asm.emitPOP_Reg(T0);                  // object ref
      asm.emitPUSH_RegIdx(T0, S0, Assembler.BYTE, NO_SLOT); // pushes [T0+S0]
    }
  }
  static {
    MagicGenerator g = new Load32_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.loadAddress, Offset.class, Address.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.prepareAddress, Offset.class, Address.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadWord, Offset.class, Word.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.prepareWord, Offset.class, Word.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadInt, Offset.class, int.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.prepareInt, Offset.class, int.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadFloat, Offset.class, float.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getIntAtOffset, Object.class, Offset.class, int.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getWordAtOffset, Object.class, Offset.class, Word.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.prepareInt, Object.class, Offset.class, int.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.prepareAddress, Object.class, Offset.class, Address.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.prepareWord, Object.class, Offset.class, Word.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new LateReferenceCheckDecorator(NO_SLOT, g);
    }
    generators.put(getMethodReference(Address.class, MagicNames.prepareObjectReference, Offset.class, ObjectReference.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadObjectReference, Offset.class, ObjectReference.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getObjectAtOffset, Object.class, Offset.class, Object.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getTIBAtOffset, Object.class, Offset.class, TIB.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.prepareObject, Object.class, Offset.class, Object.class), g);
  }

  /**
   * Load a 32bit quantity from an address and offset parameter
   */
  private static final class Magic_Load32_MD extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(S0);                  // discard meta-data
      // Load at offset
      asm.emitPOP_Reg(S0);                  // offset
      asm.emitPOP_Reg(T0);                  // object ref
      asm.emitPUSH_RegIdx(T0, S0, Assembler.BYTE, NO_SLOT); // pushes [T0+S0]
    }
  }
  static {
    MagicGenerator g = new Magic_Load32_MD();
    generators.put(getMethodReference(Magic.class, MagicNames.getWordAtOffset, Object.class, Offset.class, int.class, Word.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new LateReferenceCheckDecorator(NO_SLOT, g);
    }
    generators.put(getMethodReference(Magic.class, MagicNames.getObjectAtOffset, Object.class, Offset.class, int.class, Object.class), g);
  }

  /**
   * Load a byte from an address
   */
  private static final class LoadByte extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // No offset
      asm.emitPOP_Reg(T0);                  // base
      asm.emitMOVSX_Reg_RegInd_Byte(T0, T0);
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    // Load a byte
    MagicGenerator g = new LoadByte();
    generators.put(getMethodReference(Address.class, MagicNames.loadByte, byte.class), g);
  }

  /**
   * Load a byte from an address and offset parameter
   */
  private static final class LoadByte_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Load at offset
      asm.emitPOP_Reg(S0);                  // offset
      asm.emitPOP_Reg(T0);                  // base
      asm.emitMOVSX_Reg_RegIdx_Byte(T0, T0, S0, Assembler.BYTE, NO_SLOT); // load and sign extend byte [T0+S0]
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    MagicGenerator g = new LoadByte_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.loadByte, Offset.class, byte.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getByteAtOffset, Object.class, Offset.class, byte.class), g);
  }

  /**
   * Load an unsigned byte from an address and offset parameter
   */
  private static final class LoadUnsignedByte_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Load at offset
      asm.emitPOP_Reg(S0);                  // offset
      asm.emitPOP_Reg(T0);                  // base
      asm.emitMOVZX_Reg_RegIdx_Byte(T0, T0, S0, Assembler.BYTE, NO_SLOT); // load and sign extend byte [T0+S0]
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    MagicGenerator g = new LoadUnsignedByte_Offset();
    generators.put(getMethodReference(Magic.class, MagicNames.getUnsignedByteAtOffset, Object.class, Offset.class, byte.class), g);
  }

  /**
   * Load a short quantity from an address
   */
  private static final class LoadShort extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // No offset
      asm.emitPOP_Reg(T0);                  // base
      asm.emitMOVSX_Reg_RegInd_Word(T0, T0);
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    MagicGenerator g = new LoadShort();
    generators.put(getMethodReference(Address.class, MagicNames.loadShort, short.class), g);
  }

  /**
   * Load a short quantity from an address plus offset
   */
  private static final class LoadShort_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Load at offset
      asm.emitPOP_Reg(S0);                  // offset
      asm.emitPOP_Reg(T0);                  // base
      asm.emitMOVSX_Reg_RegIdx_Word(T0, T0, S0, Assembler.BYTE, NO_SLOT); // load and sign extend word [T0+S0]
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    MagicGenerator g = new LoadShort_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.loadShort, Offset.class, short.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getShortAtOffset, Object.class, Offset.class, short.class), g);
  }

  /**
   * Load a char from an address
   */
  private static final class LoadChar extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // No offset
      asm.emitPOP_Reg(T0);                  // base
      asm.emitMOVZX_Reg_RegInd_Word(T0, T0);
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    MagicGenerator g = new LoadChar();
    generators.put(getMethodReference(Address.class, MagicNames.loadChar, char.class), g);
  }

  /**
   * Load a char from an address plus offset
   */
  private static final class LoadChar_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Load at offset
      asm.emitPOP_Reg(S0);                  // offset
      asm.emitPOP_Reg(T0);                  // base
      asm.emitMOVZX_Reg_RegIdx_Word(T0, T0, S0, Assembler.BYTE, NO_SLOT); // load and sign extend word [T0+S0]
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    MagicGenerator g = new LoadChar_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.loadChar, Offset.class, char.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getCharAtOffset, Object.class, Offset.class, char.class), g);
  }

  /**
   * Load a 64bit quantity from an address
   */
  private static final class Load64 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // No offset
      asm.emitPOP_Reg(T0);                // base
      asm.emitPUSH_RegDisp(T0, ONE_SLOT); // pushes [T0+4]
      asm.emitPUSH_RegInd(T0);            // pushes [T0]
    }
  }
  static {
    MagicGenerator g = new Load64();
    generators.put(getMethodReference(Address.class, MagicNames.loadDouble, double.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadLong, long.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.prepareLong, long.class), g);
  }

  /**
   * Load a 32bit quantity from an address plus offset
   */
  private static final class Load64_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Load at offset
      asm.emitPOP_Reg(S0);                  // offset
      asm.emitPOP_Reg(T0);                  // base
      asm.emitPUSH_RegIdx(T0, S0, Assembler.BYTE, ONE_SLOT); // pushes [T0+S0+4]
      asm.emitPUSH_RegIdx(T0, S0, Assembler.BYTE, NO_SLOT);  // pushes [T0+S0]
    }
  }
  static {
    MagicGenerator g = new Load64_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.loadDouble, Offset.class, double.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.loadLong, Offset.class, long.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.prepareLong, Offset.class, long.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getDoubleAtOffset, Object.class, Offset.class, double.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getLongAtOffset, Object.class, Offset.class, long.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.prepareLong, Object.class, Offset.class, long.class), g);
  }

  /**
   * Store a 32bit quantity to an address
   */
  private static final class Store32 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // No offset
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(S0);                   // address
      asm.emitMOV_RegInd_Reg(S0, T0);         // [S0+0] <- T0
    }
  }
  static {
    MagicGenerator g = new Store32();
    generators.put(getMethodReference(Address.class, MagicNames.store, Address.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, Word.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, int.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, float.class, void.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new EarlyReferenceCheckDecorator(NO_SLOT, g);
    }
    generators.put(getMethodReference(Address.class, MagicNames.store, ObjectReference.class, void.class), g);
  }

  /**
   * Store a 32bit quantity to an address plus offset
   */
  private static final class Store32_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Store at offset
      asm.emitPOP_Reg(S0);                   // offset
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(T1);                   // address
      asm.emitMOV_RegIdx_Reg(T1, S0, Assembler.BYTE, NO_SLOT, T0); // [T1+S0] <- T0
    }
  }
  static {
    MagicGenerator g = new Store32_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.store, Address.class, Offset.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, Word.class, Offset.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, int.class, Offset.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, float.class, Offset.class, void.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new EarlyReferenceCheckDecorator(ONE_SLOT, g);
    }
    generators.put(getMethodReference(Address.class, MagicNames.store, ObjectReference.class, Offset.class, void.class), g);
  }

  /**
   * Store a 32bit quantity to an address plus offset in the format used in
   * {@link Magic}
   */
  private static final class Magic_Store32 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(S0);                   // offset
      asm.emitPOP_Reg(T1);                   // obj ref
      asm.emitMOV_RegIdx_Reg(T1, S0, Assembler.BYTE, NO_SLOT, T0); // [T1+S0] <- T0
    }
  }
  static {
    MagicGenerator g = new Magic_Store32();
    generators.put(getMethodReference(Magic.class, MagicNames.setIntAtOffset, Object.class, Offset.class, int.class, void.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.setWordAtOffset, Object.class, Offset.class, Word.class, void.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new EarlyReferenceCheckDecorator(NO_SLOT, g);
    }
    generators.put(getMethodReference(Magic.class, MagicNames.setObjectAtOffset, Object.class, Offset.class, Object.class, void.class), g);
  }

  /**
   * Store a 32bit quantity to an address plus offset in the format used in
   * {@link Magic} with an additional meta-data argument
   */
  private static final class Magic_Store32_MD extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);                   // discard meta-data
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(S0);                   // offset
      asm.emitPOP_Reg(T1);                   // obj ref
      asm.emitMOV_RegIdx_Reg(T1, S0, Assembler.BYTE, NO_SLOT, T0); // [T1+S0] <- T0
    }
  }
  static {
    MagicGenerator g = new Magic_Store32_MD();
    generators.put(getMethodReference(Magic.class, MagicNames.setWordAtOffset, Object.class, Offset.class, Word.class, int.class, void.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new EarlyReferenceCheckDecorator(ONE_SLOT, g);
    }
    generators.put(getMethodReference(Magic.class, MagicNames.setObjectAtOffset, Object.class, Offset.class, Object.class, int.class, void.class), g);
  }

  /**
   * Store a byte quantity to an address plus offset
   */
  private static final class StoreByte extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // No offset
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(T1);                   // base
      asm.emitMOV_RegInd_Reg_Byte(T1, T0);
    }
  }
  static {
    MagicGenerator g = new StoreByte();
    generators.put(getMethodReference(Address.class, MagicNames.store, byte.class, void.class), g);
  }

  /**
   * Store a byte quantity to an address plus offset
   */
  private static final class StoreByte_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Store at offset
      asm.emitPOP_Reg(S0);                   // offset
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(T1);                   // base
      asm.emitMOV_RegIdx_Reg_Byte(T1, S0, Assembler.BYTE, NO_SLOT, T0); // [T1+S0] <- (byte) T0
    }
  }
  static {
    MagicGenerator g = new StoreByte_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.store, byte.class, Offset.class, void.class), g);
  }

  /**
   * Store a byte quantity to an address plus offset in the format used in {@link Magic}
   */
  private static final class Magic_StoreByte extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(S0);                   // offset
      asm.emitPOP_Reg(T1);                   // obj ref
      asm.emitMOV_RegIdx_Reg_Byte(T1, S0, Assembler.BYTE, NO_SLOT, T0); // [T1+S0] <- (byte) T0
    }
  }
  static {
    MagicGenerator g = new Magic_StoreByte();
    generators.put(getMethodReference(Magic.class, MagicNames.setByteAtOffset, Object.class, Offset.class, byte.class, void.class), g);
  }

  /**
   * Store a 16bit quantity to an address
   */
  private static final class Store16 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // No offset
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(T1);                   // base
      asm.emitMOV_RegInd_Reg_Word(T1, T0);
    }
  }
  static {
    MagicGenerator g = new Store16();
    generators.put(getMethodReference(Address.class, MagicNames.store, short.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, char.class, void.class), g);
  }

  /**
   * Store a 16bit quantity to an address plus offset
   */
  private static final class Store16_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Store at offset
      asm.emitPOP_Reg(S0);                   // offset
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(T1);                   // base
      asm.emitMOV_RegIdx_Reg_Word(T1, S0, Assembler.BYTE, NO_SLOT, T0); // [T1+S0] <- (word) T0
    }
  }
  static {
    MagicGenerator g = new Store16_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.store, short.class, Offset.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, char.class, Offset.class, void.class), g);

  }

  /**
   * Store a char to an address plus offset in the format used in {@link Magic}
   */
  private static final class Magic_StoreChar extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);                   // value
      asm.emitPOP_Reg(S0);                   // offset
      asm.emitPOP_Reg(T1);                   // obj ref
      asm.emitMOV_RegIdx_Reg_Word(T1, S0, Assembler.BYTE, NO_SLOT, T0); // [T1+S0] <- (word) T0
    }
  }
  static {
    MagicGenerator g = new Magic_StoreChar();
    generators.put(getMethodReference(Magic.class, MagicNames.setCharAtOffset, Object.class, Offset.class, char.class, void.class), g);
  }

  /**
   * Store a 64bit quantity to an address
   */
  private static final class Store64 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // No offset
      asm.emitMOV_Reg_RegInd(T0, SP);             // value high
      asm.emitMOV_Reg_RegDisp(T1, SP, TWO_SLOTS); // base
      asm.emitMOV_RegInd_Reg(T1, T0);             // [T1] <- T0
      asm.emitMOV_Reg_RegDisp(T0, SP, ONE_SLOT);  // value low
      asm.emitMOV_RegDisp_Reg(T1, ONE_SLOT, T0);  // [T1+4] <- T0
      asm.emitADD_Reg_Imm(SP, WORDSIZE * 3);      // pop stack locations
    }
  }
  static {
    MagicGenerator g = new Store64();
    generators.put(getMethodReference(Address.class, MagicNames.store, long.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, double.class, void.class), g);
  }

  /**
   * Store a 64bit quantity to an address plus offset
   */
  private static final class Store64_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Store at offset
      asm.emitMOV_Reg_RegDisp(T0, SP, ONE_SLOT);          // value high
      asm.emitMOV_Reg_RegInd(S0, SP);     // offset
      asm.emitMOV_Reg_RegDisp(T1, SP, THREE_SLOTS);     // base
      asm.emitMOV_RegIdx_Reg(T1, S0, Assembler.BYTE, NO_SLOT, T0); // [T1+S0] <- T0
      asm.emitMOV_Reg_RegDisp(T0, SP, TWO_SLOTS);     // value low
      asm.emitMOV_RegIdx_Reg(T1, S0, Assembler.BYTE, ONE_SLOT, T0); // [T1+S0+4] <- T0
      asm.emitADD_Reg_Imm(SP, WORDSIZE * 4); // pop stack locations
    }
  }
  static {
    MagicGenerator g = new Store64_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.store, long.class, Offset.class, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.store, double.class, Offset.class, void.class), g);
  }

  /**
   * Store a 64bit quantity to an address plus offset in the format used in
   * {@link Magic}
   */
  private static final class Magic_Store64 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitMOV_Reg_RegInd(T0, SP);          // value high
      asm.emitMOV_Reg_RegDisp(S0, SP, TWO_SLOTS);     // offset
      asm.emitMOV_Reg_RegDisp(T1, SP, THREE_SLOTS);     // obj ref
      asm.emitMOV_RegIdx_Reg(T1, S0, Assembler.BYTE, NO_SLOT, T0); // [T1+S0] <- T0
      asm.emitMOV_Reg_RegDisp(T0, SP, ONE_SLOT);     // value low
      asm.emitMOV_RegIdx_Reg(T1, S0, Assembler.BYTE, ONE_SLOT, T0); // [T1+S0+4] <- T0
      asm.emitADD_Reg_Imm(SP, WORDSIZE * 4); // pop stack locations
    }
  }
  static {
    MagicGenerator g = new Magic_Store64();
    generators.put(getMethodReference(Magic.class, MagicNames.setLongAtOffset, Object.class, Offset.class, long.class, void.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.setDoubleAtOffset, Object.class, Offset.class, double.class, void.class), g);
  }

  /**
   * Compare and swap a 32bit value
   */
  private static final class Attempt32 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T1);          // newVal
      asm.emitPOP_Reg(EAX);         // oldVal (EAX is implicit arg to LCMPX
      // No offset
      asm.emitMOV_Reg_RegInd(S0, SP);  // S0 = base
      asm.emitLockNextInstruction();
      asm.emitCMPXCHG_RegInd_Reg(S0, T1);   // atomic compare-and-exchange
      asm.emitMOV_RegInd_Imm(SP, 1);        // 'push' true (overwriting base)
      asm.emitBranchLikelyNextInstruction();
      ForwardReference fr = asm.forwardJcc(Assembler.EQ); // skip if compare fails
      asm.emitMOV_RegInd_Imm(SP, 0);        // 'push' false (overwriting base)
      fr.resolve(asm);
    }
  }
  static {
    MagicGenerator g = new Attempt32();
    generators.put(getMethodReference(Address.class, MagicNames.attempt, Address.class, Address.class, boolean.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.attempt, Word.class, Word.class, boolean.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.attempt, int.class, int.class, boolean.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new EarlyReferenceCheckDecorator(NO_SLOT, g);
      g = new EarlyReferenceCheckDecorator(ONE_SLOT, g);
    }
    generators.put(getMethodReference(Address.class, MagicNames.attempt, ObjectReference.class, ObjectReference.class, boolean.class), g);
  }

  /**
   * Compare and swap a 32bit value at an address plus offset
   */
  private static final class Attempt32_Offset extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // Offset passed
      asm.emitPOP_Reg(S0);        // S0 = offset
      asm.emitPOP_Reg(T1);          // newVal
      asm.emitPOP_Reg(EAX);         // oldVal (EAX is implicit arg to LCMPX
      asm.emitADD_Reg_RegInd(S0, SP);  // S0 += base
      asm.emitLockNextInstruction();
      asm.emitCMPXCHG_RegInd_Reg(S0, T1);   // atomic compare-and-exchange
      asm.emitMOV_RegInd_Imm(SP, 1);        // 'push' true (overwriting base)
      asm.emitBranchLikelyNextInstruction();
      ForwardReference fr = asm.forwardJcc(Assembler.EQ); // skip if compare fails
      asm.emitMOV_RegInd_Imm(SP, 0);        // 'push' false (overwriting base)
      fr.resolve(asm);
    }
  }
  static {
    MagicGenerator g = new Attempt32_Offset();
    generators.put(getMethodReference(Address.class, MagicNames.attempt, Address.class, Address.class, Offset.class, boolean.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.attempt, Word.class, Word.class, Offset.class, boolean.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.attempt, int.class, int.class, Offset.class, boolean.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new EarlyReferenceCheckDecorator(ONE_SLOT, g);
      g = new EarlyReferenceCheckDecorator(TWO_SLOTS, g);
    }
    generators.put(getMethodReference(Address.class, MagicNames.attempt, ObjectReference.class, ObjectReference.class, Offset.class, boolean.class), g);
  }

  /**
   * Compare and swap a 32bit value in the format used in {@link Magic}
   */
  private static final class Magic_Attempt32 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // attempt gets called with four arguments: base, offset, oldVal, newVal
      // returns ([base+offset] == oldVal)
      // if ([base+offset] == oldVal) [base+offset] := newVal
      // (operation on memory is atomic)
      asm.emitPOP_Reg(T1);            // newVal
      asm.emitPOP_Reg(EAX);           // oldVal (EAX is implicit arg to LCMPXCNG
      asm.emitPOP_Reg(S0);            // S0 = offset
      asm.emitADD_Reg_RegInd(S0, SP);  // S0 += base
      asm.emitLockNextInstruction();
      asm.emitCMPXCHG_RegInd_Reg(S0, T1);   // atomic compare-and-exchange
      asm.emitMOV_RegInd_Imm(SP, 1);        // 'push' true (overwriting base)
      asm.emitBranchLikelyNextInstruction();
      ForwardReference fr = asm.forwardJcc(Assembler.EQ); // skip if compare fails
      asm.emitMOV_RegInd_Imm(SP, 0);        // 'push' false (overwriting base)
      fr.resolve(asm);
    }
  }
  static {
    MagicGenerator g = new Magic_Attempt32();
    generators.put(getMethodReference(Magic.class, MagicNames.attemptInt, Object.class, Offset.class, int.class, int.class, boolean.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.attemptAddress, Object.class, Offset.class, Address.class, Address.class, boolean.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.attemptWord, Object.class, Offset.class, Word.class, Word.class, boolean.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new EarlyReferenceCheckDecorator(NO_SLOT, g);
      g = new EarlyReferenceCheckDecorator(ONE_SLOT, g);
      g = new EarlyReferenceCheckDecorator(THREE_SLOTS, g);
    }
    generators.put(getMethodReference(Magic.class, MagicNames.attemptObject, Object.class, Offset.class, Object.class, Object.class, boolean.class), g);
  }

  /**
   * Compare and swap a 64bit value in the format used in {@link Magic}
   */
  private static final class Magic_Attempt64 extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // attempt gets called with four arguments: base, offset, oldVal, newVal
      // returns ([base+offset] == oldVal)
      // if ([base+offset] == oldVal) [base+offset] := newVal
      // (operation on memory is atomic)
      //t1:t0 with s0:ebx
      asm.emitMOV_Reg_RegDisp(T1, SP, THREE_SLOTS);
      asm.emitMOV_Reg_RegDisp(T0, SP, TWO_SLOTS);     // T1:T0 (EDX:EAX) -> oldVal
      asm.emitMOV_RegDisp_Reg(SP, THREE_SLOTS, EBX);  // Save EBX
      asm.emitMOV_RegDisp_Reg(SP, TWO_SLOTS, ESI);    // Save ESI
      asm.emitMOV_Reg_RegInd(EBX, SP);
      asm.emitMOV_Reg_RegDisp(S0, SP, ONE_SLOT);      // S0:EBX (ECX:EBX) -> newVal
      asm.emitMOV_Reg_RegDisp(ESI, SP, FIVE_SLOTS);   // ESI := base
      asm.emitADD_Reg_RegDisp(ESI, SP, FOUR_SLOTS);   // ESI += offset
      asm.emitLockNextInstruction();
      asm.emitCMPXCHG8B_RegInd(ESI);                  // atomic compare-and-exchange
      ForwardReference fr1 = asm.forwardJcc(Assembler.NE); // skip if compare fails
      asm.emitMOV_RegDisp_Imm(SP, FIVE_SLOTS, 1);     // 'push' true (overwriting base)
      ForwardReference fr2 = asm.forwardJMP();     // skip if compare fails
      fr1.resolve(asm);
      asm.emitMOV_RegDisp_Imm(SP, FIVE_SLOTS, 0);     // 'push' false (overwriting base)
      fr2.resolve(asm);
      asm.emitMOV_Reg_RegDisp(EBX, SP, THREE_SLOTS);  // Restore EBX
      asm.emitMOV_Reg_RegDisp(ESI, SP, TWO_SLOTS);    // Restore ESI
      asm.emitADD_Reg_Imm(SP, WORDSIZE*5);            // adjust SP popping the 4 args (6 slots) and pushing the result
    }
  }
  static {
    MagicGenerator g = new Magic_Attempt64();
    generators.put(getMethodReference(Magic.class, MagicNames.attemptLong, Object.class, Offset.class, long.class, long.class, boolean.class), g);
  }

  /**
   * Prefetch from an address
   */
  private static final class Prefetch extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitPREFETCHNTA_Reg(T0);
    }
  }
  static {
    MagicGenerator g = new Prefetch();
    generators.put(getMethodReference(Address.class, MagicNames.prefetch, void.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.prefetchNTA, void.class), g);
  }

  /**
   * Get the type from an object
   */
  private static final class GetObjectType extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);                               // object ref
      BaselineCompilerImpl.baselineEmitLoadTIB(asm, S0, T0);
      asm.emitPUSH_RegDisp(S0, Offset.fromIntZeroExtend(TIB_TYPE_INDEX << LG_WORDSIZE)); // push RVMType slot of TIB
    }
  }
  static {
    MagicGenerator g = new GetObjectType();
    generators.put(getMethodReference(Magic.class, MagicNames.getObjectType, Object.class, RVMType.class), g);
  }

  /**
   * Perform no-operation
   */
  private static final class Nop extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
    }
  }
  static {
    MagicGenerator g = new Nop();
    Class<?>[] unboxedTypes = new Class<?>[]{Address.class, Extent.class, Offset.class, Word.class};
    for (Class<?> type : unboxedTypes) {
      generators.put(getMethodReference(type, MagicNames.wordFromInt, int.class, type), g);
      generators.put(getMethodReference(type, MagicNames.wordFromIntSignExtend, int.class, type), g);
      generators.put(getMethodReference(type, MagicNames.wordFromIntZeroExtend, int.class, type), g);
      generators.put(getMethodReference(type, MagicNames.wordToInt, int.class), g);
      if (type != Address.class)
        generators.put(getMethodReference(type, MagicNames.wordToAddress, Address.class), g);
      if (type != Extent.class)
        generators.put(getMethodReference(type, MagicNames.wordToExtent, Extent.class), g);
      if (type != Offset.class)
        generators.put(getMethodReference(type, MagicNames.wordToOffset, Offset.class), g);
      if (type != Word.class)
        generators.put(getMethodReference(type, MagicNames.wordToWord, Word.class), g);
    }
    generators.put(getMethodReference(Magic.class, MagicNames.floatAsIntBits, float.class, int.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.intBitsAsFloat, int.class, float.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.doubleAsLongBits, double.class, long.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.longBitsAsDouble, long.class, double.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.sync, void.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.isync, void.class), g);
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new EarlyReferenceCheckDecorator(NO_SLOT, g);
    }
    for (Class<?> type : unboxedTypes) {
      generators.put(getMethodReference(type, MagicNames.wordFromObject, Object.class, type), g);
      generators.put(getMethodReference(type, MagicNames.wordToObject, Object.class), g);
      generators.put(getMethodReference(type, MagicNames.wordToObjectReference, ObjectReference.class), g);
    }
    generators.put(getMethodReference(ObjectReference.class, MagicNames.wordFromObject, Object.class, ObjectReference.class), g);
    generators.put(getMethodReference(ObjectReference.class, MagicNames.wordToObject, Object.class), g);
    generators.put(getMethodReference(ObjectReference.class, MagicNames.wordToAddress, Address.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.codeArrayAsObject, CodeArray.class, Object.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.tibAsObject, TIB.class, Object.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.objectAsAddress, Object.class, Address.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.addressAsByteArray, Address.class, byte[].class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.addressAsObject, Address.class, Object.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.addressAsTIB, Address.class, TIB.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.objectAsType, Object.class, RVMType.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.objectAsShortArray, Object.class, short[].class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.objectAsIntArray, Object.class, int[].class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.objectAsProcessor, Object.class, Processor.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.processorAsGreenProcessor, Processor.class, GreenProcessor.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.objectAsThread, Object.class, RVMThread.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.threadAsCollectorThread, RVMThread.class, CollectorThread.class), g);
  }

  /**
   * Generate an address constant
   */
  private static final class AddressConstant extends MagicGenerator {
    final int value;
    AddressConstant(int value) {
      this.value = value;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPUSH_Imm(value);
    }
  }
  static {
    MagicGenerator zero = new AddressConstant(0);
    MagicGenerator one = new AddressConstant(1);
    MagicGenerator max = new AddressConstant(-1);
    Class<?>[] unboxedTypes = new Class<?>[]{Address.class, Extent.class, Offset.class, Word.class};
    for (Class<?> type : unboxedTypes) {
      generators.put(getMethodReference(type, MagicNames.wordZero, type), zero);
      generators.put(getMethodReference(type, MagicNames.wordOne, type), one);
      generators.put(getMethodReference(type, MagicNames.wordMax, type), max);
    }
    generators.put(getMethodReference(ObjectReference.class, MagicNames.wordNull, ObjectReference.class), zero);
    MagicGenerator g = new AddressConstant(Magic.getTocPointer().toInt());
    generators.put(getMethodReference(Magic.class, MagicNames.getJTOC, Address.class), g);
    generators.put(getMethodReference(Magic.class, MagicNames.getTocPointer, Address.class), g);
  }

  /**
   * Address comparison
   */
  private static final class AddressComparison extends MagicGenerator {
    final byte comparator;
    AddressComparison(byte comparator) {
      this.comparator = comparator;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(S0);
      asm.emitPOP_Reg(T0);
      asm.emitCMP_Reg_Reg(T0, S0);
      ForwardReference fr1 = asm.forwardJcc(comparator);
      asm.emitPUSH_Imm(0);
      ForwardReference fr2 = asm.forwardJMP();
      fr1.resolve(asm);
      asm.emitPUSH_Imm(1);
      fr2.resolve(asm);
    }
  }
  static {
    MagicGenerator llt = new AddressComparison(Assembler.LLT);
    MagicGenerator lle = new AddressComparison(Assembler.LLE);
    MagicGenerator lgt = new AddressComparison(Assembler.LGT);
    MagicGenerator lge = new AddressComparison(Assembler.LGE);
    MagicGenerator eq = new AddressComparison(Assembler.EQ);
    MagicGenerator ne = new AddressComparison(Assembler.NE);
    // Unsigned unboxed types
    Class<?>[] unboxedTypes = new Class<?>[]{Address.class, Extent.class, Word.class};
    for (Class<?> type : unboxedTypes) {
      generators.put(getMethodReference(type, MagicNames.wordLT, type, boolean.class), llt);
      generators.put(getMethodReference(type, MagicNames.wordLE, type, boolean.class), lle);
      generators.put(getMethodReference(type, MagicNames.wordGT, type, boolean.class), lgt);
      generators.put(getMethodReference(type, MagicNames.wordGE, type, boolean.class), lge);
      generators.put(getMethodReference(type, MagicNames.wordEQ, type, boolean.class), eq);
      generators.put(getMethodReference(type, MagicNames.wordNE, type, boolean.class), ne);
    }
    MagicGenerator lt = new AddressComparison(Assembler.LT);
    MagicGenerator le = new AddressComparison(Assembler.LE);
    MagicGenerator gt = new AddressComparison(Assembler.GT);
    MagicGenerator ge = new AddressComparison(Assembler.GE);
    // Signed unboxed types
    unboxedTypes = new Class<?>[]{Offset.class};
    for (Class<?> type : unboxedTypes) {
      generators.put(getMethodReference(type, MagicNames.wordsLT, type, boolean.class), lt);
      generators.put(getMethodReference(type, MagicNames.wordsLE, type, boolean.class), le);
      generators.put(getMethodReference(type, MagicNames.wordsGT, type, boolean.class), gt);
      generators.put(getMethodReference(type, MagicNames.wordsGE, type, boolean.class), ge);
      generators.put(getMethodReference(type, MagicNames.wordEQ, type, boolean.class), eq);
      generators.put(getMethodReference(type, MagicNames.wordNE, type, boolean.class), ne);
    }
  }

  /**
   * Is an address zero?
   */
  private static final class AddressComparison_isZero extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitTEST_Reg_Reg(T0, T0);
      ForwardReference fr1 = asm.forwardJcc(Assembler.EQ);
      asm.emitPUSH_Imm(0);
      ForwardReference fr2 = asm.forwardJMP();
      fr1.resolve(asm);
      asm.emitPUSH_Imm(1);
      fr2.resolve(asm);
    }
  }
  static {
    MagicGenerator g = new AddressComparison_isZero();
    Class<?>[] unboxedTypes = new Class<?>[]{Address.class, Extent.class, Offset.class, Word.class};
    for (Class<?> type : unboxedTypes) {
      generators.put(getMethodReference(type, MagicNames.wordIsZero, boolean.class), g);
    }
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new EarlyReferenceCheckDecorator(NO_SLOT, g);
    }
    generators.put(getMethodReference(ObjectReference.class, MagicNames.wordIsNull, boolean.class), g);
  }

  /**
   * Is an address max?
   */
  private static final class AddressComparison_isMax extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitCMP_Reg_Imm(T0, -1);
      ForwardReference fr1 = asm.forwardJcc(Assembler.EQ);
      asm.emitPUSH_Imm(0);
      ForwardReference fr2 = asm.forwardJMP();
      fr1.resolve(asm);
      asm.emitPUSH_Imm(1);
      fr2.resolve(asm);
    }
  }
  static {
    MagicGenerator g = new AddressComparison_isMax();
    Class<?>[] unboxedTypes = new Class<?>[]{Address.class, Extent.class, Offset.class, Word.class};
    for (Class<?> type : unboxedTypes) {
      generators.put(getMethodReference(type, MagicNames.wordIsMax, boolean.class), g);
    }
  }

  /**
   * Addition of words
   */
  private static final class WordPlus extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitADD_RegInd_Reg(SP, T0);
    }
  }
  static {
    MagicGenerator g = new WordPlus();
    generators.put(getMethodReference(Address.class, MagicNames.wordPlus, int.class, Address.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.wordPlus, Offset.class, Address.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.wordPlus, Extent.class, Address.class), g);
    generators.put(getMethodReference(Extent.class, MagicNames.wordPlus, int.class, Extent.class), g);
    generators.put(getMethodReference(Extent.class, MagicNames.wordPlus, Extent.class, Extent.class), g);
    generators.put(getMethodReference(Offset.class, MagicNames.wordPlus, int.class, Offset.class), g);
    generators.put(getMethodReference(Word.class, MagicNames.wordPlus, Word.class, Word.class), g);
    generators.put(getMethodReference(Word.class, MagicNames.wordPlus, Offset.class, Word.class), g);
    generators.put(getMethodReference(Word.class, MagicNames.wordPlus, Extent.class, Word.class), g);
  }

  /**
   * Subtraction of words
   */
  private static final class WordMinus extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitSUB_RegInd_Reg(SP, T0);
    }
  }
  static {
    MagicGenerator g = new WordMinus();
    generators.put(getMethodReference(Address.class, MagicNames.wordMinus, int.class, Address.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.wordMinus, Offset.class, Address.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.wordMinus, Extent.class, Address.class), g);
    generators.put(getMethodReference(Address.class, MagicNames.wordDiff, Address.class, Offset.class), g);
    generators.put(getMethodReference(Extent.class, MagicNames.wordMinus, int.class, Extent.class), g);
    generators.put(getMethodReference(Extent.class, MagicNames.wordMinus, Extent.class, Extent.class), g);
    generators.put(getMethodReference(Offset.class, MagicNames.wordMinus, int.class, Offset.class), g);
    generators.put(getMethodReference(Offset.class, MagicNames.wordMinus, Offset.class, Offset.class), g);
    generators.put(getMethodReference(Word.class, MagicNames.wordMinus, Word.class, Word.class), g);
    generators.put(getMethodReference(Word.class, MagicNames.wordMinus, Offset.class, Word.class), g);
    generators.put(getMethodReference(Word.class, MagicNames.wordMinus, Extent.class, Word.class), g);
  }

  /**
   * Logical and of words
   */
  private static final class WordAnd extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitAND_RegInd_Reg(SP, T0);
    }
  }
  static {
    MagicGenerator g = new WordAnd();
    generators.put(getMethodReference(Word.class, MagicNames.wordAnd, Word.class, Word.class), g);
  }

  /**
   * Logical or of words
   */
  private static final class WordOr extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitOR_RegInd_Reg(SP, T0);
    }
  }
  static {
    MagicGenerator g = new WordOr();
    generators.put(getMethodReference(Word.class, MagicNames.wordOr, Word.class, Word.class), g);
  }

  /**
   * Logical xor of words
   */
  private static final class WordXor extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitXOR_RegInd_Reg(SP, T0);
    }
  }
  static {
    MagicGenerator g = new WordXor();
    generators.put(getMethodReference(Word.class, MagicNames.wordXor, Word.class, Word.class), g);
  }

  /**
   * Logical left shift of words
   */
  private static final class WordLsh extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(ECX);
      asm.emitSHL_RegInd_Reg(SP, ECX);
    }
  }
  static {
    MagicGenerator g = new WordLsh();
    generators.put(getMethodReference(Word.class, MagicNames.wordLsh, int.class, Word.class), g);
  }

  /**
   * Logical right shift of words
   */
  private static final class WordRshl extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(ECX);
      asm.emitSHR_RegInd_Reg(SP, ECX);
    }
  }
  static {
    MagicGenerator g = new WordRshl();
    generators.put(getMethodReference(Word.class, MagicNames.wordRshl, int.class, Word.class), g);
  }

  /**
   * Arithmetic right shift of words
   */
  private static final class WordRsha extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(ECX);
      asm.emitSAR_RegInd_Reg(SP, ECX);
    }
  }
  static {
    MagicGenerator g = new WordRsha();
    generators.put(getMethodReference(Word.class, MagicNames.wordRsha, int.class, Word.class), g);
  }

  /**
   * Logical not of word
   */
  private static final class WordNot extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitNOT_RegInd(SP);
    }
  }
  static {
    MagicGenerator g = new WordNot();
    generators.put(getMethodReference(Word.class, MagicNames.wordNot, Word.class), g);
  }

  /**
   * Convert word to long
   */
  private static final class WordToLong extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitPUSH_Imm(0); // upper 32 bits
      asm.emitPUSH_Reg(T0); // lower 32 bits
    }
  }
  static {
    MagicGenerator g = new WordToLong();
    Class<?>[] unboxedTypes = new Class<?>[]{Address.class, Extent.class, Offset.class, Word.class};
    for (Class<?> type : unboxedTypes) {
      generators.put(getMethodReference(type, MagicNames.wordToLong, long.class), g);
    }
  }

  /**
   * Set a register to a value from the stack
   */
  private static final class SetRegister extends MagicGenerator {
    private final GPR reg;
    SetRegister(GPR reg) {
      this.reg = reg;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(reg);
    }
  }
  static {
    generators.put(getMethodReference(Magic.class, MagicNames.setESIAsProcessor, Processor.class, void.class),
        new SetRegister(ESI));
    generators.put(getMethodReference(Magic.class, MagicNames.setProcessorRegister, Processor.class, void.class),
        new SetRegister(PR));
  }

  /**
   * Put a register on to the stack
   */
  private static final class GetRegister extends MagicGenerator {
    private final GPR reg;
    GetRegister(GPR reg) {
      this.reg = reg;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPUSH_Reg(reg);
    }
  }
  static {
    generators.put(getMethodReference(Magic.class, MagicNames.getESIAsProcessor, Processor.class),
        new GetRegister(ESI));
    generators.put(getMethodReference(Magic.class, MagicNames.getProcessorRegister, Processor.class),
        new GetRegister(PR));
  }

  /**
   * Reflective method dispatch
   */
  private static final class InvokeMethodReturningObject extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      Offset offset = ArchEntrypoints.reflectiveMethodInvokerInstructionsField.getOffset();
      BaselineCompilerImpl.genParameterRegisterLoad(asm, 5); // pass 5 parameter words
      asm.emitCALL_Abs(Magic.getTocPointer().plus(offset));
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    MagicGenerator g = new InvokeMethodReturningObject();
    if (VALIDATE_OBJECT_REFERENCES) {
      g = new LateReferenceCheckDecorator(NO_SLOT, g);
    }
    generators.put(getMethodReference(Magic.class, MagicNames.invokeMethodReturningObject, CodeArray.class, WordArray.class, double[].class, byte[].class, WordArray.class, Object.class), g);
  }

  /**
   * Reflective method dispatch
   */
  private static final class InvokeMethodReturningVoid extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      Offset offset = ArchEntrypoints.reflectiveMethodInvokerInstructionsField.getOffset();
      BaselineCompilerImpl.genParameterRegisterLoad(asm, 5); // pass 5 parameter words
      asm.emitCALL_Abs(Magic.getTocPointer().plus(offset));
    }
  }
  static {
    MagicGenerator g = new InvokeMethodReturningVoid();
    generators.put(getMethodReference(Magic.class, MagicNames.invokeMethodReturningVoid, CodeArray.class, WordArray.class, double[].class, byte[].class, WordArray.class, void.class), g);
  }

  /**
   * Reflective method dispatch
   */
  private static final class InvokeMethodReturningInt extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      Offset offset = ArchEntrypoints.reflectiveMethodInvokerInstructionsField.getOffset();
      BaselineCompilerImpl.genParameterRegisterLoad(asm, 5); // pass 5 parameter words
      asm.emitCALL_Abs(Magic.getTocPointer().plus(offset));
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    MagicGenerator g = new InvokeMethodReturningInt();
    generators.put(getMethodReference(Magic.class, MagicNames.invokeMethodReturningInt, CodeArray.class, WordArray.class, double[].class, byte[].class, WordArray.class, int.class), g);
  }

  /**
   * Reflective method dispatch
   */
  private static final class InvokeMethodReturningLong extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      Offset offset = ArchEntrypoints.reflectiveMethodInvokerInstructionsField.getOffset();
      BaselineCompilerImpl.genParameterRegisterLoad(asm, 5); // pass 5 parameter words
      asm.emitCALL_Abs(Magic.getTocPointer().plus(offset));
      asm.emitPUSH_Reg(T0); // high half
      asm.emitPUSH_Reg(T1); // low half
    }
  }
  static {
    MagicGenerator g = new InvokeMethodReturningLong();
    generators.put(getMethodReference(Magic.class, MagicNames.invokeMethodReturningLong, CodeArray.class, WordArray.class, double[].class, byte[].class, WordArray.class, long.class), g);
  }

  /**
   * Reflective method dispatch
   */
  private static final class InvokeMethodReturningFloat extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      Offset offset = ArchEntrypoints.reflectiveMethodInvokerInstructionsField.getOffset();
      BaselineCompilerImpl.genParameterRegisterLoad(asm, 5); // pass 5 parameter words
      asm.emitCALL_Abs(Magic.getTocPointer().plus(offset));
      asm.emitSUB_Reg_Imm(SP, 4);
      if (SSE2_FULL) {
        asm.emitMOVSS_RegInd_Reg(SP, XMM0);
      } else {
        asm.emitFSTP_RegInd_Reg(SP, FP0);
      }
    }
  }
  static {
    MagicGenerator g = new InvokeMethodReturningFloat();
    generators.put(getMethodReference(Magic.class, MagicNames.invokeMethodReturningFloat, CodeArray.class, WordArray.class, double[].class, byte[].class, WordArray.class, float.class), g);
  }

  /**
   * Reflective method dispatch
   */
  private static final class InvokeMethodReturningDouble extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      Offset offset = ArchEntrypoints.reflectiveMethodInvokerInstructionsField.getOffset();
      BaselineCompilerImpl.genParameterRegisterLoad(asm, 5); // pass 5 parameter words
      asm.emitCALL_Abs(Magic.getTocPointer().plus(offset));
      asm.emitSUB_Reg_Imm(SP, 8);
      if (SSE2_FULL) {
        asm.emitMOVLPD_RegInd_Reg(SP, XMM0);
      } else {
        asm.emitFSTP_RegInd_Reg_Quad(SP, FP0);
      }
    }
  }
  static {
    MagicGenerator g = new InvokeMethodReturningDouble();
    generators.put(getMethodReference(Magic.class, MagicNames.invokeMethodReturningDouble, CodeArray.class, WordArray.class, double[].class, byte[].class, WordArray.class, double.class), g);
  }

  /**
   * Invoke an entry point taking values off of the stack
   */
  private static final class InvokeEntryPoint extends MagicGenerator {
    private final Offset offset;
    private final int args;
    InvokeEntryPoint(Offset offset, int args) {
      this.offset = offset;
      this.args = args;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      BaselineCompilerImpl.genParameterRegisterLoad(asm, args);
      asm.emitCALL_Abs(Magic.getTocPointer().plus(offset));
    }
  }
  static {
    generators.put(getMethodReference(Magic.class, MagicNames.saveThreadState, Registers.class, void.class),
        new InvokeEntryPoint(ArchEntrypoints.saveThreadStateInstructionsField.getOffset(), 1));
    generators.put(getMethodReference(Magic.class, MagicNames.threadSwitch, RVMThread.class, Registers.class, void.class),
        new InvokeEntryPoint(ArchEntrypoints.threadSwitchInstructionsField.getOffset(), 2));
    generators.put(getMethodReference(Magic.class, MagicNames.restoreHardwareExceptionState, Registers.class, void.class),
        new InvokeEntryPoint(ArchEntrypoints.restoreHardwareExceptionStateInstructionsField.getOffset(), 1));
  }

  /**
   * Perform dynamic bridge from linker to compiled code
   */
  private static final class DynamicBridgeTo extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      if (VM.VerifyAssertions) VM._assert(cm.getDeclaringClass().hasDynamicBridgeAnnotation());

      // save the branch address for later
      asm.emitPOP_Reg(S0);             // S0<-code address

      asm.emitADD_Reg_Imm(SP, sd.toInt() - 4); // just popped 4 bytes above.

      if (SSE2_FULL) {
        // TODO: Restore SSE2 Control word?
        asm.emitMOVQ_Reg_RegDisp(XMM0, SP, XMM_SAVE_OFFSET.plus(0));
        asm.emitMOVQ_Reg_RegDisp(XMM1, SP, XMM_SAVE_OFFSET.plus(8));
        asm.emitMOVQ_Reg_RegDisp(XMM2, SP, XMM_SAVE_OFFSET.plus(16));
        asm.emitMOVQ_Reg_RegDisp(XMM3, SP, XMM_SAVE_OFFSET.plus(24));
      } else {
        // restore FPU state
        asm.emitFRSTOR_RegDisp(SP, FPU_SAVE_OFFSET);
      }

      // restore GPRs
      asm.emitMOV_Reg_RegDisp(T0, SP, T0_SAVE_OFFSET);
      asm.emitMOV_Reg_RegDisp(T1, SP, T1_SAVE_OFFSET);
      asm.emitMOV_Reg_RegDisp(EBX, SP, EBX_SAVE_OFFSET);
      asm.emitMOV_Reg_RegDisp(EDI, SP, EDI_SAVE_OFFSET);

      // pop frame
      asm.emitPOP_RegDisp(PR, ArchEntrypoints.framePointerField.getOffset()); // FP<-previous FP

      // branch
      asm.emitJMP_Reg(S0);
    }
  }
  static {
    MagicGenerator g = new DynamicBridgeTo();
    generators.put(getMethodReference(Magic.class, MagicNames.dynamicBridgeTo, CodeArray.class, void.class), g);
  }

  /**
   * Exchange stacks
   */
  private static final class ReturnToNewStack extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      // SP gets frame pointer for new stack
      asm.emitPOP_Reg(SP);

      // restore nonvolatile registers
      asm.emitMOV_Reg_RegDisp(EDI, SP, EDI_SAVE_OFFSET);
      asm.emitMOV_Reg_RegDisp(EBX, SP, EBX_SAVE_OFFSET);

      // discard current stack frame
      asm.emitPOP_RegDisp(PR, ArchEntrypoints.framePointerField.getOffset());

      // return to caller- pop parameters from stack
      int parameterWords = cm.getParameterWords() + (cm.isStatic() ? 0 : 1); // add 1 for this pointer
      asm.emitRET_Imm(parameterWords << LG_WORDSIZE);
    }
  }
  static {
    MagicGenerator g = new ReturnToNewStack();
    generators.put(getMethodReference(Magic.class, MagicNames.returnToNewStack, Address.class, void.class), g);
  }

  /**
   * Boot up calling of class initializers
   */
  private static final class InvokeClassInitializer extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(S0);
      asm.emitCALL_Reg(S0); // call address just popped
    }
  }
  static {
    MagicGenerator g = new InvokeClassInitializer();
    generators.put(getMethodReference(Magic.class, MagicNames.invokeClassInitializer, CodeArray.class, void.class), g);
  }

  /**
   * Get frame pointer on entry to method
   */
  private static final class GetFramePointer extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitLEA_Reg_RegDisp(S0, SP, sd);
      asm.emitPUSH_Reg(S0);
    }
  }
  static {
    MagicGenerator g = new GetFramePointer();
    generators.put(getMethodReference(Magic.class, MagicNames.getFramePointer, Address.class), g);
  }

  /**
   * Load an address from the stack and load the value at it plus a displacement
   */
  private static final class GetValueAtDisplacement extends MagicGenerator {
    final Offset disp;
    GetValueAtDisplacement(Offset disp) {
      this.disp = disp;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);
      asm.emitPUSH_RegDisp(T0, disp);
    }
  }
  static {
    generators.put(getMethodReference(Magic.class, MagicNames.getCallerFramePointer, Address.class, Address.class),
        new GetValueAtDisplacement(Offset.fromIntSignExtend(STACKFRAME_FRAME_POINTER_OFFSET)));
    generators.put(getMethodReference(Magic.class, MagicNames.getCompiledMethodID, Address.class, int.class),
        new GetValueAtDisplacement(Offset.fromIntSignExtend(STACKFRAME_METHOD_ID_OFFSET)));
    MagicGenerator g = new GetValueAtDisplacement(ObjectModel.getArrayLengthOffset());
    generators.put(getMethodReference(Magic.class, MagicNames.getArrayLength, Object.class, int.class), g);
    Class<?>[] unboxedTypes = new Class<?>[]{AddressArray.class, CodeArray.class, ExtentArray.class, FunctionTable.class, IMT.class, ObjectReferenceArray.class, OffsetArray.class, ProcessorTable.class, TIB.class, WordArray.class};
    for (Class<?> type : unboxedTypes) {
      generators.put(getMethodReference(type, MagicNames.addressArrayLength, int.class), g);
    }
  }

  /**
   * Store a value to an address from the stack plus a displacement
   */
  private static final class SetValueAtDisplacement extends MagicGenerator {
    final Offset disp;
    SetValueAtDisplacement(Offset disp) {
      this.disp = disp;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0);  // value
      asm.emitPOP_Reg(S0);  // fp
      asm.emitMOV_RegDisp_Reg(S0, disp, T0); // [S0+disp] <- T0
    }
  }
  static {
    generators.put(getMethodReference(Magic.class, MagicNames.setCallerFramePointer, Address.class, Address.class, void.class),
        new SetValueAtDisplacement(Offset.fromIntSignExtend(STACKFRAME_FRAME_POINTER_OFFSET)));
    generators.put(getMethodReference(Magic.class, MagicNames.setCompiledMethodID, Address.class, int.class, void.class),
        new SetValueAtDisplacement(Offset.fromIntSignExtend(STACKFRAME_METHOD_ID_OFFSET)));
  }

  /**
   * Create an array for a runtime table
   * @see org.jikesrvm.objectmodel.RuntimeTable
   */
  private static final class CreateArray extends MagicGenerator {
    private final RVMArray array;
    CreateArray(RVMArray array) {
      this.array = array;
    }
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      int width = array.getLogElementSize();
      Offset tibOffset = array.getTibOffset();
      int headerSize = ObjectModel.computeHeaderSize(array);
      int whichAllocator = MemoryManager.pickAllocator(array, cm);
      int site = MemoryManager.getAllocationSite(true);
      int align = ObjectModel.getAlignment(array);
      int offset = ObjectModel.getOffsetForAlignment(array, false);
      // count is already on stack- nothing required
      asm.emitPUSH_Imm(width);                 // logElementSize
      asm.emitPUSH_Imm(headerSize);            // headerSize
      asm.emitPUSH_Abs(Magic.getTocPointer().plus(tibOffset));   // tib
      asm.emitPUSH_Imm(whichAllocator);        // allocator
      asm.emitPUSH_Imm(align);
      asm.emitPUSH_Imm(offset);
      asm.emitPUSH_Imm(site);
      BaselineCompilerImpl.genParameterRegisterLoad(asm, 8);             // pass 8 parameter words
      asm.emitCALL_Abs(Magic.getTocPointer().plus(Entrypoints.resolvedNewArrayMethod.getOffset()));
      asm.emitPUSH_Reg(T0);
    }
  }
  static {
    Class<?>[] unboxedTypes = new Class<?>[] { AddressArray.class,
        CodeArray.class, ExtentArray.class, ObjectReferenceArray.class,
        OffsetArray.class, WordArray.class };
    for (Class<?> type : unboxedTypes) {
      MagicGenerator g = new CreateArray(TypeReference.findOrCreate(type).resolve().asArray());
      generators.put(getMethodReference(type, MagicNames.addressArrayCreate, int.class, type), g);
    }
  }

  /**
   * Get an element from a runtime table
   * @see org.jikesrvm.objectmodel.RuntimeTable#get(int)
   */
  private static final class Load32_Array extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitMOV_Reg_RegInd(T0, SP);            // T0 is array index
      asm.emitMOV_Reg_RegDisp(S0, SP, ONE_SLOT); // S0 is array ref
      asm.emitADD_Reg_Imm(SP, WORDSIZE * 2);     // complete popping the 2 args
      BaselineCompilerImpl.genBoundsCheck(asm, T0, S0); // T0 is index, S0 is address of array
      // push [S0+T0<<2]
      asm.emitPUSH_RegIdx(S0, T0, Assembler.WORD, NO_SLOT);
    }
  }
  static {
    MagicGenerator g = new Load32_Array();
    Class<?>[] unboxedTypes = new Class<?>[] { AddressArray.class,
        ExtentArray.class, FunctionTable.class, IMT.class,
        ObjectReferenceArray.class, OffsetArray.class, ProcessorTable.class,
        TIB.class, WordArray.class };
    Class<?>[] resultTypes = new Class<?>[] { Address.class, Extent.class,
        CodeArray.class, CodeArray.class, ObjectReference.class, Offset.class,
        Processor.class, Object.class, Word.class };
    for (int i=0; i < unboxedTypes.length; i++) {
      Class<?> type = unboxedTypes[i];
      Class<?> result = resultTypes[i];
      generators.put(getMethodReference(type, MagicNames.addressArrayGet, int.class, result), g);
    }
  }

  /**
   * Get a byte element from a runtime table
   */
  private static final class LoadByte_Array extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPOP_Reg(T0); // T0 is array index
      asm.emitPOP_Reg(S0); // S0 is array ref
      BaselineCompilerImpl.genBoundsCheck(asm, T0, S0); // T0 is index, S0 is address of array
      // T1 = (int)[S0+T0<<1]
      asm.emitMOVSX_Reg_RegIdx_Byte(T1, S0, T0, Assembler.BYTE, NO_SLOT);
      asm.emitPUSH_Reg(T1);        // push byte onto stack
    }
  }
  static {
    MagicGenerator g = new LoadByte_Array();
    generators.put(getMethodReference(CodeArray.class, MagicNames.addressArrayGet, int.class, byte.class), g);
  }

  /**
   * Store an element to a runtime table
   * @see org.jikesrvm.objectmodel.RuntimeTable#set(int, Object)
   */
  private static final class Store32_Array extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      Barriers.compileModifyCheck(asm, 8);
      asm.emitPOP_Reg(T1); // T1 is the value
      asm.emitPOP_Reg(T0); // T0 is array index
      asm.emitPOP_Reg(S0); // S0 is array ref
      BaselineCompilerImpl.genBoundsCheck(asm, T0, S0);                // T0 is index, S0 is address of array
      asm.emitMOV_RegIdx_Reg(S0, T0, Assembler.WORD, NO_SLOT, T1); // [S0 + T0<<2] <- T1
    }
  }
  static {
    MagicGenerator g = new Store32_Array();
    Class<?>[] unboxedTypes = new Class<?>[] { AddressArray.class,
        ExtentArray.class, FunctionTable.class, IMT.class,
        ObjectReferenceArray.class, OffsetArray.class, ProcessorTable.class,
        TIB.class, WordArray.class };
    Class<?>[] operandTypes = new Class<?>[] { Address.class, Extent.class,
        CodeArray.class, CodeArray.class, ObjectReference.class, Offset.class,
        Processor.class, Object.class, Word.class };
    for (int i=0; i < unboxedTypes.length; i++) {
      Class<?> type = unboxedTypes[i];
      Class<?> operand = operandTypes[i];
      generators.put(getMethodReference(type, MagicNames.addressArraySet, int.class, operand, void.class), g);
    }
  }

  /**
   * Set a byte in a runtime table
   */
  private static final class StoreByte_Array extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      Barriers.compileModifyCheck(asm, 8);
      asm.emitPOP_Reg(T1); // T1 is the value
      asm.emitPOP_Reg(T0); // T0 is array index
      asm.emitPOP_Reg(S0); // S0 is array ref
      BaselineCompilerImpl.genBoundsCheck(asm, T0, S0);                // T0 is index, S0 is address of array
      asm.emitMOV_RegIdx_Reg_Byte(S0, T0, Assembler.BYTE, NO_SLOT, T1); // [S0 + T0<<2] <- T1
    }
  }
  static {
    MagicGenerator g = new StoreByte_Array();
    generators.put(getMethodReference(CodeArray.class, MagicNames.addressArraySet, int.class, byte.class, void.class), g);
  }

  /**
   * Create address that holds return address
   */
  private static final class GetReturnAddressLocation extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitADD_RegInd_Imm(SP, STACKFRAME_RETURN_ADDRESS_OFFSET);
    }
  }
  static {
    MagicGenerator g = new GetReturnAddressLocation();
    generators.put(getMethodReference(Magic.class, MagicNames.getReturnAddressLocation, Address.class, Address.class), g);
  }

  /**
   * Get a 64bit time base value (not accurate on certain multi-cores)
   */
  private static final class GetTimeBase extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitRDTSC();       // read timestamp counter instruction
      asm.emitPUSH_Reg(EDX); // upper 32 bits
      asm.emitPUSH_Reg(EAX); // lower 32 bits
    }
  }
  static {
    MagicGenerator g = new GetTimeBase();
    generators.put(getMethodReference(Magic.class, MagicNames.getTimeBase, long.class), g);
  }

  /**
   * Pause hint that thread is contending for a lock
   */
  private static final class Pause extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      asm.emitPAUSE();
    }
  }
  static {
    MagicGenerator g = new Pause();
    generators.put(getMethodReference(Magic.class, MagicNames.pause, void.class), g);
  }

  /**
   * Floating point square root
   */
  private static final class Fsqrt extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      if (SSE2_BASE) {
        asm.emitSQRTSS_Reg_RegInd(XMM0, SP);            // XMM0 = sqrt(value)
        asm.emitMOVSS_RegInd_Reg(SP, XMM0);            // set result on stack
      } else {
        VM.sysFail("Hardware sqrt only available for SSE");
      }
    }
  }
  static {
    MagicGenerator g = new Fsqrt();
    generators.put(getMethodReference(Magic.class, MagicNames.sqrt, float.class, float.class), g);
  }

  /**
   * Double precision square root
   */
  private static final class Dsqrt extends MagicGenerator {
    void generateMagic(Assembler asm, MethodReference m, RVMMethod cm, Offset sd) {
      if (SSE2_BASE) {
        asm.emitSQRTSD_Reg_RegInd(XMM0, SP);            // XMM0 = sqrt(value)
        asm.emitMOVLPD_RegInd_Reg(SP, XMM0);            // set result on stack
      } else {
        VM.sysFail("Hardware sqrt only available for SSE");
      }
    }
  }
  static {
    MagicGenerator g = new Dsqrt();
    generators.put(getMethodReference(Magic.class, MagicNames.sqrt, double.class, double.class), g);
  }
}
