Merge "Handle all known tag types in StackFrame.GetValues." into dalvik-dev
diff --git a/build/Android.common.mk b/build/Android.common.mk
index dd92042..aee7bdd 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -239,7 +239,6 @@
 	src/compiler/codegen/arm/ArchUtility.cc \
 	src/compiler/codegen/arm/ArmRallocUtil.cc \
 	src/compiler/codegen/arm/Assemble.cc \
-	src/compiler/codegen/arm/LocalOptimizations.cc \
 	src/compiler/codegen/arm/armv7-a/Codegen.cc \
 	src/jni_internal_arm.cc \
 	src/jni_internal_x86.cc
diff --git a/src/compiler/Compiler.h b/src/compiler/Compiler.h
index 16a48df..a7dc798 100644
--- a/src/compiler/Compiler.h
+++ b/src/compiler/Compiler.h
@@ -32,10 +32,19 @@
 #define DEBUGGER_METHOD_ENTRY -1
 #define DEBUGGER_METHOD_EXIT -2
 
+/*
+ * Assembly is an iterative process, and usually terminates within
+ * two or three passes.  This should be high enough to handle bizarre
+ * cases, but detect an infinite loop bug.
+ */
+#define MAX_ASSEMBLER_RETRIES 50
+
 typedef enum OatInstructionSetType {
     DALVIK_OAT_NONE = 0,
     DALVIK_OAT_ARM,
     DALVIK_OAT_THUMB2,
+    DALVIK_OAT_IA32,
+    DALVIK_OAT_MIPS32
 } OatInstructionSetType;
 
 /* Supress optimization if corresponding bit set */
@@ -206,6 +215,8 @@
 u8 oatGetRegResourceMask(int reg);
 void oatDumpCFG(struct CompilationUnit* cUnit, const char* dirPrefix);
 void oatProcessSwitchTables(CompilationUnit* cUnit);
+bool oatIsFpReg(int reg);
+uint32_t oatFpRegMask(void);
 
 }  // namespace art
 
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 9a992a1..66cc322 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -56,6 +56,34 @@
     s2 sRegLow;           // SSA name for low Dalvik word
 } RegLocation;
 
+ /*
+ * Data structure tracking the mapping between a Dalvik register (pair) and a
+ * native register (pair). The idea is to reuse the previously loaded value
+ * if possible, otherwise to keep the value in a native register as long as
+ * possible.
+ */
+typedef struct RegisterInfo {
+    int reg;                    // Reg number
+    bool inUse;                 // Has it been allocated?
+    bool isTemp;                // Can allocate as temp?
+    bool pair;                  // Part of a register pair?
+    int partner;                // If pair, other reg of pair
+    bool live;                  // Is there an associated SSA name?
+    bool dirty;                 // If live, is it dirty?
+    int sReg;                   // Name of live value
+    struct LIR *defStart;       // Starting inst in last def sequence
+    struct LIR *defEnd;         // Ending inst in last def sequence
+} RegisterInfo;
+
+typedef struct RegisterPool {
+    int numCoreRegs;
+    RegisterInfo *coreRegs;
+    int nextCoreReg;
+    int numFPRegs;
+    RegisterInfo *FPRegs;
+    int nextFPReg;
+} RegisterPool;
+
 #define INVALID_SREG (-1)
 #define INVALID_VREG (0xFFFFU)
 #define INVALID_REG (0xFF)
@@ -342,6 +370,17 @@
      struct Memstats* mstats;
 } CompilationUnit;
 
+typedef enum OpSize {
+    kWord,
+    kLong,
+    kSingle,
+    kDouble,
+    kUnsignedHalf,
+    kSignedHalf,
+    kUnsignedByte,
+    kSignedByte,
+} OpSize;
+
 BasicBlock* oatNewBB(CompilationUnit* cUnit, BBType blockType, int blockId);
 
 void oatAppendMIR(BasicBlock* bb, MIR* mir);
diff --git a/src/compiler/Ralloc.cc b/src/compiler/Ralloc.cc
index b450393..bf9cb6a 100644
--- a/src/compiler/Ralloc.cc
+++ b/src/compiler/Ralloc.cc
@@ -293,9 +293,10 @@
              i, storageName[table[i].location], table[i].wide ? 'W' : 'N',
              table[i].defined ? 'D' : 'U', table[i].fp ? 'F' : 'C',
              table[i].highWord ? 'H' : 'L', table[i].home ? 'h' : 't',
-             FPREG(table[i].lowReg) ? 's' : 'r', table[i].lowReg & FP_REG_MASK,
-             FPREG(table[i].highReg) ? 's' : 'r', table[i].highReg & FP_REG_MASK,
-             table[i].sRegLow);
+             oatIsFpReg(table[i].lowReg) ? 's' : 'r',
+             table[i].lowReg & oatFpRegMask(),
+             oatIsFpReg(table[i].highReg) ? 's' : 'r',
+             table[i].highReg & oatFpRegMask(), table[i].sRegLow);
         LOG(INFO) << buf;
     }
 }
diff --git a/src/compiler/codegen/CodegenFactory.cc b/src/compiler/codegen/CodegenFactory.cc
index 4b2fd4a..d141156 100644
--- a/src/compiler/codegen/CodegenFactory.cc
+++ b/src/compiler/codegen/CodegenFactory.cc
@@ -28,6 +28,8 @@
  * Prior to including this file, TGT_LIR should be #defined.
  * For example, for arm:
  *    #define TGT_LIR ArmLIR
+ * for MIPS:
+ *    #define TGT_LIR MipsLIR
  * and for x86:
  *    #define TGT_LIR X86LIR
  */
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
new file mode 100644
index 0000000..1f05a17
--- /dev/null
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+STATIC void pushWord(std::vector<uint16_t>&buf, int data) {
+    buf.push_back( data & 0xffff);
+    buf.push_back( (data >> 16) & 0xffff);
+}
+
+void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
+    while (buf.size() < (offset/2))
+        buf.push_back(0);
+}
+
+/* Write the literal pool to the output stream */
+STATIC void installLiteralPools(CompilationUnit* cUnit)
+{
+    alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
+    TGT_LIR* dataLIR = (TGT_LIR*) cUnit->literalList;
+    while (dataLIR != NULL) {
+        pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
+        dataLIR = NEXT_LIR(dataLIR);
+    }
+}
+
+/* Write the switch tables to the output stream */
+STATIC void installSwitchTables(CompilationUnit* cUnit)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
+    while (true) {
+        SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        alignBuffer(cUnit->codeBuffer, tabRec->offset);
+        int bxOffset = tabRec->bxInst->generic.offset + 4;
+        if (cUnit->printMe) {
+            LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
+        }
+        if (tabRec->table[0] == kSparseSwitchSignature) {
+            int* keys = (int*)&(tabRec->table[2]);
+            for (int elems = 0; elems < tabRec->table[1]; elems++) {
+                int disp = tabRec->targets[elems]->generic.offset - bxOffset;
+                if (cUnit->printMe) {
+                    LOG(INFO) << "    Case[" << elems << "] key: 0x" <<
+                        std::hex << keys[elems] << ", disp: 0x" <<
+                        std::hex << disp;
+                }
+                pushWord(cUnit->codeBuffer, keys[elems]);
+                pushWord(cUnit->codeBuffer,
+                    tabRec->targets[elems]->generic.offset - bxOffset);
+            }
+        } else {
+            DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
+            for (int elems = 0; elems < tabRec->table[1]; elems++) {
+                int disp = tabRec->targets[elems]->generic.offset - bxOffset;
+                if (cUnit->printMe) {
+                    LOG(INFO) << "    Case[" << elems << "] disp: 0x" <<
+                        std::hex << disp;
+                }
+                pushWord(cUnit->codeBuffer,
+                         tabRec->targets[elems]->generic.offset - bxOffset);
+            }
+        }
+    }
+}
+
+/* Write the fill array dta to the output stream */
+STATIC void installFillArrayData(CompilationUnit* cUnit)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
+    while (true) {
+        FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        alignBuffer(cUnit->codeBuffer, tabRec->offset);
+        for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
+            cUnit->codeBuffer.push_back( tabRec->table[i]);
+        }
+    }
+}
+
+STATIC int assignLiteralOffsetCommon(LIR* lir, int offset)
+{
+    for (;lir != NULL; lir = lir->next) {
+        lir->offset = offset;
+        offset += 4;
+    }
+    return offset;
+}
+
+STATIC void createMappingTable(CompilationUnit* cUnit)
+{
+    TGT_LIR* tgtLIR;
+    int currentDalvikOffset = -1;
+
+    for (tgtLIR = (TGT_LIR *) cUnit->firstLIRInsn;
+         tgtLIR;
+         tgtLIR = NEXT_LIR(tgtLIR)) {
+        if ((tgtLIR->opcode >= 0) && !tgtLIR->flags.isNop &&
+            (currentDalvikOffset != tgtLIR->generic.dalvikOffset)) {
+            // Changed - need to emit a record
+            cUnit->mappingTable.push_back(tgtLIR->generic.offset);
+            cUnit->mappingTable.push_back(tgtLIR->generic.dalvikOffset);
+            currentDalvikOffset = tgtLIR->generic.dalvikOffset;
+        }
+    }
+}
+
+/* Determine the offset of each literal field */
+STATIC int assignLiteralOffset(CompilationUnit* cUnit, int offset)
+{
+    offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
+    return offset;
+}
+
+STATIC int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
+    while (true) {
+        SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        tabRec->offset = offset;
+        if (tabRec->table[0] == kSparseSwitchSignature) {
+            offset += tabRec->table[1] * (sizeof(int) * 2);
+        } else {
+            DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
+            offset += tabRec->table[1] * sizeof(int);
+        }
+    }
+    return offset;
+}
+
+STATIC int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
+    while (true) {
+        FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        tabRec->offset = offset;
+        offset += tabRec->size;
+        // word align
+        offset = (offset + 3) & ~3;
+        }
+    return offset;
+}
+
+/*
+ * Walk the compilation unit and assign offsets to instructions
+ * and literals and compute the total size of the compiled unit.
+ */
+void oatAssignOffsets(CompilationUnit* cUnit)
+{
+    int offset = oatAssignInsnOffsets(cUnit);
+
+    /* Const values have to be word aligned */
+    offset = (offset + 3) & ~3;
+
+    /* Set up offsets for literals */
+    cUnit->dataOffset = offset;
+
+    offset = assignLiteralOffset(cUnit, offset);
+
+    offset = assignSwitchTablesOffset(cUnit, offset);
+
+    offset = assignFillArrayDataOffset(cUnit, offset);
+
+    cUnit->totalSize = offset;
+}
+
+/*
+ * Go over each instruction in the list and calculate the offset from the top
+ * before sending them off to the assembler. If out-of-range branch distance is
+ * seen rearrange the instructions a bit to correct it.
+ */
+void oatAssembleLIR(CompilationUnit* cUnit)
+{
+    oatAssignOffsets(cUnit);
+    /*
+     * Assemble here.  Note that we generate code with optimistic assumptions
+     * and if found now to work, we'll have to redo the sequence and retry.
+     */
+
+    while (true) {
+        AssemblerStatus res = oatAssembleInstructions(cUnit, 0);
+        if (res == kSuccess) {
+            break;
+        } else {
+            cUnit->assemblerRetries++;
+            if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
+                LOG(FATAL) << "Assembler error - too many retries";
+            }
+            // Redo offsets and try again
+            oatAssignOffsets(cUnit);
+            cUnit->codeBuffer.clear();
+        }
+    }
+
+    // Install literals
+    installLiteralPools(cUnit);
+
+    // Install switch tables
+    installSwitchTables(cUnit);
+
+    // Install fill array data
+    installFillArrayData(cUnit);
+
+    /*
+     * Create the mapping table
+     */
+    createMappingTable(cUnit);
+}
+
+
+
+}  // namespace art
diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/CompilerCodegen.h
index f1ca07a..ae85bb3 100644
--- a/src/compiler/codegen/CompilerCodegen.h
+++ b/src/compiler/codegen/CompilerCodegen.h
@@ -26,6 +26,10 @@
 
 /* Assemble LIR into machine code */
 void oatAssembleLIR(CompilationUnit* cUnit);
+AssemblerStatus oatAssembleInstructions(CompilationUnit* cUnit,
+                                        intptr_t startAddr);
+void oatAssignOffsets(CompilationUnit* cUnit);
+int oatAssignInsnOffsets(CompilationUnit* cUnit);
 
 /* Implemented in the codegen/<target>/ArchUtility.c */
 void oatCodegenDump(CompilationUnit* cUnit);
diff --git a/src/compiler/codegen/arm/LocalOptimizations.cc b/src/compiler/codegen/LocalOptimizations.cc
similarity index 93%
rename from src/compiler/codegen/arm/LocalOptimizations.cc
rename to src/compiler/codegen/LocalOptimizations.cc
index 9098627..cc276f2 100644
--- a/src/compiler/codegen/arm/LocalOptimizations.cc
+++ b/src/compiler/codegen/LocalOptimizations.cc
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-#include "../../Dalvik.h"
-#include "../../CompilerInternals.h"
-#include "ArmLIR.h"
-#include "Codegen.h"
-
 namespace art {
 
 #define DEBUG_OPT(X)
@@ -32,7 +27,7 @@
 #define LDLD_DISTANCE 4
 #define LD_LATENCY 2
 
-STATIC inline bool isDalvikRegisterClobbered(ArmLIR* lir1, ArmLIR* lir2)
+STATIC inline bool isDalvikRegisterClobbered(TGT_LIR* lir1, TGT_LIR* lir2)
 {
     int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->aliasInfo);
     int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->aliasInfo);
@@ -43,11 +38,11 @@
 }
 
 /* Convert a more expensive instruction (ie load) into a move */
-STATIC void convertMemOpIntoMove(CompilationUnit* cUnit, ArmLIR* origLIR,
+STATIC void convertMemOpIntoMove(CompilationUnit* cUnit, TGT_LIR* origLIR,
                                  int dest, int src)
 {
     /* Insert a move to replace the load */
-    ArmLIR* moveLIR;
+    TGT_LIR* moveLIR;
     moveLIR = oatRegCopyNoInsert( cUnit, dest, src);
     /*
      * Insert the converted instruction after the original since the
@@ -77,10 +72,10 @@
  *   2) The memory location is not written to in between
  */
 STATIC void applyLoadStoreElimination(CompilationUnit* cUnit,
-                                      ArmLIR* headLIR,
-                                      ArmLIR* tailLIR)
+                                      TGT_LIR* headLIR,
+                                      TGT_LIR* tailLIR)
 {
-    ArmLIR* thisLIR;
+    TGT_LIR* thisLIR;
 
     if (headLIR == tailLIR) return;
 
@@ -98,7 +93,7 @@
 
         int nativeRegId = thisLIR->operands[0];
         bool isThisLIRLoad = EncodingMap[thisLIR->opcode].flags & IS_LOAD;
-        ArmLIR* checkLIR;
+        TGT_LIR* checkLIR;
         /* Use the mem mask to determine the rough memory location */
         u8 thisMemMask = (thisLIR->useMask | thisLIR->defMask) & ENCODE_MEM;
 
@@ -235,8 +230,8 @@
                                                 "REG CLOBBERED"));
                 /* Only sink store instructions */
                 if (sinkDistance && !isThisLIRLoad) {
-                    ArmLIR* newStoreLIR =
-                        (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR), true,
+                    TGT_LIR* newStoreLIR =
+                        (TGT_LIR* ) oatNew(cUnit, sizeof(TGT_LIR), true,
                                           kAllocLIR);
                     *newStoreLIR = *thisLIR;
                     /*
@@ -261,15 +256,15 @@
  * superblock, to try to hoist loads to earlier slots.
  */
 STATIC void applyLoadHoisting(CompilationUnit* cUnit,
-                              ArmLIR* headLIR,
-                              ArmLIR* tailLIR)
+                              TGT_LIR* headLIR,
+                              TGT_LIR* tailLIR)
 {
-    ArmLIR* thisLIR, *checkLIR;
+    TGT_LIR* thisLIR, *checkLIR;
     /*
      * Store the list of independent instructions that can be hoisted past.
      * Will decide the best place to insert later.
      */
-    ArmLIR* prevInstList[MAX_HOIST_DISTANCE];
+    TGT_LIR* prevInstList[MAX_HOIST_DISTANCE];
 
     /* Empty block */
     if (headLIR == tailLIR) return;
@@ -378,7 +373,7 @@
         if (nextSlot >= 2) {
             int firstSlot = nextSlot - 2;
             int slot;
-            ArmLIR* depLIR = prevInstList[nextSlot-1];
+            TGT_LIR* depLIR = prevInstList[nextSlot-1];
             /* If there is ld-ld dependency, wait LDLD_DISTANCE cycles */
             if (!isPseudoOpcode(depLIR->opcode) &&
                 (EncodingMap[depLIR->opcode].flags & IS_LOAD)) {
@@ -389,8 +384,8 @@
              * when the loop is first entered.
              */
             for (slot = firstSlot; slot >= 0; slot--) {
-                ArmLIR* curLIR = prevInstList[slot];
-                ArmLIR* prevLIR = prevInstList[slot+1];
+                TGT_LIR* curLIR = prevInstList[slot];
+                TGT_LIR* prevLIR = prevInstList[slot+1];
 
                 /* Check the highest instruction */
                 if (prevLIR->defMask == ENCODE_ALL) {
@@ -423,8 +418,8 @@
 
             /* Found a slot to hoist to */
             if (slot >= 0) {
-                ArmLIR* curLIR = prevInstList[slot];
-                ArmLIR* newLoadLIR = (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR),
+                TGT_LIR* curLIR = prevInstList[slot];
+                TGT_LIR* newLoadLIR = (TGT_LIR* ) oatNew(cUnit, sizeof(TGT_LIR),
                                                        true, kAllocLIR);
                 *newLoadLIR = *thisLIR;
                 /*
@@ -442,11 +437,11 @@
                                         LIR* tailLIR)
 {
     if (!(cUnit->disableOpt & (1 << kLoadStoreElimination))) {
-        applyLoadStoreElimination(cUnit, (ArmLIR* ) headLIR,
-                                  (ArmLIR* ) tailLIR);
+        applyLoadStoreElimination(cUnit, (TGT_LIR* ) headLIR,
+                                  (TGT_LIR* ) tailLIR);
     }
     if (!(cUnit->disableOpt & (1 << kLoadHoisting))) {
-        applyLoadHoisting(cUnit, (ArmLIR* ) headLIR, (ArmLIR* ) tailLIR);
+        applyLoadHoisting(cUnit, (TGT_LIR* ) headLIR, (TGT_LIR* ) tailLIR);
     }
 }
 
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
new file mode 100644
index 0000000..72b3d6e
--- /dev/null
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "object_utils.h"
+
+namespace art {
+
+#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
+    (1 << kDebugDisplayMissingTargets))
+
+STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0,
+                                   INVALID_REG, INVALID_REG, INVALID_SREG};
+
+/* Mark register usage state and return long retloc */
+STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE;
+    oatLockTemp(cUnit, res.lowReg);
+    oatLockTemp(cUnit, res.highReg);
+    oatMarkPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN;
+    oatLockTemp(cUnit, res.lowReg);
+    return res;
+}
+
+STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir,
+                      InvokeType type, bool isRange)
+{
+    DecodedInstruction* dInsn = &mir->dalvikInsn;
+    int callState = 0;
+    TGT_LIR* nullCk;
+    TGT_LIR** pNullCk = NULL;
+    NextCallInsn nextCallInsn;
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    // Explicit register usage
+    oatLockCallTemps(cUnit);
+
+    uint32_t dexMethodIdx = dInsn->vB;
+    int vtableIdx;
+    bool skipThis;
+    bool fastPath =
+        cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit, type,
+                                           vtableIdx)
+        && !SLOW_INVOKE_PATH;
+    if (type == kInterface) {
+      nextCallInsn = fastPath ? nextInterfaceCallInsn
+                              : nextInterfaceCallInsnWithAccessCheck;
+      skipThis = false;
+    } else if (type == kDirect) {
+      if (fastPath) {
+        pNullCk = &nullCk;
+      }
+      nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
+      skipThis = false;
+    } else if (type == kStatic) {
+      nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
+      skipThis = false;
+    } else if (type == kSuper) {
+      nextCallInsn = fastPath ? nextSuperCallInsn : nextSuperCallInsnSP;
+      skipThis = fastPath;
+    } else {
+      DCHECK_EQ(type, kVirtual);
+      nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
+      skipThis = fastPath;
+    }
+    if (!isRange) {
+        callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
+                                         nextCallInsn, dexMethodIdx,
+                                         vtableIdx, skipThis);
+    } else {
+        callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
+                                       nextCallInsn, dexMethodIdx, vtableIdx,
+                                       skipThis);
+    }
+    // Finish up any of the call sequence not interleaved in arg loading
+    while (callState >= 0) {
+        callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
+                                 vtableIdx);
+    }
+    if (DISPLAY_MISSING_TARGETS) {
+        genShowTarget(cUnit);
+    }
+    opReg(cUnit, kOpBlx, rLR);
+    oatClobberCalleeSave(cUnit);
+}
+
+/*
+ * Target-independent code generation.  Use only high-level
+ * load/store utilities here, or target-dependent genXX() handlers
+ * when necessary.
+ */
+STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
+                                     BasicBlock* bb, TGT_LIR* labelList)
+{
+    bool res = false;   // Assume success
+    RegLocation rlSrc[3];
+    RegLocation rlDest = badLoc;
+    RegLocation rlResult = badLoc;
+    Opcode opcode = mir->dalvikInsn.opcode;
+
+    /* Prep Src and Dest locations */
+    int nextSreg = 0;
+    int nextLoc = 0;
+    int attrs = oatDataFlowAttributes[opcode];
+    rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
+    if (attrs & DF_UA) {
+        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
+        nextSreg++;
+    } else if (attrs & DF_UA_WIDE) {
+        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
+                                                 nextSreg + 1);
+        nextSreg+= 2;
+    }
+    if (attrs & DF_UB) {
+        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
+        nextSreg++;
+    } else if (attrs & DF_UB_WIDE) {
+        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
+                                                 nextSreg + 1);
+        nextSreg+= 2;
+    }
+    if (attrs & DF_UC) {
+        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
+    } else if (attrs & DF_UC_WIDE) {
+        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
+                                                 nextSreg + 1);
+    }
+    if (attrs & DF_DA) {
+        rlDest = oatGetDest(cUnit, mir, 0);
+    } else if (attrs & DF_DA_WIDE) {
+        rlDest = oatGetDestWide(cUnit, mir, 0, 1);
+    }
+
+    switch(opcode) {
+        case OP_NOP:
+            break;
+
+        case OP_MOVE_EXCEPTION:
+            int exOffset;
+            int resetReg;
+            exOffset = Thread::ExceptionOffset().Int32Value();
+            resetReg = oatAllocTemp(cUnit);
+            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
+            loadConstant(cUnit, resetReg, 0);
+            storeWordDisp(cUnit, rSELF, exOffset, resetReg);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_RETURN_VOID:
+            genSuspendTest(cUnit, mir);
+            break;
+
+        case OP_RETURN:
+        case OP_RETURN_OBJECT:
+            genSuspendTest(cUnit, mir);
+            storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
+            break;
+
+        case OP_RETURN_WIDE:
+            genSuspendTest(cUnit, mir);
+            storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
+            break;
+
+        case OP_MOVE_RESULT_WIDE:
+            if (mir->optimizationFlags & MIR_INLINED)
+                break;  // Nop - combined w/ previous invoke
+            storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
+            break;
+
+        case OP_MOVE_RESULT:
+        case OP_MOVE_RESULT_OBJECT:
+            if (mir->optimizationFlags & MIR_INLINED)
+                break;  // Nop - combined w/ previous invoke
+            storeValue(cUnit, rlDest, getRetLoc(cUnit));
+            break;
+
+        case OP_MOVE:
+        case OP_MOVE_OBJECT:
+        case OP_MOVE_16:
+        case OP_MOVE_OBJECT_16:
+        case OP_MOVE_FROM16:
+        case OP_MOVE_OBJECT_FROM16:
+            storeValue(cUnit, rlDest, rlSrc[0]);
+            break;
+
+        case OP_MOVE_WIDE:
+        case OP_MOVE_WIDE_16:
+        case OP_MOVE_WIDE_FROM16:
+            storeValueWide(cUnit, rlDest, rlSrc[0]);
+            break;
+
+        case OP_CONST:
+        case OP_CONST_4:
+        case OP_CONST_16:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_HIGH16:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantNoClobber(cUnit, rlResult.lowReg,
+                                  mir->dalvikInsn.vB << 16);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_WIDE_16:
+        case OP_CONST_WIDE_32:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+                                  mir->dalvikInsn.vB,
+                                  (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_WIDE:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+                          mir->dalvikInsn.vB_wide & 0xffffffff,
+                          (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_WIDE_HIGH16:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+                                  0, mir->dalvikInsn.vB << 16);
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_MONITOR_ENTER:
+            genMonitorEnter(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_MONITOR_EXIT:
+            genMonitorExit(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_CHECK_CAST:
+            genCheckCast(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_INSTANCE_OF:
+            genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_NEW_INSTANCE:
+            genNewInstance(cUnit, mir, rlDest);
+            break;
+
+        case OP_THROW:
+            genThrow(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_THROW_VERIFICATION_ERROR:
+            genThrowVerificationError(cUnit, mir);
+            break;
+
+        case OP_ARRAY_LENGTH:
+            int lenOffset;
+            lenOffset = Array::LengthOffset().Int32Value();
+            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
+            genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
+            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
+                         rlResult.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_STRING:
+        case OP_CONST_STRING_JUMBO:
+            genConstString(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_CONST_CLASS:
+            genConstClass(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_FILL_ARRAY_DATA:
+            genFillArrayData(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_FILLED_NEW_ARRAY:
+            genFilledNewArray(cUnit, mir, false /* not range */);
+            break;
+
+        case OP_FILLED_NEW_ARRAY_RANGE:
+            genFilledNewArray(cUnit, mir, true /* range */);
+            break;
+
+        case OP_NEW_ARRAY:
+            genNewArray(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_GOTO:
+        case OP_GOTO_16:
+        case OP_GOTO_32:
+            if (bb->taken->startOffset <= mir->offset) {
+                genSuspendTest(cUnit, mir);
+            }
+            genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
+            break;
+
+        case OP_PACKED_SWITCH:
+            genPackedSwitch(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_SPARSE_SWITCH:
+            genSparseSwitch(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_CMPL_FLOAT:
+        case OP_CMPG_FLOAT:
+        case OP_CMPL_DOUBLE:
+        case OP_CMPG_DOUBLE:
+            res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_CMP_LONG:
+            genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_IF_EQ:
+        case OP_IF_NE:
+        case OP_IF_LT:
+        case OP_IF_GE:
+        case OP_IF_GT:
+        case OP_IF_LE: {
+            bool backwardBranch;
+            backwardBranch = (bb->taken->startOffset <= mir->offset);
+            if (backwardBranch) {
+                genSuspendTest(cUnit, mir);
+            }
+            genCompareAndBranch(cUnit, bb, mir, rlSrc[0], rlSrc[1], labelList);
+            break;
+            }
+
+        case OP_IF_EQZ:
+        case OP_IF_NEZ:
+        case OP_IF_LTZ:
+        case OP_IF_GEZ:
+        case OP_IF_GTZ:
+        case OP_IF_LEZ: {
+            bool backwardBranch;
+            backwardBranch = (bb->taken->startOffset <= mir->offset);
+            if (backwardBranch) {
+                genSuspendTest(cUnit, mir);
+            }
+            genCompareZeroAndBranch(cUnit, bb, mir, rlSrc[0], labelList);
+            break;
+            }
+
+      case OP_AGET_WIDE:
+            genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
+            break;
+        case OP_AGET:
+        case OP_AGET_OBJECT:
+            genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
+            break;
+        case OP_AGET_BOOLEAN:
+            genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
+                        rlDest, 0);
+            break;
+        case OP_AGET_BYTE:
+            genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
+            break;
+        case OP_AGET_CHAR:
+            genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
+                        rlDest, 1);
+            break;
+        case OP_AGET_SHORT:
+            genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
+            break;
+        case OP_APUT_WIDE:
+            genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
+            break;
+        case OP_APUT:
+            genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
+            break;
+        case OP_APUT_OBJECT:
+            genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
+            break;
+        case OP_APUT_SHORT:
+        case OP_APUT_CHAR:
+            genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
+                        rlSrc[0], 1);
+            break;
+        case OP_APUT_BYTE:
+        case OP_APUT_BOOLEAN:
+            genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
+                        rlSrc[0], 0);
+            break;
+
+        case OP_IGET_OBJECT:
+        case OP_IGET_OBJECT_VOLATILE:
+            genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, true);
+            break;
+
+        case OP_IGET_WIDE:
+        case OP_IGET_WIDE_VOLATILE:
+            genIGet(cUnit, mir, kLong, rlDest, rlSrc[0], true, false);
+            break;
+
+        case OP_IGET:
+        case OP_IGET_VOLATILE:
+            genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, false);
+            break;
+
+        case OP_IGET_CHAR:
+            genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0], false, false);
+            break;
+
+        case OP_IGET_SHORT:
+            genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0], false, false);
+            break;
+
+        case OP_IGET_BOOLEAN:
+        case OP_IGET_BYTE:
+            genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0], false, false);
+            break;
+
+        case OP_IPUT_WIDE:
+        case OP_IPUT_WIDE_VOLATILE:
+            genIPut(cUnit, mir, kLong, rlSrc[0], rlSrc[1], true, false);
+            break;
+
+        case OP_IPUT_OBJECT:
+        case OP_IPUT_OBJECT_VOLATILE:
+            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, true);
+            break;
+
+        case OP_IPUT:
+        case OP_IPUT_VOLATILE:
+            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, false);
+            break;
+
+        case OP_IPUT_BOOLEAN:
+        case OP_IPUT_BYTE:
+            genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false, false);
+            break;
+
+        case OP_IPUT_CHAR:
+            genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false);
+            break;
+
+        case OP_IPUT_SHORT:
+            genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false, false);
+            break;
+
+        case OP_SGET_OBJECT:
+            genSget(cUnit, mir, rlDest, false, true);
+            break;
+        case OP_SGET:
+        case OP_SGET_BOOLEAN:
+        case OP_SGET_BYTE:
+        case OP_SGET_CHAR:
+        case OP_SGET_SHORT:
+            genSget(cUnit, mir, rlDest, false, false);
+            break;
+
+        case OP_SGET_WIDE:
+            genSget(cUnit, mir, rlDest, true, false);
+            break;
+
+        case OP_SPUT_OBJECT:
+            genSput(cUnit, mir, rlSrc[0], false, true);
+            break;
+
+        case OP_SPUT:
+        case OP_SPUT_BOOLEAN:
+        case OP_SPUT_BYTE:
+        case OP_SPUT_CHAR:
+        case OP_SPUT_SHORT:
+            genSput(cUnit, mir, rlSrc[0], false, false);
+            break;
+
+        case OP_SPUT_WIDE:
+            genSput(cUnit, mir, rlSrc[0], true, false);
+            break;
+
+        case OP_INVOKE_STATIC_RANGE:
+            genInvoke(cUnit, mir, kStatic, true /*range*/);
+            break;
+        case OP_INVOKE_STATIC:
+            genInvoke(cUnit, mir, kStatic, false /*range*/);
+            break;
+
+        case OP_INVOKE_DIRECT:
+            genInvoke(cUnit, mir, kDirect, false /*range*/);
+            break;
+        case OP_INVOKE_DIRECT_RANGE:
+            genInvoke(cUnit, mir, kDirect, true /*range*/);
+            break;
+
+        case OP_INVOKE_VIRTUAL:
+            genInvoke(cUnit, mir, kVirtual, false /*range*/);
+            break;
+        case OP_INVOKE_VIRTUAL_RANGE:
+            genInvoke(cUnit, mir, kVirtual, true /*range*/);
+            break;
+
+        case OP_INVOKE_SUPER:
+            genInvoke(cUnit, mir, kSuper, false /*range*/);
+            break;
+        case OP_INVOKE_SUPER_RANGE:
+            genInvoke(cUnit, mir, kSuper, true /*range*/);
+            break;
+
+        case OP_INVOKE_INTERFACE:
+            genInvoke(cUnit, mir, kInterface, false /*range*/);
+            break;
+        case OP_INVOKE_INTERFACE_RANGE:
+            genInvoke(cUnit, mir, kInterface, true /*range*/);
+            break;
+
+        case OP_NEG_INT:
+        case OP_NOT_INT:
+            res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+            break;
+
+        case OP_NEG_LONG:
+        case OP_NOT_LONG:
+            res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+            break;
+
+        case OP_NEG_FLOAT:
+            res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+            break;
+
+        case OP_NEG_DOUBLE:
+            res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+            break;
+
+        case OP_INT_TO_LONG:
+            genIntToLong(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_LONG_TO_INT:
+            rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
+            rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
+            storeValue(cUnit, rlDest, rlSrc[0]);
+            break;
+
+        case OP_INT_TO_BYTE:
+        case OP_INT_TO_SHORT:
+        case OP_INT_TO_CHAR:
+            genIntNarrowing(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_INT_TO_FLOAT:
+        case OP_INT_TO_DOUBLE:
+        case OP_LONG_TO_FLOAT:
+        case OP_LONG_TO_DOUBLE:
+        case OP_FLOAT_TO_INT:
+        case OP_FLOAT_TO_LONG:
+        case OP_FLOAT_TO_DOUBLE:
+        case OP_DOUBLE_TO_INT:
+        case OP_DOUBLE_TO_LONG:
+        case OP_DOUBLE_TO_FLOAT:
+            genConversion(cUnit, mir);
+            break;
+
+        case OP_ADD_INT:
+        case OP_SUB_INT:
+        case OP_MUL_INT:
+        case OP_DIV_INT:
+        case OP_REM_INT:
+        case OP_AND_INT:
+        case OP_OR_INT:
+        case OP_XOR_INT:
+        case OP_SHL_INT:
+        case OP_SHR_INT:
+        case OP_USHR_INT:
+        case OP_ADD_INT_2ADDR:
+        case OP_SUB_INT_2ADDR:
+        case OP_MUL_INT_2ADDR:
+        case OP_DIV_INT_2ADDR:
+        case OP_REM_INT_2ADDR:
+        case OP_AND_INT_2ADDR:
+        case OP_OR_INT_2ADDR:
+        case OP_XOR_INT_2ADDR:
+        case OP_SHL_INT_2ADDR:
+        case OP_SHR_INT_2ADDR:
+        case OP_USHR_INT_2ADDR:
+            genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_ADD_LONG:
+        case OP_SUB_LONG:
+        case OP_MUL_LONG:
+        case OP_DIV_LONG:
+        case OP_REM_LONG:
+        case OP_AND_LONG:
+        case OP_OR_LONG:
+        case OP_XOR_LONG:
+        case OP_ADD_LONG_2ADDR:
+        case OP_SUB_LONG_2ADDR:
+        case OP_MUL_LONG_2ADDR:
+        case OP_DIV_LONG_2ADDR:
+        case OP_REM_LONG_2ADDR:
+        case OP_AND_LONG_2ADDR:
+        case OP_OR_LONG_2ADDR:
+        case OP_XOR_LONG_2ADDR:
+            genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_SHL_LONG:
+        case OP_SHR_LONG:
+        case OP_USHR_LONG:
+        case OP_SHL_LONG_2ADDR:
+        case OP_SHR_LONG_2ADDR:
+        case OP_USHR_LONG_2ADDR:
+            genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_ADD_FLOAT:
+        case OP_SUB_FLOAT:
+        case OP_MUL_FLOAT:
+        case OP_DIV_FLOAT:
+        case OP_REM_FLOAT:
+        case OP_ADD_FLOAT_2ADDR:
+        case OP_SUB_FLOAT_2ADDR:
+        case OP_MUL_FLOAT_2ADDR:
+        case OP_DIV_FLOAT_2ADDR:
+        case OP_REM_FLOAT_2ADDR:
+            genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_ADD_DOUBLE:
+        case OP_SUB_DOUBLE:
+        case OP_MUL_DOUBLE:
+        case OP_DIV_DOUBLE:
+        case OP_REM_DOUBLE:
+        case OP_ADD_DOUBLE_2ADDR:
+        case OP_SUB_DOUBLE_2ADDR:
+        case OP_MUL_DOUBLE_2ADDR:
+        case OP_DIV_DOUBLE_2ADDR:
+        case OP_REM_DOUBLE_2ADDR:
+            genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_RSUB_INT:
+        case OP_ADD_INT_LIT16:
+        case OP_MUL_INT_LIT16:
+        case OP_DIV_INT_LIT16:
+        case OP_REM_INT_LIT16:
+        case OP_AND_INT_LIT16:
+        case OP_OR_INT_LIT16:
+        case OP_XOR_INT_LIT16:
+        case OP_ADD_INT_LIT8:
+        case OP_RSUB_INT_LIT8:
+        case OP_MUL_INT_LIT8:
+        case OP_DIV_INT_LIT8:
+        case OP_REM_INT_LIT8:
+        case OP_AND_INT_LIT8:
+        case OP_OR_INT_LIT8:
+        case OP_XOR_INT_LIT8:
+        case OP_SHL_INT_LIT8:
+        case OP_SHR_INT_LIT8:
+        case OP_USHR_INT_LIT8:
+            genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+            break;
+
+        default:
+            res = true;
+    }
+    return res;
+}
+
+STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
+    "kMirOpPhi",
+    "kMirOpNullNRangeUpCheck",
+    "kMirOpNullNRangeDownCheck",
+    "kMirOpLowerBound",
+    "kMirOpPunt",
+    "kMirOpCheckInlinePrediction",
+};
+
+/* Extended MIR instructions like PHI */
+STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
+{
+    int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
+    char* msg = NULL;
+    if (cUnit->printMe) {
+        msg = (char*)oatNew(cUnit, strlen(extendedMIROpNames[opOffset]) + 1,
+                            false, kAllocDebugInfo);
+        strcpy(msg, extendedMIROpNames[opOffset]);
+    }
+    TGT_LIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
+
+    switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
+        case kMirOpPhi: {
+            char* ssaString = NULL;
+            if (cUnit->printMe) {
+                ssaString = oatGetSSAString(cUnit, mir->ssaRep);
+            }
+            op->flags.isNop = true;
+            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+/* Handle the content in each basic block */
+STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    MIR* mir;
+    TGT_LIR* labelList = (TGT_LIR*) cUnit->blockLabelList;
+    int blockId = bb->id;
+
+    cUnit->curBlock = bb;
+    labelList[blockId].operands[0] = bb->startOffset;
+
+    /* Insert the block label */
+    labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
+    oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
+
+    /* Reset local optimization data on block boundaries */
+    oatResetRegPool(cUnit);
+    oatClobberAllRegs(cUnit);
+    oatResetDefTracking(cUnit);
+
+    TGT_LIR* headLIR = NULL;
+
+    if (bb->blockType == kEntryBlock) {
+        genEntrySequence(cUnit, bb);
+    } else if (bb->blockType == kExitBlock) {
+        genExitSequence(cUnit, bb);
+    }
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+
+        oatResetRegPool(cUnit);
+        if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
+            oatClobberAllRegs(cUnit);
+        }
+
+        if (cUnit->disableOpt & (1 << kSuppressLoads)) {
+            oatResetDefTracking(cUnit);
+        }
+
+        if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
+            handleExtendedMethodMIR(cUnit, mir);
+            continue;
+        }
+
+        cUnit->currentDalvikOffset = mir->offset;
+
+        Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+        InstructionFormat dalvikFormat =
+            dexGetFormatFromOpcode(dalvikOpcode);
+
+        TGT_LIR* boundaryLIR;
+
+        /* Mark the beginning of a Dalvik instruction for line tracking */
+        char* instStr = cUnit->printMe ?
+           oatGetDalvikDisassembly(cUnit, &mir->dalvikInsn, "") : NULL;
+        boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
+                              (intptr_t) instStr);
+        cUnit->boundaryMap.insert(std::make_pair(mir->offset,
+                                 (LIR*)boundaryLIR));
+        /* Remember the first LIR for this block */
+        if (headLIR == NULL) {
+            headLIR = boundaryLIR;
+            /* Set the first boundaryLIR as a scheduling barrier */
+            headLIR->defMask = ENCODE_ALL;
+        }
+
+        /* If we're compiling for the debugger, generate an update callout */
+        if (cUnit->genDebugger) {
+            genDebuggerUpdate(cUnit, mir->offset);
+        }
+
+        /* Don't generate the SSA annotation unless verbose mode is on */
+        if (cUnit->printMe && mir->ssaRep) {
+            char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
+            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
+        }
+
+        bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
+
+        if (notHandled) {
+            char buf[100];
+            snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
+                 mir->offset,
+                 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
+                 dalvikFormat);
+            LOG(FATAL) << buf;
+        }
+    }
+
+    if (headLIR) {
+        /*
+         * Eliminate redundant loads/stores and delay stores into later
+         * slots
+         */
+        oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
+                                           cUnit->lastLIRInsn);
+
+        /*
+         * Generate an unconditional branch to the fallthrough block.
+         */
+        if (bb->fallThrough) {
+            genUnconditionalBranch(cUnit,
+                                   &labelList[bb->fallThrough->id]);
+        }
+    }
+    return false;
+}
+
+void oatMethodMIR2LIR(CompilationUnit* cUnit)
+{
+    /* Used to hold the labels of each block */
+    cUnit->blockLabelList =
+        (void *) oatNew(cUnit, sizeof(TGT_LIR) * cUnit->numBlocks, true,
+                        kAllocLIR);
+
+    oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
+                                  kPreOrderDFSTraversal, false /* Iterative */);
+    handleSuspendLaunchpads(cUnit);
+
+    handleThrowLaunchpads(cUnit);
+
+    removeRedundantBranches(cUnit);
+}
+
+/* Needed by the ld/st optmizatons */
+TGT_LIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
+{
+    return genRegCopyNoInsert(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+void oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
+{
+    genRegCopy(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
+                            int srcLo, int srcHi)
+{
+    genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
+}
+
+void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size)
+{
+    storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
+}
+
+void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi)
+{
+    storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/Ralloc.h b/src/compiler/codegen/Ralloc.h
index e72cdcb..c9e5308 100644
--- a/src/compiler/codegen/Ralloc.h
+++ b/src/compiler/codegen/Ralloc.h
@@ -24,25 +24,18 @@
 #include "../CompilerUtility.h"
 #include "../CompilerIR.h"
 #include "../Dataflow.h"
-#include "arm/ArmLIR.h"
 
 namespace art {
 
-/*
- * Return most flexible allowed register class based on size.
- * Bug: 2813841
- * Must use a core register for data types narrower than word (due
- * to possible unaligned load/store.
- */
-STATIC inline RegisterClass oatRegClassBySize(OpSize size)
-{
-    return (size == kUnsignedHalf ||
-            size == kSignedHalf ||
-            size == kUnsignedByte ||
-            size == kSignedByte ) ? kCoreReg : kAnyReg;
-}
+/* Static register use counts */
+typedef struct RefCounts {
+    int count;
+    int sReg;
+    bool doubleStart;   // Starting vReg for a double
+} RefCounts;
 
-STATIC inline int oatS2VReg(CompilationUnit* cUnit, int sReg)
+
+inline int oatS2VReg(CompilationUnit* cUnit, int sReg)
 {
     DCHECK_NE(sReg, INVALID_SREG);
     return DECODE_REG(oatConvertSSARegToDalvik(cUnit, sReg));
@@ -58,18 +51,18 @@
  * identified by the dataflow pass what it's new name is.
  */
 
-STATIC inline int oatSRegHi(int lowSreg) {
+inline int oatSRegHi(int lowSreg) {
     return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
 }
 
 
-STATIC inline bool oatLiveOut(CompilationUnit* cUnit, int sReg)
+inline bool oatLiveOut(CompilationUnit* cUnit, int sReg)
 {
     //For now.
     return true;
 }
 
-STATIC inline int oatSSASrc(MIR* mir, int num)
+inline int oatSSASrc(MIR* mir, int num)
 {
     DCHECK_GT(mir->ssaRep->numUses, num);
     return mir->ssaRep->uses[num];
@@ -108,7 +101,7 @@
 extern void oatResetDefLoc(CompilationUnit* cUnit, RegLocation rl);
 
 /* Set up temp & preserved register pools specialized by target */
-extern void oatInitPool(RegisterInfo* regs, int* regNums, int num);
+extern void oatInitPool(struct RegisterInfo* regs, int* regNums, int num);
 
 /*
  * Mark the beginning and end LIR of a def sequence.  Note that
@@ -212,6 +205,13 @@
 
 extern void oatFlushReg(CompilationUnit* cUnit, int reg);
 
+extern void oatDoPromotion(CompilationUnit* cUnit);
+extern int oatVRegOffset(CompilationUnit* cUnit, int reg);
+extern int oatSRegOffset(CompilationUnit* cUnit, int reg);
+extern void oatCountRefs(CompilationUnit*, BasicBlock*, RefCounts*, RefCounts*);
+extern int oatSortCounts(const void *val1, const void *val2);
+extern void oatDumpCounts(const RefCounts* arr, int size, const char* msg);
+
 /*
  * Architecture-dependent register allocation routines implemented in
  * ${TARGET_ARCH}/${TARGET_ARCH_VARIANT}/Ralloc.c
@@ -222,8 +222,6 @@
 extern int oatAllocTypedTemp(CompilationUnit* cUnit, bool fpHint,
                              int regClass);
 
-extern ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc);
-
 extern void oatRegCopyWide(CompilationUnit* cUnit, int destLo,
                            int destHi, int srcLo, int srcHi);
 
@@ -233,13 +231,16 @@
 extern void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
                                 int displacement, int rSrcLo, int rSrcHi);
 
-extern void oatDoPromotion(CompilationUnit* cUnit);
-extern int oatVRegOffset(CompilationUnit* cUnit, int reg);
-extern int oatSRegOffset(CompilationUnit* cUnit, int reg);
 extern void oatDumpCoreRegPool(CompilationUnit* cUint);
 extern void oatDumpFPRegPool(CompilationUnit* cUint);
 extern bool oatCheckCorePoolSanity(CompilationUnit* cUnit);
 extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg);
+extern void oatNopLIR(LIR* lir);
+extern bool oatIsFPReg(int reg);
+extern uint32_t oatFPRegMask(void);
+extern void oatAdjustSpillMask(CompilationUnit* cUnit);
+void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg);
+void oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc);
 
 }  // namespace art
 
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc
index 2a4fe59..77fb23b 100644
--- a/src/compiler/codegen/RallocUtil.cc
+++ b/src/compiler/codegen/RallocUtil.cc
@@ -58,7 +58,10 @@
     }
 }
 
- /* Set up temp & preserved register pools specialized by target */
+ /*
+  * Set up temp & preserved register pools specialized by target.
+  * Note: numRegs may be zero.
+  */
 extern void oatInitPool(RegisterInfo* regs, int* regNums, int num)
 {
     int i;
@@ -99,43 +102,6 @@
     dumpRegPool(cUnit->regPool->FPRegs, cUnit->regPool->numFPRegs);
 }
 
-void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
-{
-    RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
-    RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
-    DCHECK(info1 && info2 && info1->pair && info2->pair &&
-           (info1->partner == info2->reg) &&
-           (info2->partner == info1->reg));
-    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
-        if (!(info1->isTemp && info2->isTemp)) {
-            /* Should not happen.  If it does, there's a problem in evalLoc */
-            LOG(FATAL) << "Long half-temp, half-promoted";
-        }
-
-        info1->dirty = false;
-        info2->dirty = false;
-        if (oatS2VReg(cUnit, info2->sReg) <
-            oatS2VReg(cUnit, info1->sReg))
-            info1 = info2;
-        int vReg = oatS2VReg(cUnit, info1->sReg);
-        oatFlushRegWideImpl(cUnit, rSP,
-                                    oatVRegOffset(cUnit, vReg),
-                                    info1->reg, info1->partner);
-    }
-}
-
-void oatFlushReg(CompilationUnit* cUnit, int reg)
-{
-    RegisterInfo* info = oatGetRegInfo(cUnit, reg);
-    if (info->live && info->dirty) {
-        info->dirty = false;
-        int vReg = oatS2VReg(cUnit, info->sReg);
-        oatFlushRegImpl(cUnit, rSP,
-                                oatVRegOffset(cUnit, vReg),
-                                reg, kWord);
-    }
-}
-
 /* Mark a temp register as dead.  Does not affect allocation state. */
 static inline void clobberBody(CompilationUnit *cUnit, RegisterInfo* p)
 {
@@ -204,28 +170,6 @@
 }
 
 /*
- * Mark a callee-save fp register as promoted.  Note that
- * vpush/vpop uses contiguous register lists so we must
- * include any holes in the mask.  Associate holes with
- * Dalvik register INVALID_VREG (0xFFFFU).
- */
-STATIC void markPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
-{
-    DCHECK_GE(reg, FP_REG_MASK + FP_CALLEE_SAVE_BASE);
-    reg = (reg & FP_REG_MASK) - FP_CALLEE_SAVE_BASE;
-    // Ensure fpVmapTable is large enough
-    int tableSize = cUnit->fpVmapTable.size();
-    for (int i = tableSize; i < (reg + 1); i++) {
-        cUnit->fpVmapTable.push_back(INVALID_VREG);
-    }
-    // Add the current mapping
-    cUnit->fpVmapTable[reg] = sReg;
-    // Size of fpVmapTable is high-water mark, use to set mask
-    cUnit->numFPSpills = cUnit->fpVmapTable.size();
-    cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << FP_CALLEE_SAVE_BASE;
-}
-
-/*
  * Reserve a callee-save fp single register.  Try to fullfill request for
  * even/odd  allocation, but go ahead and allocate anything if not
  * available.  If nothing's available, return -1.
@@ -241,7 +185,7 @@
             FPRegs[i].inUse = true;
             //  Should be promoting based on initial sReg set
             DCHECK_EQ(sReg, oatS2VReg(cUnit, sReg));
-            markPreservedSingle(cUnit, sReg, res);
+            oatMarkPreservedSingle(cUnit, sReg, res);
             cUnit->promotionMap[sReg].fpLocation = kLocPhysReg;
             cUnit->promotionMap[sReg].fpReg = res;
             break;
@@ -280,7 +224,7 @@
         res = p->reg;
         p->inUse = true;
         DCHECK_EQ((res & 1), 0);
-        markPreservedSingle(cUnit, sReg, res);
+        oatMarkPreservedSingle(cUnit, sReg, res);
     } else {
         RegisterInfo* FPRegs = cUnit->regPool->FPRegs;
         for (int i = 0; i < cUnit->regPool->numFPRegs; i++) {
@@ -291,10 +235,10 @@
                 (FPRegs[i].reg + 1) == FPRegs[i+1].reg) {
                 res = FPRegs[i].reg;
                 FPRegs[i].inUse = true;
-                markPreservedSingle(cUnit, sReg, res);
+                oatMarkPreservedSingle(cUnit, sReg, res);
                 FPRegs[i+1].inUse = true;
                 DCHECK_EQ(res + 1, FPRegs[i+1].reg);
-                markPreservedSingle(cUnit, sReg+1, res+1);
+                oatMarkPreservedSingle(cUnit, sReg+1, res+1);
                 break;
             }
         }
@@ -600,8 +544,7 @@
         LIR *p;
         DCHECK_EQ(sReg1, sReg2);
         for (p = start; ;p = p->next) {
-            ((ArmLIR *)p)->flags.isNop = true;
-            ((ArmLIR *)p)->flags.squashed = true;
+            oatNopLIR(p);
             if (p == finish)
                 break;
         }
@@ -714,26 +657,6 @@
     }
 }
 
-/* To be used when explicitly managing register use */
-extern void oatLockCallTemps(CompilationUnit* cUnit)
-{
-    //TODO: Arm specific - move to target dependent code
-    oatLockTemp(cUnit, r0);
-    oatLockTemp(cUnit, r1);
-    oatLockTemp(cUnit, r2);
-    oatLockTemp(cUnit, r3);
-}
-
-/* To be used when explicitly managing register use */
-extern void oatFreeCallTemps(CompilationUnit* cUnit)
-{
-    //TODO: Arm specific - move to target dependent code
-    oatFreeTemp(cUnit, r0);
-    oatFreeTemp(cUnit, r1);
-    oatFreeTemp(cUnit, r2);
-    oatFreeTemp(cUnit, r3);
-}
-
 // Make sure nothing is live and dirty
 STATIC void flushAllRegsBody(CompilationUnit* cUnit, RegisterInfo* info,
                              int numRegs)
@@ -766,9 +689,9 @@
     if (regClass == kAnyReg) {
         return true;
     } else if (regClass == kCoreReg) {
-        return !FPREG(reg);
+        return !oatIsFpReg(reg);
     } else {
-        return FPREG(reg);
+        return oatIsFpReg(reg);
     }
 }
 
@@ -926,9 +849,9 @@
         match = match && (infoLo != NULL);
         match = match && (infoHi != NULL);
         // Are they both core or both FP?
-        match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
+        match = match && (oatIsFpReg(infoLo->reg) == oatIsFpReg(infoHi->reg));
         // If a pair of floating point singles, are they properly aligned?
-        if (match && FPREG(infoLo->reg)) {
+        if (match && oatIsFpReg(infoLo->reg)) {
             match &= ((infoLo->reg & 0x1) == 0);
             match &= ((infoHi->reg - infoLo->reg) == 1);
         }
@@ -944,7 +867,7 @@
             loc.highReg = infoHi->reg;
             loc.location = kLocPhysReg;
             oatMarkPair(cUnit, loc.lowReg, loc.highReg);
-            DCHECK(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+            DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
             return loc;
         }
         // Can't easily reuse - clobber and free any overlaps
@@ -987,8 +910,8 @@
 
     /* If already in registers, we can assume proper form.  Right reg class? */
     if (loc.location == kLocPhysReg) {
-        DCHECK_EQ(FPREG(loc.lowReg), FPREG(loc.highReg));
-        DCHECK(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+        DCHECK_EQ(oatIsFpReg(loc.lowReg), oatIsFpReg(loc.highReg));
+        DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
         if (!regClassMatches(regClass, loc.lowReg)) {
             /* Wrong register class.  Reallocate and copy */
             newRegs = oatAllocTypedTempPair(cUnit, loc.fp, regClass);
@@ -1003,7 +926,7 @@
             loc.lowReg = lowReg;
             loc.highReg = highReg;
             oatMarkPair(cUnit, loc.lowReg, loc.highReg);
-            DCHECK(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+            DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
         }
         return loc;
     }
@@ -1021,7 +944,7 @@
         oatMarkLive(cUnit, loc.lowReg, loc.sRegLow);
         oatMarkLive(cUnit, loc.highReg, oatSRegHi(loc.sRegLow));
     }
-    DCHECK(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+    DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
     return loc;
 }
 
@@ -1092,4 +1015,247 @@
     return res;
 }
 
+/* USE SSA names to count references of base Dalvik vRegs. */
+void oatCountRefs(CompilationUnit *cUnit, BasicBlock* bb,
+                      RefCounts* coreCounts, RefCounts* fpCounts)
+{
+    MIR* mir;
+    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
+        bb->blockType != kExitBlock)
+        return;
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        SSARepresentation *ssaRep = mir->ssaRep;
+        if (ssaRep) {
+            for (int i = 0; i < ssaRep->numDefs;) {
+                RegLocation loc = cUnit->regLocation[ssaRep->defs[i]];
+                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
+                int vReg = oatS2VReg(cUnit, ssaRep->defs[i]);
+                if (loc.defined) {
+                    counts[vReg].count++;
+                }
+                if (loc.wide) {
+                    if (loc.defined) {
+                        if (loc.fp) {
+                            counts[vReg].doubleStart = true;
+                        }
+                        counts[vReg+1].count++;
+                    }
+                    i += 2;
+                } else {
+                    i++;
+                }
+            }
+            for (int i = 0; i < ssaRep->numUses;) {
+                RegLocation loc = cUnit->regLocation[ssaRep->uses[i]];
+                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
+                int vReg = oatS2VReg(cUnit, ssaRep->uses[i]);
+                if (loc.defined) {
+                    counts[vReg].count++;
+                }
+                if (loc.wide) {
+                    if (loc.defined) {
+                        if (loc.fp) {
+                            counts[vReg].doubleStart = true;
+                        }
+                        counts[vReg+1].count++;
+                    }
+                    i += 2;
+                } else {
+                    i++;
+                }
+            }
+        }
+    }
+}
+
+/* qsort callback function, sort descending */
+int oatSortCounts(const void *val1, const void *val2)
+{
+    const RefCounts* op1 = (const RefCounts*)val1;
+    const RefCounts* op2 = (const RefCounts*)val2;
+    return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
+}
+
+void oatDumpCounts(const RefCounts* arr, int size, const char* msg)
+{
+    LOG(INFO) << msg;
+    for (int i = 0; i < size; i++) {
+        LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
+    }
+}
+
+/*
+ * Note: some portions of this code required even if the kPromoteRegs
+ * optimization is disabled.
+ */
+extern void oatDoPromotion(CompilationUnit* cUnit)
+{
+    int numRegs = cUnit->numDalvikRegisters;
+
+    // Allow target code to add any special registers
+    oatAdjustSpillMask(cUnit);
+
+    /*
+     * Simple register promotion. Just do a static count of the uses
+     * of Dalvik registers.  Note that we examine the SSA names, but
+     * count based on original Dalvik register name.  Count refs
+     * separately based on type in order to give allocation
+     * preference to fp doubles - which must be allocated sequential
+     * physical single fp registers started with an even-numbered
+     * reg.
+     * TUNING: replace with linear scan once we have the ability
+     * to describe register live ranges for GC.
+     */
+    RefCounts *coreRegs = (RefCounts *)
+          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
+    RefCounts *fpRegs = (RefCounts *)
+          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
+    for (int i = 0; i < numRegs; i++) {
+        coreRegs[i].sReg = fpRegs[i].sReg = i;
+    }
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
+    while (true) {
+        BasicBlock* bb;
+        bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
+        if (bb == NULL) break;
+        oatCountRefs(cUnit, bb, coreRegs, fpRegs);
+    }
+
+    /*
+     * Ideally, we'd allocate doubles starting with an even-numbered
+     * register.  Bias the counts to try to allocate any vreg that's
+     * used as the start of a pair first.
+     */
+    for (int i = 0; i < numRegs; i++) {
+        if (fpRegs[i].doubleStart) {
+            fpRegs[i].count *= 2;
+        }
+    }
+
+    // Sort the count arrays
+    qsort(coreRegs, numRegs, sizeof(RefCounts), oatSortCounts);
+    qsort(fpRegs, numRegs, sizeof(RefCounts), oatSortCounts);
+
+    if (cUnit->printMe) {
+        oatDumpCounts(coreRegs, numRegs, "Core regs after sort");
+        oatDumpCounts(fpRegs, numRegs, "Fp regs after sort");
+    }
+
+    if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
+        // Promote fpRegs
+        for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
+            if (cUnit->promotionMap[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
+                if (fpRegs[i].sReg >= cUnit->numRegs) {
+                    // don't promote arg regs
+                    continue;
+                }
+                int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
+                    fpRegs[i].doubleStart);
+                if (reg < 0) {
+                    break;  // No more left
+                }
+            }
+        }
+
+        // Promote core regs
+        for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
+            if (cUnit->promotionMap[coreRegs[i].sReg].coreLocation !=
+                    kLocPhysReg) {
+                if (coreRegs[i].sReg >= cUnit->numRegs) {
+                    // don't promote arg regs
+                    continue;
+                }
+                int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
+                if (reg < 0) {
+                   break;  // No more left
+                }
+            }
+        }
+    }
+
+    // Now, update SSA names to new home locations
+    for (int i = 0; i < cUnit->numSSARegs; i++) {
+        RegLocation *curr = &cUnit->regLocation[i];
+        int baseVReg = oatS2VReg(cUnit, curr->sRegLow);
+        if (!curr->wide) {
+            if (curr->fp) {
+                if (cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) {
+                    curr->location = kLocPhysReg;
+                    curr->lowReg = cUnit->promotionMap[baseVReg].fpReg;
+                    curr->home = true;
+                }
+            } else {
+                if (cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg) {
+                    curr->location = kLocPhysReg;
+                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
+                    curr->home = true;
+                }
+            }
+            curr->highReg = INVALID_REG;
+        } else {
+            if (curr->highWord) {
+                continue;
+            }
+            if (curr->fp) {
+                if ((cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) &&
+                    (cUnit->promotionMap[baseVReg+1].fpLocation ==
+                    kLocPhysReg)) {
+                    int lowReg = cUnit->promotionMap[baseVReg].fpReg;
+                    int highReg = cUnit->promotionMap[baseVReg+1].fpReg;
+                    // Doubles require pair of singles starting at even reg
+                    if (((lowReg & 0x1) == 0) && ((lowReg + 1) == highReg)) {
+                        curr->location = kLocPhysReg;
+                        curr->lowReg = lowReg;
+                        curr->highReg = highReg;
+                        curr->home = true;
+                    }
+                }
+            } else {
+                if ((cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg)
+                     && (cUnit->promotionMap[baseVReg+1].coreLocation ==
+                     kLocPhysReg)) {
+                    curr->location = kLocPhysReg;
+                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
+                    curr->highReg = cUnit->promotionMap[baseVReg+1].coreReg;
+                    curr->home = true;
+                }
+            }
+        }
+    }
+}
+
+/* Returns sp-relative offset in bytes for a VReg */
+extern int oatVRegOffset(CompilationUnit* cUnit, int vReg)
+{
+    return (vReg < cUnit->numRegs) ? cUnit->regsOffset + (vReg << 2) :
+            cUnit->insOffset + ((vReg - cUnit->numRegs) << 2);
+}
+
+/* Returns sp-relative offset in bytes for a SReg */
+extern int oatSRegOffset(CompilationUnit* cUnit, int sReg)
+{
+    return oatVRegOffset(cUnit, oatS2VReg(cUnit, sReg));
+}
+
+
+/* Return sp-relative offset in bytes using Method* */
+extern int oatVRegOffset(const DexFile::CodeItem* code_item,
+                         uint32_t core_spills, uint32_t fp_spills,
+                         size_t frame_size, int reg)
+{
+    int numIns = code_item->ins_size_;
+    int numRegs = code_item->registers_size_ - numIns;
+    int numOuts = code_item->outs_size_;
+    int numSpills = __builtin_popcount(core_spills) +
+                    __builtin_popcount(fp_spills);
+    int numPadding = (STACK_ALIGN_WORDS -
+        (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
+    int regsOffset = (numOuts + numPadding + 1) * 4;
+    int insOffset = frame_size + 4;
+    return (reg < numRegs) ? regsOffset + (reg << 2) :
+           insOffset + ((reg - numRegs) << 2);
+}
+
 }  // namespace art
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index d700e48..62e4b3e 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -22,11 +22,64 @@
  *
  */
 
+#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath))
+#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath))
+#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath))
+#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath))
+#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \
+    (1 << kDebugSlowestFieldPath))
+#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \
+    (1 << kDebugSlowestStringPath))
+#define EXERCISE_RESOLVE_METHOD (cUnit->enableDebug & \
+    (1 << kDebugExerciseResolveMethod))
+
 namespace art {
 
-STATIC ArmLIR* genUnconditionalBranch(CompilationUnit*, ArmLIR*);
-STATIC ArmLIR* genConditionalBranch(CompilationUnit*, ArmConditionCode,
-                                    ArmLIR*);
+STATIC void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
+
+/* Generate conditional branch instructions */
+STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
+                                    ArmConditionCode cond,
+                                    ArmLIR* target)
+{
+    ArmLIR* branch = opCondBranch(cUnit, cond);
+    branch->generic.target = (LIR*) target;
+    return branch;
+}
+
+/* Generate unconditional branch instructions */
+STATIC ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
+{
+    ArmLIR* branch = opNone(cUnit, kOpUncondBr);
+    branch->generic.target = (LIR*) target;
+    return branch;
+}
+
+STATIC ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
+{
+    oatClobberCalleeSave(cUnit);
+    return opReg(cUnit, kOpBlx, reg);
+}
+
+/*
+ * Mark garbage collection card. Skip if the value we're storing is null.
+ */
+STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
+{
+    int regCardBase = oatAllocTemp(cUnit);
+    int regCardNo = oatAllocTemp(cUnit);
+    ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
+    loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
+                 regCardBase);
+    opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
+    storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
+                     kUnsignedByte);
+    ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR*)target;
+    oatFreeTemp(cUnit, regCardBase);
+    oatFreeTemp(cUnit, regCardNo);
+}
 
 /*
  * Utiltiy to load the current Method*.  Broken out
@@ -113,4 +166,1154 @@
     return branch;
 }
 
+/*
+ * Let helper function take care of everything.  Will call
+ * Array::AllocFromCode(type_idx, method, count);
+ * Note: AllocFromCode will handle checks for errNegativeArraySize.
+ */
+STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    uint32_t type_idx = mir->dalvikInsn.vC;
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+                                                    cUnit->dex_cache,
+                                                    *cUnit->dex_file,
+                                                    type_idx)) {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
+    }
+    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
+    loadConstant(cUnit, r0, type_idx);            // arg0 <- type_id
+    loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
+    callRuntimeHelper(cUnit, rLR);
+    RegLocation rlResult = oatGetReturn(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+/*
+ * Similar to genNewArray, but with post-allocation initialization.
+ * Verifier guarantees we're dealing with an array class.  Current
+ * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
+ * Current code also throws internal unimp if not 'L', '[' or 'I'.
+ */
+STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
+{
+    DecodedInstruction* dInsn = &mir->dalvikInsn;
+    int elems = dInsn->vA;
+    int typeId = dInsn->vB;
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+                                                    cUnit->dex_cache,
+                                                    *cUnit->dex_file,
+                                                    typeId)) {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
+    }
+    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
+    loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
+    loadConstant(cUnit, r2, elems);               // arg2 <- count
+    callRuntimeHelper(cUnit, rLR);
+    /*
+     * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
+     * return region.  Because AllocFromCode placed the new array
+     * in r0, we'll just lock it into place.  When debugger support is
+     * added, it may be necessary to additionally copy all return
+     * values to a home location in thread-local storage
+     */
+    oatLockTemp(cUnit, r0);
+
+    // Having a range of 0 is legal
+    if (isRange && (dInsn->vA > 0)) {
+        /*
+         * Bit of ugliness here.  We're going generate a mem copy loop
+         * on the register range, but it is possible that some regs
+         * in the range have been promoted.  This is unlikely, but
+         * before generating the copy, we'll just force a flush
+         * of any regs in the source range that have been promoted to
+         * home location.
+         */
+        for (unsigned int i = 0; i < dInsn->vA; i++) {
+            RegLocation loc = oatUpdateLoc(cUnit,
+                oatGetSrc(cUnit, mir, i));
+            if (loc.location == kLocPhysReg) {
+                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
+                              loc.lowReg, kWord);
+            }
+        }
+        /*
+         * TUNING note: generated code here could be much improved, but
+         * this is an uncommon operation and isn't especially performance
+         * critical.
+         */
+        int rSrc = oatAllocTemp(cUnit);
+        int rDst = oatAllocTemp(cUnit);
+        int rIdx = oatAllocTemp(cUnit);
+        int rVal = rLR;  // Using a lot of temps, rLR is known free here
+        // Set up source pointer
+        RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
+        opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
+                    oatSRegOffset(cUnit, rlFirst.sRegLow));
+        // Set up the target pointer
+        opRegRegImm(cUnit, kOpAdd, rDst, r0,
+                    Array::DataOffset().Int32Value());
+        // Set up the loop counter (known to be > 0)
+        loadConstant(cUnit, rIdx, dInsn->vA - 1);
+        // Generate the copy loop.  Going backwards for convenience
+        ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
+        target->defMask = ENCODE_ALL;
+        // Copy next element
+        loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
+        storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
+        // Use setflags encoding here
+        newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
+        ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
+        branch->generic.target = (LIR*)target;
+    } else if (!isRange) {
+        // TUNING: interleave
+        for (unsigned int i = 0; i < dInsn->vA; i++) {
+            RegLocation rlArg = loadValue(cUnit,
+                oatGetSrc(cUnit, mir, i), kCoreReg);
+            storeBaseDisp(cUnit, r0,
+                          Array::DataOffset().Int32Value() +
+                          i * 4, rlArg.lowReg, kWord);
+            // If the loadValue caused a temp to be allocated, free it
+            if (oatIsTemp(cUnit, rlArg.lowReg)) {
+                oatFreeTemp(cUnit, rlArg.lowReg);
+            }
+        }
+    }
+}
+
+STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
+                    bool isLongOrDouble, bool isObject)
+{
+    int fieldOffset;
+    int ssbIndex;
+    bool isVolatile;
+    bool isReferrersClass;
+    uint32_t fieldIdx = mir->dalvikInsn.vB;
+    bool fastPath =
+        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
+                                                fieldOffset, ssbIndex,
+                                                isReferrersClass, isVolatile, true);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        DCHECK_GE(fieldOffset, 0);
+        int rBase;
+        int rMethod;
+        if (isReferrersClass) {
+            // Fast path, static storage base is this method's class
+            rMethod  = loadCurrMethod(cUnit);
+            rBase = oatAllocTemp(cUnit);
+            loadWordDisp(cUnit, rMethod,
+                         Method::DeclaringClassOffset().Int32Value(), rBase);
+        } else {
+            // Medium path, static storage base in a different class which
+            // requires checks that the other class is initialized.
+            DCHECK_GE(ssbIndex, 0);
+            // May do runtime call so everything to home locations.
+            oatFlushAllRegs(cUnit);
+            // Using fixed register to sync with possible call to runtime
+            // support.
+            rMethod = r1;
+            oatLockTemp(cUnit, rMethod);
+            loadCurrMethodDirect(cUnit, rMethod);
+            rBase = r0;
+            oatLockTemp(cUnit, rBase);
+            loadWordDisp(cUnit, rMethod,
+                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
+                rBase);
+            loadWordDisp(cUnit, rBase,
+                         Array::DataOffset().Int32Value() + sizeof(int32_t*) *
+                         ssbIndex, rBase);
+            // rBase now points at appropriate static storage base (Class*)
+            // or NULL if not initialized. Check for NULL and call helper if NULL.
+            // TUNING: fast path should fall through
+            ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
+            loadConstant(cUnit, r0, ssbIndex);
+            callRuntimeHelper(cUnit, rLR);
+            ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+            skipTarget->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR*)skipTarget;
+        }
+        // rBase now holds static storage base
+        oatFreeTemp(cUnit, rMethod);
+        if (isLongOrDouble) {
+            rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+            rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+        } else {
+            rlSrc = oatGetSrc(cUnit, mir, 0);
+            rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+        }
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kST);
+        }
+        if (isLongOrDouble) {
+            storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
+                              rlSrc.highReg);
+        } else {
+            storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
+        }
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kSY);
+        }
+        if (isObject) {
+            markGCCard(cUnit, rlSrc.lowReg, rBase);
+        }
+        oatFreeTemp(cUnit, rBase);
+    } else {
+        oatFlushAllRegs(cUnit);  // Everything to home locations
+        int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
+                                     : OFFSETOF_MEMBER(Thread, pSet32Static));
+        loadWordDisp(cUnit, rSELF, setterOffset, rLR);
+        loadConstant(cUnit, r0, fieldIdx);
+        if (isLongOrDouble) {
+            loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
+        } else {
+            loadValueDirect(cUnit, rlSrc, r1);
+        }
+        callRuntimeHelper(cUnit, rLR);
+    }
+}
+
+STATIC void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                    bool isLongOrDouble, bool isObject)
+{
+    int fieldOffset;
+    int ssbIndex;
+    bool isVolatile;
+    bool isReferrersClass;
+    uint32_t fieldIdx = mir->dalvikInsn.vB;
+    bool fastPath =
+        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
+                                                fieldOffset, ssbIndex,
+                                                isReferrersClass, isVolatile, false);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        DCHECK_GE(fieldOffset, 0);
+        int rBase;
+        int rMethod;
+        if (isReferrersClass) {
+            // Fast path, static storage base is this method's class
+            rMethod  = loadCurrMethod(cUnit);
+            rBase = oatAllocTemp(cUnit);
+            loadWordDisp(cUnit, rMethod,
+                         Method::DeclaringClassOffset().Int32Value(), rBase);
+        } else {
+            // Medium path, static storage base in a different class which
+            // requires checks that the other class is initialized
+            DCHECK_GE(ssbIndex, 0);
+            // May do runtime call so everything to home locations.
+            oatFlushAllRegs(cUnit);
+            // Using fixed register to sync with possible call to runtime
+            // support
+            rMethod = r1;
+            oatLockTemp(cUnit, rMethod);
+            loadCurrMethodDirect(cUnit, rMethod);
+            rBase = r0;
+            oatLockTemp(cUnit, rBase);
+            loadWordDisp(cUnit, rMethod,
+                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
+                rBase);
+            loadWordDisp(cUnit, rBase,
+                         Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
+                         rBase);
+            // rBase now points at appropriate static storage base (Class*)
+            // or NULL if not initialized. Check for NULL and call helper if NULL.
+            // TUNING: fast path should fall through
+            ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
+            loadConstant(cUnit, r0, ssbIndex);
+            callRuntimeHelper(cUnit, rLR);
+            ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+            skipTarget->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR*)skipTarget;
+        }
+        // rBase now holds static storage base
+        oatFreeTemp(cUnit, rMethod);
+        rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
+                                : oatGetDest(cUnit, mir, 0);
+        RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kSY);
+        }
+        if (isLongOrDouble) {
+            loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
+                             rlResult.highReg, INVALID_SREG);
+        } else {
+            loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
+        }
+        oatFreeTemp(cUnit, rBase);
+        if (isLongOrDouble) {
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    } else {
+        oatFlushAllRegs(cUnit);  // Everything to home locations
+        int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
+                                     : OFFSETOF_MEMBER(Thread, pGet32Static));
+        loadWordDisp(cUnit, rSELF, getterOffset, rLR);
+        loadConstant(cUnit, r0, fieldIdx);
+        callRuntimeHelper(cUnit, rLR);
+        if (isLongOrDouble) {
+            RegLocation rlResult = oatGetReturnWide(cUnit);
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            RegLocation rlResult = oatGetReturn(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    }
+}
+
+typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
+                            uint32_t methodIdx);
+
+/*
+ * Bit of a hack here - in leiu of a real scheduling pass,
+ * emit the next instruction in static & direct invoke sequences.
+ */
+STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
+                          int state, uint32_t dexIdx, uint32_t unused)
+{
+    switch(state) {
+        case 0:  // Get the current Method* [sets r0]
+            loadCurrMethodDirect(cUnit, r0);
+            break;
+        case 1:  // Get method->code_and_direct_methods_
+            loadWordDisp(cUnit, r0,
+                Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
+                r0);
+            break;
+        case 2:  // Grab target method* and target code_
+            loadWordDisp(cUnit, r0,
+                CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
+            loadWordDisp(cUnit, r0,
+                CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
+            break;
+        default:
+            return -1;
+    }
+    return state + 1;
+}
+
+/*
+ * Bit of a hack here - in leiu of a real scheduling pass,
+ * emit the next instruction in a virtual invoke sequence.
+ * We can use rLR as a temp prior to target address loading
+ * Note also that we'll load the first argument ("this") into
+ * r1 here rather than the standard loadArgRegs.
+ */
+STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
+                         int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    RegLocation rlArg;
+    /*
+     * This is the fast path in which the target virtual method is
+     * fully resolved at compile time.
+     */
+    switch(state) {
+        case 0:  // Get "this" [set r1]
+            rlArg = oatGetSrc(cUnit, mir, 0);
+            loadValueDirectFixed(cUnit, rlArg, r1);
+            break;
+        case 1: // Is "this" null? [use r1]
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+            // get this->klass_ [use r1, set rLR]
+            loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
+            break;
+        case 2: // Get this->klass_->vtable [usr rLR, set rLR]
+            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
+            break;
+        case 3: // Get target method [use rLR, set r0]
+            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
+                         Array::DataOffset().Int32Value(), r0);
+            break;
+        case 4: // Get the target compiled code address [uses r0, sets rLR]
+            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
+            break;
+        default:
+            return -1;
+    }
+    return state + 1;
+}
+
+/*
+ * Interleave launch code for INVOKE_SUPER.  See comments
+ * for nextVCallIns.
+ */
+STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
+                             int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    /*
+     * This is the fast path in which the target virtual method is
+     * fully resolved at compile time.  Note also that this path assumes
+     * that the check to verify that the target method index falls
+     * within the size of the super's vtable has been done at compile-time.
+     */
+    RegLocation rlArg;
+    switch(state) {
+        case 0: // Get current Method* [set r0]
+            loadCurrMethodDirect(cUnit, r0);
+            // Load "this" [set r1]
+            rlArg = oatGetSrc(cUnit, mir, 0);
+            loadValueDirectFixed(cUnit, rlArg, r1);
+            // Get method->declaring_class_ [use r0, set rLR]
+            loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
+                         rLR);
+            // Is "this" null? [use r1]
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+            break;
+        case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
+            loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
+                         rLR);
+            break;
+        case 2: // Get ...->super_class_->vtable [u/s rLR]
+            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
+            break;
+        case 3: // Get target method [use rLR, set r0]
+            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
+                         Array::DataOffset().Int32Value(), r0);
+            break;
+        case 4: // Get the target compiled code address [uses r0, sets rLR]
+            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
+            break;
+        default:
+            return -1;
+    }
+    return state + 1;
+}
+
+STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline,
+                            int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    /*
+     * This handles the case in which the base method is not fully
+     * resolved at compile time, we bail to a runtime helper.
+     */
+    if (state == 0) {
+        // Load trampoline target
+        loadWordDisp(cUnit, rSELF, trampoline, rLR);
+        // Load r0 with method index
+        loadConstant(cUnit, r0, dexIdx);
+        return 1;
+    }
+    return -1;
+}
+
+STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                               int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                           int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+/*
+ * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
+ * which will locate the target and continue on via a tail call.
+ */
+STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
+                                 int state, uint32_t dexIdx, uint32_t unused)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
+                                                MIR* mir, int state,
+                                                uint32_t dexIdx,
+                                                uint32_t unused)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
+                          DecodedInstruction* dInsn, int callState,
+                          NextCallInsn nextCallInsn, uint32_t dexIdx,
+                          uint32_t methodIdx, bool skipThis)
+{
+    int nextReg = r1;
+    int nextArg = 0;
+    if (skipThis) {
+        nextReg++;
+        nextArg++;
+    }
+    for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
+        RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
+        rlArg = oatUpdateRawLoc(cUnit, rlArg);
+        if (rlArg.wide && (nextReg <= r2)) {
+            loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
+            nextReg++;
+            nextArg++;
+        } else {
+            rlArg.wide = false;
+            loadValueDirectFixed(cUnit, rlArg, nextReg);
+        }
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    }
+    return callState;
+}
+
+/*
+ * Load up to 5 arguments, the first three of which will be in
+ * r1 .. r3.  On entry r0 contains the current method pointer,
+ * and as part of the load sequence, it must be replaced with
+ * the target method pointer.  Note, this may also be called
+ * for "range" variants if the number of arguments is 5 or fewer.
+ */
+STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
+                                DecodedInstruction* dInsn, int callState,
+                                ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
+                                uint32_t dexIdx, uint32_t methodIdx,
+                                bool skipThis)
+{
+    RegLocation rlArg;
+
+    /* If no arguments, just return */
+    if (dInsn->vA == 0)
+        return callState;
+
+    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+
+    DCHECK_LE(dInsn->vA, 5U);
+    if (dInsn->vA > 3) {
+        uint32_t nextUse = 3;
+        //Detect special case of wide arg spanning arg3/arg4
+        RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
+        RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
+        RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
+        if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
+            rlUse2.wide) {
+            int reg;
+            // Wide spans, we need the 2nd half of uses[2].
+            rlArg = oatUpdateLocWide(cUnit, rlUse2);
+            if (rlArg.location == kLocPhysReg) {
+                reg = rlArg.highReg;
+            } else {
+                // r2 & r3 can safely be used here
+                reg = r3;
+                loadWordDisp(cUnit, rSP,
+                             oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
+                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+                                         methodIdx);
+            }
+            storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
+            storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
+            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+            nextUse++;
+        }
+        // Loop through the rest
+        while (nextUse < dInsn->vA) {
+            int lowReg;
+            int highReg;
+            rlArg = oatGetRawSrc(cUnit, mir, nextUse);
+            rlArg = oatUpdateRawLoc(cUnit, rlArg);
+            if (rlArg.location == kLocPhysReg) {
+                lowReg = rlArg.lowReg;
+                highReg = rlArg.highReg;
+            } else {
+                lowReg = r2;
+                highReg = r3;
+                if (rlArg.wide) {
+                    loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
+                } else {
+                    loadValueDirectFixed(cUnit, rlArg, lowReg);
+                }
+                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+                                         methodIdx);
+            }
+            int outsOffset = (nextUse + 1) * 4;
+            if (rlArg.wide) {
+                storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
+                nextUse += 2;
+            } else {
+                storeWordDisp(cUnit, rSP, outsOffset, lowReg);
+                nextUse++;
+            }
+            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        }
+    }
+
+    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+                            dexIdx, methodIdx, skipThis);
+
+    if (pcrLabel) {
+        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+    }
+    return callState;
+}
+
+/*
+ * May have 0+ arguments (also used for jumbo).  Note that
+ * source virtual registers may be in physical registers, so may
+ * need to be flushed to home location before copying.  This
+ * applies to arg3 and above (see below).
+ *
+ * Two general strategies:
+ *    If < 20 arguments
+ *       Pass args 3-18 using vldm/vstm block copy
+ *       Pass arg0, arg1 & arg2 in r1-r3
+ *    If 20+ arguments
+ *       Pass args arg19+ using memcpy block copy
+ *       Pass arg0, arg1 & arg2 in r1-r3
+ *
+ */
+STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
+                              DecodedInstruction* dInsn, int callState,
+                              ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
+                              uint32_t dexIdx, uint32_t methodIdx,
+                              bool skipThis)
+{
+    int firstArg = dInsn->vC;
+    int numArgs = dInsn->vA;
+
+    // If we can treat it as non-range (Jumbo ops will use range form)
+    if (numArgs <= 5)
+        return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
+                                    nextCallInsn, dexIdx, methodIdx,
+                                    skipThis);
+    /*
+     * Make sure range list doesn't span the break between in normal
+     * Dalvik vRegs and the ins.
+     */
+    int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
+    int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
+    if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
+        LOG(FATAL) << "Argument list spanned locals & args";
+    }
+
+    /*
+     * First load the non-register arguments.  Both forms expect all
+     * of the source arguments to be in their home frame location, so
+     * scan the sReg names and flush any that have been promoted to
+     * frame backing storage.
+     */
+    // Scan the rest of the args - if in physReg flush to memory
+    for (int nextArg = 0; nextArg < numArgs;) {
+        RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
+        if (loc.wide) {
+            loc = oatUpdateLocWide(cUnit, loc);
+            if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
+                storeBaseDispWide(cUnit, rSP,
+                                  oatSRegOffset(cUnit, loc.sRegLow),
+                                  loc.lowReg, loc.highReg);
+            }
+            nextArg += 2;
+        } else {
+            loc = oatUpdateLoc(cUnit, loc);
+            if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
+                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
+                              loc.lowReg, kWord);
+            }
+            nextArg++;
+        }
+    }
+
+    int startOffset = oatSRegOffset(cUnit,
+        cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
+    int outsOffset = 4 /* Method* */ + (3 * 4);
+    if (numArgs >= 20) {
+        // Generate memcpy
+        opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
+        opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
+        loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
+        loadConstant(cUnit, r2, (numArgs - 3) * 4);
+        callRuntimeHelper(cUnit, rLR);
+        // Restore Method*
+        loadCurrMethodDirect(cUnit, r0);
+    } else {
+        // Use vldm/vstm pair using r3 as a temp
+        int regsLeft = std::min(numArgs - 3, 16);
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
+        ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
+        //TUNING: loosen barrier
+        ld->defMask = ENCODE_ALL;
+        setMemRefType(ld, true /* isLoad */, kDalvikReg);
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
+        setMemRefType(st, false /* isLoad */, kDalvikReg);
+        st->defMask = ENCODE_ALL;
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    }
+
+    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+                            dexIdx, methodIdx, skipThis);
+
+    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    if (pcrLabel) {
+        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+    }
+    return callState;
+}
+
+// Debugging routine - if null target, branch to DebugMe
+STATIC void genShowTarget(CompilationUnit* cUnit)
+{
+    ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
+    ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = -1;
+    branchOver->generic.target = (LIR*)target;
+}
+
+STATIC void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
+{
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
+    loadConstant(cUnit, r0, mir->dalvikInsn.vA);
+    loadConstant(cUnit, r1, mir->dalvikInsn.vB);
+    callRuntimeHelper(cUnit, rLR);
+}
+
+STATIC void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
+                                MIR* mir, RegLocation rlSrc1,
+                                RegLocation rlSrc2, ArmLIR* labelList)
+{
+    ArmConditionCode cond;
+    rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+    opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
+    Opcode opcode = mir->dalvikInsn.opcode;
+    switch(opcode) {
+        case OP_IF_EQ:
+            cond = kArmCondEq;
+            break;
+        case OP_IF_NE:
+            cond = kArmCondNe;
+            break;
+        case OP_IF_LT:
+            cond = kArmCondLt;
+            break;
+        case OP_IF_GE:
+            cond = kArmCondGe;
+            break;
+        case OP_IF_GT:
+            cond = kArmCondGt;
+            break;
+        case OP_IF_LE:
+            cond = kArmCondLe;
+            break;
+        default:
+            cond = (ArmConditionCode)0;
+            LOG(FATAL) << "Unexpected opcode " << (int)opcode;
+    }
+    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+}
+
+STATIC void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
+                                   MIR* mir, RegLocation rlSrc,
+                                   ArmLIR* labelList)
+{
+    ArmConditionCode cond;
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
+    Opcode opcode = mir->dalvikInsn.opcode;
+    switch(opcode) {
+        case OP_IF_EQZ:
+            cond = kArmCondEq;
+            break;
+        case OP_IF_NEZ:
+            cond = kArmCondNe;
+            break;
+        case OP_IF_LTZ:
+            cond = kArmCondLt;
+            break;
+        case OP_IF_GEZ:
+            cond = kArmCondGe;
+            break;
+        case OP_IF_GTZ:
+            cond = kArmCondGt;
+            break;
+        case OP_IF_LEZ:
+            cond = kArmCondLe;
+            break;
+        default:
+            cond = (ArmConditionCode)0;
+            LOG(FATAL) << "Unexpected opcode " << (int)opcode;
+    }
+    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+}
+
+STATIC void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                         RegLocation rlSrc)
+{
+    RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+    if (rlSrc.location == kLocPhysReg) {
+        genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+    } else {
+        loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
+    }
+    opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
+                rlResult.lowReg, 31);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+STATIC void genIntNarrowing(CompilationUnit* cUnit, MIR* mir,
+                            RegLocation rlDest, RegLocation rlSrc)
+{
+     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+     RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+     OpKind op = kOpInvalid;
+     switch(mir->dalvikInsn.opcode) {
+         case OP_INT_TO_BYTE:
+             op = kOp2Byte;
+             break;
+         case OP_INT_TO_SHORT:
+              op = kOp2Short;
+              break;
+         case OP_INT_TO_CHAR:
+              op = kOp2Char;
+              break;
+         default:
+             LOG(ERROR) << "Bad int conversion type";
+     }
+     opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
+     storeValue(cUnit, rlDest, rlResult);
+}
+
+/*
+ * If there are any ins passed in registers that have not been promoted
+ * to a callee-save register, flush them to the frame.  Perform intial
+ * assignment of promoted arguments.
+ */
+STATIC void flushIns(CompilationUnit* cUnit)
+{
+    if (cUnit->numIns == 0)
+        return;
+    int firstArgReg = r1;
+    int lastArgReg = r3;
+    int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
+    /*
+     * Arguments passed in registers should be flushed
+     * to their backing locations in the frame for now.
+     * Also, we need to do initial assignment for promoted
+     * arguments.  NOTE: an older version of dx had an issue
+     * in which it would reuse static method argument registers.
+     * This could result in the same Dalvik virtual register
+     * being promoted to both core and fp regs.  In those
+     * cases, copy argument to both.  This will be uncommon
+     * enough that it isn't worth attempting to optimize.
+     */
+    for (int i = 0; i < cUnit->numIns; i++) {
+        PromotionMap vMap = cUnit->promotionMap[startVReg + i];
+        if (i <= (lastArgReg - firstArgReg)) {
+            // If arriving in register
+            if (vMap.coreLocation == kLocPhysReg) {
+                genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
+            }
+            if (vMap.fpLocation == kLocPhysReg) {
+                genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
+            }
+            // Also put a copy in memory in case we're partially promoted
+            storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                          firstArgReg + i, kWord);
+        } else {
+            // If arriving in frame & promoted
+            if (vMap.coreLocation == kLocPhysReg) {
+                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                             vMap.coreReg);
+            }
+            if (vMap.fpLocation == kLocPhysReg) {
+                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                             vMap.fpReg);
+            }
+        }
+    }
+}
+
+STATIC void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
+    /*
+     * On entry, r0, r1, r2 & r3 are live.  Let the register allocation
+     * mechanism know so it doesn't try to use any of them when
+     * expanding the frame or flushing.  This leaves the utility
+     * code with a single temp: r12.  This should be enough.
+     */
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+    oatLockTemp(cUnit, r2);
+    oatLockTemp(cUnit, r3);
+
+    /*
+     * We can safely skip the stack overflow check if we're
+     * a leaf *and* our frame size < fudge factor.
+     */
+    bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
+                              ((size_t)cUnit->frameSize <
+                              Thread::kStackOverflowReservedBytes));
+    newLIR0(cUnit, kArmPseudoMethodEntry);
+    if (!skipOverflowCheck) {
+        /* Load stack limit */
+        loadWordDisp(cUnit, rSELF,
+                     Thread::StackEndOffset().Int32Value(), r12);
+    }
+    /* Spill core callee saves */
+    newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
+    /* Need to spill any FP regs? */
+    if (cUnit->numFPSpills) {
+        /*
+         * NOTE: fp spills are a little different from core spills in that
+         * they are pushed as a contiguous block.  When promoting from
+         * the fp set, we must allocate all singles from s16..highest-promoted
+         */
+        newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
+    }
+    if (!skipOverflowCheck) {
+        opRegRegImm(cUnit, kOpSub, rLR, rSP,
+                    cUnit->frameSize - (spillCount * 4));
+        genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
+                       kArmThrowStackOverflow);
+        genRegCopy(cUnit, rSP, rLR);         // Establish stack
+    } else {
+        opRegImm(cUnit, kOpSub, rSP,
+                 cUnit->frameSize - (spillCount * 4));
+    }
+    storeBaseDisp(cUnit, rSP, 0, r0, kWord);
+    flushIns(cUnit);
+
+    if (cUnit->genDebugger) {
+        // Refresh update debugger callout
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+        genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
+    }
+
+    oatFreeTemp(cUnit, r0);
+    oatFreeTemp(cUnit, r1);
+    oatFreeTemp(cUnit, r2);
+    oatFreeTemp(cUnit, r3);
+}
+
+STATIC void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
+    /*
+     * In the exit path, r0/r1 are live - make sure they aren't
+     * allocated by the register utilities as temps.
+     */
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+
+    newLIR0(cUnit, kArmPseudoMethodExit);
+    /* If we're compiling for the debugger, generate an update callout */
+    if (cUnit->genDebugger) {
+        genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
+    }
+    opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
+    /* Need to restore any FP callee saves? */
+    if (cUnit->numFPSpills) {
+        newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
+    }
+    if (cUnit->coreSpillMask & (1 << rLR)) {
+        /* Unspill rLR to rPC */
+        cUnit->coreSpillMask &= ~(1 << rLR);
+        cUnit->coreSpillMask |= (1 << rPC);
+    }
+    newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
+    if (!(cUnit->coreSpillMask & (1 << rPC))) {
+        /* We didn't pop to rPC, so must do a bv rLR */
+        newLIR1(cUnit, kThumbBx, rLR);
+    }
+}
+
+/*
+ * Nop any unconditional branches that go to the next instruction.
+ * Note: new redundant branches may be inserted later, and we'll
+ * use a check in final instruction assembly to nop those out.
+ */
+void removeRedundantBranches(CompilationUnit* cUnit)
+{
+    ArmLIR* thisLIR;
+
+    for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
+         thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
+         thisLIR = NEXT_LIR(thisLIR)) {
+
+        /* Branch to the next instruction */
+        if ((thisLIR->opcode == kThumbBUncond) ||
+            (thisLIR->opcode == kThumb2BUncond)) {
+            ArmLIR* nextLIR = thisLIR;
+
+            while (true) {
+                nextLIR = NEXT_LIR(nextLIR);
+
+                /*
+                 * Is the branch target the next instruction?
+                 */
+                if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
+                    thisLIR->flags.isNop = true;
+                    break;
+                }
+
+                /*
+                 * Found real useful stuff between the branch and the target.
+                 * Need to explicitly check the lastLIRInsn here because it
+                 * might be the last real instruction.
+                 */
+                if (!isPseudoOpcode(nextLIR->opcode) ||
+                    (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
+                    break;
+            }
+        }
+    }
+}
+
+STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
+{
+    ArmLIR** suspendLabel =
+        (ArmLIR **) cUnit->suspendLaunchpads.elemList;
+    int numElems = cUnit->suspendLaunchpads.numUsed;
+
+    for (int i = 0; i < numElems; i++) {
+        /* TUNING: move suspend count load into helper */
+        ArmLIR* lab = suspendLabel[i];
+        ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
+        if (!cUnit->genDebugger) {
+            // use rSUSPEND for suspend count
+            loadWordDisp(cUnit, rSELF,
+                         Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
+        }
+        opReg(cUnit, kOpBlx, rLR);
+        if ( cUnit->genDebugger) {
+            // use rSUSPEND for update debugger
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+        }
+        genUnconditionalBranch(cUnit, resumeLab);
+    }
+}
+
+STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
+{
+    ArmLIR** throwLabel =
+        (ArmLIR **) cUnit->throwLaunchpads.elemList;
+    int numElems = cUnit->throwLaunchpads.numUsed;
+    int i;
+
+    for (i = 0; i < numElems; i++) {
+        ArmLIR* lab = throwLabel[i];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        int funcOffset = 0;
+        int v1 = lab->operands[2];
+        int v2 = lab->operands[3];
+        switch(lab->operands[0]) {
+            case kArmThrowNullPointer:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
+                break;
+            case kArmThrowArrayBounds:
+                if (v2 != r0) {
+                    genRegCopy(cUnit, r0, v1);
+                    genRegCopy(cUnit, r1, v2);
+                } else {
+                    if (v1 == r1) {
+                        genRegCopy(cUnit, r12, v1);
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, r12);
+                    } else {
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, v1);
+                    }
+                }
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
+                break;
+            case kArmThrowDivZero:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
+                break;
+            case kArmThrowVerificationError:
+                loadConstant(cUnit, r0, v1);
+                loadConstant(cUnit, r1, v2);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
+                break;
+            case kArmThrowNegArraySize:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
+                break;
+            case kArmThrowNoSuchMethod:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
+                break;
+            case kArmThrowStackOverflow:
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
+                // Restore stack alignment
+                opRegImm(cUnit, kOpAdd, rSP,
+                         (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
+                break;
+            default:
+                LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
+        }
+        loadWordDisp(cUnit, rSELF, funcOffset, rLR);
+        callRuntimeHelper(cUnit, rLR);
+    }
+}
+
+/* Common initialization routine for an architecture family */
+bool oatArchInit()
+{
+    int i;
+
+    for (i = 0; i < kArmLast; i++) {
+        if (EncodingMap[i].opcode != i) {
+            LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
+               " is wrong: expecting " << i << ", seeing " <<
+               (int)EncodingMap[i].opcode;
+        }
+    }
+
+    return oatArchVariantInit();
+}
+
+/* Needed by the Assembler */
+void oatSetupResourceMasks(ArmLIR* lir)
+{
+    setupResourceMasks(lir);
+}
+
 }  // namespace art
diff --git a/src/compiler/codegen/arm/ArchUtility.cc b/src/compiler/codegen/arm/ArchUtility.cc
index c9a30fd..75ae456 100644
--- a/src/compiler/codegen/arm/ArchUtility.cc
+++ b/src/compiler/codegen/arm/ArchUtility.cc
@@ -363,9 +363,8 @@
             } else {
                 std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr));
                 std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr));
-                LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s%s", baseAddr + offset, offset,
-                    op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "",
-                    lir->flags.squashed ? "(squashed)" : "");
+                LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s", baseAddr + offset, offset,
+                    op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "");
             }
             break;
     }
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index 510a5ea..a9c8286 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -125,41 +125,9 @@
 #define rNone   (-1)
 
 /* RegisterLocation templates return values (r0, or r0/r1) */
-#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 1, r0, INVALID_REG, INVALID_SREG}
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 1, r0, INVALID_REG,\
+                      INVALID_SREG}
 #define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG}
-/* RegisterLocation templates for interpState->retVal; */
-#define LOC_DALVIK_RETURN_VAL {kLocPhysReg, 0, 0, 0, 0, 0, 1, r0, INVALID_REG, \
-                      INVALID_SREG}
-#define LOC_DALVIK_RETURN_VAL_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, \
-                      INVALID_SREG}
-
- /*
- * Data structure tracking the mapping between a Dalvik register (pair) and a
- * native register (pair). The idea is to reuse the previously loaded value
- * if possible, otherwise to keep the value in a native register as long as
- * possible.
- */
-typedef struct RegisterInfo {
-    int reg;                    // Reg number
-    bool inUse;                 // Has it been allocated?
-    bool isTemp;                // Can allocate as temp?
-    bool pair;                  // Part of a register pair?
-    int partner;                // If pair, other reg of pair
-    bool live;                  // Is there an associated SSA name?
-    bool dirty;                 // If live, is it dirty?
-    int sReg;                   // Name of live value
-    struct LIR *defStart;       // Starting inst in last def sequence
-    struct LIR *defEnd;         // Ending inst in last def sequence
-} RegisterInfo;
-
-typedef struct RegisterPool {
-    int numCoreRegs;
-    RegisterInfo *coreRegs;
-    int nextCoreReg;
-    int numFPRegs;
-    RegisterInfo *FPRegs;
-    int nextFPReg;
-} RegisterPool;
 
 typedef enum ResourceEncodingPos {
     kGPReg0     = 0,
@@ -199,17 +167,6 @@
 #define DECODE_ALIAS_INFO_REG(X)        (X & 0xffff)
 #define DECODE_ALIAS_INFO_WIDE(X)       ((X & 0x80000000) ? 1 : 0)
 
-typedef enum OpSize {
-    kWord,
-    kLong,
-    kSingle,
-    kDouble,
-    kUnsignedHalf,
-    kSignedHalf,
-    kUnsignedByte,
-    kSignedByte,
-} OpSize;
-
 typedef enum OpKind {
     kOpMov,
     kOpMvn,
@@ -243,6 +200,7 @@
     kOp2Byte,
     kOpCondBr,
     kOpUncondBr,
+    kOpInvalid,
 } OpKind;
 
 /*
@@ -844,12 +802,10 @@
     int operands[4];            // [0..3] = [dest, src1, src2, extra]
     struct {
         bool isNop:1;           // LIR is optimized away
-        bool insertWrapper:1;   // insert branch to emulate memory accesses
-        bool squashed:1;        // Eliminated def
         bool pcRelFixup:1;      // May need pc-relative fixup
         unsigned int age:4;     // default is 0, set lazily by the optimizer
         unsigned int size:3;    // bytes (2 for thumb, 2/4 for thumb2)
-        unsigned int unused:21;
+        unsigned int unused:23;
     } flags;
     int aliasInfo;              // For Dalvik register & litpool disambiguation
     u8 useMask;                 // Resource mask for use
@@ -871,10 +827,6 @@
     int vaddr;                 // Dalvik offset of OP_FILL_ARRAY_DATA opcode
 } FillArrayData;
 
-/* Init values when a predicted chain is initially assembled */
-/* E7FE is branch to self */
-#define PREDICTED_CHAIN_BX_PAIR_INIT     0xe7fe
-
 /* Utility macros to traverse the LIR/ArmLIR list */
 #define NEXT_LIR(lir) ((ArmLIR *) lir->generic.next)
 #define PREV_LIR(lir) ((ArmLIR *) lir->generic.prev)
@@ -882,11 +834,6 @@
 #define NEXT_LIR_LVALUE(lir) (lir)->generic.next
 #define PREV_LIR_LVALUE(lir) (lir)->generic.prev
 
-#define CHAIN_CELL_OFFSET_TAG   0xcdab
-
-#define CHAIN_CELL_NORMAL_SIZE 12
-#define CHAIN_CELL_PREDICTED_SIZE 16
-
 }  // namespace art
 
 #endif  // ART_SRC_COMPILER_CODEGEN_ARM_ARMLIR_H_
diff --git a/src/compiler/codegen/arm/ArmRallocUtil.cc b/src/compiler/codegen/arm/ArmRallocUtil.cc
index 1986b0f..38f1b88 100644
--- a/src/compiler/codegen/arm/ArmRallocUtil.cc
+++ b/src/compiler/codegen/arm/ArmRallocUtil.cc
@@ -28,262 +28,87 @@
 namespace art {
 
 /*
- * Placeholder routine until we do proper register allocation.
+ * TUNING: is leaf?  Can't just use "hasInvoke" to determine as some
+ * instructions might call out to C/assembly helper functions.  Until
+ * machinery is in place, always spill lr.
  */
 
-typedef struct RefCounts {
-    int count;
-    int sReg;
-    bool doubleStart;   // Starting vReg for a double
-} RefCounts;
-
-/* USE SSA names to count references of base Dalvik vRegs. */
-STATIC void countRefs(CompilationUnit *cUnit, BasicBlock* bb,
-                      RefCounts* coreCounts, RefCounts* fpCounts)
+void oatAdjustSpillMask(CompilationUnit* cUnit)
 {
-    MIR* mir;
-    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
-        bb->blockType != kExitBlock)
-        return;
-
-    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
-        SSARepresentation *ssaRep = mir->ssaRep;
-        if (ssaRep) {
-            for (int i = 0; i < ssaRep->numDefs;) {
-                RegLocation loc = cUnit->regLocation[ssaRep->defs[i]];
-                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
-                int vReg = oatS2VReg(cUnit, ssaRep->defs[i]);
-                if (loc.defined) {
-                    counts[vReg].count++;
-                }
-                if (loc.wide) {
-                    if (loc.defined) {
-                        if (loc.fp) {
-                            counts[vReg].doubleStart = true;
-                        }
-                        counts[vReg+1].count++;
-                    }
-                    i += 2;
-                } else {
-                    i++;
-                }
-            }
-            for (int i = 0; i < ssaRep->numUses;) {
-                RegLocation loc = cUnit->regLocation[ssaRep->uses[i]];
-                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
-                int vReg = oatS2VReg(cUnit, ssaRep->uses[i]);
-                if (loc.defined) {
-                    counts[vReg].count++;
-                }
-                if (loc.wide) {
-                    if (loc.defined) {
-                        if (loc.fp) {
-                            counts[vReg].doubleStart = true;
-                        }
-                        counts[vReg+1].count++;
-                    }
-                    i += 2;
-                } else {
-                    i++;
-                }
-            }
-        }
-    }
-}
-
-/* qsort callback function, sort descending */
-STATIC int sortCounts(const void *val1, const void *val2)
-{
-    const RefCounts* op1 = (const RefCounts*)val1;
-    const RefCounts* op2 = (const RefCounts*)val2;
-    return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
-}
-
-STATIC void dumpCounts(const RefCounts* arr, int size, const char* msg)
-{
-    LOG(INFO) << msg;
-    for (int i = 0; i < size; i++) {
-        LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
-    }
+    cUnit->coreSpillMask |= (1 << rLR);
+    cUnit->numCoreSpills++;
 }
 
 /*
- * Note: some portions of this code required even if the kPromoteRegs
- * optimization is disabled.
+ * Mark a callee-save fp register as promoted.  Note that
+ * vpush/vpop uses contiguous register lists so we must
+ * include any holes in the mask.  Associate holes with
+ * Dalvik register INVALID_VREG (0xFFFFU).
  */
-extern void oatDoPromotion(CompilationUnit* cUnit)
+void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
 {
-    int numRegs = cUnit->numDalvikRegisters;
-
-    /*
-     * TUNING: is leaf?  Can't just use "hasInvoke" to determine as some
-     * instructions might call out to C/assembly helper functions.  Until
-     * machinery is in place, always spill lr.
-     */
-    cUnit->coreSpillMask |= (1 << rLR);
-    cUnit->numCoreSpills++;
-    /*
-     * Simple hack for testing register allocation.  Just do a static
-     * count of the uses of Dalvik registers.  Note that we examine
-     * the SSA names, but count based on original Dalvik register name.
-     * Count refs separately based on type in order to give allocation
-     * preference to fp doubles - which must be allocated sequential
-     * physical single fp registers started with an even-numbered
-     * reg.
-     */
-    RefCounts *coreRegs = (RefCounts *)
-          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
-    RefCounts *fpRegs = (RefCounts *)
-          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
-    for (int i = 0; i < numRegs; i++) {
-        coreRegs[i].sReg = fpRegs[i].sReg = i;
+    DCHECK_GE(reg, FP_REG_MASK + FP_CALLEE_SAVE_BASE);
+    reg = (reg & FP_REG_MASK) - FP_CALLEE_SAVE_BASE;
+    // Ensure fpVmapTable is large enough
+    int tableSize = cUnit->fpVmapTable.size();
+    for (int i = tableSize; i < (reg + 1); i++) {
+        cUnit->fpVmapTable.push_back(INVALID_VREG);
     }
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
-    while (true) {
-        BasicBlock* bb;
-        bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
-        if (bb == NULL) break;
-        countRefs(cUnit, bb, coreRegs, fpRegs);
-    }
+    // Add the current mapping
+    cUnit->fpVmapTable[reg] = sReg;
+    // Size of fpVmapTable is high-water mark, use to set mask
+    cUnit->numFPSpills = cUnit->fpVmapTable.size();
+    cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << FP_CALLEE_SAVE_BASE;
+}
 
-    /*
-     * Ideally, we'd allocate doubles starting with an even-numbered
-     * register.  Bias the counts to try to allocate any vreg that's
-     * used as the start of a pair first.
-     */
-    for (int i = 0; i < numRegs; i++) {
-        if (fpRegs[i].doubleStart) {
-            fpRegs[i].count *= 2;
-        }
-    }
-
-    // Sort the count arrays
-    qsort(coreRegs, numRegs, sizeof(RefCounts), sortCounts);
-    qsort(fpRegs, numRegs, sizeof(RefCounts), sortCounts);
-
-    if (cUnit->printMe) {
-        dumpCounts(coreRegs, numRegs, "Core regs after sort");
-        dumpCounts(fpRegs, numRegs, "Fp regs after sort");
-    }
-
-    if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
-        // Promote fpRegs
-        for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
-            if (cUnit->promotionMap[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
-                if (fpRegs[i].sReg >= cUnit->numRegs) {
-                    // don't promote arg regs
-                    continue;
-                }
-                int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
-                    fpRegs[i].doubleStart);
-                if (reg < 0) {
-                    break;  // No more left
-                }
-            }
+void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
+{
+    RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
+    RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
+    DCHECK(info1 && info2 && info1->pair && info2->pair &&
+           (info1->partner == info2->reg) &&
+           (info2->partner == info1->reg));
+    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
+        if (!(info1->isTemp && info2->isTemp)) {
+            /* Should not happen.  If it does, there's a problem in evalLoc */
+            LOG(FATAL) << "Long half-temp, half-promoted";
         }
 
-        // Promote core regs
-        for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
-            if (cUnit->promotionMap[coreRegs[i].sReg].coreLocation !=
-                    kLocPhysReg) {
-                if (coreRegs[i].sReg >= cUnit->numRegs) {
-                    // don't promote arg regs
-                    continue;
-                }
-                int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
-                if (reg < 0) {
-                   break;  // No more left
-                }
-            }
-        }
-    }
-
-    // Now, update SSA names to new home locations
-    for (int i = 0; i < cUnit->numSSARegs; i++) {
-        RegLocation *curr = &cUnit->regLocation[i];
-        int baseVReg = oatS2VReg(cUnit, curr->sRegLow);
-        if (!curr->wide) {
-            if (curr->fp) {
-                if (cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) {
-                    curr->location = kLocPhysReg;
-                    curr->lowReg = cUnit->promotionMap[baseVReg].fpReg;
-                    curr->home = true;
-                }
-            } else {
-                if (cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg) {
-                    curr->location = kLocPhysReg;
-                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
-                    curr->home = true;
-                }
-            }
-            curr->highReg = INVALID_REG;
-        } else {
-            if (curr->highWord) {
-                continue;
-            }
-            if (curr->fp) {
-                if ((cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) &&
-                    (cUnit->promotionMap[baseVReg+1].fpLocation ==
-                    kLocPhysReg)) {
-                    int lowReg = cUnit->promotionMap[baseVReg].fpReg;
-                    int highReg = cUnit->promotionMap[baseVReg+1].fpReg;
-                    // Doubles require pair of singles starting at even reg
-                    if (((lowReg & 0x1) == 0) && ((lowReg + 1) == highReg)) {
-                        curr->location = kLocPhysReg;
-                        curr->lowReg = lowReg;
-                        curr->highReg = highReg;
-                        curr->home = true;
-                    }
-                }
-            } else {
-                if ((cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg)
-                     && (cUnit->promotionMap[baseVReg+1].coreLocation ==
-                     kLocPhysReg)) {
-                    curr->location = kLocPhysReg;
-                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
-                    curr->highReg = cUnit->promotionMap[baseVReg+1].coreReg;
-                    curr->home = true;
-                }
-            }
-        }
+        info1->dirty = false;
+        info2->dirty = false;
+        if (oatS2VReg(cUnit, info2->sReg) <
+            oatS2VReg(cUnit, info1->sReg))
+            info1 = info2;
+        int vReg = oatS2VReg(cUnit, info1->sReg);
+        oatFlushRegWideImpl(cUnit, rSP,
+                                    oatVRegOffset(cUnit, vReg),
+                                    info1->reg, info1->partner);
     }
 }
 
-/* Returns sp-relative offset in bytes for a VReg */
-extern int oatVRegOffset(CompilationUnit* cUnit, int vReg)
+void oatFlushReg(CompilationUnit* cUnit, int reg)
 {
-    return (vReg < cUnit->numRegs) ? cUnit->regsOffset + (vReg << 2) :
-            cUnit->insOffset + ((vReg - cUnit->numRegs) << 2);
+    RegisterInfo* info = oatGetRegInfo(cUnit, reg);
+    if (info->live && info->dirty) {
+        info->dirty = false;
+        int vReg = oatS2VReg(cUnit, info->sReg);
+        oatFlushRegImpl(cUnit, rSP,
+                                oatVRegOffset(cUnit, vReg),
+                                reg, kWord);
+    }
 }
 
-/* Returns sp-relative offset in bytes for a SReg */
-extern int oatSRegOffset(CompilationUnit* cUnit, int sReg)
-{
-    return oatVRegOffset(cUnit, oatS2VReg(cUnit, sReg));
+/* Give access to the target-dependent FP register encoding to common code */
+bool oatIsFpReg(int reg) {
+    return FPREG(reg);
 }
 
-
-/* Return sp-relative offset in bytes using Method* */
-extern int oatVRegOffset(const DexFile::CodeItem* code_item,
-                         uint32_t core_spills, uint32_t fp_spills,
-                         size_t frame_size, int reg)
-{
-    int numIns = code_item->ins_size_;
-    int numRegs = code_item->registers_size_ - numIns;
-    int numOuts = code_item->outs_size_;
-    int numSpills = __builtin_popcount(core_spills) +
-                    __builtin_popcount(fp_spills);
-    int numPadding = (STACK_ALIGN_WORDS -
-        (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
-    int regsOffset = (numOuts + numPadding + 1) * 4;
-    int insOffset = frame_size + 4;
-    return (reg < numRegs) ? regsOffset + (reg << 2) :
-           insOffset + ((reg - numRegs) << 2);
+uint32_t oatFpRegMask() {
+    return FP_REG_MASK;
 }
 
 /* Clobber all regs that might be used by an external C call */
-extern void oatClobberCalleeSave(CompilationUnit *cUnit)
+void oatClobberCalleeSave(CompilationUnit *cUnit)
 {
     oatClobber(cUnit, r0);
     oatClobber(cUnit, r1);
@@ -340,4 +165,28 @@
                       : &cUnit->regPool->coreRegs[reg];
 }
 
+/* To be used when explicitly managing register use */
+extern void oatLockCallTemps(CompilationUnit* cUnit)
+{
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+    oatLockTemp(cUnit, r2);
+    oatLockTemp(cUnit, r3);
+}
+
+/* To be used when explicitly managing register use */
+extern void oatFreeCallTemps(CompilationUnit* cUnit)
+{
+    oatFreeTemp(cUnit, r0);
+    oatFreeTemp(cUnit, r1);
+    oatFreeTemp(cUnit, r2);
+    oatFreeTemp(cUnit, r3);
+}
+
+/* Convert an instruction to a NOP */
+STATIC void oatNopLIR( LIR* lir)
+{
+    ((ArmLIR*)lir)->flags.isNop = true;
+}
+
 }  // namespace art
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index 2990631..0cd7605 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -22,8 +22,6 @@
 
 namespace art {
 
-#define MAX_ASSEMBLER_RETRIES 50
-
 /*
  * opcode: ArmOpcode enum
  * skeleton: pre-designated bit-pattern for this opcode
@@ -977,92 +975,13 @@
  */
 #define PADDING_MOV_R5_R5               0x1C2D
 
-STATIC void pushWord(std::vector<uint16_t>&buf, int data) {
-    buf.push_back( data & 0xffff);
-    buf.push_back( (data >> 16) & 0xffff);
-}
-
-void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
-    while (buf.size() < (offset/2))
-        buf.push_back(0);
-}
-
-/* Write the numbers in the constant to the output stream */
-STATIC void installLiteralPools(CompilationUnit* cUnit)
-{
-    alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
-    ArmLIR* dataLIR = (ArmLIR*) cUnit->literalList;
-    while (dataLIR) {
-        pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
-        dataLIR = NEXT_LIR(dataLIR);
-    }
-}
-
-/* Write the switch tables to the output stream */
-STATIC void installSwitchTables(CompilationUnit* cUnit)
-{
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
-    while (true) {
-        SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
-             &iterator);
-        if (tabRec == NULL) break;
-        alignBuffer(cUnit->codeBuffer, tabRec->offset);
-        int bxOffset = tabRec->bxInst->generic.offset + 4;
-        if (cUnit->printMe) {
-            LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
-        }
-        if (tabRec->table[0] == kSparseSwitchSignature) {
-            int* keys = (int*)&(tabRec->table[2]);
-            for (int elems = 0; elems < tabRec->table[1]; elems++) {
-                int disp = tabRec->targets[elems]->generic.offset - bxOffset;
-                if (cUnit->printMe) {
-                    LOG(INFO) << "    Case[" << elems << "] key: 0x" <<
-                        std::hex << keys[elems] << ", disp: 0x" <<
-                        std::hex << disp;
-                }
-                pushWord(cUnit->codeBuffer, keys[elems]);
-                pushWord(cUnit->codeBuffer,
-                    tabRec->targets[elems]->generic.offset - bxOffset);
-            }
-        } else {
-            DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
-            for (int elems = 0; elems < tabRec->table[1]; elems++) {
-                int disp = tabRec->targets[elems]->generic.offset - bxOffset;
-                if (cUnit->printMe) {
-                    LOG(INFO) << "    Case[" << elems << "] disp: 0x" <<
-                        std::hex << disp;
-                }
-                pushWord(cUnit->codeBuffer,
-                         tabRec->targets[elems]->generic.offset - bxOffset);
-            }
-        }
-    }
-}
-
-/* Write the fill array dta to the output stream */
-STATIC void installFillArrayData(CompilationUnit* cUnit)
-{
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
-    while (true) {
-        FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
-             &iterator);
-        if (tabRec == NULL) break;
-        alignBuffer(cUnit->codeBuffer, tabRec->offset);
-        for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
-            cUnit->codeBuffer.push_back( tabRec->table[i]);
-        }
-    }
-}
-
 /*
  * Assemble the LIR into binary instruction format.  Note that we may
  * discover that pc-relative displacements may not fit the selected
  * instruction.
  */
-STATIC AssemblerStatus assembleInstructions(CompilationUnit* cUnit,
-                                            intptr_t startAddr)
+AssemblerStatus oatAssembleInstructions(CompilationUnit* cUnit,
+                                        intptr_t startAddr)
 {
     ArmLIR* lir;
     AssemblerStatus res = kSuccess;  // Assume success
@@ -1461,80 +1380,12 @@
     return res;
 }
 
-STATIC int assignLiteralOffsetCommon(LIR* lir, int offset)
-{
-    for (;lir != NULL; lir = lir->next) {
-        lir->offset = offset;
-        offset += 4;
-    }
-    return offset;
-}
-
-STATIC void createMappingTable(CompilationUnit* cUnit)
-{
-    ArmLIR* armLIR;
-    int currentDalvikOffset = -1;
-
-    for (armLIR = (ArmLIR *) cUnit->firstLIRInsn;
-         armLIR;
-         armLIR = NEXT_LIR(armLIR)) {
-        if ((armLIR->opcode >= 0) && !armLIR->flags.isNop &&
-            (currentDalvikOffset != armLIR->generic.dalvikOffset)) {
-            // Changed - need to emit a record
-            cUnit->mappingTable.push_back(armLIR->generic.offset);
-            cUnit->mappingTable.push_back(armLIR->generic.dalvikOffset);
-            currentDalvikOffset = armLIR->generic.dalvikOffset;
-        }
-    }
-}
-
-/* Determine the offset of each literal field */
-STATIC int assignLiteralOffset(CompilationUnit* cUnit, int offset)
-{
-    offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
-    return offset;
-}
-
-STATIC int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
-{
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
-    while (true) {
-        SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
-             &iterator);
-        if (tabRec == NULL) break;
-        tabRec->offset = offset;
-        if (tabRec->table[0] == kSparseSwitchSignature) {
-            offset += tabRec->table[1] * (sizeof(int) * 2);
-        } else {
-            DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
-            offset += tabRec->table[1] * sizeof(int);
-        }
-    }
-    return offset;
-}
-
-STATIC int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
-{
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
-    while (true) {
-        FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
-             &iterator);
-        if (tabRec == NULL) break;
-        tabRec->offset = offset;
-        offset += tabRec->size;
-        // word align
-        offset = (offset + 3) & ~3;
-        }
-    return offset;
-}
-
 /*
- * Walk the compilation unit and assign offsets to instructions
- * and literals and compute the total size of the compiled unit.
+ * Target-dependent offset assignment.
+ * TODO: normalize usage of flags.size and make this target
+ * independent.
  */
-void assignOffsets(CompilationUnit* cUnit)
+int oatAssignInsnOffsets(CompilationUnit* cUnit)
 {
     ArmLIR* armLIR;
     int offset = 0;
@@ -1559,61 +1410,7 @@
         /* Pseudo opcodes don't consume space */
     }
 
-    /* Const values have to be word aligned */
-    offset = (offset + 3) & ~3;
-
-    /* Set up offsets for literals */
-    cUnit->dataOffset = offset;
-
-    offset = assignLiteralOffset(cUnit, offset);
-
-    offset = assignSwitchTablesOffset(cUnit, offset);
-
-    offset = assignFillArrayDataOffset(cUnit, offset);
-
-    cUnit->totalSize = offset;
-}
-/*
- * Go over each instruction in the list and calculate the offset from the top
- * before sending them off to the assembler. If out-of-range branch distance is
- * seen rearrange the instructions a bit to correct it.
- */
-void oatAssembleLIR(CompilationUnit* cUnit)
-{
-    assignOffsets(cUnit);
-    /*
-     * Assemble here.  Note that we generate code with optimistic assumptions
-     * and if found now to work, we'll have to redo the sequence and retry.
-     */
-
-    while (true) {
-        AssemblerStatus res = assembleInstructions(cUnit, 0);
-        if (res == kSuccess) {
-            break;
-        } else {
-            cUnit->assemblerRetries++;
-            if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
-                LOG(FATAL) << "Assembler error - too many retries";
-            }
-            // Redo offsets and try again
-            assignOffsets(cUnit);
-            cUnit->codeBuffer.clear();
-        }
-    }
-
-    // Install literals
-    installLiteralPools(cUnit);
-
-    // Install switch tables
-    installSwitchTables(cUnit);
-
-    // Install fill array data
-    installFillArrayData(cUnit);
-
-    /*
-     * Create the mapping table
-     */
-    createMappingTable(cUnit);
+    return offset;
 }
 
 }  // namespace art
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
deleted file mode 100644
index 4efa27a..0000000
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ /dev/null
@@ -1,1978 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "object_utils.h"
-
-namespace art {
-
-#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
-    (1 << kDebugDisplayMissingTargets))
-
-STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, INVALID_REG,
-                                   INVALID_REG, INVALID_SREG};
-
-/* Mark register usage state and return long retloc */
-STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
-{
-    RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
-    oatLockTemp(cUnit, res.lowReg);
-    oatLockTemp(cUnit, res.highReg);
-    oatMarkPair(cUnit, res.lowReg, res.highReg);
-    return res;
-}
-
-STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
-{
-    RegLocation res = LOC_DALVIK_RETURN_VAL;
-    oatLockTemp(cUnit, res.lowReg);
-    return res;
-}
-
-/*
- * Let helper function take care of everything.  Will call
- * Array::AllocFromCode(type_idx, method, count);
- * Note: AllocFromCode will handle checks for errNegativeArraySize.
- */
-STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
-                        RegLocation rlSrc)
-{
-    oatFlushAllRegs(cUnit);    /* Everything to home location */
-    uint32_t type_idx = mir->dalvikInsn.vC;
-    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
-                                                    cUnit->dex_cache,
-                                                    *cUnit->dex_file,
-                                                    type_idx)) {
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
-    } else {
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
-    }
-    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
-    loadConstant(cUnit, r0, type_idx);            // arg0 <- type_id
-    loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
-    callRuntimeHelper(cUnit, rLR);
-    RegLocation rlResult = oatGetReturn(cUnit);
-    storeValue(cUnit, rlDest, rlResult);
-}
-
-/*
- * Similar to genNewArray, but with post-allocation initialization.
- * Verifier guarantees we're dealing with an array class.  Current
- * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
- * Current code also throws internal unimp if not 'L', '[' or 'I'.
- */
-STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
-{
-    DecodedInstruction* dInsn = &mir->dalvikInsn;
-    int elems = dInsn->vA;
-    int typeId = dInsn->vB;
-    oatFlushAllRegs(cUnit);    /* Everything to home location */
-    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
-                                                    cUnit->dex_cache,
-                                                    *cUnit->dex_file,
-                                                    typeId)) {
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
-    } else {
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
-    }
-    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
-    loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
-    loadConstant(cUnit, r2, elems);               // arg2 <- count
-    callRuntimeHelper(cUnit, rLR);
-    /*
-     * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
-     * return region.  Because AllocFromCode placed the new array
-     * in r0, we'll just lock it into place.  When debugger support is
-     * added, it may be necessary to additionally copy all return
-     * values to a home location in thread-local storage
-     */
-    oatLockTemp(cUnit, r0);
-
-    // Having a range of 0 is legal
-    if (isRange && (dInsn->vA > 0)) {
-        /*
-         * Bit of ugliness here.  We're going generate a mem copy loop
-         * on the register range, but it is possible that some regs
-         * in the range have been promoted.  This is unlikely, but
-         * before generating the copy, we'll just force a flush
-         * of any regs in the source range that have been promoted to
-         * home location.
-         */
-        for (unsigned int i = 0; i < dInsn->vA; i++) {
-            RegLocation loc = oatUpdateLoc(cUnit,
-                oatGetSrc(cUnit, mir, i));
-            if (loc.location == kLocPhysReg) {
-                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
-                              loc.lowReg, kWord);
-            }
-        }
-        /*
-         * TUNING note: generated code here could be much improved, but
-         * this is an uncommon operation and isn't especially performance
-         * critical.
-         */
-        int rSrc = oatAllocTemp(cUnit);
-        int rDst = oatAllocTemp(cUnit);
-        int rIdx = oatAllocTemp(cUnit);
-        int rVal = rLR;  // Using a lot of temps, rLR is known free here
-        // Set up source pointer
-        RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
-        opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
-                    oatSRegOffset(cUnit, rlFirst.sRegLow));
-        // Set up the target pointer
-        opRegRegImm(cUnit, kOpAdd, rDst, r0,
-                    Array::DataOffset().Int32Value());
-        // Set up the loop counter (known to be > 0)
-        loadConstant(cUnit, rIdx, dInsn->vA - 1);
-        // Generate the copy loop.  Going backwards for convenience
-        ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
-        target->defMask = ENCODE_ALL;
-        // Copy next element
-        loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
-        storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
-        // Use setflags encoding here
-        newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
-        ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
-        branch->generic.target = (LIR*)target;
-    } else if (!isRange) {
-        // TUNING: interleave
-        for (unsigned int i = 0; i < dInsn->vA; i++) {
-            RegLocation rlArg = loadValue(cUnit,
-                oatGetSrc(cUnit, mir, i), kCoreReg);
-            storeBaseDisp(cUnit, r0,
-                          Array::DataOffset().Int32Value() +
-                          i * 4, rlArg.lowReg, kWord);
-            // If the loadValue caused a temp to be allocated, free it
-            if (oatIsTemp(cUnit, rlArg.lowReg)) {
-                oatFreeTemp(cUnit, rlArg.lowReg);
-            }
-        }
-    }
-}
-
-STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
-                    bool isLongOrDouble, bool isObject)
-{
-    int fieldOffset;
-    int ssbIndex;
-    bool isVolatile;
-    bool isReferrersClass;
-    uint32_t fieldIdx = mir->dalvikInsn.vB;
-    bool fastPath =
-        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
-                                                fieldOffset, ssbIndex,
-                                                isReferrersClass, isVolatile, true);
-    if (fastPath && !SLOW_FIELD_PATH) {
-        DCHECK_GE(fieldOffset, 0);
-        int rBase;
-        int rMethod;
-        if (isReferrersClass) {
-            // Fast path, static storage base is this method's class
-            rMethod  = loadCurrMethod(cUnit);
-            rBase = oatAllocTemp(cUnit);
-            loadWordDisp(cUnit, rMethod,
-                         Method::DeclaringClassOffset().Int32Value(), rBase);
-        } else {
-            // Medium path, static storage base in a different class which
-            // requires checks that the other class is initialized.
-            DCHECK_GE(ssbIndex, 0);
-            // May do runtime call so everything to home locations.
-            oatFlushAllRegs(cUnit);
-            // Using fixed register to sync with possible call to runtime
-            // support.
-            rMethod = r1;
-            oatLockTemp(cUnit, rMethod);
-            loadCurrMethodDirect(cUnit, rMethod);
-            rBase = r0;
-            oatLockTemp(cUnit, rBase);
-            loadWordDisp(cUnit, rMethod,
-                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
-                rBase);
-            loadWordDisp(cUnit, rBase,
-                         Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
-                         rBase);
-            // rBase now points at appropriate static storage base (Class*)
-            // or NULL if not initialized. Check for NULL and call helper if NULL.
-            // TUNING: fast path should fall through
-            ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
-            loadWordDisp(cUnit, rSELF,
-                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
-            loadConstant(cUnit, r0, ssbIndex);
-            callRuntimeHelper(cUnit, rLR);
-            ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
-            skipTarget->defMask = ENCODE_ALL;
-            branchOver->generic.target = (LIR*)skipTarget;
-        }
-        // rBase now holds static storage base
-        oatFreeTemp(cUnit, rMethod);
-        if (isLongOrDouble) {
-            rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
-            rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
-        } else {
-            rlSrc = oatGetSrc(cUnit, mir, 0);
-            rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
-        }
-        if (isVolatile) {
-            oatGenMemBarrier(cUnit, kST);
-        }
-        if (isLongOrDouble) {
-            storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
-                              rlSrc.highReg);
-        } else {
-            storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
-        }
-        if (isVolatile) {
-            oatGenMemBarrier(cUnit, kSY);
-        }
-        if (isObject) {
-            markGCCard(cUnit, rlSrc.lowReg, rBase);
-        }
-        oatFreeTemp(cUnit, rBase);
-    } else {
-        oatFlushAllRegs(cUnit);  // Everything to home locations
-        int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
-                           (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
-                                     : OFFSETOF_MEMBER(Thread, pSet32Static));
-        loadWordDisp(cUnit, rSELF, setterOffset, rLR);
-        loadConstant(cUnit, r0, fieldIdx);
-        if (isLongOrDouble) {
-            loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
-        } else {
-            loadValueDirect(cUnit, rlSrc, r1);
-        }
-        callRuntimeHelper(cUnit, rLR);
-    }
-}
-
-STATIC void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
-                    bool isLongOrDouble, bool isObject)
-{
-    int fieldOffset;
-    int ssbIndex;
-    bool isVolatile;
-    bool isReferrersClass;
-    uint32_t fieldIdx = mir->dalvikInsn.vB;
-    bool fastPath =
-        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
-                                                fieldOffset, ssbIndex,
-                                                isReferrersClass, isVolatile, false);
-    if (fastPath && !SLOW_FIELD_PATH) {
-        DCHECK_GE(fieldOffset, 0);
-        int rBase;
-        int rMethod;
-        if (isReferrersClass) {
-            // Fast path, static storage base is this method's class
-            rMethod  = loadCurrMethod(cUnit);
-            rBase = oatAllocTemp(cUnit);
-            loadWordDisp(cUnit, rMethod,
-                         Method::DeclaringClassOffset().Int32Value(), rBase);
-        } else {
-            // Medium path, static storage base in a different class which
-            // requires checks that the other class is initialized
-            DCHECK_GE(ssbIndex, 0);
-            // May do runtime call so everything to home locations.
-            oatFlushAllRegs(cUnit);
-            // Using fixed register to sync with possible call to runtime
-            // support
-            rMethod = r1;
-            oatLockTemp(cUnit, rMethod);
-            loadCurrMethodDirect(cUnit, rMethod);
-            rBase = r0;
-            oatLockTemp(cUnit, rBase);
-            loadWordDisp(cUnit, rMethod,
-                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
-                rBase);
-            loadWordDisp(cUnit, rBase,
-                         Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
-                         rBase);
-            // rBase now points at appropriate static storage base (Class*)
-            // or NULL if not initialized. Check for NULL and call helper if NULL.
-            // TUNING: fast path should fall through
-            ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
-            loadWordDisp(cUnit, rSELF,
-                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
-            loadConstant(cUnit, r0, ssbIndex);
-            callRuntimeHelper(cUnit, rLR);
-            ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
-            skipTarget->defMask = ENCODE_ALL;
-            branchOver->generic.target = (LIR*)skipTarget;
-        }
-        // rBase now holds static storage base
-        oatFreeTemp(cUnit, rMethod);
-        rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
-                                : oatGetDest(cUnit, mir, 0);
-        RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-        if (isVolatile) {
-            oatGenMemBarrier(cUnit, kSY);
-        }
-        if (isLongOrDouble) {
-            loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
-                             rlResult.highReg, INVALID_SREG);
-        } else {
-            loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
-        }
-        oatFreeTemp(cUnit, rBase);
-        if (isLongOrDouble) {
-            storeValueWide(cUnit, rlDest, rlResult);
-        } else {
-            storeValue(cUnit, rlDest, rlResult);
-        }
-    } else {
-        oatFlushAllRegs(cUnit);  // Everything to home locations
-        int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
-                           (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
-                                     : OFFSETOF_MEMBER(Thread, pGet32Static));
-        loadWordDisp(cUnit, rSELF, getterOffset, rLR);
-        loadConstant(cUnit, r0, fieldIdx);
-        callRuntimeHelper(cUnit, rLR);
-        if (isLongOrDouble) {
-            RegLocation rlResult = oatGetReturnWide(cUnit);
-            storeValueWide(cUnit, rlDest, rlResult);
-        } else {
-            RegLocation rlResult = oatGetReturn(cUnit);
-            storeValue(cUnit, rlDest, rlResult);
-        }
-    }
-}
-
-typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
-                            uint32_t methodIdx);
-
-/*
- * Bit of a hack here - in leiu of a real scheduling pass,
- * emit the next instruction in static & direct invoke sequences.
- */
-STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
-                          int state, uint32_t dexIdx, uint32_t unused)
-{
-    switch(state) {
-        case 0:  // Get the current Method* [sets r0]
-            loadCurrMethodDirect(cUnit, r0);
-            break;
-        case 1:  // Get method->code_and_direct_methods_
-            loadWordDisp(cUnit, r0,
-                Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
-                r0);
-            break;
-        case 2:  // Grab target method* and target code_
-            loadWordDisp(cUnit, r0,
-                CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
-            loadWordDisp(cUnit, r0,
-                CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
-            break;
-        default:
-            return -1;
-    }
-    return state + 1;
-}
-
-/*
- * Bit of a hack here - in leiu of a real scheduling pass,
- * emit the next instruction in a virtual invoke sequence.
- * We can use rLR as a temp prior to target address loading
- * Note also that we'll load the first argument ("this") into
- * r1 here rather than the standard loadArgRegs.
- */
-STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
-                         int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-    RegLocation rlArg;
-    /*
-     * This is the fast path in which the target virtual method is
-     * fully resolved at compile time.
-     */
-    switch(state) {
-        case 0:  // Get "this" [set r1]
-            rlArg = oatGetSrc(cUnit, mir, 0);
-            loadValueDirectFixed(cUnit, rlArg, r1);
-            break;
-        case 1: // Is "this" null? [use r1]
-            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
-            // get this->klass_ [use r1, set rLR]
-            loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
-            break;
-        case 2: // Get this->klass_->vtable [usr rLR, set rLR]
-            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
-            break;
-        case 3: // Get target method [use rLR, set r0]
-            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
-                         Array::DataOffset().Int32Value(), r0);
-            break;
-        case 4: // Get the target compiled code address [uses r0, sets rLR]
-            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
-            break;
-        default:
-            return -1;
-    }
-    return state + 1;
-}
-
-/*
- * Interleave launch code for INVOKE_SUPER.  See comments
- * for nextVCallIns.
- */
-STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
-                             int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-    /*
-     * This is the fast path in which the target virtual method is
-     * fully resolved at compile time.  Note also that this path assumes
-     * that the check to verify that the target method index falls
-     * within the size of the super's vtable has been done at compile-time.
-     */
-    RegLocation rlArg;
-    switch(state) {
-        case 0: // Get current Method* [set r0]
-            loadCurrMethodDirect(cUnit, r0);
-            // Load "this" [set r1]
-            rlArg = oatGetSrc(cUnit, mir, 0);
-            loadValueDirectFixed(cUnit, rlArg, r1);
-            // Get method->declaring_class_ [use r0, set rLR]
-            loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
-                         rLR);
-            // Is "this" null? [use r1]
-            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
-            break;
-        case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
-            loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
-                         rLR);
-            break;
-        case 2: // Get ...->super_class_->vtable [u/s rLR]
-            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
-            break;
-        case 3: // Get target method [use rLR, set r0]
-            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
-                         Array::DataOffset().Int32Value(), r0);
-            break;
-        case 4: // Get the target compiled code address [uses r0, sets rLR]
-            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
-            break;
-        default:
-            return -1;
-    }
-    return state + 1;
-}
-
-STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline,
-                            int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-    /*
-     * This handles the case in which the base method is not fully
-     * resolved at compile time, we bail to a runtime helper.
-     */
-    if (state == 0) {
-        // Load trampoline target
-        loadWordDisp(cUnit, rSELF, trampoline, rLR);
-        // Load r0 with method index
-        loadConstant(cUnit, r0, dexIdx);
-        return 1;
-    }
-    return -1;
-}
-
-STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
-                                int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir,
-                                int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
-                               int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
-                           int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-/*
- * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
- * which will locate the target and continue on via a tail call.
- */
-STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
-                                 int state, uint32_t dexIdx, uint32_t unused)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
-                                                MIR* mir, int state,
-                                                uint32_t dexIdx,
-                                                uint32_t unused)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
-                          DecodedInstruction* dInsn, int callState,
-                          NextCallInsn nextCallInsn, uint32_t dexIdx,
-                          uint32_t methodIdx, bool skipThis)
-{
-    int nextReg = r1;
-    int nextArg = 0;
-    if (skipThis) {
-        nextReg++;
-        nextArg++;
-    }
-    for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
-        RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
-        rlArg = oatUpdateRawLoc(cUnit, rlArg);
-        if (rlArg.wide && (nextReg <= r2)) {
-            loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
-            nextReg++;
-            nextArg++;
-        } else {
-            rlArg.wide = false;
-            loadValueDirectFixed(cUnit, rlArg, nextReg);
-        }
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-    }
-    return callState;
-}
-
-/*
- * Load up to 5 arguments, the first three of which will be in
- * r1 .. r3.  On entry r0 contains the current method pointer,
- * and as part of the load sequence, it must be replaced with
- * the target method pointer.  Note, this may also be called
- * for "range" variants if the number of arguments is 5 or fewer.
- */
-STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
-                                DecodedInstruction* dInsn, int callState,
-                                ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
-                                uint32_t dexIdx, uint32_t methodIdx,
-                                bool skipThis)
-{
-    RegLocation rlArg;
-
-    /* If no arguments, just return */
-    if (dInsn->vA == 0)
-        return callState;
-
-    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-
-    DCHECK_LE(dInsn->vA, 5U);
-    if (dInsn->vA > 3) {
-        uint32_t nextUse = 3;
-        //Detect special case of wide arg spanning arg3/arg4
-        RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
-        RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
-        RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
-        if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
-            rlUse2.wide) {
-            int reg;
-            // Wide spans, we need the 2nd half of uses[2].
-            rlArg = oatUpdateLocWide(cUnit, rlUse2);
-            if (rlArg.location == kLocPhysReg) {
-                reg = rlArg.highReg;
-            } else {
-                // r2 & r3 can safely be used here
-                reg = r3;
-                loadWordDisp(cUnit, rSP,
-                             oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
-                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
-                                         methodIdx);
-            }
-            storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
-            storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
-            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-            nextUse++;
-        }
-        // Loop through the rest
-        while (nextUse < dInsn->vA) {
-            int lowReg;
-            int highReg;
-            rlArg = oatGetRawSrc(cUnit, mir, nextUse);
-            rlArg = oatUpdateRawLoc(cUnit, rlArg);
-            if (rlArg.location == kLocPhysReg) {
-                lowReg = rlArg.lowReg;
-                highReg = rlArg.highReg;
-            } else {
-                lowReg = r2;
-                highReg = r3;
-                if (rlArg.wide) {
-                    loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
-                } else {
-                    loadValueDirectFixed(cUnit, rlArg, lowReg);
-                }
-                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
-                                         methodIdx);
-            }
-            int outsOffset = (nextUse + 1) * 4;
-            if (rlArg.wide) {
-                storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
-                nextUse += 2;
-            } else {
-                storeWordDisp(cUnit, rSP, outsOffset, lowReg);
-                nextUse++;
-            }
-            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-        }
-    }
-
-    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
-                            dexIdx, methodIdx, skipThis);
-
-    if (pcrLabel) {
-        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
-    }
-    return callState;
-}
-
-/*
- * May have 0+ arguments (also used for jumbo).  Note that
- * source virtual registers may be in physical registers, so may
- * need to be flushed to home location before copying.  This
- * applies to arg3 and above (see below).
- *
- * Two general strategies:
- *    If < 20 arguments
- *       Pass args 3-18 using vldm/vstm block copy
- *       Pass arg0, arg1 & arg2 in r1-r3
- *    If 20+ arguments
- *       Pass args arg19+ using memcpy block copy
- *       Pass arg0, arg1 & arg2 in r1-r3
- *
- */
-STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
-                              DecodedInstruction* dInsn, int callState,
-                              ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
-                              uint32_t dexIdx, uint32_t methodIdx,
-                              bool skipThis)
-{
-    int firstArg = dInsn->vC;
-    int numArgs = dInsn->vA;
-
-    // If we can treat it as non-range (Jumbo ops will use range form)
-    if (numArgs <= 5)
-        return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
-                                    nextCallInsn, dexIdx, methodIdx,
-                                    skipThis);
-    /*
-     * Make sure range list doesn't span the break between in normal
-     * Dalvik vRegs and the ins.
-     */
-    int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
-    int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
-    if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
-        LOG(FATAL) << "Argument list spanned locals & args";
-    }
-
-    /*
-     * First load the non-register arguments.  Both forms expect all
-     * of the source arguments to be in their home frame location, so
-     * scan the sReg names and flush any that have been promoted to
-     * frame backing storage.
-     */
-    // Scan the rest of the args - if in physReg flush to memory
-    for (int nextArg = 0; nextArg < numArgs;) {
-        RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
-        if (loc.wide) {
-            loc = oatUpdateLocWide(cUnit, loc);
-            if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
-                storeBaseDispWide(cUnit, rSP,
-                                  oatSRegOffset(cUnit, loc.sRegLow),
-                                  loc.lowReg, loc.highReg);
-            }
-            nextArg += 2;
-        } else {
-            loc = oatUpdateLoc(cUnit, loc);
-            if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
-                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
-                              loc.lowReg, kWord);
-            }
-            nextArg++;
-        }
-    }
-
-    int startOffset = oatSRegOffset(cUnit,
-        cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
-    int outsOffset = 4 /* Method* */ + (3 * 4);
-    if (numArgs >= 20) {
-        // Generate memcpy
-        opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
-        opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
-        loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
-        loadConstant(cUnit, r2, (numArgs - 3) * 4);
-        callRuntimeHelper(cUnit, rLR);
-        // Restore Method*
-        loadCurrMethodDirect(cUnit, r0);
-    } else {
-        // Use vldm/vstm pair using r3 as a temp
-        int regsLeft = std::min(numArgs - 3, 16);
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-        opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
-        ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
-        //TUNING: loosen barrier
-        ld->defMask = ENCODE_ALL;
-        setMemRefType(ld, true /* isLoad */, kDalvikReg);
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-        opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-        ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
-        setMemRefType(st, false /* isLoad */, kDalvikReg);
-        st->defMask = ENCODE_ALL;
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-    }
-
-    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
-                            dexIdx, methodIdx, skipThis);
-
-    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-    if (pcrLabel) {
-        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
-    }
-    return callState;
-}
-
-// Debugging routine - if null target, branch to DebugMe
-STATIC void genShowTarget(CompilationUnit* cUnit)
-{
-    ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
-    loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
-    ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
-    target->defMask = -1;
-    branchOver->generic.target = (LIR*)target;
-}
-
-STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir,
-                      InvokeType type, bool isRange)
-{
-    DecodedInstruction* dInsn = &mir->dalvikInsn;
-    int callState = 0;
-    ArmLIR* nullCk;
-    ArmLIR** pNullCk = NULL;
-    NextCallInsn nextCallInsn;
-    oatFlushAllRegs(cUnit);    /* Everything to home location */
-    // Explicit register usage
-    oatLockCallTemps(cUnit);
-
-    uint32_t dexMethodIdx = dInsn->vB;
-    int vtableIdx;
-    bool skipThis;
-    bool fastPath =
-        cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit, type,
-                                           vtableIdx)
-        && !SLOW_INVOKE_PATH;
-    if (type == kInterface) {
-      nextCallInsn = fastPath ? nextInterfaceCallInsn
-                              : nextInterfaceCallInsnWithAccessCheck;
-      skipThis = false;
-    } else if (type == kDirect) {
-      if (fastPath) {
-        pNullCk = &nullCk;
-      }
-      nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
-      skipThis = false;
-    } else if (type == kStatic) {
-      nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
-      skipThis = false;
-    } else if (type == kSuper) {
-      nextCallInsn = fastPath ? nextSuperCallInsn : nextSuperCallInsnSP;
-      skipThis = fastPath;
-    } else {
-      DCHECK_EQ(type, kVirtual);
-      nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
-      skipThis = fastPath;
-    }
-    if (!isRange) {
-        callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
-                                         nextCallInsn, dexMethodIdx,
-                                         vtableIdx, skipThis);
-    } else {
-        callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
-                                       nextCallInsn, dexMethodIdx, vtableIdx,
-                                       skipThis);
-    }
-    // Finish up any of the call sequence not interleaved in arg loading
-    while (callState >= 0) {
-        callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
-                                 vtableIdx);
-    }
-    if (DISPLAY_MISSING_TARGETS) {
-        genShowTarget(cUnit);
-    }
-    opReg(cUnit, kOpBlx, rLR);
-    oatClobberCalleeSave(cUnit);
-}
-
-STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
-                                     BasicBlock* bb, ArmLIR* labelList)
-{
-    bool res = false;   // Assume success
-    RegLocation rlSrc[3];
-    RegLocation rlDest = badLoc;
-    RegLocation rlResult = badLoc;
-    Opcode opcode = mir->dalvikInsn.opcode;
-
-    /* Prep Src and Dest locations */
-    int nextSreg = 0;
-    int nextLoc = 0;
-    int attrs = oatDataFlowAttributes[opcode];
-    rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
-    if (attrs & DF_UA) {
-        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
-        nextSreg++;
-    } else if (attrs & DF_UA_WIDE) {
-        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
-                                                 nextSreg + 1);
-        nextSreg+= 2;
-    }
-    if (attrs & DF_UB) {
-        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
-        nextSreg++;
-    } else if (attrs & DF_UB_WIDE) {
-        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
-                                                 nextSreg + 1);
-        nextSreg+= 2;
-    }
-    if (attrs & DF_UC) {
-        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
-    } else if (attrs & DF_UC_WIDE) {
-        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
-                                                 nextSreg + 1);
-    }
-    if (attrs & DF_DA) {
-        rlDest = oatGetDest(cUnit, mir, 0);
-    } else if (attrs & DF_DA_WIDE) {
-        rlDest = oatGetDestWide(cUnit, mir, 0, 1);
-    }
-
-    switch(opcode) {
-        case OP_NOP:
-            break;
-
-        case OP_MOVE_EXCEPTION:
-            int exOffset;
-            int resetReg;
-            exOffset = Thread::ExceptionOffset().Int32Value();
-            resetReg = oatAllocTemp(cUnit);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
-            loadConstant(cUnit, resetReg, 0);
-            storeWordDisp(cUnit, rSELF, exOffset, resetReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_RETURN_VOID:
-            genSuspendTest(cUnit, mir);
-            break;
-
-        case OP_RETURN:
-        case OP_RETURN_OBJECT:
-            genSuspendTest(cUnit, mir);
-            storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
-            break;
-
-        case OP_RETURN_WIDE:
-            genSuspendTest(cUnit, mir);
-            storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
-            break;
-
-        case OP_MOVE_RESULT_WIDE:
-            if (mir->optimizationFlags & MIR_INLINED)
-                break;  // Nop - combined w/ previous invoke
-            storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
-            break;
-
-        case OP_MOVE_RESULT:
-        case OP_MOVE_RESULT_OBJECT:
-            if (mir->optimizationFlags & MIR_INLINED)
-                break;  // Nop - combined w/ previous invoke
-            storeValue(cUnit, rlDest, getRetLoc(cUnit));
-            break;
-
-        case OP_MOVE:
-        case OP_MOVE_OBJECT:
-        case OP_MOVE_16:
-        case OP_MOVE_OBJECT_16:
-        case OP_MOVE_FROM16:
-        case OP_MOVE_OBJECT_FROM16:
-            storeValue(cUnit, rlDest, rlSrc[0]);
-            break;
-
-        case OP_MOVE_WIDE:
-        case OP_MOVE_WIDE_16:
-        case OP_MOVE_WIDE_FROM16:
-            storeValueWide(cUnit, rlDest, rlSrc[0]);
-            break;
-
-        case OP_CONST:
-        case OP_CONST_4:
-        case OP_CONST_16:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_HIGH16:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantNoClobber(cUnit, rlResult.lowReg,
-                                  mir->dalvikInsn.vB << 16);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_WIDE_16:
-        case OP_CONST_WIDE_32:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
-                                  mir->dalvikInsn.vB,
-                                  (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
-            storeValueWide(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_WIDE:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
-                          mir->dalvikInsn.vB_wide & 0xffffffff,
-                          (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
-            storeValueWide(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_WIDE_HIGH16:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
-                                  0, mir->dalvikInsn.vB << 16);
-            storeValueWide(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_MONITOR_ENTER:
-            genMonitorEnter(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_MONITOR_EXIT:
-            genMonitorExit(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_CHECK_CAST:
-            genCheckCast(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_INSTANCE_OF:
-            genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
-            break;
-
-        case OP_NEW_INSTANCE:
-            genNewInstance(cUnit, mir, rlDest);
-            break;
-
-        case OP_THROW:
-            genThrow(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_THROW_VERIFICATION_ERROR:
-            loadWordDisp(cUnit, rSELF,
-                OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
-            loadConstant(cUnit, r0, mir->dalvikInsn.vA);
-            loadConstant(cUnit, r1, mir->dalvikInsn.vB);
-            callRuntimeHelper(cUnit, rLR);
-            break;
-
-        case OP_ARRAY_LENGTH:
-            int lenOffset;
-            lenOffset = Array::LengthOffset().Int32Value();
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
-                         rlResult.lowReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_STRING:
-        case OP_CONST_STRING_JUMBO:
-            genConstString(cUnit, mir, rlDest, rlSrc[0]);
-            break;
-
-        case OP_CONST_CLASS:
-            genConstClass(cUnit, mir, rlDest, rlSrc[0]);
-            break;
-
-        case OP_FILL_ARRAY_DATA:
-            genFillArrayData(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_FILLED_NEW_ARRAY:
-            genFilledNewArray(cUnit, mir, false /* not range */);
-            break;
-
-        case OP_FILLED_NEW_ARRAY_RANGE:
-            genFilledNewArray(cUnit, mir, true /* range */);
-            break;
-
-        case OP_NEW_ARRAY:
-            genNewArray(cUnit, mir, rlDest, rlSrc[0]);
-            break;
-
-        case OP_GOTO:
-        case OP_GOTO_16:
-        case OP_GOTO_32:
-            if (bb->taken->startOffset <= mir->offset) {
-                genSuspendTest(cUnit, mir);
-            }
-            genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
-            break;
-
-        case OP_PACKED_SWITCH:
-            genPackedSwitch(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_SPARSE_SWITCH:
-            genSparseSwitch(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_CMPL_FLOAT:
-        case OP_CMPG_FLOAT:
-        case OP_CMPL_DOUBLE:
-        case OP_CMPG_DOUBLE:
-            res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_CMP_LONG:
-            genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_IF_EQ:
-        case OP_IF_NE:
-        case OP_IF_LT:
-        case OP_IF_GE:
-        case OP_IF_GT:
-        case OP_IF_LE: {
-            bool backwardBranch;
-            ArmConditionCode cond;
-            backwardBranch = (bb->taken->startOffset <= mir->offset);
-            if (backwardBranch) {
-                genSuspendTest(cUnit, mir);
-            }
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
-            opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
-            switch(opcode) {
-                case OP_IF_EQ:
-                    cond = kArmCondEq;
-                    break;
-                case OP_IF_NE:
-                    cond = kArmCondNe;
-                    break;
-                case OP_IF_LT:
-                    cond = kArmCondLt;
-                    break;
-                case OP_IF_GE:
-                    cond = kArmCondGe;
-                    break;
-                case OP_IF_GT:
-                    cond = kArmCondGt;
-                    break;
-                case OP_IF_LE:
-                    cond = kArmCondLe;
-                    break;
-                default:
-                    cond = (ArmConditionCode)0;
-                    LOG(FATAL) << "Unexpected opcode " << (int)opcode;
-            }
-            genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
-            genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
-            break;
-            }
-
-        case OP_IF_EQZ:
-        case OP_IF_NEZ:
-        case OP_IF_LTZ:
-        case OP_IF_GEZ:
-        case OP_IF_GTZ:
-        case OP_IF_LEZ: {
-            bool backwardBranch;
-            ArmConditionCode cond;
-            backwardBranch = (bb->taken->startOffset <= mir->offset);
-            if (backwardBranch) {
-                genSuspendTest(cUnit, mir);
-            }
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
-            switch(opcode) {
-                case OP_IF_EQZ:
-                    cond = kArmCondEq;
-                    break;
-                case OP_IF_NEZ:
-                    cond = kArmCondNe;
-                    break;
-                case OP_IF_LTZ:
-                    cond = kArmCondLt;
-                    break;
-                case OP_IF_GEZ:
-                    cond = kArmCondGe;
-                    break;
-                case OP_IF_GTZ:
-                    cond = kArmCondGt;
-                    break;
-                case OP_IF_LEZ:
-                    cond = kArmCondLe;
-                    break;
-                default:
-                    cond = (ArmConditionCode)0;
-                    LOG(FATAL) << "Unexpected opcode " << (int)opcode;
-            }
-            genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
-            genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
-            break;
-            }
-
-      case OP_AGET_WIDE:
-            genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
-            break;
-        case OP_AGET:
-        case OP_AGET_OBJECT:
-            genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
-            break;
-        case OP_AGET_BOOLEAN:
-            genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
-                        rlDest, 0);
-            break;
-        case OP_AGET_BYTE:
-            genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
-            break;
-        case OP_AGET_CHAR:
-            genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
-                        rlDest, 1);
-            break;
-        case OP_AGET_SHORT:
-            genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
-            break;
-        case OP_APUT_WIDE:
-            genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
-            break;
-        case OP_APUT:
-            genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
-            break;
-        case OP_APUT_OBJECT:
-            genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
-            break;
-        case OP_APUT_SHORT:
-        case OP_APUT_CHAR:
-            genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
-                        rlSrc[0], 1);
-            break;
-        case OP_APUT_BYTE:
-        case OP_APUT_BOOLEAN:
-            genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
-                        rlSrc[0], 0);
-            break;
-
-        case OP_IGET_OBJECT:
-        case OP_IGET_OBJECT_VOLATILE:
-            genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, true);
-            break;
-
-        case OP_IGET_WIDE:
-        case OP_IGET_WIDE_VOLATILE:
-            genIGet(cUnit, mir, kLong, rlDest, rlSrc[0], true, false);
-            break;
-
-        case OP_IGET:
-        case OP_IGET_VOLATILE:
-            genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, false);
-            break;
-
-        case OP_IGET_CHAR:
-            genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0], false, false);
-            break;
-
-        case OP_IGET_SHORT:
-            genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0], false, false);
-            break;
-
-        case OP_IGET_BOOLEAN:
-        case OP_IGET_BYTE:
-            genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0], false, false);
-            break;
-
-        case OP_IPUT_WIDE:
-        case OP_IPUT_WIDE_VOLATILE:
-            genIPut(cUnit, mir, kLong, rlSrc[0], rlSrc[1], true, false);
-            break;
-
-        case OP_IPUT_OBJECT:
-        case OP_IPUT_OBJECT_VOLATILE:
-            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, true);
-            break;
-
-        case OP_IPUT:
-        case OP_IPUT_VOLATILE:
-            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, false);
-            break;
-
-        case OP_IPUT_BOOLEAN:
-        case OP_IPUT_BYTE:
-            genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false, false);
-            break;
-
-        case OP_IPUT_CHAR:
-            genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false);
-            break;
-
-        case OP_IPUT_SHORT:
-            genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false, false);
-            break;
-
-        case OP_SGET_OBJECT:
-          genSget(cUnit, mir, rlDest, false, true);
-          break;
-        case OP_SGET:
-        case OP_SGET_BOOLEAN:
-        case OP_SGET_BYTE:
-        case OP_SGET_CHAR:
-        case OP_SGET_SHORT:
-            genSget(cUnit, mir, rlDest, false, false);
-            break;
-
-        case OP_SGET_WIDE:
-            genSget(cUnit, mir, rlDest, true, false);
-            break;
-
-        case OP_SPUT_OBJECT:
-          genSput(cUnit, mir, rlSrc[0], false, true);
-          break;
-
-        case OP_SPUT:
-        case OP_SPUT_BOOLEAN:
-        case OP_SPUT_BYTE:
-        case OP_SPUT_CHAR:
-        case OP_SPUT_SHORT:
-            genSput(cUnit, mir, rlSrc[0], false, false);
-            break;
-
-        case OP_SPUT_WIDE:
-            genSput(cUnit, mir, rlSrc[0], true, false);
-            break;
-
-        case OP_INVOKE_STATIC_RANGE:
-            genInvoke(cUnit, mir, kStatic, true /*range*/);
-            break;
-        case OP_INVOKE_STATIC:
-            genInvoke(cUnit, mir, kStatic, false /*range*/);
-            break;
-
-        case OP_INVOKE_DIRECT:
-            genInvoke(cUnit, mir, kDirect, false /*range*/);
-            break;
-        case OP_INVOKE_DIRECT_RANGE:
-            genInvoke(cUnit, mir, kDirect, true /*range*/);
-            break;
-
-        case OP_INVOKE_VIRTUAL:
-            genInvoke(cUnit, mir, kVirtual, false /*range*/);
-            break;
-        case OP_INVOKE_VIRTUAL_RANGE:
-            genInvoke(cUnit, mir, kVirtual, true /*range*/);
-            break;
-
-        case OP_INVOKE_SUPER:
-            genInvoke(cUnit, mir, kSuper, false /*range*/);
-            break;
-        case OP_INVOKE_SUPER_RANGE:
-            genInvoke(cUnit, mir, kSuper, true /*range*/);
-            break;
-
-        case OP_INVOKE_INTERFACE:
-            genInvoke(cUnit, mir, kInterface, false /*range*/);
-            break;
-        case OP_INVOKE_INTERFACE_RANGE:
-            genInvoke(cUnit, mir, kInterface, true /*range*/);
-            break;
-
-        case OP_NEG_INT:
-        case OP_NOT_INT:
-            res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
-            break;
-
-        case OP_NEG_LONG:
-        case OP_NOT_LONG:
-            res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
-            break;
-
-        case OP_NEG_FLOAT:
-            res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
-            break;
-
-        case OP_NEG_DOUBLE:
-            res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
-            break;
-
-        case OP_INT_TO_LONG:
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            if (rlSrc[0].location == kLocPhysReg) {
-                genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
-            } else {
-                loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
-            }
-            opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
-                        rlResult.lowReg, 31);
-            storeValueWide(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_LONG_TO_INT:
-            rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
-            rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
-            storeValue(cUnit, rlDest, rlSrc[0]);
-            break;
-
-        case OP_INT_TO_BYTE:
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_INT_TO_SHORT:
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_INT_TO_CHAR:
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_INT_TO_FLOAT:
-        case OP_INT_TO_DOUBLE:
-        case OP_LONG_TO_FLOAT:
-        case OP_LONG_TO_DOUBLE:
-        case OP_FLOAT_TO_INT:
-        case OP_FLOAT_TO_LONG:
-        case OP_FLOAT_TO_DOUBLE:
-        case OP_DOUBLE_TO_INT:
-        case OP_DOUBLE_TO_LONG:
-        case OP_DOUBLE_TO_FLOAT:
-            genConversion(cUnit, mir);
-            break;
-
-        case OP_ADD_INT:
-        case OP_SUB_INT:
-        case OP_MUL_INT:
-        case OP_DIV_INT:
-        case OP_REM_INT:
-        case OP_AND_INT:
-        case OP_OR_INT:
-        case OP_XOR_INT:
-        case OP_SHL_INT:
-        case OP_SHR_INT:
-        case OP_USHR_INT:
-        case OP_ADD_INT_2ADDR:
-        case OP_SUB_INT_2ADDR:
-        case OP_MUL_INT_2ADDR:
-        case OP_DIV_INT_2ADDR:
-        case OP_REM_INT_2ADDR:
-        case OP_AND_INT_2ADDR:
-        case OP_OR_INT_2ADDR:
-        case OP_XOR_INT_2ADDR:
-        case OP_SHL_INT_2ADDR:
-        case OP_SHR_INT_2ADDR:
-        case OP_USHR_INT_2ADDR:
-            genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_ADD_LONG:
-        case OP_SUB_LONG:
-        case OP_MUL_LONG:
-        case OP_DIV_LONG:
-        case OP_REM_LONG:
-        case OP_AND_LONG:
-        case OP_OR_LONG:
-        case OP_XOR_LONG:
-        case OP_ADD_LONG_2ADDR:
-        case OP_SUB_LONG_2ADDR:
-        case OP_MUL_LONG_2ADDR:
-        case OP_DIV_LONG_2ADDR:
-        case OP_REM_LONG_2ADDR:
-        case OP_AND_LONG_2ADDR:
-        case OP_OR_LONG_2ADDR:
-        case OP_XOR_LONG_2ADDR:
-            genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_SHL_LONG:
-        case OP_SHR_LONG:
-        case OP_USHR_LONG:
-        case OP_SHL_LONG_2ADDR:
-        case OP_SHR_LONG_2ADDR:
-        case OP_USHR_LONG_2ADDR:
-            genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_ADD_FLOAT:
-        case OP_SUB_FLOAT:
-        case OP_MUL_FLOAT:
-        case OP_DIV_FLOAT:
-        case OP_REM_FLOAT:
-        case OP_ADD_FLOAT_2ADDR:
-        case OP_SUB_FLOAT_2ADDR:
-        case OP_MUL_FLOAT_2ADDR:
-        case OP_DIV_FLOAT_2ADDR:
-        case OP_REM_FLOAT_2ADDR:
-            genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_ADD_DOUBLE:
-        case OP_SUB_DOUBLE:
-        case OP_MUL_DOUBLE:
-        case OP_DIV_DOUBLE:
-        case OP_REM_DOUBLE:
-        case OP_ADD_DOUBLE_2ADDR:
-        case OP_SUB_DOUBLE_2ADDR:
-        case OP_MUL_DOUBLE_2ADDR:
-        case OP_DIV_DOUBLE_2ADDR:
-        case OP_REM_DOUBLE_2ADDR:
-            genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_RSUB_INT:
-        case OP_ADD_INT_LIT16:
-        case OP_MUL_INT_LIT16:
-        case OP_DIV_INT_LIT16:
-        case OP_REM_INT_LIT16:
-        case OP_AND_INT_LIT16:
-        case OP_OR_INT_LIT16:
-        case OP_XOR_INT_LIT16:
-        case OP_ADD_INT_LIT8:
-        case OP_RSUB_INT_LIT8:
-        case OP_MUL_INT_LIT8:
-        case OP_DIV_INT_LIT8:
-        case OP_REM_INT_LIT8:
-        case OP_AND_INT_LIT8:
-        case OP_OR_INT_LIT8:
-        case OP_XOR_INT_LIT8:
-        case OP_SHL_INT_LIT8:
-        case OP_SHR_INT_LIT8:
-        case OP_USHR_INT_LIT8:
-            genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
-            break;
-
-        default:
-            res = true;
-    }
-    return res;
-}
-
-STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
-    "kMirOpPhi",
-    "kMirOpNullNRangeUpCheck",
-    "kMirOpNullNRangeDownCheck",
-    "kMirOpLowerBound",
-    "kMirOpPunt",
-    "kMirOpCheckInlinePrediction",
-};
-
-/* Extended MIR instructions like PHI */
-STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
-{
-    int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
-    char* msg = NULL;
-    if (cUnit->printMe) {
-        msg = (char*)oatNew(cUnit, strlen(extendedMIROpNames[opOffset]) + 1,
-                            false, kAllocDebugInfo);
-        strcpy(msg, extendedMIROpNames[opOffset]);
-    }
-    ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
-
-    switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
-        case kMirOpPhi: {
-            char* ssaString = NULL;
-            if (cUnit->printMe) {
-                ssaString = oatGetSSAString(cUnit, mir->ssaRep);
-            }
-            op->flags.isNop = true;
-            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
-            break;
-        }
-        default:
-            break;
-    }
-}
-
-/*
- * If there are any ins passed in registers that have not been promoted
- * to a callee-save register, flush them to the frame.  Perform intial
- * assignment of promoted arguments.
- */
-STATIC void flushIns(CompilationUnit* cUnit)
-{
-    if (cUnit->numIns == 0)
-        return;
-    int firstArgReg = r1;
-    int lastArgReg = r3;
-    int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
-    /*
-     * Arguments passed in registers should be flushed
-     * to their backing locations in the frame for now.
-     * Also, we need to do initial assignment for promoted
-     * arguments.  NOTE: an older version of dx had an issue
-     * in which it would reuse static method argument registers.
-     * This could result in the same Dalvik virtual register
-     * being promoted to both core and fp regs.  In those
-     * cases, copy argument to both.  This will be uncommon
-     * enough that it isn't worth attempting to optimize.
-     */
-    for (int i = 0; i < cUnit->numIns; i++) {
-        PromotionMap vMap = cUnit->promotionMap[startVReg + i];
-        if (i <= (lastArgReg - firstArgReg)) {
-            // If arriving in register
-            if (vMap.coreLocation == kLocPhysReg) {
-                genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
-            }
-            if (vMap.fpLocation == kLocPhysReg) {
-                genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
-            }
-            // Also put a copy in memory in case we're partially promoted
-            storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
-                          firstArgReg + i, kWord);
-        } else {
-            // If arriving in frame & promoted
-            if (vMap.coreLocation == kLocPhysReg) {
-                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
-                             vMap.coreReg);
-            }
-            if (vMap.fpLocation == kLocPhysReg) {
-                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
-                             vMap.fpReg);
-            }
-        }
-    }
-}
-
-/* Handle the content in each basic block */
-STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
-{
-    MIR* mir;
-    ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
-    int blockId = bb->id;
-
-    cUnit->curBlock = bb;
-    labelList[blockId].operands[0] = bb->startOffset;
-
-    /* Insert the block label */
-    labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
-    oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
-
-    /* Reset local optimization data on block boundaries */
-    oatResetRegPool(cUnit);
-    oatClobberAllRegs(cUnit);
-    oatResetDefTracking(cUnit);
-
-    ArmLIR* headLIR = NULL;
-
-    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
-    if (bb->blockType == kEntryBlock) {
-        /*
-         * On entry, r0, r1, r2 & r3 are live.  Let the register allocation
-         * mechanism know so it doesn't try to use any of them when
-         * expanding the frame or flushing.  This leaves the utility
-         * code with a single temp: r12.  This should be enough.
-         */
-        oatLockTemp(cUnit, r0);
-        oatLockTemp(cUnit, r1);
-        oatLockTemp(cUnit, r2);
-        oatLockTemp(cUnit, r3);
-
-        /*
-         * We can safely skip the stack overflow check if we're
-         * a leaf *and* our frame size < fudge factor.
-         */
-        bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
-                                  ((size_t)cUnit->frameSize <
-                                  Thread::kStackOverflowReservedBytes));
-        newLIR0(cUnit, kArmPseudoMethodEntry);
-        if (!skipOverflowCheck) {
-            /* Load stack limit */
-            loadWordDisp(cUnit, rSELF,
-                         Thread::StackEndOffset().Int32Value(), r12);
-        }
-        /* Spill core callee saves */
-        newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
-        /* Need to spill any FP regs? */
-        if (cUnit->numFPSpills) {
-            /*
-             * NOTE: fp spills are a little different from core spills in that
-             * they are pushed as a contiguous block.  When promoting from
-             * the fp set, we must allocate all singles from s16..highest-promoted
-             */
-            newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
-        }
-        if (!skipOverflowCheck) {
-            opRegRegImm(cUnit, kOpSub, rLR, rSP,
-                        cUnit->frameSize - (spillCount * 4));
-            genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
-                           kArmThrowStackOverflow);
-            genRegCopy(cUnit, rSP, rLR);         // Establish stack
-        } else {
-            opRegImm(cUnit, kOpSub, rSP,
-                     cUnit->frameSize - (spillCount * 4));
-        }
-        storeBaseDisp(cUnit, rSP, 0, r0, kWord);
-        flushIns(cUnit);
-
-        if (cUnit->genDebugger) {
-            // Refresh update debugger callout
-            loadWordDisp(cUnit, rSELF,
-                         OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
-            genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
-        }
-
-        oatFreeTemp(cUnit, r0);
-        oatFreeTemp(cUnit, r1);
-        oatFreeTemp(cUnit, r2);
-        oatFreeTemp(cUnit, r3);
-    } else if (bb->blockType == kExitBlock) {
-        /*
-         * In the exit path, r0/r1 are live - make sure they aren't
-         * allocated by the register utilities as temps.
-         */
-        oatLockTemp(cUnit, r0);
-        oatLockTemp(cUnit, r1);
-
-        newLIR0(cUnit, kArmPseudoMethodExit);
-        /* If we're compiling for the debugger, generate an update callout */
-        if (cUnit->genDebugger) {
-            genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
-        }
-        opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
-        /* Need to restore any FP callee saves? */
-        if (cUnit->numFPSpills) {
-            newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
-        }
-        if (cUnit->coreSpillMask & (1 << rLR)) {
-            /* Unspill rLR to rPC */
-            cUnit->coreSpillMask &= ~(1 << rLR);
-            cUnit->coreSpillMask |= (1 << rPC);
-        }
-        newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
-        if (!(cUnit->coreSpillMask & (1 << rPC))) {
-            /* We didn't pop to rPC, so must do a bv rLR */
-            newLIR1(cUnit, kThumbBx, rLR);
-        }
-    }
-
-    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
-
-        oatResetRegPool(cUnit);
-        if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
-            oatClobberAllRegs(cUnit);
-        }
-
-        if (cUnit->disableOpt & (1 << kSuppressLoads)) {
-            oatResetDefTracking(cUnit);
-        }
-
-        if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
-            handleExtendedMethodMIR(cUnit, mir);
-            continue;
-        }
-
-        cUnit->currentDalvikOffset = mir->offset;
-
-        Opcode dalvikOpcode = mir->dalvikInsn.opcode;
-        InstructionFormat dalvikFormat =
-            dexGetFormatFromOpcode(dalvikOpcode);
-
-        ArmLIR* boundaryLIR;
-
-        /* Mark the beginning of a Dalvik instruction for line tracking */
-        char* instStr = cUnit->printMe ?
-           oatGetDalvikDisassembly(cUnit, &mir->dalvikInsn, "") : NULL;
-        boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
-                              (intptr_t) instStr);
-        cUnit->boundaryMap.insert(std::make_pair(mir->offset,
-                                 (LIR*)boundaryLIR));
-        /* Remember the first LIR for this block */
-        if (headLIR == NULL) {
-            headLIR = boundaryLIR;
-            /* Set the first boundaryLIR as a scheduling barrier */
-            headLIR->defMask = ENCODE_ALL;
-        }
-
-        /* If we're compiling for the debugger, generate an update callout */
-        if (cUnit->genDebugger) {
-            genDebuggerUpdate(cUnit, mir->offset);
-        }
-
-        /* Don't generate the SSA annotation unless verbose mode is on */
-        if (cUnit->printMe && mir->ssaRep) {
-            char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
-            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
-        }
-
-        bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
-
-        if (notHandled) {
-            char buf[100];
-            snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
-                 mir->offset,
-                 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
-                 dalvikFormat);
-            LOG(FATAL) << buf;
-        }
-    }
-
-    if (headLIR) {
-        /*
-         * Eliminate redundant loads/stores and delay stores into later
-         * slots
-         */
-        oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
-                                           cUnit->lastLIRInsn);
-
-        /*
-         * Generate an unconditional branch to the fallthrough block.
-         */
-        if (bb->fallThrough) {
-            genUnconditionalBranch(cUnit,
-                                   &labelList[bb->fallThrough->id]);
-        }
-    }
-    return false;
-}
-
-/*
- * Nop any unconditional branches that go to the next instruction.
- * Note: new redundant branches may be inserted later, and we'll
- * use a check in final instruction assembly to nop those out.
- */
-void removeRedundantBranches(CompilationUnit* cUnit)
-{
-    ArmLIR* thisLIR;
-
-    for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
-         thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
-         thisLIR = NEXT_LIR(thisLIR)) {
-
-        /* Branch to the next instruction */
-        if ((thisLIR->opcode == kThumbBUncond) ||
-            (thisLIR->opcode == kThumb2BUncond)) {
-            ArmLIR* nextLIR = thisLIR;
-
-            while (true) {
-                nextLIR = NEXT_LIR(nextLIR);
-
-                /*
-                 * Is the branch target the next instruction?
-                 */
-                if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
-                    thisLIR->flags.isNop = true;
-                    break;
-                }
-
-                /*
-                 * Found real useful stuff between the branch and the target.
-                 * Need to explicitly check the lastLIRInsn here because it
-                 * might be the last real instruction.
-                 */
-                if (!isPseudoOpcode(nextLIR->opcode) ||
-                    (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
-                    break;
-            }
-        }
-    }
-}
-
-STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
-{
-    ArmLIR** suspendLabel =
-        (ArmLIR **) cUnit->suspendLaunchpads.elemList;
-    int numElems = cUnit->suspendLaunchpads.numUsed;
-
-    for (int i = 0; i < numElems; i++) {
-        /* TUNING: move suspend count load into helper */
-        ArmLIR* lab = suspendLabel[i];
-        ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
-        cUnit->currentDalvikOffset = lab->operands[1];
-        oatAppendLIR(cUnit, (LIR *)lab);
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
-        if (!cUnit->genDebugger) {
-            // use rSUSPEND for suspend count
-            loadWordDisp(cUnit, rSELF,
-                         Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
-        }
-        opReg(cUnit, kOpBlx, rLR);
-        if ( cUnit->genDebugger) {
-            // use rSUSPEND for update debugger
-            loadWordDisp(cUnit, rSELF,
-                         OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
-        }
-        genUnconditionalBranch(cUnit, resumeLab);
-    }
-}
-
-STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
-{
-    ArmLIR** throwLabel =
-        (ArmLIR **) cUnit->throwLaunchpads.elemList;
-    int numElems = cUnit->throwLaunchpads.numUsed;
-    int i;
-
-    for (i = 0; i < numElems; i++) {
-        ArmLIR* lab = throwLabel[i];
-        cUnit->currentDalvikOffset = lab->operands[1];
-        oatAppendLIR(cUnit, (LIR *)lab);
-        int funcOffset = 0;
-        int v1 = lab->operands[2];
-        int v2 = lab->operands[3];
-        switch(lab->operands[0]) {
-            case kArmThrowNullPointer:
-                funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
-                break;
-            case kArmThrowArrayBounds:
-                if (v2 != r0) {
-                    genRegCopy(cUnit, r0, v1);
-                    genRegCopy(cUnit, r1, v2);
-                } else {
-                    if (v1 == r1) {
-                        genRegCopy(cUnit, r12, v1);
-                        genRegCopy(cUnit, r1, v2);
-                        genRegCopy(cUnit, r0, r12);
-                    } else {
-                        genRegCopy(cUnit, r1, v2);
-                        genRegCopy(cUnit, r0, v1);
-                    }
-                }
-                funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
-                break;
-            case kArmThrowDivZero:
-                funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
-                break;
-            case kArmThrowVerificationError:
-                loadConstant(cUnit, r0, v1);
-                loadConstant(cUnit, r1, v2);
-                funcOffset =
-                    OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
-                break;
-            case kArmThrowNegArraySize:
-                genRegCopy(cUnit, r0, v1);
-                funcOffset =
-                    OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
-                break;
-            case kArmThrowNoSuchMethod:
-                genRegCopy(cUnit, r0, v1);
-                funcOffset =
-                    OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
-                break;
-            case kArmThrowStackOverflow:
-                funcOffset =
-                    OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
-                // Restore stack alignment
-                opRegImm(cUnit, kOpAdd, rSP,
-                         (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
-                break;
-            default:
-                LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
-        }
-        loadWordDisp(cUnit, rSELF, funcOffset, rLR);
-        callRuntimeHelper(cUnit, rLR);
-    }
-}
-
-void oatMethodMIR2LIR(CompilationUnit* cUnit)
-{
-    /* Used to hold the labels of each block */
-    cUnit->blockLabelList =
-        (void *) oatNew(cUnit, sizeof(ArmLIR) * cUnit->numBlocks, true,
-                        kAllocLIR);
-
-    oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
-                                  kPreOrderDFSTraversal, false /* Iterative */);
-    handleSuspendLaunchpads(cUnit);
-
-    handleThrowLaunchpads(cUnit);
-
-    removeRedundantBranches(cUnit);
-}
-
-/* Common initialization routine for an architecture family */
-bool oatArchInit()
-{
-    int i;
-
-    for (i = 0; i < kArmLast; i++) {
-        if (EncodingMap[i].opcode != i) {
-            LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
-               " is wrong: expecting " << i << ", seeing " <<
-               (int)EncodingMap[i].opcode;
-        }
-    }
-
-    return oatArchVariantInit();
-}
-
-/* Needed by the Assembler */
-void oatSetupResourceMasks(ArmLIR* lir)
-{
-    setupResourceMasks(lir);
-}
-
-/* Needed by the ld/st optmizatons */
-ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
-{
-    return genRegCopyNoInsert(cUnit, rDest, rSrc);
-}
-
-/* Needed by the register allocator */
-ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
-{
-    return genRegCopy(cUnit, rDest, rSrc);
-}
-
-/* Needed by the register allocator */
-void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
-                            int srcLo, int srcHi)
-{
-    genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
-}
-
-void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
-                             int displacement, int rSrc, OpSize size)
-{
-    storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
-}
-
-void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
-                                 int displacement, int rSrcLo, int rSrcHi)
-{
-    storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
-}
-
-}  // namespace art
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index dff05b7..c385f35 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -22,19 +22,22 @@
  *
  */
 
-#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath))
-#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath))
-#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath))
-#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath))
-#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \
-    (1 << kDebugSlowestFieldPath))
-#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \
-    (1 << kDebugSlowestStringPath))
-#define EXERCISE_RESOLVE_METHOD (cUnit->enableDebug & \
-    (1 << kDebugExerciseResolveMethod))
-
 namespace art {
 
+/*
+ * Return most flexible allowed register class based on size.
+ * Bug: 2813841
+ * Must use a core register for data types narrower than word (due
+ * to possible unaligned load/store.
+ */
+STATIC inline RegisterClass oatRegClassBySize(OpSize size)
+{
+    return (size == kUnsignedHalf ||
+            size == kSignedHalf ||
+            size == kUnsignedByte ||
+            size == kSignedByte ) ? kCoreReg : kAnyReg;
+}
+
 STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
 
 void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
@@ -67,20 +70,6 @@
 }
 #endif
 
-STATIC ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
-{
-    oatClobberCalleeSave(cUnit);
-    return opReg(cUnit, kOpBlx, reg);
-}
-
-/* Generate unconditional branch instructions */
-STATIC ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
-{
-    ArmLIR* branch = opNone(cUnit, kOpUncondBr);
-    branch->generic.target = (LIR*) target;
-    return branch;
-}
-
 /*
  * Generate a Thumb2 IT instruction, which can nullify up to
  * four subsequent instructions based on a condition and its
@@ -386,26 +375,6 @@
     callRuntimeHelper(cUnit, rLR);
 }
 
-/*
- * Mark garbage collection card. Skip if the value we're storing is null.
- */
-STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
-{
-    int regCardBase = oatAllocTemp(cUnit);
-    int regCardNo = oatAllocTemp(cUnit);
-    ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
-    loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
-                 regCardBase);
-    opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
-    storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
-                     kUnsignedByte);
-    ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
-    target->defMask = ENCODE_ALL;
-    branchOver->generic.target = (LIR*)target;
-    oatFreeTemp(cUnit, regCardBase);
-    oatFreeTemp(cUnit, regCardNo);
-}
-
 STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
                     RegLocation rlDest, RegLocation rlObj,
                     bool isLongOrDouble, bool isObject)
@@ -1274,16 +1243,6 @@
     return false;
 }
 
-/* Generate conditional branch instructions */
-STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
-                                    ArmConditionCode cond,
-                                    ArmLIR* target)
-{
-    ArmLIR* branch = opCondBranch(cUnit, cond);
-    branch->generic.target = (LIR*) target;
-    return branch;
-}
-
 /*
  * Generate array store
  *
diff --git a/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc b/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc
index 00339ef..f042d5d 100644
--- a/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc
+++ b/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc
@@ -18,11 +18,8 @@
 #define TGT_LIR ArmLIR
 
 #include "../../../Dalvik.h"
-//#include "interp/InterpDefs.h"
-//#include "libdex/DexOpcodes.h"
 #include "../../../CompilerInternals.h"
 #include "../arm/ArmLIR.h"
-//#include "mterp/common/FindInterface.h"
 #include "../../Ralloc.h"
 #include "../Codegen.h"
 
@@ -45,7 +42,13 @@
 #include "../Thumb2/Ralloc.cc"
 
 /* MIR2LIR dispatcher and architectural independent codegen routines */
-#include "../MethodCodegenDriver.cc"
+#include "../../MethodCodegenDriver.cc"
+
+/* Target-independent local optimizations */
+#include "../../LocalOptimizations.cc"
+
+/* Common codegen utility code */
+#include "../../CodegenUtil.cc"
 
 /* Architecture manifest */
 #include "ArchVariant.cc"
diff --git a/src/compiler/codegen/arm/armv7-a/Codegen.cc b/src/compiler/codegen/arm/armv7-a/Codegen.cc
index 384ce15..633ab1e 100644
--- a/src/compiler/codegen/arm/armv7-a/Codegen.cc
+++ b/src/compiler/codegen/arm/armv7-a/Codegen.cc
@@ -18,11 +18,8 @@
 #define TGT_LIR ArmLIR
 
 #include "../../../Dalvik.h"
-//#include "interp/InterpDefs.h"
-//#include "libdex/DexOpcodes.h"
 #include "../../../CompilerInternals.h"
 #include "../ArmLIR.h"
-//#include "mterp/common/FindInterface.h"
 #include "../../Ralloc.h"
 #include "../Codegen.h"
 
@@ -45,7 +42,13 @@
 #include "../Thumb2/Ralloc.cc"
 
 /* MIR2LIR dispatcher and architectural independent codegen routines */
-#include "../MethodCodegenDriver.cc"
+#include "../../MethodCodegenDriver.cc"
+
+/* Target-independent local optimizations */
+#include "../../LocalOptimizations.cc"
+
+/* Common codegen utility code */
+#include "../../CodegenUtil.cc"
 
 /* Architecture manifest */
 #include "ArchVariant.cc"
diff --git a/src/compiler/codegen/mips/ArchFactory.cc b/src/compiler/codegen/mips/ArchFactory.cc
new file mode 100644
index 0000000..6a3e667
--- /dev/null
+++ b/src/compiler/codegen/mips/ArchFactory.cc
@@ -0,0 +1,1416 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains mips-specific codegen factory support.
+ * It is included by
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath))
+#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath))
+#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath))
+#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath))
+#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \
+    (1 << kDebugSlowestFieldPath))
+#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \
+    (1 << kDebugSlowestStringPath))
+#define EXERCISE_RESOLVE_METHOD (cUnit->enableDebug & \
+    (1 << kDebugExerciseResolveMethod))
+
+// FIXME - this is the Mips version, change to MIPS
+
+namespace art {
+
+STATIC void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
+
+/* Generate conditional branch instructions */
+STATIC MipsLIR* genConditionalBranch(CompilationUnit* cUnit,
+                                    MipsConditionCode cond,
+                                    MipsLIR* target)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return NULL;
+#if 0
+    MipsLIR* branch = opCondBranch(cUnit, cond);
+    branch->generic.target = (LIR*) target;
+    return branch;
+#endif
+}
+
+/* Generate unconditional branch instructions */
+STATIC MipsLIR* genUnconditionalBranch(CompilationUnit* cUnit, MipsLIR* target)
+{
+    MipsLIR* branch = opNone(cUnit, kOpUncondBr);
+    branch->generic.target = (LIR*) target;
+    return branch;
+}
+
+STATIC MipsLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
+{
+    oatClobberCalleeSave(cUnit);
+    return opReg(cUnit, kOpBlx, reg);
+}
+
+/*
+ * Mark garbage collection card. Skip if the value we're storing is null.
+ */
+STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int regCardBase = oatAllocTemp(cUnit);
+    int regCardNo = oatAllocTemp(cUnit);
+    MipsLIR* branchOver = genCmpImmBranch(cUnit, kMipsCondEq, valReg, 0);
+    loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
+                 regCardBase);
+    opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
+    storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
+                     kUnsignedByte);
+    MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR*)target;
+    oatFreeTemp(cUnit, regCardBase);
+    oatFreeTemp(cUnit, regCardNo);
+#endif
+}
+
+/*
+ * Utiltiy to load the current Method*.  Broken out
+ * to allow easy change between placing the current Method* in a
+ * dedicated register or its home location in the frame.
+ */
+STATIC void loadCurrMethodDirect(CompilationUnit *cUnit, int rTgt)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+#if defined(METHOD_IN_REG)
+    genRegCopy(cUnit, rTgt, rMETHOD);
+#else
+    loadWordDisp(cUnit, rSP, 0, rTgt);
+#endif
+#endif
+}
+
+STATIC int loadCurrMethod(CompilationUnit *cUnit)
+{
+#if defined(METHOD_IN_REG)
+    return rMETHOD;
+#else
+    int mReg = oatAllocTemp(cUnit);
+    loadCurrMethodDirect(cUnit, mReg);
+    return mReg;
+#endif
+}
+
+STATIC MipsLIR* genCheck(CompilationUnit* cUnit, MipsConditionCode cCode,
+                        MIR* mir, MipsThrowKind kind)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return 0;
+#if 0
+    MipsLIR* tgt = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    tgt->opcode = kMipsPseudoThrowTarget;
+    tgt->operands[0] = kind;
+    tgt->operands[1] = mir ? mir->offset : 0;
+    MipsLIR* branch = genConditionalBranch(cUnit, cCode, tgt);
+    // Remember branch target - will process later
+    oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
+    return branch;
+#endif
+}
+
+STATIC MipsLIR* genImmedCheck(CompilationUnit* cUnit, MipsConditionCode cCode,
+                             int reg, int immVal, MIR* mir, MipsThrowKind kind)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return 0;
+#if 0
+    MipsLIR* tgt = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    tgt->opcode = kMipsPseudoThrowTarget;
+    tgt->operands[0] = kind;
+    tgt->operands[1] = mir->offset;
+    MipsLIR* branch;
+    if (cCode == kMipsCondAl) {
+        branch = genUnconditionalBranch(cUnit, tgt);
+    } else {
+        branch = genCmpImmBranch(cUnit, cCode, reg, immVal);
+        branch->generic.target = (LIR*)tgt;
+    }
+    // Remember branch target - will process later
+    oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
+    return branch;
+#endif
+}
+
+/* Perform null-check on a register.  */
+STATIC MipsLIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg,
+                             MIR* mir)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return 0;
+#if 0
+    if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
+        mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
+        return NULL;
+    }
+    return genImmedCheck(cUnit, kMipsCondEq, mReg, 0, mir, kMipsThrowNullPointer);
+#endif
+}
+
+/* Perform check on two registers */
+STATIC TGT_LIR* genRegRegCheck(CompilationUnit* cUnit, MipsConditionCode cCode,
+                               int reg1, int reg2, MIR* mir, MipsThrowKind kind)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return 0;
+#if 0
+    MipsLIR* tgt = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    tgt->opcode = kMipsPseudoThrowTarget;
+    tgt->operands[0] = kind;
+    tgt->operands[1] = mir ? mir->offset : 0;
+    tgt->operands[2] = reg1;
+    tgt->operands[3] = reg2;
+    opRegReg(cUnit, kOpCmp, reg1, reg2);
+    MipsLIR* branch = genConditionalBranch(cUnit, cCode, tgt);
+    // Remember branch target - will process later
+    oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
+    return branch;
+#endif
+}
+
+/*
+ * Let helper function take care of everything.  Will call
+ * Array::AllocFromCode(type_idx, method, count);
+ * Note: AllocFromCode will handle checks for errNegativeArraySize.
+ */
+STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    uint32_t type_idx = mir->dalvikInsn.vC;
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+                                                    cUnit->dex_cache,
+                                                    *cUnit->dex_file,
+                                                    type_idx)) {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
+    }
+    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
+    loadConstant(cUnit, r0, type_idx);            // arg0 <- type_id
+    loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
+    callRuntimeHelper(cUnit, rLR);
+    RegLocation rlResult = oatGetReturn(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+#endif
+}
+
+/*
+ * Similar to genNewArray, but with post-allocation initialization.
+ * Verifier guarantees we're dealing with an array class.  Current
+ * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
+ * Current code also throws internal unimp if not 'L', '[' or 'I'.
+ */
+STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    DecodedInstruction* dInsn = &mir->dalvikInsn;
+    int elems = dInsn->vA;
+    int typeId = dInsn->vB;
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+                                                    cUnit->dex_cache,
+                                                    *cUnit->dex_file,
+                                                    typeId)) {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
+    }
+    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
+    loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
+    loadConstant(cUnit, r2, elems);               // arg2 <- count
+    callRuntimeHelper(cUnit, rLR);
+    /*
+     * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
+     * return region.  Because AllocFromCode placed the new array
+     * in r0, we'll just lock it into place.  When debugger support is
+     * added, it may be necessary to additionally copy all return
+     * values to a home location in thread-local storage
+     */
+    oatLockTemp(cUnit, r0);
+
+    // Having a range of 0 is legal
+    if (isRange && (dInsn->vA > 0)) {
+        /*
+         * Bit of ugliness here.  We're going generate a mem copy loop
+         * on the register range, but it is possible that some regs
+         * in the range have been promoted.  This is unlikely, but
+         * before generating the copy, we'll just force a flush
+         * of any regs in the source range that have been promoted to
+         * home location.
+         */
+        for (unsigned int i = 0; i < dInsn->vA; i++) {
+            RegLocation loc = oatUpdateLoc(cUnit,
+                oatGetSrc(cUnit, mir, i));
+            if (loc.location == kLocPhysReg) {
+                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
+                              loc.lowReg, kWord);
+            }
+        }
+        /*
+         * TUNING note: generated code here could be much improved, but
+         * this is an uncommon operation and isn't especially performance
+         * critical.
+         */
+        int rSrc = oatAllocTemp(cUnit);
+        int rDst = oatAllocTemp(cUnit);
+        int rIdx = oatAllocTemp(cUnit);
+        int rVal = rLR;  // Using a lot of temps, rLR is known free here
+        // Set up source pointer
+        RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
+        opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
+                    oatSRegOffset(cUnit, rlFirst.sRegLow));
+        // Set up the target pointer
+        opRegRegImm(cUnit, kOpAdd, rDst, r0,
+                    Array::DataOffset().Int32Value());
+        // Set up the loop counter (known to be > 0)
+        loadConstant(cUnit, rIdx, dInsn->vA - 1);
+        // Generate the copy loop.  Going backwards for convenience
+        MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+        target->defMask = ENCODE_ALL;
+        // Copy next element
+        loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
+        storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
+        // Use setflags encoding here
+        newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
+        MipsLIR* branch = opCondBranch(cUnit, kMipsCondGe);
+        branch->generic.target = (LIR*)target;
+    } else if (!isRange) {
+        // TUNING: interleave
+        for (unsigned int i = 0; i < dInsn->vA; i++) {
+            RegLocation rlArg = loadValue(cUnit,
+                oatGetSrc(cUnit, mir, i), kCoreReg);
+            storeBaseDisp(cUnit, r0,
+                          Array::DataOffset().Int32Value() +
+                          i * 4, rlArg.lowReg, kWord);
+            // If the loadValue caused a temp to be allocated, free it
+            if (oatIsTemp(cUnit, rlArg.lowReg)) {
+                oatFreeTemp(cUnit, rlArg.lowReg);
+            }
+        }
+    }
+#endif
+}
+
+STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
+                    bool isLongOrDouble, bool isObject)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int fieldOffset;
+    int ssbIndex;
+    bool isVolatile;
+    bool isReferrersClass;
+    uint32_t fieldIdx = mir->dalvikInsn.vB;
+    bool fastPath =
+        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
+                                                fieldOffset, ssbIndex,
+                                                isReferrersClass, isVolatile, true);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        DCHECK_GE(fieldOffset, 0);
+        int rBase;
+        int rMethod;
+        if (isReferrersClass) {
+            // Fast path, static storage base is this method's class
+            rMethod  = loadCurrMethod(cUnit);
+            rBase = oatAllocTemp(cUnit);
+            loadWordDisp(cUnit, rMethod,
+                         Method::DeclaringClassOffset().Int32Value(), rBase);
+        } else {
+            // Medium path, static storage base in a different class which
+            // requires checks that the other class is initialized.
+            DCHECK_GE(ssbIndex, 0);
+            // May do runtime call so everything to home locations.
+            oatFlushAllRegs(cUnit);
+            // Using fixed register to sync with possible call to runtime
+            // support.
+            rMethod = r1;
+            oatLockTemp(cUnit, rMethod);
+            loadCurrMethodDirect(cUnit, rMethod);
+            rBase = r0;
+            oatLockTemp(cUnit, rBase);
+            loadWordDisp(cUnit, rMethod,
+                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
+                rBase);
+            loadWordDisp(cUnit, rBase,
+                         Array::DataOffset().Int32Value() + sizeof(int32_t*) *
+                         ssbIndex, rBase);
+            // rBase now points at appropriate static storage base (Class*)
+            // or NULL if not initialized. Check for NULL and call helper if NULL.
+            // TUNING: fast path should fall through
+            MipsLIR* branchOver = genCmpImmBranch(cUnit, kMipsCondNe, rBase, 0);
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
+            loadConstant(cUnit, r0, ssbIndex);
+            callRuntimeHelper(cUnit, rLR);
+            MipsLIR* skipTarget = newLIR0(cUnit, kMipsPseudoTargetLabel);
+            skipTarget->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR*)skipTarget;
+        }
+        // rBase now holds static storage base
+        oatFreeTemp(cUnit, rMethod);
+        if (isLongOrDouble) {
+            rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+            rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+        } else {
+            rlSrc = oatGetSrc(cUnit, mir, 0);
+            rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+        }
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kST);
+        }
+        if (isLongOrDouble) {
+            storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
+                              rlSrc.highReg);
+        } else {
+            storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
+        }
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kSY);
+        }
+        if (isObject) {
+            markGCCard(cUnit, rlSrc.lowReg, rBase);
+        }
+        oatFreeTemp(cUnit, rBase);
+    } else {
+        oatFlushAllRegs(cUnit);  // Everything to home locations
+        int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
+                                     : OFFSETOF_MEMBER(Thread, pSet32Static));
+        loadWordDisp(cUnit, rSELF, setterOffset, rLR);
+        loadConstant(cUnit, r0, fieldIdx);
+        if (isLongOrDouble) {
+            loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
+        } else {
+            loadValueDirect(cUnit, rlSrc, r1);
+        }
+        callRuntimeHelper(cUnit, rLR);
+    }
+#endif
+}
+
+STATIC void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                    bool isLongOrDouble, bool isObject)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int fieldOffset;
+    int ssbIndex;
+    bool isVolatile;
+    bool isReferrersClass;
+    uint32_t fieldIdx = mir->dalvikInsn.vB;
+    bool fastPath =
+        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
+                                                fieldOffset, ssbIndex,
+                                                isReferrersClass, isVolatile, false);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        DCHECK_GE(fieldOffset, 0);
+        int rBase;
+        int rMethod;
+        if (isReferrersClass) {
+            // Fast path, static storage base is this method's class
+            rMethod  = loadCurrMethod(cUnit);
+            rBase = oatAllocTemp(cUnit);
+            loadWordDisp(cUnit, rMethod,
+                         Method::DeclaringClassOffset().Int32Value(), rBase);
+        } else {
+            // Medium path, static storage base in a different class which
+            // requires checks that the other class is initialized
+            DCHECK_GE(ssbIndex, 0);
+            // May do runtime call so everything to home locations.
+            oatFlushAllRegs(cUnit);
+            // Using fixed register to sync with possible call to runtime
+            // support
+            rMethod = r1;
+            oatLockTemp(cUnit, rMethod);
+            loadCurrMethodDirect(cUnit, rMethod);
+            rBase = r0;
+            oatLockTemp(cUnit, rBase);
+            loadWordDisp(cUnit, rMethod,
+                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
+                rBase);
+            loadWordDisp(cUnit, rBase,
+                         Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
+                         rBase);
+            // rBase now points at appropriate static storage base (Class*)
+            // or NULL if not initialized. Check for NULL and call helper if NULL.
+            // TUNING: fast path should fall through
+            MipsLIR* branchOver = genCmpImmBranch(cUnit, kMipsCondNe, rBase, 0);
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
+            loadConstant(cUnit, r0, ssbIndex);
+            callRuntimeHelper(cUnit, rLR);
+            MipsLIR* skipTarget = newLIR0(cUnit, kMipsPseudoTargetLabel);
+            skipTarget->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR*)skipTarget;
+        }
+        // rBase now holds static storage base
+        oatFreeTemp(cUnit, rMethod);
+        rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
+                                : oatGetDest(cUnit, mir, 0);
+        RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kSY);
+        }
+        if (isLongOrDouble) {
+            loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
+                             rlResult.highReg, INVALID_SREG);
+        } else {
+            loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
+        }
+        oatFreeTemp(cUnit, rBase);
+        if (isLongOrDouble) {
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    } else {
+        oatFlushAllRegs(cUnit);  // Everything to home locations
+        int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
+                                     : OFFSETOF_MEMBER(Thread, pGet32Static));
+        loadWordDisp(cUnit, rSELF, getterOffset, rLR);
+        loadConstant(cUnit, r0, fieldIdx);
+        callRuntimeHelper(cUnit, rLR);
+        if (isLongOrDouble) {
+            RegLocation rlResult = oatGetReturnWide(cUnit);
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            RegLocation rlResult = oatGetReturn(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    }
+#endif
+}
+
+typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
+                            uint32_t methodIdx);
+
+/*
+ * Bit of a hack here - in leiu of a real scheduling pass,
+ * emit the next instruction in static & direct invoke sequences.
+ */
+STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
+                          int state, uint32_t dexIdx, uint32_t unused)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    switch(state) {
+        case 0:  // Get the current Method* [sets r0]
+            loadCurrMethodDirect(cUnit, r0);
+            break;
+        case 1:  // Get method->code_and_direct_methods_
+            loadWordDisp(cUnit, r0,
+                Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
+                r0);
+            break;
+        case 2:  // Grab target method* and target code_
+            loadWordDisp(cUnit, r0,
+                CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
+            loadWordDisp(cUnit, r0,
+                CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
+            break;
+        default:
+            return -1;
+    }
+#endif
+    return state + 1;
+}
+
+/*
+ * Bit of a hack here - in leiu of a real scheduling pass,
+ * emit the next instruction in a virtual invoke sequence.
+ * We can use rLR as a temp prior to target address loading
+ * Note also that we'll load the first argument ("this") into
+ * r1 here rather than the standard loadArgRegs.
+ */
+STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
+                         int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    RegLocation rlArg;
+    /*
+     * This is the fast path in which the target virtual method is
+     * fully resolved at compile time.
+     */
+    switch(state) {
+        case 0:  // Get "this" [set r1]
+            rlArg = oatGetSrc(cUnit, mir, 0);
+            loadValueDirectFixed(cUnit, rlArg, r1);
+            break;
+        case 1: // Is "this" null? [use r1]
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+            // get this->klass_ [use r1, set rLR]
+            loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
+            break;
+        case 2: // Get this->klass_->vtable [usr rLR, set rLR]
+            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
+            break;
+        case 3: // Get target method [use rLR, set r0]
+            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
+                         Array::DataOffset().Int32Value(), r0);
+            break;
+        case 4: // Get the target compiled code address [uses r0, sets rLR]
+            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
+            break;
+        default:
+            return -1;
+    }
+#endif
+    return state + 1;
+}
+
+/*
+ * Interleave launch code for INVOKE_SUPER.  See comments
+ * for nextVCallIns.
+ */
+STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
+                             int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    /*
+     * This is the fast path in which the target virtual method is
+     * fully resolved at compile time.  Note also that this path assumes
+     * that the check to verify that the target method index falls
+     * within the size of the super's vtable has been done at compile-time.
+     */
+    RegLocation rlArg;
+    switch(state) {
+        case 0: // Get current Method* [set r0]
+            loadCurrMethodDirect(cUnit, r0);
+            // Load "this" [set r1]
+            rlArg = oatGetSrc(cUnit, mir, 0);
+            loadValueDirectFixed(cUnit, rlArg, r1);
+            // Get method->declaring_class_ [use r0, set rLR]
+            loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
+                         rLR);
+            // Is "this" null? [use r1]
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+            break;
+        case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
+            loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
+                         rLR);
+            break;
+        case 2: // Get ...->super_class_->vtable [u/s rLR]
+            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
+            break;
+        case 3: // Get target method [use rLR, set r0]
+            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
+                         Array::DataOffset().Int32Value(), r0);
+            break;
+        case 4: // Get the target compiled code address [uses r0, sets rLR]
+            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
+            break;
+        default:
+            return -1;
+    }
+#endif
+    return state + 1;
+}
+
+STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline,
+                            int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    /*
+     * This handles the case in which the base method is not fully
+     * resolved at compile time, we bail to a runtime helper.
+     */
+    if (state == 0) {
+        // Load trampoline target
+        loadWordDisp(cUnit, rSELF, trampoline, rLR);
+        // Load r0 with method index
+        loadConstant(cUnit, r0, dexIdx);
+        return 1;
+    }
+#endif
+    return -1;
+}
+
+STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                               int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                           int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+/*
+ * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
+ * which will locate the target and continue on via a tail call.
+ */
+STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
+                                 int state, uint32_t dexIdx, uint32_t unused)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
+                                                MIR* mir, int state,
+                                                uint32_t dexIdx,
+                                                uint32_t unused)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
+                          DecodedInstruction* dInsn, int callState,
+                          NextCallInsn nextCallInsn, uint32_t dexIdx,
+                          uint32_t methodIdx, bool skipThis)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int nextReg = r1;
+    int nextArg = 0;
+    if (skipThis) {
+        nextReg++;
+        nextArg++;
+    }
+    for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
+        RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
+        rlArg = oatUpdateRawLoc(cUnit, rlArg);
+        if (rlArg.wide && (nextReg <= r2)) {
+            loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
+            nextReg++;
+            nextArg++;
+        } else {
+            rlArg.wide = false;
+            loadValueDirectFixed(cUnit, rlArg, nextReg);
+        }
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    }
+#endif
+    return callState;
+}
+
+/*
+ * Load up to 5 arguments, the first three of which will be in
+ * r1 .. r3.  On entry r0 contains the current method pointer,
+ * and as part of the load sequence, it must be replaced with
+ * the target method pointer.  Note, this may also be called
+ * for "range" variants if the number of arguments is 5 or fewer.
+ */
+STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
+                                DecodedInstruction* dInsn, int callState,
+                                MipsLIR** pcrLabel, NextCallInsn nextCallInsn,
+                                uint32_t dexIdx, uint32_t methodIdx,
+                                bool skipThis)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    RegLocation rlArg;
+
+    /* If no arguments, just return */
+    if (dInsn->vA == 0)
+        return callState;
+
+    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+
+    DCHECK_LE(dInsn->vA, 5U);
+    if (dInsn->vA > 3) {
+        uint32_t nextUse = 3;
+        //Detect special case of wide arg spanning arg3/arg4
+        RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
+        RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
+        RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
+        if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
+            rlUse2.wide) {
+            int reg;
+            // Wide spans, we need the 2nd half of uses[2].
+            rlArg = oatUpdateLocWide(cUnit, rlUse2);
+            if (rlArg.location == kLocPhysReg) {
+                reg = rlArg.highReg;
+            } else {
+                // r2 & r3 can safely be used here
+                reg = r3;
+                loadWordDisp(cUnit, rSP,
+                             oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
+                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+                                         methodIdx);
+            }
+            storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
+            storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
+            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+            nextUse++;
+        }
+        // Loop through the rest
+        while (nextUse < dInsn->vA) {
+            int lowReg;
+            int highReg;
+            rlArg = oatGetRawSrc(cUnit, mir, nextUse);
+            rlArg = oatUpdateRawLoc(cUnit, rlArg);
+            if (rlArg.location == kLocPhysReg) {
+                lowReg = rlArg.lowReg;
+                highReg = rlArg.highReg;
+            } else {
+                lowReg = r2;
+                highReg = r3;
+                if (rlArg.wide) {
+                    loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
+                } else {
+                    loadValueDirectFixed(cUnit, rlArg, lowReg);
+                }
+                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+                                         methodIdx);
+            }
+            int outsOffset = (nextUse + 1) * 4;
+            if (rlArg.wide) {
+                storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
+                nextUse += 2;
+            } else {
+                storeWordDisp(cUnit, rSP, outsOffset, lowReg);
+                nextUse++;
+            }
+            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        }
+    }
+
+    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+                            dexIdx, methodIdx, skipThis);
+
+    if (pcrLabel) {
+        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+    }
+#endif
+    return callState;
+}
+
+/*
+ * May have 0+ arguments (also used for jumbo).  Note that
+ * source virtual registers may be in physical registers, so may
+ * need to be flushed to home location before copying.  This
+ * applies to arg3 and above (see below).
+ *
+ * Two general strategies:
+ *    If < 20 arguments
+ *       Pass args 3-18 using vldm/vstm block copy
+ *       Pass arg0, arg1 & arg2 in r1-r3
+ *    If 20+ arguments
+ *       Pass args arg19+ using memcpy block copy
+ *       Pass arg0, arg1 & arg2 in r1-r3
+ *
+ */
+STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
+                              DecodedInstruction* dInsn, int callState,
+                              MipsLIR** pcrLabel, NextCallInsn nextCallInsn,
+                              uint32_t dexIdx, uint32_t methodIdx,
+                              bool skipThis)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int firstArg = dInsn->vC;
+    int numArgs = dInsn->vA;
+
+    // If we can treat it as non-range (Jumbo ops will use range form)
+    if (numArgs <= 5)
+        return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
+                                    nextCallInsn, dexIdx, methodIdx,
+                                    skipThis);
+    /*
+     * Make sure range list doesn't span the break between in normal
+     * Dalvik vRegs and the ins.
+     */
+    int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
+    int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
+    if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
+        LOG(FATAL) << "Argument list spanned locals & args";
+    }
+
+    /*
+     * First load the non-register arguments.  Both forms expect all
+     * of the source arguments to be in their home frame location, so
+     * scan the sReg names and flush any that have been promoted to
+     * frame backing storage.
+     */
+    // Scan the rest of the args - if in physReg flush to memory
+    for (int nextArg = 0; nextArg < numArgs;) {
+        RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
+        if (loc.wide) {
+            loc = oatUpdateLocWide(cUnit, loc);
+            if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
+                storeBaseDispWide(cUnit, rSP,
+                                  oatSRegOffset(cUnit, loc.sRegLow),
+                                  loc.lowReg, loc.highReg);
+            }
+            nextArg += 2;
+        } else {
+            loc = oatUpdateLoc(cUnit, loc);
+            if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
+                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
+                              loc.lowReg, kWord);
+            }
+            nextArg++;
+        }
+    }
+
+    int startOffset = oatSRegOffset(cUnit,
+        cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
+    int outsOffset = 4 /* Method* */ + (3 * 4);
+    if (numArgs >= 20) {
+        // Generate memcpy
+        opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
+        opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
+        loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
+        loadConstant(cUnit, r2, (numArgs - 3) * 4);
+        callRuntimeHelper(cUnit, rLR);
+        // Restore Method*
+        loadCurrMethodDirect(cUnit, r0);
+    } else {
+        // Use vldm/vstm pair using r3 as a temp
+        int regsLeft = std::min(numArgs - 3, 16);
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
+        MipsLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
+        //TUNING: loosen barrier
+        ld->defMask = ENCODE_ALL;
+        setMemRefType(ld, true /* isLoad */, kDalvikReg);
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        MipsLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
+        setMemRefType(st, false /* isLoad */, kDalvikReg);
+        st->defMask = ENCODE_ALL;
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    }
+
+    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+                            dexIdx, methodIdx, skipThis);
+
+    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    if (pcrLabel) {
+        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+    }
+#endif
+    return callState;
+}
+
+// Debugging routine - if null target, branch to DebugMe
+STATIC void genShowTarget(CompilationUnit* cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsLIR* branchOver = genCmpImmBranch(cUnit, kMipsCondNe, rLR, 0);
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
+    MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+    target->defMask = -1;
+    branchOver->generic.target = (LIR*)target;
+#endif
+}
+
+STATIC void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
+    loadConstant(cUnit, r0, mir->dalvikInsn.vA);
+    loadConstant(cUnit, r1, mir->dalvikInsn.vB);
+    callRuntimeHelper(cUnit, rLR);
+#endif
+}
+
+STATIC void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
+                                MIR* mir, RegLocation rlSrc1,
+                                RegLocation rlSrc2, MipsLIR* labelList)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsConditionCode cond;
+    rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+    opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
+    Opcode opcode = mir->dalvikInsn.opcode;
+    switch(opcode) {
+        case OP_IF_EQ:
+            cond = kMipsCondEq;
+            break;
+        case OP_IF_NE:
+            cond = kMipsCondNe;
+            break;
+        case OP_IF_LT:
+            cond = kMipsCondLt;
+            break;
+        case OP_IF_GE:
+            cond = kMipsCondGe;
+            break;
+        case OP_IF_GT:
+            cond = kMipsCondGt;
+            break;
+        case OP_IF_LE:
+            cond = kMipsCondLe;
+            break;
+        default:
+            cond = (MipsConditionCode)0;
+            LOG(FATAL) << "Unexpected opcode " << (int)opcode;
+    }
+    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+#endif
+}
+
+STATIC void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
+                                   MIR* mir, RegLocation rlSrc,
+                                   MipsLIR* labelList)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsConditionCode cond;
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
+    Opcode opcode = mir->dalvikInsn.opcode;
+    switch(opcode) {
+        case OP_IF_EQZ:
+            cond = kMipsCondEq;
+            break;
+        case OP_IF_NEZ:
+            cond = kMipsCondNe;
+            break;
+        case OP_IF_LTZ:
+            cond = kMipsCondLt;
+            break;
+        case OP_IF_GEZ:
+            cond = kMipsCondGe;
+            break;
+        case OP_IF_GTZ:
+            cond = kMipsCondGt;
+            break;
+        case OP_IF_LEZ:
+            cond = kMipsCondLe;
+            break;
+        default:
+            cond = (MipsConditionCode)0;
+            LOG(FATAL) << "Unexpected opcode " << (int)opcode;
+    }
+    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+#endif
+}
+
+STATIC void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                         RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+    if (rlSrc.location == kLocPhysReg) {
+        genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+    } else {
+        loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
+    }
+    opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
+                rlResult.lowReg, 31);
+    storeValueWide(cUnit, rlDest, rlResult);
+#endif
+}
+
+STATIC void genIntNarrowing(CompilationUnit* cUnit, MIR* mir,
+                            RegLocation rlDest, RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+     RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+     OpKind op = kOpInvalid;
+     switch(mir->dalvikInsn.opcode) {
+         case OP_INT_TO_BYTE:
+             op = kOp2Byte;
+             break;
+         case OP_INT_TO_SHORT:
+              op = kOp2Short;
+              break;
+         case OP_INT_TO_CHAR:
+              op = kOp2Char;
+              break;
+         default:
+             LOG(ERROR) << "Bad int conversion type";
+     }
+     opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
+     storeValue(cUnit, rlDest, rlResult);
+#endif
+}
+
+/*
+ * If there are any ins passed in registers that have not been promoted
+ * to a callee-save register, flush them to the frame.  Perform intial
+ * assignment of promoted arguments.
+ */
+STATIC void flushIns(CompilationUnit* cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    if (cUnit->numIns == 0)
+        return;
+    int firstArgReg = r1;
+    int lastArgReg = r3;
+    int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
+    /*
+     * Arguments passed in registers should be flushed
+     * to their backing locations in the frame for now.
+     * Also, we need to do initial assignment for promoted
+     * arguments.  NOTE: an older version of dx had an issue
+     * in which it would reuse static method argument registers.
+     * This could result in the same Dalvik virtual register
+     * being promoted to both core and fp regs.  In those
+     * cases, copy argument to both.  This will be uncommon
+     * enough that it isn't worth attempting to optimize.
+     */
+    for (int i = 0; i < cUnit->numIns; i++) {
+        PromotionMap vMap = cUnit->promotionMap[startVReg + i];
+        if (i <= (lastArgReg - firstArgReg)) {
+            // If arriving in register
+            if (vMap.coreLocation == kLocPhysReg) {
+                genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
+            }
+            if (vMap.fpLocation == kLocPhysReg) {
+                genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
+            }
+            // Also put a copy in memory in case we're partially promoted
+            storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                          firstArgReg + i, kWord);
+        } else {
+            // If arriving in frame & promoted
+            if (vMap.coreLocation == kLocPhysReg) {
+                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                             vMap.coreReg);
+            }
+            if (vMap.fpLocation == kLocPhysReg) {
+                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                             vMap.fpReg);
+            }
+        }
+    }
+#endif
+}
+
+STATIC void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
+    /*
+     * On entry, r0, r1, r2 & r3 are live.  Let the register allocation
+     * mechanism know so it doesn't try to use any of them when
+     * expanding the frame or flushing.  This leaves the utility
+     * code with a single temp: r12.  This should be enough.
+     */
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+    oatLockTemp(cUnit, r2);
+    oatLockTemp(cUnit, r3);
+
+    /*
+     * We can safely skip the stack overflow check if we're
+     * a leaf *and* our frame size < fudge factor.
+     */
+    bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
+                              ((size_t)cUnit->frameSize <
+                              Thread::kStackOverflowReservedBytes));
+    newLIR0(cUnit, kMipsPseudoMethodEntry);
+    if (!skipOverflowCheck) {
+        /* Load stack limit */
+        loadWordDisp(cUnit, rSELF,
+                     Thread::StackEndOffset().Int32Value(), r12);
+    }
+    /* Spill core callee saves */
+    newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
+    /* Need to spill any FP regs? */
+    if (cUnit->numFPSpills) {
+        /*
+         * NOTE: fp spills are a little different from core spills in that
+         * they are pushed as a contiguous block.  When promoting from
+         * the fp set, we must allocate all singles from s16..highest-promoted
+         */
+        newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
+    }
+    if (!skipOverflowCheck) {
+        opRegRegImm(cUnit, kOpSub, rLR, rSP,
+                    cUnit->frameSize - (spillCount * 4));
+        genRegRegCheck(cUnit, kMipsCondCc, rLR, r12, NULL,
+                       kMipsThrowStackOverflow);
+        genRegCopy(cUnit, rSP, rLR);         // Establish stack
+    } else {
+        opRegImm(cUnit, kOpSub, rSP,
+                 cUnit->frameSize - (spillCount * 4));
+    }
+    storeBaseDisp(cUnit, rSP, 0, r0, kWord);
+    flushIns(cUnit);
+
+    if (cUnit->genDebugger) {
+        // Refresh update debugger callout
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+        genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
+    }
+
+    oatFreeTemp(cUnit, r0);
+    oatFreeTemp(cUnit, r1);
+    oatFreeTemp(cUnit, r2);
+    oatFreeTemp(cUnit, r3);
+#endif
+}
+
+STATIC void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
+    /*
+     * In the exit path, r0/r1 are live - make sure they aren't
+     * allocated by the register utilities as temps.
+     */
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+
+    newLIR0(cUnit, kMipsPseudoMethodExit);
+    /* If we're compiling for the debugger, generate an update callout */
+    if (cUnit->genDebugger) {
+        genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
+    }
+    opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
+    /* Need to restore any FP callee saves? */
+    if (cUnit->numFPSpills) {
+        newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
+    }
+    if (cUnit->coreSpillMask & (1 << rLR)) {
+        /* Unspill rLR to rPC */
+        cUnit->coreSpillMask &= ~(1 << rLR);
+        cUnit->coreSpillMask |= (1 << rPC);
+    }
+    newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
+    if (!(cUnit->coreSpillMask & (1 << rPC))) {
+        /* We didn't pop to rPC, so must do a bv rLR */
+        newLIR1(cUnit, kThumbBx, rLR);
+    }
+#endif
+}
+
+/*
+ * Nop any unconditional branches that go to the next instruction.
+ * Note: new redundant branches may be inserted later, and we'll
+ * use a check in final instruction assembly to nop those out.
+ */
+void removeRedundantBranches(CompilationUnit* cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsLIR* thisLIR;
+
+    for (thisLIR = (MipsLIR*) cUnit->firstLIRInsn;
+         thisLIR != (MipsLIR*) cUnit->lastLIRInsn;
+         thisLIR = NEXT_LIR(thisLIR)) {
+
+        /* Branch to the next instruction */
+        if ((thisLIR->opcode == kThumbBUncond) ||
+            (thisLIR->opcode == kThumb2BUncond)) {
+            MipsLIR* nextLIR = thisLIR;
+
+            while (true) {
+                nextLIR = NEXT_LIR(nextLIR);
+
+                /*
+                 * Is the branch target the next instruction?
+                 */
+                if (nextLIR == (MipsLIR*) thisLIR->generic.target) {
+                    thisLIR->flags.isNop = true;
+                    break;
+                }
+
+                /*
+                 * Found real useful stuff between the branch and the target.
+                 * Need to explicitly check the lastLIRInsn here because it
+                 * might be the last real instruction.
+                 */
+                if (!isPseudoOpcode(nextLIR->opcode) ||
+                    (nextLIR = (MipsLIR*) cUnit->lastLIRInsn))
+                    break;
+            }
+        }
+    }
+#endif
+}
+
+STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsLIR** suspendLabel =
+        (MipsLIR **) cUnit->suspendLaunchpads.elemList;
+    int numElems = cUnit->suspendLaunchpads.numUsed;
+
+    for (int i = 0; i < numElems; i++) {
+        /* TUNING: move suspend count load into helper */
+        MipsLIR* lab = suspendLabel[i];
+        MipsLIR* resumeLab = (MipsLIR*)lab->operands[0];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
+        if (!cUnit->genDebugger) {
+            // use rSUSPEND for suspend count
+            loadWordDisp(cUnit, rSELF,
+                         Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
+        }
+        opReg(cUnit, kOpBlx, rLR);
+        if ( cUnit->genDebugger) {
+            // use rSUSPEND for update debugger
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+        }
+        genUnconditionalBranch(cUnit, resumeLab);
+    }
+#endif
+}
+
+STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsLIR** throwLabel =
+        (MipsLIR **) cUnit->throwLaunchpads.elemList;
+    int numElems = cUnit->throwLaunchpads.numUsed;
+    int i;
+
+    for (i = 0; i < numElems; i++) {
+        MipsLIR* lab = throwLabel[i];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        int funcOffset = 0;
+        int v1 = lab->operands[2];
+        int v2 = lab->operands[3];
+        switch(lab->operands[0]) {
+            case kMipsThrowNullPointer:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
+                break;
+            case kMipsThrowArrayBounds:
+                if (v2 != r0) {
+                    genRegCopy(cUnit, r0, v1);
+                    genRegCopy(cUnit, r1, v2);
+                } else {
+                    if (v1 == r1) {
+                        genRegCopy(cUnit, r12, v1);
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, r12);
+                    } else {
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, v1);
+                    }
+                }
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
+                break;
+            case kMipsThrowDivZero:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
+                break;
+            case kMipsThrowVerificationError:
+                loadConstant(cUnit, r0, v1);
+                loadConstant(cUnit, r1, v2);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
+                break;
+            case kMipsThrowNegArraySize:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
+                break;
+            case kMipsThrowNoSuchMethod:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
+                break;
+            case kMipsThrowStackOverflow:
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
+                // Restore stack alignment
+                opRegImm(cUnit, kOpAdd, rSP,
+                         (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
+                break;
+            default:
+                LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
+        }
+        loadWordDisp(cUnit, rSELF, funcOffset, rLR);
+        callRuntimeHelper(cUnit, rLR);
+    }
+#endif
+}
+
+/* Common initialization routine for an architecture family */
+bool oatArchInit()
+{
+    int i;
+
+    for (i = 0; i < kMipsLast; i++) {
+        if (EncodingMap[i].opcode != i) {
+            LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
+               " is wrong: expecting " << i << ", seeing " <<
+               (int)EncodingMap[i].opcode;
+        }
+    }
+
+    return oatArchVariantInit();
+}
+
+/* Needed by the Assembler */
+void oatSetupResourceMasks(MipsLIR* lir)
+{
+    setupResourceMasks(lir);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/ArchUtility.cc b/src/compiler/codegen/mips/ArchUtility.cc
new file mode 100644
index 0000000..f218436
--- /dev/null
+++ b/src/compiler/codegen/mips/ArchUtility.cc
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../../CompilerInternals.h"
+#include "MipsLIR.h"
+#include "../Ralloc.h"
+
+#include <string>
+
+namespace art {
+
+/* For dumping instructions */
+#define MIPS_REG_COUNT 32
+static const char *mipsRegName[MIPS_REG_COUNT] = {
+    "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+    "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
+};
+
+/*
+ * Interpret a format string and build a string no longer than size
+ * See format key in Assemble.c.
+ */
+STATIC std::string buildInsnString(const char *fmt, MipsLIR *lir, unsigned char* baseAddr)
+{
+    std::string buf;
+    int i;
+    const char *fmtEnd = &fmt[strlen(fmt)];
+    char tbuf[256];
+    char nc;
+    while (fmt < fmtEnd) {
+        int operand;
+        if (*fmt == '!') {
+            fmt++;
+            DCHECK_LT(fmt, fmtEnd);
+            nc = *fmt++;
+            if (nc=='!') {
+                strcpy(tbuf, "!");
+            } else {
+               DCHECK_LT(fmt, fmtEnd);
+               DCHECK_LT((unsigned)(nc-'0'), 4u);
+               operand = lir->operands[nc-'0'];
+               switch(*fmt++) {
+                   case 'b':
+                       strcpy(tbuf,"0000");
+                       for (i=3; i>= 0; i--) {
+                           tbuf[i] += operand & 1;
+                           operand >>= 1;
+                       }
+                       break;
+                   case 's':
+                       sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
+                       break;
+                   case 'S':
+                       DCHECK_EQ(((operand & FP_REG_MASK) & 1), 0);
+                       sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
+                       break;
+                   case 'h':
+                       sprintf(tbuf,"%04x", operand);
+                       break;
+                   case 'M':
+                   case 'd':
+                       sprintf(tbuf,"%d", operand);
+                       break;
+                   case 'D':
+                       sprintf(tbuf,"%d", operand+1);
+                       break;
+                   case 'E':
+                       sprintf(tbuf,"%d", operand*4);
+                       break;
+                   case 'F':
+                       sprintf(tbuf,"%d", operand*2);
+                       break;
+                   case 'c':
+                       switch (operand) {
+                           case kMipsCondEq:
+                               strcpy(tbuf, "eq");
+                               break;
+                           case kMipsCondNe:
+                               strcpy(tbuf, "ne");
+                               break;
+                           case kMipsCondLt:
+                               strcpy(tbuf, "lt");
+                               break;
+                           case kMipsCondGe:
+                               strcpy(tbuf, "ge");
+                               break;
+                           case kMipsCondGt:
+                               strcpy(tbuf, "gt");
+                               break;
+                           case kMipsCondLe:
+                               strcpy(tbuf, "le");
+                               break;
+                           case kMipsCondCs:
+                               strcpy(tbuf, "cs");
+                               break;
+                           case kMipsCondMi:
+                               strcpy(tbuf, "mi");
+                               break;
+                           default:
+                               strcpy(tbuf, "");
+                               break;
+                       }
+                       break;
+                   case 't':
+                       sprintf(tbuf,"0x%08x (L%p)",
+                               (int) baseAddr + lir->generic.offset + 4 +
+                               (operand << 2),
+                               lir->generic.target);
+                       break;
+                   case 'T':
+                       sprintf(tbuf,"0x%08x",
+                               (int) (operand << 2));
+                       break;
+                   case 'u': {
+                       int offset_1 = lir->operands[0];
+                       int offset_2 = NEXT_LIR(lir)->operands[0];
+                       intptr_t target =
+                           ((((intptr_t) baseAddr + lir->generic.offset + 4) &
+                            ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
+                           0xfffffffc;
+                       sprintf(tbuf, "%p", (void *) target);
+                       break;
+                    }
+
+                   /* Nothing to print for BLX_2 */
+                   case 'v':
+                       strcpy(tbuf, "see above");
+                       break;
+                   case 'r':
+                       DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
+                       strcpy(tbuf, mipsRegName[operand]);
+                       break;
+                   default:
+                       strcpy(tbuf,"DecodeError");
+                       break;
+               }
+               buf += tbuf;
+            }
+        } else {
+           buf += *fmt++;
+        }
+    }
+    return buf;
+}
+
+// FIXME: need to redo resourse maps for MIPS - fix this at that time
+void oatDumpResourceMask(LIR *lir, u8 mask, const char *prefix)
+{
+    char buf[256];
+    buf[0] = 0;
+    MipsLIR *mipsLIR = (MipsLIR *) lir;
+
+    if (mask == ENCODE_ALL) {
+        strcpy(buf, "all");
+    } else {
+        char num[8];
+        int i;
+
+        for (i = 0; i < kRegEnd; i++) {
+            if (mask & (1ULL << i)) {
+                sprintf(num, "%d ", i);
+                strcat(buf, num);
+            }
+        }
+
+        if (mask & ENCODE_CCODE) {
+            strcat(buf, "cc ");
+        }
+        if (mask & ENCODE_FP_STATUS) {
+            strcat(buf, "fpcc ");
+        }
+        /* Memory bits */
+        if (mipsLIR && (mask & ENCODE_DALVIK_REG)) {
+            sprintf(buf + strlen(buf), "dr%d%s", mipsLIR->aliasInfo & 0xffff,
+                    (mipsLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
+        }
+        if (mask & ENCODE_LITERAL) {
+            strcat(buf, "lit ");
+        }
+
+        if (mask & ENCODE_HEAP_REF) {
+            strcat(buf, "heap ");
+        }
+        if (mask & ENCODE_MUST_NOT_ALIAS) {
+            strcat(buf, "noalias ");
+        }
+    }
+    if (buf[0]) {
+        LOG(INFO) << prefix << ": " <<  buf;
+    }
+}
+
+/*
+ * Debugging macros
+ */
+#define DUMP_RESOURCE_MASK(X)
+#define DUMP_SSA_REP(X)
+
+/* Pretty-print a LIR instruction */
+void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr)
+{
+    MipsLIR* lir = (MipsLIR*) arg;
+    int offset = lir->generic.offset;
+    int dest = lir->operands[0];
+    const bool dumpNop = false;
+
+    /* Handle pseudo-ops individually, and all regular insns as a group */
+    switch(lir->opcode) {
+        case kMipsPseudoMethodEntry:
+            LOG(INFO) << "-------- method entry " <<
+                PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
+            break;
+        case kMipsPseudoMethodExit:
+            LOG(INFO) << "-------- Method_Exit";
+            break;
+        case kMipsPseudoBarrier:
+            LOG(INFO) << "-------- BARRIER";
+            break;
+        case kMipsPseudoExtended:
+            LOG(INFO) << "-------- " << (char* ) dest;
+            break;
+        case kMipsPseudoSSARep:
+            DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " <<  (char* ) dest);
+            break;
+        case kMipsPseudoEntryBlock:
+            LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest;
+            break;
+        case kMipsPseudoDalvikByteCodeBoundary:
+            LOG(INFO) << "-------- dalvik offset: 0x" << std::hex <<
+                 lir->generic.dalvikOffset << " @ " << (char* )lir->operands[0];
+            break;
+        case kMipsPseudoExitBlock:
+            LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest;
+            break;
+        case kMipsPseudoPseudoAlign4:
+            LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex <<
+                offset << "): .align4";
+            break;
+        case kMipsPseudoEHBlockLabel:
+            LOG(INFO) << "Exception_Handling:";
+            break;
+        case kMipsPseudoTargetLabel:
+        case kMipsPseudoNormalBlockLabel:
+            LOG(INFO) << "L" << (intptr_t)lir << ":";
+            break;
+        case kMipsPseudoThrowTarget:
+            LOG(INFO) << "LT" << (intptr_t)lir << ":";
+            break;
+        case kMipsPseudoSuspendTarget:
+            LOG(INFO) << "LS" << (intptr_t)lir << ":";
+            break;
+        case kMipsPseudoCaseLabel:
+            LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" <<
+                std::hex << lir->operands[0] << "|" << std::dec <<
+                lir->operands[0];
+            break;
+        default:
+            if (lir->flags.isNop && !dumpNop) {
+                break;
+            } else {
+                std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr));
+                std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr));
+                LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s", baseAddr + offset, offset,
+                    op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "");
+            }
+            break;
+    }
+
+    if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
+        DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
+                                               lir->useMask, "use"));
+    }
+    if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
+        DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
+                                               lir->defMask, "def"));
+    }
+}
+
+void oatDumpPromotionMap(CompilationUnit *cUnit)
+{
+    for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
+        PromotionMap vRegMap = cUnit->promotionMap[i];
+        char buf[100];
+        if (vRegMap.fpLocation == kLocPhysReg) {
+            snprintf(buf, 100, " : s%d", vRegMap.fpReg & FP_REG_MASK);
+        } else {
+            buf[0] = 0;
+        }
+        char buf2[100];
+        snprintf(buf2, 100, "V[%02d] -> %s%d%s", i,
+                 vRegMap.coreLocation == kLocPhysReg ?
+                 "r" : "SP+", vRegMap.coreLocation == kLocPhysReg ?
+                 vRegMap.coreReg : oatSRegOffset(cUnit, i), buf);
+        LOG(INFO) << buf2;
+    }
+}
+
+void oatDumpFullPromotionMap(CompilationUnit *cUnit)
+{
+    for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
+        PromotionMap vRegMap = cUnit->promotionMap[i];
+        LOG(INFO) << i << " -> " << "CL:" << (int)vRegMap.coreLocation <<
+            ", CR:" << (int)vRegMap.coreReg << ", FL:" <<
+            (int)vRegMap.fpLocation << ", FR:" << (int)vRegMap.fpReg <<
+            ", - " << (int)vRegMap.firstInPair;
+    }
+}
+
+/* Dump instructions and constant pool contents */
+void oatCodegenDump(CompilationUnit* cUnit)
+{
+    LOG(INFO) << "/*";
+    LOG(INFO) << "Dumping LIR insns for "
+        << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
+    LIR* lirInsn;
+    MipsLIR* mipsLIR;
+    int insnsSize = cUnit->insnsSize;
+
+    LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs;
+    LOG(INFO) << "Ins                  : " << cUnit->numIns;
+    LOG(INFO) << "Outs                 : " << cUnit->numOuts;
+    LOG(INFO) << "CoreSpills           : " << cUnit->numCoreSpills;
+    LOG(INFO) << "FPSpills             : " << cUnit->numFPSpills;
+    LOG(INFO) << "Padding              : " << cUnit->numPadding;
+    LOG(INFO) << "Frame size           : " << cUnit->frameSize;
+    LOG(INFO) << "Start of ins         : " << cUnit->insOffset;
+    LOG(INFO) << "Start of regs        : " << cUnit->regsOffset;
+    LOG(INFO) << "code size is " << cUnit->totalSize <<
+        " bytes, Dalvik size is " << insnsSize * 2;
+    LOG(INFO) << "expansion factor: " <<
+         (float)cUnit->totalSize / (float)(insnsSize * 2);
+    oatDumpPromotionMap(cUnit);
+    for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
+        oatDumpLIRInsn(cUnit, lirInsn, 0);
+    }
+    for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
+        mipsLIR = (MipsLIR*) lirInsn;
+        LOG(INFO) << StringPrintf("%x (%04x): .class (%s)",
+            mipsLIR->generic.offset, mipsLIR->generic.offset,
+            ((CallsiteInfo *) mipsLIR->operands[0])->classDescriptor);
+    }
+    for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
+        mipsLIR = (MipsLIR*) lirInsn;
+        LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)",
+            mipsLIR->generic.offset, mipsLIR->generic.offset, mipsLIR->operands[0]);
+    }
+
+    const DexFile::MethodId& method_id =
+        cUnit->dex_file->GetMethodId(cUnit->method_idx);
+    std::string signature(cUnit->dex_file->GetMethodSignature(method_id));
+    std::string name(cUnit->dex_file->GetMethodName(method_id));
+    std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id));
+
+    // Dump mapping table
+    if (cUnit->mappingTable.size() > 0) {
+        std::string line(StringPrintf("\n    MappingTable %s%s_%s_mappingTable[%zu] = {",
+            descriptor.c_str(), name.c_str(), signature.c_str(), cUnit->mappingTable.size()));
+        std::replace(line.begin(), line.end(), ';', '_');
+        LOG(INFO) << line;
+        for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) {
+            line = StringPrintf("        {0x%08x, 0x%04x},",
+                cUnit->mappingTable[i], cUnit->mappingTable[i+1]);
+            LOG(INFO) << line;
+        }
+        LOG(INFO) <<"    };\n\n";
+    }
+}
+
+} // namespace art
diff --git a/src/compiler/codegen/mips/Assemble.cc b/src/compiler/codegen/mips/Assemble.cc
new file mode 100644
index 0000000..9e8af2a
--- /dev/null
+++ b/src/compiler/codegen/mips/Assemble.cc
@@ -0,0 +1,557 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../../Dalvik.h"
+#include "../../CompilerInternals.h"
+#include "MipsLIR.h"
+#include "Codegen.h"
+#include <sys/mman.h>           /* for protection change */
+
+namespace art {
+
+#define MAX_ASSEMBLER_RETRIES 50
+
+/*
+ * opcode: MipsOpCode enum
+ * skeleton: pre-designated bit-pattern for this opcode
+ * k0: key to applying ds/de
+ * ds: dest start bit position
+ * de: dest end bit position
+ * k1: key to applying s1s/s1e
+ * s1s: src1 start bit position
+ * s1e: src1 end bit position
+ * k2: key to applying s2s/s2e
+ * s2s: src2 start bit position
+ * s2e: src2 end bit position
+ * operands: number of operands (for sanity check purposes)
+ * name: mnemonic name
+ * fmt: for pretty-printing
+ */
+#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
+                     k3, k3s, k3e, flags, name, fmt, size) \
+        {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
+                    {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
+
+/* Instruction dump string format keys: !pf, where "!" is the start
+ * of the key, "p" is which numeric operand to use and "f" is the
+ * print format.
+ *
+ * [p]ositions:
+ *     0 -> operands[0] (dest)
+ *     1 -> operands[1] (src1)
+ *     2 -> operands[2] (src2)
+ *     3 -> operands[3] (extra)
+ *
+ * [f]ormats:
+ *     h -> 4-digit hex
+ *     d -> decimal
+ *     E -> decimal*4
+ *     F -> decimal*2
+ *     c -> branch condition (beq, bne, etc.)
+ *     t -> pc-relative target
+ *     T -> pc-region target
+ *     u -> 1st half of bl[x] target
+ *     v -> 2nd half ob bl[x] target
+ *     R -> register list
+ *     s -> single precision floating point register
+ *     S -> double precision floating point register
+ *     m -> Thumb2 modified immediate
+ *     n -> complimented Thumb2 modified immediate
+ *     M -> Thumb2 16-bit zero-extended immediate
+ *     b -> 4-digit binary
+ *
+ *  [!] escape.  To insert "!", use "!!"
+ */
+/* NOTE: must be kept in sync with enum MipsOpcode from MipsLIR.h */
+MipsEncodingMap EncodingMap[kMipsLast] = {
+    ENCODING_MAP(kMips32BitData, 0x00000000,
+                 kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP,
+                 "data", "0x!0h(!0d)", 2),
+    ENCODING_MAP(kMipsAddiu, 0x24000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "addiu", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsAddu, 0x00000021,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "addu", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsAnd, 0x00000024,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "and", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsAndi, 0x30000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "andi", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsB, 0x10000000,
+                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
+                 "b", "!0t", 2),
+    ENCODING_MAP(kMipsBal, 0x04110000,
+                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
+                 "bal", "!0t", 2),
+    ENCODING_MAP(kMipsBeq, 0x10000000,
+                 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
+                 "beq", "!0r,!1r,!2t", 2),
+    ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
+                 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+                 "beqz", "!0r,!1t", 2),
+    ENCODING_MAP(kMipsBgez, 0x04010000,
+                 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+                 "bgez", "!0r,!1t", 2),
+    ENCODING_MAP(kMipsBgtz, 0x1C000000,
+                 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+                 "bgtz", "!0r,!1t", 2),
+    ENCODING_MAP(kMipsBlez, 0x18000000,
+                 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+                 "blez", "!0r,!1t", 2),
+    ENCODING_MAP(kMipsBltz, 0x04000000,
+                 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+                 "bltz", "!0r,!1t", 2),
+    ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
+                 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+                 "bnez", "!0r,!1t", 2),
+    ENCODING_MAP(kMipsBne, 0x14000000,
+                 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
+                 "bne", "!0r,!1r,!2t", 2),
+    ENCODING_MAP(kMipsDiv, 0x0000001a,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
+                 kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
+                 "div", "!2r,!3r", 2),
+#if __mips_isa_rev>=2
+    ENCODING_MAP(kMipsExt, 0x7c000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
+                 kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
+                 "ext", "!0r,!1r,!2d,!3D", 2),
+#endif
+    ENCODING_MAP(kMipsJal, 0x0c000000,
+                 kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
+                 "jal", "!0T(!0E)", 2),
+    ENCODING_MAP(kMipsJalr, 0x00000009,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
+                 "jalr", "!0r,!1r", 2),
+    ENCODING_MAP(kMipsJr, 0x00000008,
+                 kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
+                 "jr", "!0r", 2),
+    ENCODING_MAP(kMipsLahi, 0x3C000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "lahi/lui", "!0r,0x!1h(!1d)", 2),
+    ENCODING_MAP(kMipsLalo, 0x34000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "lalo/ori", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsLui, 0x3C000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "lui", "!0r,0x!1h(!1d)", 2),
+    ENCODING_MAP(kMipsLb, 0x80000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lb", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsLbu, 0x90000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lbu", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsLh, 0x84000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lh", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsLhu, 0x94000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lhu", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsLw, 0x8C000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lw", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsMfhi, 0x00000010,
+                 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mfhi", "!0r", 2),
+    ENCODING_MAP(kMipsMflo, 0x00000012,
+                 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mflo", "!0r", 2),
+    ENCODING_MAP(kMipsMove, 0x00000025, /* or using zero reg */
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "move", "!0r,!1r", 2),
+    ENCODING_MAP(kMipsMovz, 0x0000000a,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "movz", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsMul, 0x70000002,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "mul", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsNop, 0x00000000,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND,
+                 "nop", "", 2),
+    ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "nor", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsOr, 0x00000025,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "or", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsOri, 0x34000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "ori", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsPref, 0xCC000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
+                 "pref", "!0d,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsSb, 0xA0000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "sb", "!0r,!1d(!2r)", 2),
+#if __mips_isa_rev>=2
+    ENCODING_MAP(kMipsSeb, 0x7c000420,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "seb", "!0r,!1r", 2),
+    ENCODING_MAP(kMipsSeh, 0x7c000620,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "seh", "!0r,!1r", 2),
+#endif
+    ENCODING_MAP(kMipsSh, 0xA4000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "sh", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsSll, 0x00000000,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "sll", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsSllv, 0x00000004,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "sllv", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSlt, 0x0000002a,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "slt", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSlti, 0x28000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "slti", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsSltu, 0x0000002b,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "sltu", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSra, 0x00000003,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "sra", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsSrav, 0x00000007,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "srav", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSrl, 0x00000002,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "srl", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsSrlv, 0x00000006,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "srlv", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSubu, 0x00000023, /* used for "neg" too */
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "subu", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSw, 0xAC000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "sw", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsXor, 0x00000026,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "xor", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsXori, 0x38000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "xori", "!0r,!1r,0x!2h(!2d)", 2),
+#ifdef __mips_hard_float
+    ENCODING_MAP(kMipsFadds, 0x46000000,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "add.s", "!0s,!1s,!2s", 2),
+    ENCODING_MAP(kMipsFsubs, 0x46000001,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "sub.s", "!0s,!1s,!2s", 2),
+    ENCODING_MAP(kMipsFmuls, 0x46000002,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "mul.s", "!0s,!1s,!2s", 2),
+    ENCODING_MAP(kMipsFdivs, 0x46000003,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "div.s", "!0s,!1s,!2s", 2),
+    ENCODING_MAP(kMipsFaddd, 0x46200000,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "add.d", "!0S,!1S,!2S", 2),
+    ENCODING_MAP(kMipsFsubd, 0x46200001,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "sub.d", "!0S,!1S,!2S", 2),
+    ENCODING_MAP(kMipsFmuld, 0x46200002,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "mul.d", "!0S,!1S,!2S", 2),
+    ENCODING_MAP(kMipsFdivd, 0x46200003,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "div.d", "!0S,!1S,!2S", 2),
+    ENCODING_MAP(kMipsFcvtsd, 0x46200020,
+                 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.s.d", "!0s,!1S", 2),
+    ENCODING_MAP(kMipsFcvtsw, 0x46800020,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.s.w", "!0s,!1s", 2),
+    ENCODING_MAP(kMipsFcvtds, 0x46000021,
+                 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.d.s", "!0S,!1s", 2),
+    ENCODING_MAP(kMipsFcvtdw, 0x46800021,
+                 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.d.w", "!0S,!1s", 2),
+    ENCODING_MAP(kMipsFcvtws, 0x46000024,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.w.s", "!0s,!1s", 2),
+    ENCODING_MAP(kMipsFcvtwd, 0x46200024,
+                 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.w.d", "!0s,!1S", 2),
+    ENCODING_MAP(kMipsFmovs, 0x46000006,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mov.s", "!0s,!1s", 2),
+    ENCODING_MAP(kMipsFmovd, 0x46200006,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mov.d", "!0S,!1S", 2),
+    ENCODING_MAP(kMipsFlwc1, 0xC4000000,
+                 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lwc1", "!0s,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsFldc1, 0xD4000000,
+                 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "ldc1", "!0S,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsFswc1, 0xE4000000,
+                 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "swc1", "!0s,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsFsdc1, 0xF4000000,
+                 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "sdc1", "!0S,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsMfc1, 0x44000000,
+                 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mfc1", "!0r,!1s", 2),
+    ENCODING_MAP(kMipsMtc1, 0x44800000,
+                 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
+                 "mtc1", "!0r,!1s", 2),
+#endif
+    ENCODING_MAP(kMipsUndefined, 0x64000000,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND,
+                 "undefined", "", 2),
+};
+
+/*
+ * Assemble the LIR into binary instruction format.  Note that we may
+ * discover that pc-relative displacements may not fit the selected
+ * instruction.  In those cases we will try to substitute a new code
+ * sequence or request that the trace be shortened and retried.
+ */
+AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit,
+                                        intptr_t startAddr)
+{
+    UNIMPLEMENTED(FATAL) << "Rework for art code buffer";
+#if 0
+    int *bufferAddr = (int *) cUnit->codeBuffer;
+    MipsLIR *lir;
+
+    for (lir = (MipsLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
+        if (lir->opcode < 0) {
+            continue;
+        }
+
+
+        if (lir->flags.isNop) {
+            continue;
+        }
+
+        if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t pc = lir->generic.offset + 4;
+            intptr_t target = targetLIR->generic.offset;
+            int delta = target - pc;
+            if (delta & 0x3) {
+                LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
+            }
+            if (delta > 131068 || delta < -131069) {
+                LOG(FATAL) << "Unconditional branch out of range: " << delta;
+            }
+            lir->operands[0] = delta >> 2;
+        } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t pc = lir->generic.offset + 4;
+            intptr_t target = targetLIR->generic.offset;
+            int delta = target - pc;
+            if (delta & 0x3) {
+                LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
+            }
+            if (delta > 131068 || delta < -131069) {
+                LOG(FATAL) << "Conditional branch out of range: " << delta;
+            }
+            lir->operands[1] = delta >> 2;
+        } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t pc = lir->generic.offset + 4;
+            intptr_t target = targetLIR->generic.offset;
+            int delta = target - pc;
+            if (delta & 0x3) {
+                LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
+            }
+            if (delta > 131068 || delta < -131069) {
+                LOG(FATAL) << "Conditional branch out of range: " << delta;
+            }
+            lir->operands[2] = delta >> 2;
+        } else if (lir->opcode == kMipsJal) {
+            intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3;
+            intptr_t target = lir->operands[0];
+            /* ensure PC-region branch can be used */
+            DCHECK_EQ((curPC & 0xF0000000), (target & 0xF0000000));
+            if (target & 0x3) {
+                LOG(FATAL) << "Jump target not multiple of 4: " << target;
+            }
+            lir->operands[0] =  target >> 2;
+        } else if (lir->opcode == kMipsLahi) { /* load address hi (via lui) */
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t target = startAddr + targetLIR->generic.offset;
+            lir->operands[1] = target >> 16;
+        } else if (lir->opcode == kMipsLalo) { /* load address lo (via ori) */
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t target = startAddr + targetLIR->generic.offset;
+            lir->operands[2] = lir->operands[2] + target;
+        }
+
+        MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
+        u4 bits = encoder->skeleton;
+        int i;
+        for (i = 0; i < 4; i++) {
+            u4 operand;
+            u4 value;
+            operand = lir->operands[i];
+            switch(encoder->fieldLoc[i].kind) {
+                case kFmtUnused:
+                    break;
+                case kFmtBitBlt:
+                    if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
+                        value = operand;
+                    } else {
+                        value = (operand << encoder->fieldLoc[i].start) &
+                                ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+                    }
+                    bits |= value;
+                    break;
+                case kFmtDfp: {
+                    DCHECK(DOUBLEREG(operand));
+                    DCHECK_EQ((operand & 0x1), 0);
+                    value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
+                            ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+                    bits |= value;
+                    break;
+                }
+                case kFmtSfp:
+                    DCHECK(SINGLEREG(operand));
+                    value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
+                            ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+                    bits |= value;
+                    break;
+                default:
+                    LOG(FATAL) << "Bad encoder format: "
+                               << encoder->fieldLoc[i].kind;
+            }
+        }
+        DCHECK_EQ(encoder->size, 2);
+        *bufferAddr++ = bits;
+    }
+#endif
+    return kSuccess;
+}
+
+/*
+ * Target-dependent offset assignment.
+ * TODO: normalize usage of flags.size and make this target
+ * independent.
+ */
+int oatAssignInsnOffsets(CompilationUnit* cUnit)
+{
+    MipsLIR* mipsLIR;
+    int offset = 0;
+
+    for (mipsLIR = (MipsLIR *) cUnit->firstLIRInsn;
+         mipsLIR;
+         mipsLIR = NEXT_LIR(mipsLIR)) {
+        mipsLIR->generic.offset = offset;
+        if (mipsLIR->opcode >= 0) {
+            if (!mipsLIR->flags.isNop) {
+                mipsLIR->flags.size = EncodingMap[mipsLIR->opcode].size * 2;
+                offset += mipsLIR->flags.size;
+            }
+        } else if (mipsLIR->opcode == kMipsPseudoPseudoAlign4) {
+            if (offset & 0x2) {
+                offset += 2;
+                mipsLIR->operands[0] = 1;
+            } else {
+                mipsLIR->operands[0] = 0;
+            }
+        }
+        /* Pseudo opcodes don't consume space */
+    }
+
+    return offset;
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/Codegen.h b/src/compiler/codegen/mips/Codegen.h
new file mode 100644
index 0000000..b350dae
--- /dev/null
+++ b/src/compiler/codegen/mips/Codegen.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "../../CompilerIR.h"
+
+namespace art {
+
+#if defined(_CODEGEN_C)
+/*
+ * loadConstant() sometimes needs to add a small imm to a pre-existing constant
+ */
+STATIC MipsLIR *opRegImm(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
+                        int value);
+STATIC MipsLIR *opRegReg(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
+                        int rSrc2);
+
+/* Forward decalraton the portable versions due to circular dependency */
+STATIC bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
+                                    RegLocation rlDest, RegLocation rlSrc1,
+                                    RegLocation rlSrc2);
+
+STATIC bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
+                                     RegLocation rlDest, RegLocation rlSrc1,
+                                     RegLocation rlSrc2);
+
+STATIC bool genConversionPortable(CompilationUnit* cUnit, MIR* mir);
+
+#endif
+
+extern void oatSetupResourceMasks(MipsLIR* lir);
+
+extern MipsLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest,
+                                          int rSrc);
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/CodegenCommon.cc b/src/compiler/codegen/mips/CodegenCommon.cc
new file mode 100644
index 0000000..3645643
--- /dev/null
+++ b/src/compiler/codegen/mips/CodegenCommon.cc
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+/*
+ * This file contains codegen and support common to all supported
+ * Mips variants.  It is included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ * which combines this common code with specific support found in the
+ * applicable directory below this one.
+ */
+
+/* Track exercised opcodes */
+static int opcodeCoverage[kNumPackedOpcodes];
+
+static void setMemRefType(MipsLIR *lir, bool isLoad, int memType)
+{
+    /* MIPSTODO simplify setMemRefType() */
+    u8 *maskPtr;
+    u8 mask = ENCODE_MEM;;
+    DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
+
+    if (isLoad) {
+        maskPtr = &lir->useMask;
+    } else {
+        maskPtr = &lir->defMask;
+    }
+    /* Clear out the memref flags */
+    *maskPtr &= ~mask;
+    /* ..and then add back the one we need */
+    switch(memType) {
+        case kLiteral:
+            DCHECK(isLoad);
+            *maskPtr |= ENCODE_LITERAL;
+            break;
+        case kDalvikReg:
+            *maskPtr |= ENCODE_DALVIK_REG;
+            break;
+        case kHeapRef:
+            *maskPtr |= ENCODE_HEAP_REF;
+            break;
+        case kMustNotAlias:
+            /* Currently only loads can be marked as kMustNotAlias */
+            DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE));
+            *maskPtr |= ENCODE_MUST_NOT_ALIAS;
+            break;
+        default:
+            LOG(FATAL) << "Oat: invalid memref kind - " << memType;
+    }
+}
+
+/*
+ * Mark load/store instructions that access Dalvik registers through rFP +
+ * offset.
+ */
+STATIC void annotateDalvikRegAccess(MipsLIR *lir, int regId, bool isLoad)
+{
+    /* MIPSTODO simplify annotateDalvikRegAccess() */
+    setMemRefType(lir, isLoad, kDalvikReg);
+
+    /*
+     * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
+     * access.
+     */
+    lir->aliasInfo = regId;
+    if (DOUBLEREG(lir->operands[0])) {
+        lir->aliasInfo |= 0x80000000;
+    }
+}
+
+/*
+ * Decode the register id
+ */
+STATIC inline u8 getRegMaskCommon(int reg)
+{
+    u8 seed;
+    int shift;
+    int regId = reg & 0x1f;
+
+    /*
+     * Each double register is equal to a pair of single-precision FP registers
+     */
+    if (!DOUBLEREG(reg)) {
+        seed = 1;
+    } else {
+        DCHECK_EQ((regId & 1), 0); /* double registers must be even */
+        seed = 3;
+    }
+
+    if (FPREG(reg)) {
+       DCHECK_LT(regId, 16); /* only 16 fp regs */
+       shift = kFPReg0;
+    } else if (EXTRAREG(reg)) {
+       DCHECK_LT(regId, 3); /* only 3 extra regs */
+       shift = kFPRegEnd;
+    } else {
+       shift = 0;
+    }
+
+    /* Expand the double register id into single offset */
+    shift += regId;
+    return (seed << shift);
+}
+
+/*
+ * Mark the corresponding bit(s).
+ */
+STATIC inline void setupRegMask(u8 *mask, int reg)
+{
+    *mask |= getRegMaskCommon(reg);
+}
+
+/*
+ * Set up the proper fields in the resource mask
+ */
+STATIC void setupResourceMasks(MipsLIR *lir)
+{
+    /* MIPSTODO simplify setupResourceMasks() */
+    int opcode = lir->opcode;
+    int flags;
+
+    if (opcode <= 0) {
+        lir->useMask = lir->defMask = 0;
+        return;
+    }
+
+    flags = EncodingMap[lir->opcode].flags;
+
+    // TODO: do we need this for MIPS?  if so, add to inst table defs
+#if 0
+    if (flags & NEEDS_FIXUP) {
+        lir->flags.pcRelFixup = true;
+    }
+#endif
+
+    /* Set up the mask for resources that are updated */
+    if (flags & (IS_LOAD | IS_STORE)) {
+        /* Default to heap - will catch specialized classes later */
+        setMemRefType(lir, flags & IS_LOAD, kHeapRef);
+    }
+
+    /*
+     * Conservatively assume the branch here will call out a function that in
+     * turn will trash everything.
+     */
+    if (flags & IS_BRANCH) {
+        lir->defMask = lir->useMask = ENCODE_ALL;
+        return;
+    }
+
+    if (flags & REG_DEF0) {
+        setupRegMask(&lir->defMask, lir->operands[0]);
+    }
+
+    if (flags & REG_DEF1) {
+        setupRegMask(&lir->defMask, lir->operands[1]);
+    }
+
+    if (flags & REG_DEF_SP) {
+        lir->defMask |= ENCODE_REG_SP;
+    }
+
+    if (flags & REG_DEF_LR) {
+        lir->defMask |= ENCODE_REG_LR;
+    }
+
+    if (flags & REG_DEF_LIST0) {
+        lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
+    }
+
+    if (flags & REG_DEF_LIST1) {
+        lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
+    }
+
+    if (flags & SETS_CCODES) {
+        lir->defMask |= ENCODE_CCODE;
+    }
+
+    // TODO: needed for MIPS?
+    /* Conservatively treat the IT block */
+    if (flags & IS_IT) {
+        lir->defMask = ENCODE_ALL;
+    }
+
+    if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+        int i;
+
+        for (i = 0; i < 4; i++) {
+            if (flags & (1 << (kRegUse0 + i))) {
+                setupRegMask(&lir->useMask, lir->operands[i]);
+            }
+        }
+    }
+
+    if (flags & REG_USE_PC) {
+        lir->useMask |= ENCODE_REG_PC;
+    }
+
+    if (flags & REG_USE_SP) {
+        lir->useMask |= ENCODE_REG_SP;
+    }
+
+    if (flags & REG_USE_LIST0) {
+        lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
+    }
+
+    if (flags & REG_USE_LIST1) {
+        lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
+    }
+
+    if (flags & USES_CCODES) {
+        lir->useMask |= ENCODE_CCODE;
+    }
+}
+
+/*
+ * Set up the accurate resource mask for branch instructions
+ */
+static void relaxBranchMasks(MipsLIR *lir)
+{
+    int flags = EncodingMap[lir->opcode].flags;
+
+    /* Make sure only branch instructions are passed here */
+    DCHECK(flags & IS_BRANCH);
+
+    lir->defMask |= ENCODE_REG_PC;
+    lir->useMask |= ENCODE_REG_PC;
+
+
+    if (flags & REG_DEF_LR) {
+        lir->defMask |= ENCODE_REG_LR;
+    }
+
+    if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+        int i;
+
+        for (i = 0; i < 4; i++) {
+            if (flags & (1 << (kRegUse0 + i))) {
+                setupRegMask(&lir->useMask, lir->operands[i]);
+            }
+        }
+    }
+
+    if (flags & USES_CCODES) {
+        lir->useMask |= ENCODE_CCODE;
+    }
+}
+
+/*
+ * The following are building blocks to construct low-level IRs with 0 - 4
+ * operands.
+ */
+static MipsLIR *newLIR0(CompilationUnit *cUnit, MipsOpCode opcode)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    DCHECK(isPseudoOpCode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
+    insn->opcode = opcode;
+    setupResourceMasks(insn);
+    insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static MipsLIR *newLIR1(CompilationUnit *cUnit, MipsOpCode opcode,
+                           int dest)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    DCHECK(isPseudoOpCode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    setupResourceMasks(insn);
+    insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static MipsLIR *newLIR2(CompilationUnit *cUnit, MipsOpCode opcode,
+                           int dest, int src1)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    DCHECK(isPseudoOpCode(opcode) ||
+           (EncodingMap[opcode].flags & IS_BINARY_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    insn->operands[1] = src1;
+    setupResourceMasks(insn);
+    insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static MipsLIR *newLIR3(CompilationUnit *cUnit, MipsOpCode opcode,
+                           int dest, int src1, int src2)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    if (!(EncodingMap[opcode].flags & IS_TERTIARY_OP)) {
+        LOG(FATAL) << "Bad LIR3: " << EncodingMap[opcode].name;
+    }
+    DCHECK(isPseudoOpCode(opcode) ||
+           (EncodingMap[opcode].flags & IS_TERTIARY_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    insn->operands[1] = src1;
+    insn->operands[2] = src2;
+    setupResourceMasks(insn);
+    insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static MipsLIR *newLIR4(CompilationUnit *cUnit, MipsOpCode opcode,
+                           int dest, int src1, int src2, int info)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    DCHECK(isPseudoOpCode(opcode) ||
+           (EncodingMap[opcode].flags & IS_QUAD_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    insn->operands[1] = src1;
+    insn->operands[2] = src2;
+    insn->operands[3] = info;
+    setupResourceMasks(insn);
+    insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+/*
+ * The following are building blocks to insert constants into the pool or
+ * instruction streams.
+ */
+
+/* Add a 32-bit constant either in the constant pool or mixed with code */
+static MipsLIR *addWordData(CompilationUnit *cUnit, LIR **constantListP,
+                           int value)
+{
+    /* Add the constant to the literal pool */
+    if (constantListP) {
+        MipsLIR *newValue = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true,
+                                               kAllocData);
+        newValue->operands[0] = value;
+        newValue->generic.next = *constantListP;
+        *constantListP = (LIR *) newValue;
+        return newValue;
+    } else {
+        /* Add the constant in the middle of code stream */
+        newLIR1(cUnit, kMips32BitData, value);
+    }
+    return NULL;
+}
+
+/*
+ * Generate an kMipsPseudoBarrier marker to indicate the boundary of special
+ * blocks.
+ */
+static void genBarrier(CompilationUnit *cUnit)
+{
+    MipsLIR *barrier = newLIR0(cUnit, kMipsPseudoBarrier);
+    /* Mark all resources as being clobbered */
+    barrier->defMask = -1;
+}
+
+} // namespace art
diff --git a/src/compiler/codegen/mips/FP/MipsFP.cc b/src/compiler/codegen/mips/FP/MipsFP.cc
new file mode 100644
index 0000000..fd07a34
--- /dev/null
+++ b/src/compiler/codegen/mips/FP/MipsFP.cc
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+extern void oatFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
+                                              int reg1, int reg2);
+extern void oatFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg);
+
+/* First, flush any registers associated with this value */
+static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
+                             int rDest)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+     rlSrc = rlSrc.wide ? oatUpdateLocWide(cUnit, rlSrc) :
+                          oatUpdateLoc(cUnit, rlSrc);
+     if (rlSrc.location == kLocPhysReg) {
+         if (rlSrc.wide) {
+             oatFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg,
+                                               rlSrc.highReg);
+         } else {
+             oatFlushRegForV5TEVFP(cUnit, rlSrc.lowReg);
+         }
+     }
+     opRegRegImm(cUnit, kOpAdd, rDest, rFP,
+                 oatS2VReg(cUnit, rlSrc.sRegLow) << 2);
+#endif
+}
+
+/*
+ * TUNING: On some implementations, it is quicker to pass addresses
+ * to the handlers rather than load the operands into core registers
+ * and then move the values to FP regs in the handlers.  Other implementations
+ * may prefer passing data in registers (and the latter approach would
+ * yeild cleaner register handling - avoiding the requirement that operands
+ * be flushed to memory prior to the call).
+ */
+static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+                            RegLocation rlDest, RegLocation rlSrc1,
+                            RegLocation rlSrc2)
+{
+#ifdef __mips_hard_float
+    int op = kMipsNop;
+    RegLocation rlResult;
+
+    /*
+     * Don't attempt to optimize register usage since these opcodes call out to
+     * the handlers.
+     */
+    switch (mir->dalvikInsn.opcode) {
+        case OP_ADD_FLOAT_2ADDR:
+        case OP_ADD_FLOAT:
+            op = kMipsFadds;
+            break;
+        case OP_SUB_FLOAT_2ADDR:
+        case OP_SUB_FLOAT:
+            op = kMipsFsubs;
+            break;
+        case OP_DIV_FLOAT_2ADDR:
+        case OP_DIV_FLOAT:
+            op = kMipsFdivs;
+            break;
+        case OP_MUL_FLOAT_2ADDR:
+        case OP_MUL_FLOAT:
+            op = kMipsFmuls;
+            break;
+        case OP_REM_FLOAT_2ADDR:
+        case OP_REM_FLOAT:
+        case OP_NEG_FLOAT: {
+            return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+        }
+        default:
+            return true;
+    }
+    rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
+    rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    storeValue(cUnit, rlDest, rlResult);
+
+    return false;
+#else
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+    return false;
+#if 0
+    TemplateOpcode opcode;
+
+    /*
+     * Don't attempt to optimize register usage since these opcodes call out to
+     * the handlers.
+     */
+    switch (mir->dalvikInsn.opcode) {
+        case OP_ADD_FLOAT_2ADDR:
+        case OP_ADD_FLOAT:
+            opcode = TEMPLATE_ADD_FLOAT_VFP;
+            break;
+        case OP_SUB_FLOAT_2ADDR:
+        case OP_SUB_FLOAT:
+            opcode = TEMPLATE_SUB_FLOAT_VFP;
+            break;
+        case OP_DIV_FLOAT_2ADDR:
+        case OP_DIV_FLOAT:
+            opcode = TEMPLATE_DIV_FLOAT_VFP;
+            break;
+        case OP_MUL_FLOAT_2ADDR:
+        case OP_MUL_FLOAT:
+            opcode = TEMPLATE_MUL_FLOAT_VFP;
+            break;
+        case OP_REM_FLOAT_2ADDR:
+        case OP_REM_FLOAT:
+        case OP_NEG_FLOAT: {
+            return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+        }
+        default:
+            return true;
+    }
+    loadValueAddress(cUnit, rlDest, r_A0);
+    oatClobber(cUnit, r_A0);
+    loadValueAddress(cUnit, rlSrc1, r_A1);
+    oatClobber(cUnit, r_A1);
+    loadValueAddress(cUnit, rlSrc2, r_A2);
+    UNIMP(FATAL) << "Need callout to handler";
+#if 0
+    genDispatchToHandler(cUnit, opcode);
+#endif
+    rlDest = oatUpdateLoc(cUnit, rlDest);
+    if (rlDest.location == kLocPhysReg) {
+        oatClobber(cUnit, rlDest.lowReg);
+    }
+    return false;
+#endif
+#endif
+}
+
+static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+                             RegLocation rlDest, RegLocation rlSrc1,
+                             RegLocation rlSrc2)
+{
+#ifdef __mips_hard_float
+    int op = kMipsNop;
+    RegLocation rlResult;
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_ADD_DOUBLE_2ADDR:
+        case OP_ADD_DOUBLE:
+            op = kMipsFaddd;
+            break;
+        case OP_SUB_DOUBLE_2ADDR:
+        case OP_SUB_DOUBLE:
+            op = kMipsFsubd;
+            break;
+        case OP_DIV_DOUBLE_2ADDR:
+        case OP_DIV_DOUBLE:
+            op = kMipsFdivd;
+            break;
+        case OP_MUL_DOUBLE_2ADDR:
+        case OP_MUL_DOUBLE:
+            op = kMipsFmuld;
+            break;
+        case OP_REM_DOUBLE_2ADDR:
+        case OP_REM_DOUBLE:
+        case OP_NEG_DOUBLE: {
+            return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+        }
+        default:
+            return true;
+    }
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
+    DCHECK(rlSrc1.wide);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
+    DCHECK(rlSrc2.wide);
+    rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
+    DCHECK(rlDest.wide);
+    DCHECK(rlResult.wide);
+    newLIR3(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc1.lowReg, rlSrc1.highReg),
+            S2D(rlSrc2.lowReg, rlSrc2.highReg));
+    storeValueWide(cUnit, rlDest, rlResult);
+    return false;
+#else
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+    return false;
+#if 0
+    TemplateOpcode opcode;
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_ADD_DOUBLE_2ADDR:
+        case OP_ADD_DOUBLE:
+            opcode = TEMPLATE_ADD_DOUBLE_VFP;
+            break;
+        case OP_SUB_DOUBLE_2ADDR:
+        case OP_SUB_DOUBLE:
+            opcode = TEMPLATE_SUB_DOUBLE_VFP;
+            break;
+        case OP_DIV_DOUBLE_2ADDR:
+        case OP_DIV_DOUBLE:
+            opcode = TEMPLATE_DIV_DOUBLE_VFP;
+            break;
+        case OP_MUL_DOUBLE_2ADDR:
+        case OP_MUL_DOUBLE:
+            opcode = TEMPLATE_MUL_DOUBLE_VFP;
+            break;
+        case OP_REM_DOUBLE_2ADDR:
+        case OP_REM_DOUBLE:
+        case OP_NEG_DOUBLE: {
+            return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
+                                               rlSrc2);
+        }
+        default:
+            return true;
+    }
+    loadValueAddress(cUnit, rlDest, r_A0);
+    oatClobber(cUnit, r_A0);
+    loadValueAddress(cUnit, rlSrc1, r_A1);
+    oatClobber(cUnit, r_A1);
+    loadValueAddress(cUnit, rlSrc2, r_A2);
+    UNIMP(FATAL) << "Need callout to handler";
+#if 0
+    genDispatchToHandler(cUnit, opcode);
+#endif
+    rlDest = oatUpdateLocWide(cUnit, rlDest);
+    if (rlDest.location == kLocPhysReg) {
+        oatClobber(cUnit, rlDest.lowReg);
+        oatClobber(cUnit, rlDest.highReg);
+    }
+    return false;
+#endif
+#endif
+}
+
+static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode opcode = mir->dalvikInsn.opcode;
+    bool longSrc = false;
+    bool longDest = false;
+    RegLocation rlSrc;
+    RegLocation rlDest;
+#ifdef __mips_hard_float
+    int op = kMipsNop;
+    int srcReg;
+    RegLocation rlResult;
+
+    switch (opcode) {
+        case OP_INT_TO_FLOAT:
+            longSrc = false;
+            longDest = false;
+            op = kMipsFcvtsw;
+            break;
+        case OP_DOUBLE_TO_FLOAT:
+            longSrc = true;
+            longDest = false;
+            op = kMipsFcvtsd;
+            break;
+        case OP_FLOAT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            op = kMipsFcvtds;
+            break;
+        case OP_INT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            op = kMipsFcvtdw;
+            break;
+        case OP_FLOAT_TO_INT:
+        case OP_DOUBLE_TO_INT:
+        case OP_LONG_TO_DOUBLE:
+        case OP_FLOAT_TO_LONG:
+        case OP_LONG_TO_FLOAT:
+        case OP_DOUBLE_TO_LONG:
+            return genConversionPortable(cUnit, mir);
+        default:
+            return true;
+    }
+    if (longSrc) {
+        rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+        rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+        srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
+    } else {
+        rlSrc = oatGetSrc(cUnit, mir, 0);
+        rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+        srcReg = rlSrc.lowReg;
+    }
+    if (longDest) {
+        rlDest = oatGetDestWide(cUnit, mir, 0, 1);
+        rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
+        newLIR2(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else {
+        rlDest = oatGetDest(cUnit, mir, 0);
+        rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
+        newLIR2(cUnit, (MipsOpCode)op, rlResult.lowReg, srcReg);
+        storeValue(cUnit, rlDest, rlResult);
+    }
+    return false;
+#else
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+    return false;
+#if 0
+    TemplateOpcode templateOpcode;
+    switch (opcode) {
+        case OP_INT_TO_FLOAT:
+            longSrc = false;
+            longDest = false;
+            templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP;
+            break;
+        case OP_FLOAT_TO_INT:
+            longSrc = false;
+            longDest = false;
+            templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP;
+            break;
+        case OP_DOUBLE_TO_FLOAT:
+            longSrc = true;
+            longDest = false;
+            templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
+            break;
+        case OP_FLOAT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
+            break;
+        case OP_INT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP;
+            break;
+        case OP_DOUBLE_TO_INT:
+            longSrc = true;
+            longDest = false;
+            templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP;
+            break;
+        case OP_LONG_TO_DOUBLE:
+        case OP_FLOAT_TO_LONG:
+        case OP_LONG_TO_FLOAT:
+        case OP_DOUBLE_TO_LONG:
+            return genConversionPortable(cUnit, mir);
+        default:
+            return true;
+    }
+
+    if (longSrc) {
+        rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+    } else {
+        rlSrc = oatGetSrc(cUnit, mir, 0);
+    }
+
+    if (longDest) {
+        rlDest = oatGetDestWide(cUnit, mir, 0, 1);
+    } else {
+        rlDest = oatGetDest(cUnit, mir, 0);
+    }
+    loadValueAddress(cUnit, rlDest, r_A0);
+    oatClobber(cUnit, r_A0);
+    loadValueAddress(cUnit, rlSrc, r_A1);
+    UNIMP(FATAL) << "Need callout to handler";
+#if 0
+    genDispatchToHandler(cUnit, templateOpcode);
+#endif
+    if (rlDest.wide) {
+        rlDest = oatUpdateLocWide(cUnit, rlDest);
+        oatClobber(cUnit, rlDest.highReg);
+    } else {
+        rlDest = oatUpdateLoc(cUnit, rlDest);
+    }
+    oatClobber(cUnit, rlDest.lowReg);
+    return false;
+#endif
+#endif
+}
+
+static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                     RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+    return false;
+#if 0
+    TemplateOpcode templateOpcode;
+    RegLocation rlResult = oatGetReturn(cUnit);
+    bool wide = true;
+
+    switch(mir->dalvikInsn.opcode) {
+        case OP_CMPL_FLOAT:
+            templateOpcode = TEMPLATE_CMPL_FLOAT_VFP;
+            wide = false;
+            break;
+        case OP_CMPG_FLOAT:
+            templateOpcode = TEMPLATE_CMPG_FLOAT_VFP;
+            wide = false;
+            break;
+        case OP_CMPL_DOUBLE:
+            templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP;
+            break;
+        case OP_CMPG_DOUBLE:
+            templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP;
+            break;
+        default:
+            return true;
+    }
+    loadValueAddress(cUnit, rlSrc1, r_A0);
+    oatClobber(cUnit, r_A0);
+    loadValueAddress(cUnit, rlSrc2, r_A1);
+    UNIMP(FATAL) << "Need callout to handler";
+#if 0
+    genDispatchToHandler(cUnit, templateOpcode);
+#endif
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+#endif
+}
+
+} //  namespace art
diff --git a/src/compiler/codegen/mips/Mips32/Factory.cc b/src/compiler/codegen/mips/Mips32/Factory.cc
new file mode 100644
index 0000000..ffbb223
--- /dev/null
+++ b/src/compiler/codegen/mips/Mips32/Factory.cc
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+/*
+ * This file contains codegen for the MIPS32 ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+static int coreRegs[] = {r_ZERO, r_AT, r_V0, r_V1, r_A0, r_A1, r_A2, r_A3,
+                         r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7,
+                         r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8,
+                         r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA};
+static int reservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP};
+static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
+                          r_T3, r_T4, r_T5, r_T6, r_T7, r_T8, r_T9};
+#ifdef __mips_hard_float
+static int fpRegs[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
+                       r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
+static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
+                        r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
+#endif
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg,
+                      int highReg);
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
+static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
+                            int rDest);
+static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc);
+static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
+                              MipsConditionCode cond,
+                              int reg1, int reg2, int dOffset,
+                              MipsLIR *pcrLabel);
+static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
+
+#ifdef __mips_hard_float
+static MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    MipsLIR* res = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    res->operands[0] = rDest;
+    res->operands[1] = rSrc;
+    if (rDest == rSrc) {
+        res->flags.isNop = true;
+    } else {
+        /* must be both DOUBLE or both not DOUBLE */
+        DCHECK_EQ(DOUBLEREG(rDest),DOUBLEREG(rSrc));
+        if (DOUBLEREG(rDest)) {
+            res->opcode = kMipsFmovd;
+        } else {
+            if (SINGLEREG(rDest)) {
+                if (SINGLEREG(rSrc)) {
+                    res->opcode = kMipsFmovs;
+                } else {
+                    /* note the operands are swapped for the mtc1 instr */
+                    res->opcode = kMipsMtc1;
+                    res->operands[0] = rSrc;
+                    res->operands[1] = rDest;
+                }
+            } else {
+                DCHECK(SINGLEREG(rSrc));
+                res->opcode = kMipsMfc1;
+            }
+        }
+    }
+    setupResourceMasks(res);
+    return res;
+}
+#endif
+
+/*
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool.  If target is
+ * a high register, build constant into a low register and copy.
+ *
+ * No additional register clobbering operation performed. Use this version when
+ * 1) rDest is freshly returned from oatAllocTemp or
+ * 2) The codegen is under fixed register usage
+ */
+static MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
+                                     int value)
+{
+    MipsLIR *res;
+
+#ifdef __mips_hard_float
+    int rDestSave = rDest;
+    int isFpReg = FPREG(rDest);
+    if (isFpReg) {
+        DCHECK(SINGLEREG(rDest));
+        rDest = oatAllocTemp(cUnit);
+    }
+#endif
+
+    /* See if the value can be constructed cheaply */
+    if (value == 0) {
+        res = newLIR2(cUnit, kMipsMove, rDest, r_ZERO);
+    } else if ((value > 0) && (value <= 65535)) {
+        res = newLIR3(cUnit, kMipsOri, rDest, r_ZERO, value);
+    } else if ((value < 0) && (value >= -32768)) {
+        res = newLIR3(cUnit, kMipsAddiu, rDest, r_ZERO, value);
+    } else {
+        res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
+        if (value & 0xffff)
+            newLIR3(cUnit, kMipsOri, rDest, rDest, value);
+    }
+
+#ifdef __mips_hard_float
+    if (isFpReg) {
+        newLIR2(cUnit, kMipsMtc1, rDest, rDestSave);
+        oatFreeTemp(cUnit, rDest);
+    }
+#endif
+
+    return res;
+}
+
+/*
+ * Load an immediate value into a fixed or temp register.  Target
+ * register is clobbered, and marked inUse.
+ */
+static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
+{
+    if (oatIsTemp(cUnit, rDest)) {
+        oatClobber(cUnit, rDest);
+        oatMarkInUse(cUnit, rDest);
+    }
+    return loadConstantNoClobber(cUnit, rDest, value);
+}
+
+/*
+ * Load a class pointer value into a fixed or temp register.  Target
+ * register is clobbered, and marked inUse.
+ */
+static MipsLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
+{
+    MipsLIR *res;
+    if (oatIsTemp(cUnit, rDest)) {
+        oatClobber(cUnit, rDest);
+        oatMarkInUse(cUnit, rDest);
+    }
+    res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
+    if (value & 0xffff)
+        newLIR3(cUnit, kMipsOri, rDest, rDest, value);
+    return res;
+}
+
+static MipsLIR *opNone(CompilationUnit *cUnit, OpKind op)
+{
+    MipsLIR *res;
+    MipsOpCode opcode = kMipsNop;
+    switch (op) {
+        case kOpUncondBr:
+            opcode = kMipsB;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in opNone";
+    }
+    res = newLIR0(cUnit, opcode);
+    return res;
+}
+
+static MipsLIR *opCompareBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt)
+{
+    MipsLIR *res;
+    if (rt < 0) {
+      DCHECK(opc >= kMipsBeqz && opc <= kMipsBnez);
+      res = newLIR1(cUnit, opc, rs);
+    } else  {
+      DCHECK(opc == kMipsBeq || opc == kMipsBne);
+      res = newLIR2(cUnit, opc, rs, rt);
+    }
+    return res;
+}
+
+static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
+
+static MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
+{
+    MipsOpCode opcode = kMipsNop;
+    switch (op) {
+        case kOpBlx:
+            opcode = kMipsJalr;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in opReg";
+    }
+    return newLIR2(cUnit, opcode, r_RA, rDestSrc);
+}
+
+static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int value);
+MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                  int value)
+{
+    MipsLIR *res;
+    bool neg = (value < 0);
+    int absValue = (neg) ? -value : value;
+    bool shortForm = (absValue & 0xff) == absValue;
+    MipsOpCode opcode = kMipsNop;
+    switch (op) {
+        case kOpAdd:
+            return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+            break;
+        case kOpSub:
+            return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+            break;
+        default:
+            LOG(FATAL) << "Bad case in opRegImm";
+            break;
+    }
+    if (shortForm)
+        res = newLIR2(cUnit, opcode, rDestSrc1, absValue);
+    else {
+        int rScratch = oatAllocTemp(cUnit);
+        res = loadConstant(cUnit, rScratch, value);
+        if (op == kOpCmp)
+            newLIR2(cUnit, opcode, rDestSrc1, rScratch);
+        else
+            newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch);
+    }
+    return res;
+}
+
+static MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int rSrc2)
+{
+    MipsOpCode opcode = kMipsNop;
+    switch (op) {
+        case kOpAdd:
+            opcode = kMipsAddu;
+            break;
+        case kOpSub:
+            opcode = kMipsSubu;
+            break;
+        case kOpAnd:
+            opcode = kMipsAnd;
+            break;
+        case kOpMul:
+            opcode = kMipsMul;
+            break;
+        case kOpOr:
+            opcode = kMipsOr;
+            break;
+        case kOpXor:
+            opcode = kMipsXor;
+            break;
+        case kOpLsl:
+            opcode = kMipsSllv;
+            break;
+        case kOpLsr:
+            opcode = kMipsSrlv;
+            break;
+        case kOpAsr:
+            opcode = kMipsSrav;
+            break;
+        default:
+            LOG(FATAL) << "bad case in opRegRegReg";
+            break;
+    }
+    return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
+}
+
+static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int value)
+{
+    MipsLIR *res;
+    MipsOpCode opcode = kMipsNop;
+    bool shortForm = true;
+
+    switch(op) {
+        case kOpAdd:
+            if (IS_SIMM16(value)) {
+                opcode = kMipsAddiu;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsAddu;
+            }
+            break;
+        case kOpSub:
+            if (IS_SIMM16((-value))) {
+                value = -value;
+                opcode = kMipsAddiu;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsSubu;
+            }
+            break;
+        case kOpLsl:
+                DCHECK(value >= 0 && value <= 31);
+                opcode = kMipsSll;
+                break;
+        case kOpLsr:
+                DCHECK(value >= 0 && value <= 31);
+                opcode = kMipsSrl;
+                break;
+        case kOpAsr:
+                DCHECK(value >= 0 && value <= 31);
+                opcode = kMipsSra;
+                break;
+        case kOpAnd:
+            if (IS_UIMM16((value))) {
+                opcode = kMipsAndi;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsAnd;
+            }
+            break;
+        case kOpOr:
+            if (IS_UIMM16((value))) {
+                opcode = kMipsOri;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsOr;
+            }
+            break;
+        case kOpXor:
+            if (IS_UIMM16((value))) {
+                opcode = kMipsXori;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsXor;
+            }
+            break;
+        case kOpMul:
+            shortForm = false;
+            opcode = kMipsMul;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in opRegRegImm";
+            break;
+    }
+
+    if (shortForm)
+        res = newLIR3(cUnit, opcode, rDest, rSrc1, value);
+    else {
+        if (rDest != rSrc1) {
+            res = loadConstant(cUnit, rDest, value);
+            newLIR3(cUnit, opcode, rDest, rSrc1, rDest);
+        } else {
+            int rScratch = oatAllocTemp(cUnit);
+            res = loadConstant(cUnit, rScratch, value);
+            newLIR3(cUnit, opcode, rDest, rSrc1, rScratch);
+        }
+    }
+    return res;
+}
+
+MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                  int rSrc2)
+{
+    MipsOpCode opcode = kMipsNop;
+    MipsLIR *res;
+    switch (op) {
+        case kOpMov:
+            opcode = kMipsMove;
+            break;
+        case kOpMvn:
+            return newLIR3(cUnit, kMipsNor, rDestSrc1, rSrc2, r_ZERO);
+        case kOpNeg:
+            return newLIR3(cUnit, kMipsSubu, rDestSrc1, r_ZERO, rSrc2);
+        case kOpAdd:
+        case kOpAnd:
+        case kOpMul:
+        case kOpOr:
+        case kOpSub:
+        case kOpXor:
+            return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
+        case kOp2Byte:
+#if __mips_isa_rev>=2
+            res = newLIR2(cUnit, kMipsSeb, rDestSrc1, rSrc2);
+#else
+            res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
+            opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
+#endif
+            return res;
+        case kOp2Short:
+#if __mips_isa_rev>=2
+            res = newLIR2(cUnit, kMipsSeh, rDestSrc1, rSrc2);
+#else
+            res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
+            opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
+#endif
+            return res;
+        case kOp2Char:
+             return newLIR3(cUnit, kMipsAndi, rDestSrc1, rSrc2, 0xFFFF);
+        default:
+            LOG(FATAL) << "Bad case in opRegReg";
+            break;
+    }
+    return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
+}
+
+static MipsLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+                                     int rDestHi, int valLo, int valHi)
+{
+    MipsLIR *res;
+    res = loadConstantNoClobber(cUnit, rDestLo, valLo);
+    loadConstantNoClobber(cUnit, rDestHi, valHi);
+    return res;
+}
+
+/* Load value from base + scaled index. */
+static MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
+                               int rIndex, int rDest, int scale, OpSize size)
+{
+    MipsLIR *first = NULL;
+    MipsLIR *res;
+    MipsOpCode opcode = kMipsNop;
+    int tReg = oatAllocTemp(cUnit);
+
+#ifdef __mips_hard_float
+    if (FPREG(rDest)) {
+        DCHECK(SINGLEREG(rDest));
+        DCHECK((size == kWord) || (size == kSingle));
+        size = kSingle;
+    } else {
+        if (size == kSingle)
+            size = kWord;
+    }
+#endif
+
+    if (!scale) {
+        first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
+    } else {
+        first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
+        newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
+    }
+
+    switch (size) {
+#ifdef __mips_hard_float
+        case kSingle:
+            opcode = kMipsFlwc1;
+            break;
+#endif
+        case kWord:
+            opcode = kMipsLw;
+            break;
+        case kUnsignedHalf:
+            opcode = kMipsLhu;
+            break;
+        case kSignedHalf:
+            opcode = kMipsLh;
+            break;
+        case kUnsignedByte:
+            opcode = kMipsLbu;
+            break;
+        case kSignedByte:
+            opcode = kMipsLb;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in loadBaseIndexed";
+    }
+
+    res = newLIR3(cUnit, opcode, rDest, 0, tReg);
+    oatFreeTemp(cUnit, tReg);
+    return (first) ? first : res;
+}
+
+/* store value base base + scaled index. */
+static MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
+                                int rIndex, int rSrc, int scale, OpSize size)
+{
+    MipsLIR *first = NULL;
+    MipsLIR *res;
+    MipsOpCode opcode = kMipsNop;
+    int rNewIndex = rIndex;
+    int tReg = oatAllocTemp(cUnit);
+
+#ifdef __mips_hard_float
+    if (FPREG(rSrc)) {
+        DCHECK(SINGLEREG(rSrc));
+        DCHECK((size == kWord) || (size == kSingle));
+        size = kSingle;
+    } else {
+        if (size == kSingle)
+            size = kWord;
+    }
+#endif
+
+    if (!scale) {
+        first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
+    } else {
+        first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
+        newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
+    }
+
+    switch (size) {
+#ifdef __mips_hard_float
+        case kSingle:
+            opcode = kMipsFswc1;
+            break;
+#endif
+        case kWord:
+            opcode = kMipsSw;
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            opcode = kMipsSh;
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            opcode = kMipsSb;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in storeBaseIndexed";
+    }
+    res = newLIR3(cUnit, opcode, rSrc, 0, tReg);
+    oatFreeTemp(cUnit, rNewIndex);
+    return first;
+}
+
+static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    int i;
+    int loadCnt = 0;
+    MipsLIR *res = NULL ;
+    genBarrier(cUnit);
+
+    for (i = 0; i < 8; i++, rMask >>= 1) {
+        if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
+            newLIR3(cUnit, kMipsLw, i+r_A0, loadCnt*4, rBase);
+            loadCnt++;
+        }
+    }
+
+    if (loadCnt) {/* increment after */
+        newLIR3(cUnit, kMipsAddiu, rBase, rBase, loadCnt*4);
+    }
+
+    genBarrier(cUnit);
+    return res; /* NULL always returned which should be ok since no callers use it */
+}
+
+static MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    int i;
+    int storeCnt = 0;
+    MipsLIR *res = NULL ;
+    genBarrier(cUnit);
+
+    for (i = 0; i < 8; i++, rMask >>= 1) {
+        if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
+            newLIR3(cUnit, kMipsSw, i+r_A0, storeCnt*4, rBase);
+            storeCnt++;
+        }
+    }
+
+    if (storeCnt) { /* increment after */
+        newLIR3(cUnit, kMipsAddiu, rBase, rBase, storeCnt*4);
+    }
+
+    genBarrier(cUnit);
+    return res; /* NULL always returned which should be ok since no callers use it */
+}
+
+static MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDest, int rDestHi,
+                                OpSize size, int sReg)
+/*
+ * Load value from base + displacement.  Optionally perform null check
+ * on base (which must have an associated sReg and MIR).  If not
+ * performing null check, incoming MIR can be null. IMPORTANT: this
+ * code must not allocate any new temps.  If a new register is needed
+ * and base and dest are the same, spill some other register to
+ * rlp and then restore.
+ */
+{
+    MipsLIR *res;
+    MipsLIR *load = NULL;
+    MipsLIR *load2 = NULL;
+    MipsOpCode opcode = kMipsNop;
+    bool shortForm = IS_SIMM16(displacement);
+    bool pair = false;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            pair = true;
+            opcode = kMipsLw;
+#ifdef __mips_hard_float
+            if (FPREG(rDest)) {
+                opcode = kMipsFlwc1;
+                if (DOUBLEREG(rDest)) {
+                    rDest = rDest - FP_DOUBLE;
+                } else {
+                    DCHECK(FPREG(rDestHi));
+                    DCHECK(rDest == (rDestHi - 1));
+                }
+                rDestHi = rDest + 1;
+            }
+#endif
+            shortForm = IS_SIMM16_2WORD(displacement);
+            DCHECK_EQ((displacement & 0x3), 0);
+            break;
+        case kWord:
+        case kSingle:
+            opcode = kMipsLw;
+#ifdef __mips_hard_float
+            if (FPREG(rDest)) {
+                opcode = kMipsFlwc1;
+                DCHECK(SINGLEREG(rDest));
+            }
+#endif
+            DCHECK_EQ((displacement & 0x3), 0);
+            break;
+        case kUnsignedHalf:
+            opcode = kMipsLhu;
+            DCHECK_EQ((displacement & 0x1), 0);
+            break;
+        case kSignedHalf:
+            opcode = kMipsLh;
+            DCHECK_EQ((displacement & 0x1), 0);
+            break;
+        case kUnsignedByte:
+            opcode = kMipsLbu;
+            break;
+        case kSignedByte:
+            opcode = kMipsLb;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in loadBaseIndexedBody";
+    }
+
+    if (shortForm) {
+        if (!pair) {
+            load = res = newLIR3(cUnit, opcode, rDest, displacement, rBase);
+        } else {
+            load = res = newLIR3(cUnit, opcode, rDest, displacement + LOWORD_OFFSET, rBase);
+            load2 = newLIR3(cUnit, opcode, rDestHi, displacement + HIWORD_OFFSET, rBase);
+        }
+    } else {
+        if (pair) {
+            int rTmp = oatAllocFreeTemp(cUnit);
+            res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
+            load = newLIR3(cUnit, opcode, rDest, LOWORD_OFFSET, rTmp);
+            load2 = newLIR3(cUnit, opcode, rDestHi, HIWORD_OFFSET, rTmp);
+            oatFreeTemp(cUnit, rTmp);
+        } else {
+            int rTmp = (rBase == rDest) ? oatAllocFreeTemp(cUnit)
+                                        : rDest;
+            res = loadConstant(cUnit, rTmp, displacement);
+            load = newLIR3(cUnit, opcode, rDest, rBase, rTmp);
+            if (rTmp != rDest)
+                oatFreeTemp(cUnit, rTmp);
+        }
+    }
+
+    UNIMPLEMENTED(FATAL) << "Needs art conversion";
+#if 0
+    if (rBase == rFP) {
+        if (load != NULL)
+            annotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
+                                    true /* isLoad */);
+        if (load2 != NULL)
+            annotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
+                                    true /* isLoad */);
+    }
+#endif
+    return load;
+}
+
+static MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
+                            int displacement, int rDest, OpSize size,
+                            int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
+                            size, sReg);
+}
+
+static MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDestLo, int rDestHi,
+                                int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
+                            kLong, sReg);
+}
+
+static MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrc, int rSrcHi,
+                                 OpSize size)
+{
+    MipsLIR *res;
+    MipsLIR *store = NULL;
+    MipsLIR *store2 = NULL;
+    MipsOpCode opcode = kMipsNop;
+    bool shortForm = IS_SIMM16(displacement);
+    bool pair = false;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            pair = true;
+            opcode = kMipsSw;
+#ifdef __mips_hard_float
+            if (FPREG(rSrc)) {
+                opcode = kMipsFswc1;
+                if (DOUBLEREG(rSrc)) {
+                    rSrc = rSrc - FP_DOUBLE;
+                } else {
+                    DCHECK(FPREG(rSrcHi));
+                    DCHECK_EQ(rSrc, (rSrcHi - 1));
+                }
+                rSrcHi = rSrc + 1;
+            }
+#endif
+            shortForm = IS_SIMM16_2WORD(displacement);
+            DCHECK_EQ((displacement & 0x3), 0);
+            break;
+        case kWord:
+        case kSingle:
+            opcode = kMipsSw;
+#ifdef __mips_hard_float
+            if (FPREG(rSrc)) {
+                opcode = kMipsFswc1;
+                DCHECK(SINGLEREG(rSrc));
+            }
+#endif
+            DCHECK_EQ((displacement & 0x3), 0);
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            opcode = kMipsSh;
+            DCHECK_EQ((displacement & 0x1), 0);
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            opcode = kMipsSb;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in storeBaseIndexedBody";
+    }
+
+    if (shortForm) {
+        if (!pair) {
+            store = res = newLIR3(cUnit, opcode, rSrc, displacement, rBase);
+        } else {
+            store = res = newLIR3(cUnit, opcode, rSrc, displacement + LOWORD_OFFSET, rBase);
+            store2 = newLIR3(cUnit, opcode, rSrcHi, displacement + HIWORD_OFFSET, rBase);
+        }
+    } else {
+        int rScratch = oatAllocTemp(cUnit);
+        res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
+        if (!pair) {
+            store =  newLIR3(cUnit, opcode, rSrc, 0, rScratch);
+        } else {
+            store =  newLIR3(cUnit, opcode, rSrc, LOWORD_OFFSET, rScratch);
+            store2 = newLIR3(cUnit, opcode, rSrcHi, HIWORD_OFFSET, rScratch);
+        }
+        oatFreeTemp(cUnit, rScratch);
+    }
+
+    UNIMPLEMENTED(FATAL) << "Needs art conversion";
+#if 0
+    if (rBase == rFP) {
+        if (store != NULL)
+            annotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
+                                    false /* isLoad */);
+        if (store2 != NULL)
+            annotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
+                                    false /* isLoad */);
+    }
+#endif
+
+    return res;
+}
+
+static MipsLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
+}
+
+static MipsLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
+}
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    storeWordDisp(cUnit, base, LOWORD_OFFSET, lowReg);
+    storeWordDisp(cUnit, base, HIWORD_OFFSET, highReg);
+}
+
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    loadWordDisp(cUnit, base, LOWORD_OFFSET , lowReg);
+    loadWordDisp(cUnit, base, HIWORD_OFFSET , highReg);
+}
+
+static MipsLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    MipsLIR* res;
+    MipsOpCode opcode;
+#ifdef __mips_hard_float
+    if (FPREG(rDest) || FPREG(rSrc))
+        return fpRegCopy(cUnit, rDest, rSrc);
+#endif
+    res = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    opcode = kMipsMove;
+    DCHECK(LOWREG(rDest) && LOWREG(rSrc));
+    res->operands[0] = rDest;
+    res->operands[1] = rSrc;
+    res->opcode = opcode;
+    setupResourceMasks(res);
+    if (rDest == rSrc) {
+        res->flags.isNop = true;
+    }
+    return res;
+}
+
+static MipsLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    MipsLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
+    oatAppendLIR(cUnit, (LIR*)res);
+    return res;
+}
+
+static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+                           int srcLo, int srcHi)
+{
+#ifdef __mips_hard_float
+    bool destFP = FPREG(destLo) && FPREG(destHi);
+    bool srcFP = FPREG(srcLo) && FPREG(srcHi);
+    DCHECK_EQ(FPREG(srcLo), FPREG(srcHi));
+    DCHECK_EQ(FPREG(destLo), FPREG(destHi));
+    if (destFP) {
+        if (srcFP) {
+            genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
+        } else {
+           /* note the operands are swapped for the mtc1 instr */
+            newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
+            newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
+        }
+    } else {
+        if (srcFP) {
+            newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
+            newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
+        } else {
+            // Handle overlap
+            if (srcHi == destLo) {
+                genRegCopy(cUnit, destHi, srcHi);
+                genRegCopy(cUnit, destLo, srcLo);
+            } else {
+                genRegCopy(cUnit, destLo, srcLo);
+                genRegCopy(cUnit, destHi, srcHi);
+            }
+        }
+    }
+#else
+    // Handle overlap
+    if (srcHi == destLo) {
+        genRegCopy(cUnit, destHi, srcHi);
+        genRegCopy(cUnit, destLo, srcLo);
+    } else {
+        genRegCopy(cUnit, destLo, srcLo);
+        genRegCopy(cUnit, destHi, srcHi);
+    }
+#endif
+}
+
+static inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit,
+                                     MipsConditionCode cond, int reg,
+                                     int checkValue, int dOffset,
+                                     MipsLIR *pcrLabel)
+{
+    MipsLIR *branch = NULL;
+
+    if (checkValue == 0) {
+        MipsOpCode opc = kMipsNop;
+        if (cond == kMipsCondEq) {
+            opc = kMipsBeqz;
+        } else if (cond == kMipsCondNe) {
+            opc = kMipsBnez;
+        } else if (cond == kMipsCondLt || cond == kMipsCondMi) {
+            opc = kMipsBltz;
+        } else if (cond == kMipsCondLe) {
+            opc = kMipsBlez;
+        } else if (cond == kMipsCondGt) {
+            opc = kMipsBgtz;
+        } else if (cond == kMipsCondGe) {
+            opc = kMipsBgez;
+        } else {
+            LOG(FATAL) << "Bad case in genRegImmCheck";
+        }
+        branch = opCompareBranch(cUnit, opc, reg, -1);
+    } else if (IS_SIMM16(checkValue)) {
+        if (cond == kMipsCondLt) {
+            int tReg = oatAllocTemp(cUnit);
+            newLIR3(cUnit, kMipsSlti, tReg, reg, checkValue);
+            branch = opCompareBranch(cUnit, kMipsBne, tReg, r_ZERO);
+            oatFreeTemp(cUnit, tReg);
+        } else {
+            LOG(FATAL) << "Bad case in genRegImmCheck";
+        }
+    } else {
+        LOG(FATAL) << "Bad case in genRegImmCheck";
+    }
+
+    UNIMPLEMENTED(FATAL) << "Needs art conversion";
+    return NULL;
+#if 0
+    if (cUnit->jitMode == kJitMethod) {
+        BasicBlock *bb = cUnit->curBlock;
+        if (bb->taken) {
+            MipsLIR  *exceptionLabel = (MipsLIR *) cUnit->blockLabelList;
+            exceptionLabel += bb->taken->id;
+            branch->generic.target = (LIR *) exceptionLabel;
+            return exceptionLabel;
+        } else {
+            LOG(FATAL) <<  "Catch blocks not handled yet";
+            return NULL;
+        }
+    } else {
+        return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+    }
+#endif
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc
new file mode 100644
index 0000000..f49cdab
--- /dev/null
+++ b/src/compiler/codegen/mips/Mips32/Gen.cc
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains codegen for the Mips ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+namespace art {
+
+// FIXME: need the following:
+void genSuspendTest(CompilationUnit* cUnit, MIR* mir) {}
+void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                   RegLocation rlSrc) {}
+void genNewInstance(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlDest) {}
+void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genConstString(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlDest, RegLocation rlSrc) {}
+void genConstClass(CompilationUnit* cUnit, MIR* mir,
+                          RegLocation rlDest, RegLocation rlSrc) {}
+void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
+                        RegLocation rlArray, RegLocation rlIndex,
+                        RegLocation rlDest, int scale) {}
+void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
+                        RegLocation rlArray, RegLocation rlIndex,
+                        RegLocation rlSrc, int scale) {}
+void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlArray, RegLocation rlIndex,
+                           RegLocation rlSrc, int scale) {}
+void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
+                    RegLocation rlSrc, RegLocation rlObj,
+                    bool isLongOrDouble, bool isObject) {}
+bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
+                          RegLocation rlDest, RegLocation rlSrc1,
+                          RegLocation rlSrc2) { return 0; }
+bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlDest, RegLocation rlSrc1,
+                           RegLocation rlSrc2) { return 0; }
+bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlDest, RegLocation rlSrc1,
+                           RegLocation rlShift) { return 0; }
+bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
+                             RegLocation rlDest, RegLocation rlSrc,
+                             int lit) { return 0; }
+
+
+
+
+
+
+
+
+STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
+
+void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
+  if (field == NULL) {
+    const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
+    std::string class_name(cUnit->dex_file->GetFieldDeclaringClassDescriptor(field_id));
+    std::string field_name(cUnit->dex_file->GetFieldName(field_id));
+    LOG(INFO) << "Field " << PrettyDescriptor(class_name) << "." << field_name
+              << " unresolved at compile time";
+  } else {
+    // We also use the slow path for wide volatile fields.
+  }
+}
+
+/*
+ * Construct an s4 from two consecutive half-words of switch data.
+ * This needs to check endianness because the DEX optimizer only swaps
+ * half-words in instruction stream.
+ *
+ * "switchData" must be 32-bit aligned.
+ */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+STATIC inline s4 s4FromSwitchData(const void* switchData) {
+    return *(s4*) switchData;
+}
+#else
+STATIC inline s4 s4FromSwitchData(const void* switchData) {
+    u2* data = switchData;
+    return data[0] | (((s4) data[1]) << 16);
+}
+#endif
+/*
+ * Insert a kMipsPseudoCaseLabel at the beginning of the Dalvik
+ * offset vaddr.  This label will be used to fix up the case
+ * branch table during the assembly phase.  Be sure to set
+ * all resource flags on this to prevent code motion across
+ * target boundaries.  KeyVal is just there for debugging.
+ */
+STATIC MipsLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
+{
+    std::map<unsigned int, LIR*>::iterator it;
+    it = cUnit->boundaryMap.find(vaddr);
+    if (it == cUnit->boundaryMap.end()) {
+        LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
+    }
+    MipsLIR* newLabel = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    newLabel->generic.dalvikOffset = vaddr;
+    newLabel->opcode = kMipsPseudoCaseLabel;
+    newLabel->operands[0] = keyVal;
+    oatInsertLIRAfter(it->second, (LIR*)newLabel);
+    return newLabel;
+}
+
+STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
+{
+    const u2* table = tabRec->table;
+    int baseVaddr = tabRec->vaddr;
+    int *targets = (int*)&table[4];
+    int entries = table[1];
+    int lowKey = s4FromSwitchData(&table[2]);
+    for (int i = 0; i < entries; i++) {
+        tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
+                                             i + lowKey);
+    }
+}
+
+STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
+{
+    const u2* table = tabRec->table;
+    int baseVaddr = tabRec->vaddr;
+    int entries = table[1];
+    int* keys = (int*)&table[2];
+    int* targets = &keys[entries];
+    for (int i = 0; i < entries; i++) {
+        tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
+                                             keys[i]);
+    }
+}
+
+void oatProcessSwitchTables(CompilationUnit* cUnit)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
+    while (true) {
+        SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        if (tabRec->table[0] == kPackedSwitchSignature)
+            markPackedCaseLabels(cUnit, tabRec);
+        else if (tabRec->table[0] == kSparseSwitchSignature)
+            markSparseCaseLabels(cUnit, tabRec);
+        else {
+            LOG(FATAL) << "Invalid switch table";
+        }
+    }
+}
+
+STATIC void dumpSparseSwitchTable(const u2* table)
+    /*
+     * Sparse switch data format:
+     *  ushort ident = 0x0200   magic value
+     *  ushort size             number of entries in the table; > 0
+     *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (2+size*4) 16-bit code units.
+     */
+{
+    u2 ident = table[0];
+    int entries = table[1];
+    int* keys = (int*)&table[2];
+    int* targets = &keys[entries];
+    LOG(INFO) <<  "Sparse switch table - ident:0x" << std::hex << ident <<
+       ", entries: " << std::dec << entries;
+    for (int i = 0; i < entries; i++) {
+        LOG(INFO) << "    Key[" << keys[i] << "] -> 0x" << std::hex <<
+        targets[i];
+    }
+}
+
+STATIC void dumpPackedSwitchTable(const u2* table)
+    /*
+     * Packed switch data format:
+     *  ushort ident = 0x0100   magic value
+     *  ushort size             number of entries in the table
+     *  int first_key           first (and lowest) switch case value
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (4+size*2) 16-bit code units.
+     */
+{
+    u2 ident = table[0];
+    int* targets = (int*)&table[4];
+    int entries = table[1];
+    int lowKey = s4FromSwitchData(&table[2]);
+    LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
+        ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
+    for (int i = 0; i < entries; i++) {
+        LOG(INFO) << "    Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
+            targets[i];
+    }
+}
+
+/*
+ * The sparse table in the literal pool is an array of <key,displacement>
+ * pairs.  For each set, we'll load them as a pair using ldmia.
+ * This means that the register number of the temp we use for the key
+ * must be lower than the reg for the displacement.
+ *
+ * The test loop will look something like:
+ *
+ *   adr   rBase, <table>
+ *   ldr   rVal, [rSP, vRegOff]
+ *   mov   rIdx, #tableSize
+ * lp:
+ *   ldmia rBase!, {rKey, rDisp}
+ *   sub   rIdx, #1
+ *   cmp   rVal, rKey
+ *   ifeq
+ *   add   rPC, rDisp   ; This is the branch from which we compute displacement
+ *   cbnz  rIdx, lp
+ */
+STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir,
+                            RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
+    if (cUnit->printMe) {
+        dumpSparseSwitchTable(table);
+    }
+    // Add the table to the list - we'll process it later
+    SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
+                         true, kAllocData);
+    tabRec->table = table;
+    tabRec->vaddr = mir->offset;
+    int size = table[1];
+    tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
+                                        kAllocLIR);
+    oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
+
+    // Get the switch value
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    int rBase = oatAllocTemp(cUnit);
+    /* Allocate key and disp temps */
+    int rKey = oatAllocTemp(cUnit);
+    int rDisp = oatAllocTemp(cUnit);
+    // Make sure rKey's register number is less than rDisp's number for ldmia
+    if (rKey > rDisp) {
+        int tmp = rDisp;
+        rDisp = rKey;
+        rKey = tmp;
+    }
+    // Materialize a pointer to the switch table
+    newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
+    // Set up rIdx
+    int rIdx = oatAllocTemp(cUnit);
+    loadConstant(cUnit, rIdx, size);
+    // Establish loop branch target
+    MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    // Load next key/disp
+    newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
+    opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
+    // Go if match. NOTE: No instruction set switch here - must stay Thumb2
+    genIT(cUnit, kMipsCondEq, "");
+    MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
+    tabRec->bxInst = switchBranch;
+    // Needs to use setflags encoding here
+    newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
+    MipsLIR* branch = opCondBranch(cUnit, kMipsCondNe);
+    branch->generic.target = (LIR*)target;
+#endif
+}
+
+STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
+                            RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
+    if (cUnit->printMe) {
+        dumpPackedSwitchTable(table);
+    }
+    // Add the table to the list - we'll process it later
+    SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
+                                                true, kAllocData);
+    tabRec->table = table;
+    tabRec->vaddr = mir->offset;
+    int size = table[1];
+    tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
+                                        kAllocLIR);
+    oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
+
+    // Get the switch value
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    int tableBase = oatAllocTemp(cUnit);
+    // Materialize a pointer to the switch table
+    newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
+    int lowKey = s4FromSwitchData(&table[2]);
+    int keyReg;
+    // Remove the bias, if necessary
+    if (lowKey == 0) {
+        keyReg = rlSrc.lowReg;
+    } else {
+        keyReg = oatAllocTemp(cUnit);
+        opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
+    }
+    // Bounds check - if < 0 or >= size continue following switch
+    opRegImm(cUnit, kOpCmp, keyReg, size-1);
+    MipsLIR* branchOver = opCondBranch(cUnit, kMipsCondHi);
+
+    // Load the displacement from the switch table
+    int dispReg = oatAllocTemp(cUnit);
+    loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
+
+    // ..and go! NOTE: No instruction set switch here - must stay Thumb2
+    MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
+    tabRec->bxInst = switchBranch;
+
+    /* branchOver target here */
+    MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR*)target;
+#endif
+}
+
+/*
+ * Array data table format:
+ *  ushort ident = 0x0300   magic value
+ *  ushort width            width of each element in the table
+ *  uint   size             number of elements in the table
+ *  ubyte  data[size*width] table of data values (may contain a single-byte
+ *                          padding at the end)
+ *
+ * Total size is 4+(width * size + 1)/2 16-bit code units.
+ */
+STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
+                              RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
+    // Add the table to the list - we'll process it later
+    FillArrayData *tabRec = (FillArrayData *)
+         oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
+    tabRec->table = table;
+    tabRec->vaddr = mir->offset;
+    u2 width = tabRec->table[1];
+    u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
+    tabRec->size = (size * width) + 8;
+
+    oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
+
+    // Making a call - use explicit registers
+    oatFlushAllRegs(cUnit);   /* Everything to home location */
+    loadValueDirectFixed(cUnit, rlSrc, r0);
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
+    // Materialize a pointer to the fill data image
+    newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
+    callRuntimeHelper(cUnit, rLR);
+#endif
+}
+
+STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
+                    RegLocation rlDest, RegLocation rlObj,
+                    bool isLongOrDouble, bool isObject)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    int fieldOffset;
+    bool isVolatile;
+    uint32_t fieldIdx = mir->dalvikInsn.vC;
+    bool fastPath =
+        cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit,
+                                                  fieldOffset, isVolatile, false);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        RegLocation rlResult;
+        RegisterClass regClass = oatRegClassBySize(size);
+        DCHECK_GE(fieldOffset, 0);
+        rlObj = loadValue(cUnit, rlObj, kCoreReg);
+        if (isLongOrDouble) {
+            DCHECK(rlDest.wide);
+            genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
+            int regPtr = oatAllocTemp(cUnit);
+            opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+            rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
+            loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
+            if (isVolatile) {
+                oatGenMemBarrier(cUnit, kSY);
+            }
+            oatFreeTemp(cUnit, regPtr);
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
+            genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
+            loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
+                         kWord, rlObj.sRegLow);
+            if (isVolatile) {
+                oatGenMemBarrier(cUnit, kSY);
+            }
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    } else {
+        int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
+                                     : OFFSETOF_MEMBER(Thread, pGet32Instance));
+        loadWordDisp(cUnit, rSELF, getterOffset, rLR);
+        loadValueDirect(cUnit, rlObj, r1);
+        loadConstant(cUnit, r0, fieldIdx);
+        callRuntimeHelper(cUnit, rLR);
+        if (isLongOrDouble) {
+            RegLocation rlResult = oatGetReturnWide(cUnit);
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            RegLocation rlResult = oatGetReturn(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    }
+#endif
+}
+
+/*
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+STATIC void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
+                rlSrc.lowReg, 0x80000000);
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+STATIC void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
+                         RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+    rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
+                        0x80000000);
+    genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+STATIC void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
+                       RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    RegLocation rlResult;
+    loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+    genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
+    rlResult = oatGetReturnWide(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
+#endif
+}
+
+STATIC bool partialOverlap(int sreg1, int sreg2)
+{
+    return abs(sreg1 - sreg2) == 1;
+}
+
+STATIC void withCarryHelper(CompilationUnit *cUnit, MipsOpCode opc,
+                            RegLocation rlDest, RegLocation rlSrc1,
+                            RegLocation rlSrc2, int sltuSrc1, int sltuSrc2)
+{
+    int tReg = oatAllocTemp(cUnit);
+    newLIR3(cUnit, opc, rlDest.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    newLIR3(cUnit, kMipsSltu, tReg, sltuSrc1, sltuSrc2);
+    newLIR3(cUnit, opc, rlDest.highReg, rlSrc1.highReg, rlSrc2.highReg);
+    newLIR3(cUnit, opc, rlDest.highReg, rlDest.highReg, tReg);
+    oatFreeTemp(cUnit, tReg);
+}
+
+STATIC void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
+                         OpKind secondOp, RegLocation rlDest,
+                         RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    RegLocation rlResult;
+    int carryOp = (secondOp == kOpAdc || secondOp == kOpSbc);
+
+    if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
+        partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
+        partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
+        // Rare case - not enough registers to properly handle
+        genInterpSingleStep(cUnit, mir);
+    } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
+        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+        if (!carryOp) {
+            opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlResult.lowReg, rlSrc2.lowReg);
+            opRegRegReg(cUnit, secondOp, rlResult.highReg, rlResult.highReg, rlSrc2.highReg);
+        } else if (secondOp == kOpAdc) {
+            withCarryHelper(cUnit, kMipsAddu, rlResult, rlResult, rlSrc2,
+                            rlResult.lowReg, rlSrc2.lowReg);
+        } else {
+            int tReg = oatAllocTemp(cUnit);
+            newLIR2(cUnit, kMipsMove, tReg, rlResult.lowReg);
+            withCarryHelper(cUnit, kMipsSubu, rlResult, rlResult, rlSrc2,
+                            tReg, rlResult.lowReg);
+            oatFreeTemp(cUnit, tReg);
+        }
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
+        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+        rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+        if (!carryOp) {
+            opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlResult.lowReg);
+            opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlResult.highReg);
+        } else if (secondOp == kOpAdc) {
+            withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlResult,
+                            rlResult.lowReg, rlSrc1.lowReg);
+        } else {
+            withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlResult,
+                            rlSrc1.lowReg, rlResult.lowReg);
+        }
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else {
+        rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+        rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+        if (!carryOp) {
+            opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+            opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
+        } else if (secondOp == kOpAdc) {
+            withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlSrc2,
+                            rlResult.lowReg, rlSrc1.lowReg);
+        } else {
+            withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlSrc2,
+                            rlSrc1.lowReg, rlResult.lowReg);
+        }
+        storeValueWide(cUnit, rlDest, rlResult);
+    }
+#endif
+}
+
+void oatInitializeRegAlloc(CompilationUnit* cUnit)
+{
+    int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
+    int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
+    int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
+#ifdef __mips_hard_float
+    int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
+    int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
+#else
+    int numFPRegs = 0;
+    int numFPTemps = 0;
+#endif
+    RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true,
+                                                kAllocRegAlloc);
+    cUnit->regPool = pool;
+    pool->numCoreRegs = numRegs;
+    pool->coreRegs = (RegisterInfo *)
+            oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs),
+                   true, kAllocRegAlloc);
+    pool->numFPRegs = numFPRegs;
+    pool->FPRegs = numFPRegs == 0 ? NULL : (RegisterInfo *)
+            oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true,
+                   kAllocRegAlloc);
+    oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
+    oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
+    // Keep special registers from being allocated
+    for (int i = 0; i < numReserved; i++) {
+        if (NO_SUSPEND && !cUnit->genDebugger &&
+            (reservedRegs[i] == rSUSPEND)) {
+            //To measure cost of suspend check
+            continue;
+        }
+        oatMarkInUse(cUnit, reservedRegs[i]);
+    }
+    // Mark temp regs - all others not in use can be used for promotion
+    for (int i = 0; i < numTemps; i++) {
+        oatMarkTemp(cUnit, coreTemps[i]);
+    }
+    for (int i = 0; i < numFPTemps; i++) {
+        oatMarkTemp(cUnit, fpTemps[i]);
+    }
+    // Construct the alias map.
+    cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs *
+                                      sizeof(cUnit->phiAliasMap[0]), false,
+                                      kAllocDFInfo);
+    for (int i = 0; i < cUnit->numSSARegs; i++) {
+        cUnit->phiAliasMap[i] = i;
+    }
+    for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
+        int defReg = phi->ssaRep->defs[0];
+        for (int i = 0; i < phi->ssaRep->numUses; i++) {
+           for (int j = 0; j < cUnit->numSSARegs; j++) {
+               if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
+                   cUnit->phiAliasMap[j] = defReg;
+               }
+           }
+        }
+    }
+}
+
+STATIC void genMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    genMonitorPortable(cUnit, mir);
+#endif
+}
+
+STATIC void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                       RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    RegLocation rlResult;
+    loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+    genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
+    rlResult = oatGetReturn(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+#endif
+}
+
+STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
+        RegLocation rlSrc, RegLocation rlResult, int lit,
+        int firstBit, int secondBit)
+{
+    // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have
+    // to do a regular multiply.
+    opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/Mips32/Ralloc.cc b/src/compiler/codegen/mips/Mips32/Ralloc.cc
new file mode 100644
index 0000000..e0912d7
--- /dev/null
+++ b/src/compiler/codegen/mips/Mips32/Ralloc.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+/*
+ * This file contains codegen for the Mips ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Alloc a pair of core registers, or a double.  Low reg in low byte,
+ * high reg in next byte.
+ */
+int oatAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
+                                  int regClass)
+{
+    int highReg;
+    int lowReg;
+    int res = 0;
+
+#ifdef __mips_hard_float
+    if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
+        lowReg = oatAllocTempDouble(cUnit);
+        highReg = lowReg + 1;
+        res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+        return res;
+    }
+#endif
+
+    lowReg = oatAllocTemp(cUnit);
+    highReg = oatAllocTemp(cUnit);
+    res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+    return res;
+}
+
+int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
+{
+#ifdef __mips_hard_float
+    if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
+{
+        return oatAllocTempFloat(cUnit);
+}
+#endif
+    return oatAllocTemp(cUnit);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/MipsLIR.h b/src/compiler/codegen/mips/MipsLIR.h
new file mode 100644
index 0000000..a6f426e
--- /dev/null
+++ b/src/compiler/codegen/mips/MipsLIR.h
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_COMPILER_CODEGEN_MIPS_MIPSLIR_H_
+#define ART_COMPILER_COMPILER_CODEGEN_MIPS_MIPSLIR_H_
+
+#include "../../Dalvik.h"
+#include "../../CompilerInternals.h"
+
+namespace art {
+
+// Set to 1 to measure cost of suspend check
+#define NO_SUSPEND 0
+
+/*
+ * Runtime register conventions.
+ *
+ * zero is always the value 0
+ * at is scratch (normally used as temp reg by assembler)
+ * v0, v1 are scratch (normally hold subroutine return values)
+ * a0-a3 are scratch (normally hold subroutine arguments)
+ * t0-t8 are scratch
+ * t9 is scratch (normally used for function calls)
+ * s0 (rSUSPEND) is reserved [holds suspend-check counter]
+ * s1 (rSELF) is reserved [holds current &Thread]
+ * s2-s7 are callee save (promotion target)
+ * k0, k1 are reserved for use by interrupt handlers
+ * gp is reserved for global pointer
+ * sp is reserved
+ * s8 is callee save (promotion target)
+ * ra is scratch (normally holds the return addr)
+ *
+ * Preserved across C calls: s0-s8
+ * Trashed across C calls: at, v0-v1, a0-a3, t0-t9, gp, ra
+ *
+ * Floating pointer registers
+ * NOTE: there are 32 fp registers (16 df pairs), but currently
+ *       only support 16 fp registers (8 df pairs).
+ * f0-f15
+ * df0-df7, where df0={f0,f1}, df1={f2,f3}, ... , df7={f14,f15}
+ *
+ * f0-f15 (df0-df7) trashed across C calls
+ *
+ * For mips32 code use:
+ *      a0-a3 to hold operands
+ *      v0-v1 to hold results
+ *      t0-t9 for temps
+ *
+ * All jump/branch instructions have a delay slot after it.
+ *
+ *  Stack frame diagram (stack grows down, higher addresses at top):
+ *
+ * +------------------------+
+ * | IN[ins-1]              |  {Note: resides in caller's frame}
+ * |       .                |
+ * | IN[0]                  |
+ * | caller's Method*       |
+ * +========================+  {Note: start of callee's frame}
+ * | spill region           |  {variable sized - will include lr if non-leaf.}
+ * +------------------------+
+ * | ...filler word...      |  {Note: used as 2nd word of V[locals-1] if long]
+ * +------------------------+
+ * | V[locals-1]            |
+ * | V[locals-2]            |
+ * |      .                 |
+ * |      .                 |
+ * | V[1]                   |
+ * | V[0]                   |
+ * +------------------------+
+ * |  0 to 3 words padding  |
+ * +------------------------+
+ * | OUT[outs-1]            |
+ * | OUT[outs-2]            |
+ * |       .                |
+ * | OUT[0]                 |
+ * | curMethod*             | <<== sp w/ 16-byte alignment
+ * +========================+
+ */
+
+/* Offset to distingish FP regs */
+#define FP_REG_OFFSET 32
+/* Offset to distinguish DP FP regs */
+#define FP_DOUBLE 64
+/* Offset to distingish the extra regs */
+#define EXTRA_REG_OFFSET 128
+/* Reg types */
+#define REGTYPE(x) (x & (FP_REG_OFFSET | FP_DOUBLE))
+#define FPREG(x) ((x & FP_REG_OFFSET) == FP_REG_OFFSET)
+#define EXTRAREG(x) ((x & EXTRA_REG_OFFSET) == EXTRA_REG_OFFSET)
+#define LOWREG(x) ((x & 0x1f) == x)
+#define DOUBLEREG(x) ((x & FP_DOUBLE) == FP_DOUBLE)
+#define SINGLEREG(x) (FPREG(x) && !DOUBLEREG(x))
+/*
+ * Note: the low register of a floating point pair is sufficient to
+ * create the name of a double, but require both names to be passed to
+ * allow for asserts to verify that the pair is consecutive if significant
+ * rework is done in this area.  Also, it is a good reminder in the calling
+ * code that reg locations always describe doubles as a pair of singles.
+ */
+#define S2D(x,y) ((x) | FP_DOUBLE)
+/* Mask to strip off fp flags */
+#define FP_REG_MASK (FP_REG_OFFSET-1)
+/* non-existent Dalvik register */
+#define vNone   (-1)
+/* non-existant physical register */
+#define rNone   (-1)
+
+#ifdef HAVE_LITTLE_ENDIAN
+#define LOWORD_OFFSET 0
+#define HIWORD_OFFSET 4
+#define r_ARG0 r_A0
+#define r_ARG1 r_A1
+#define r_ARG2 r_A2
+#define r_ARG3 r_A3
+#define r_RESULT0 r_V0
+#define r_RESULT1 r_V1
+#else
+#define LOWORD_OFFSET 4
+#define HIWORD_OFFSET 0
+#define r_ARG0 r_A1
+#define r_ARG1 r_A0
+#define r_ARG2 r_A3
+#define r_ARG3 r_A2
+#define r_RESULT0 r_V1
+#define r_RESULT1 r_V0
+#endif
+
+/* These are the same for both big and little endian. */
+#define r_FARG0 r_F12
+#define r_FARG1 r_F13
+#define r_FRESULT0 r_F0
+#define r_FRESULT1 r_F1
+
+/* RegisterLocation templates return values (r_V0, or r_V0/r_V1) */
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 1, r_V0, INVALID_REG, \
+                      INVALID_SREG}
+#define LOC_C_RETURN_ALT {kLocPhysReg, 0, 0, 0, 0, 0, 1, r_F0, INVALID_REG, \
+                      INVALID_SREG}
+#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 1, r_V0, r_V1,\
+                           INVALID_SREG}
+#define LOC_C_RETURN_WIDE_ALT {kLocPhysReg, 1, 0, 0, 0, 0, 1, r_F0, r_F1,\
+                           INVALID_SREG}
+
+typedef enum ResourceEncodingPos {
+    kGPReg0     = 0,
+    kRegSP      = 29,
+    kRegLR      = 31,
+    kFPReg0     = 32, /* only 16 fp regs supported currently */
+    kFPRegEnd   = 48,
+    kRegHI      = kFPRegEnd,
+    kRegLO,
+    kRegPC,
+    kRegEnd     = 51,
+    kCCode      = kRegEnd,
+    kFPStatus,          // FP status word
+    // The following four bits are for memory disambiguation
+    kDalvikReg,         // 1 Dalvik Frame (can be fully disambiguated)
+    kLiteral,           // 2 Literal pool (can be fully disambiguated)
+    kHeapRef,           // 3 Somewhere on the heap (alias with any other heap)
+    kMustNotAlias,      // 4 Guaranteed to be non-alias (eg *(r6+x))
+} ResourceEncodingPos;
+
+#define ENCODE_REG_LIST(N)      ((u8) N)
+#define ENCODE_REG_SP           (1ULL << kRegSP)
+#define ENCODE_REG_LR           (1ULL << kRegLR)
+#define ENCODE_REG_PC           (1ULL << kRegPC)
+#define ENCODE_CCODE            (1ULL << kCCode)
+#define ENCODE_FP_STATUS        (1ULL << kFPStatus)
+
+/* Abstract memory locations */
+#define ENCODE_DALVIK_REG       (1ULL << kDalvikReg)
+#define ENCODE_LITERAL          (1ULL << kLiteral)
+#define ENCODE_HEAP_REF         (1ULL << kHeapRef)
+#define ENCODE_MUST_NOT_ALIAS   (1ULL << kMustNotAlias)
+
+#define ENCODE_ALL              (~0ULL)
+#define ENCODE_MEM              (ENCODE_DALVIK_REG | ENCODE_LITERAL | \
+                                 ENCODE_HEAP_REF | ENCODE_MUST_NOT_ALIAS)
+
+#define DECODE_ALIAS_INFO_REG(X)        (X & 0xffff)
+#define DECODE_ALIAS_INFO_WIDE(X)       ((X & 0x80000000) ? 1 : 0)
+
+typedef enum OpKind {
+    kOpMov,
+    kOpMvn,
+    kOpCmp,
+    kOpLsl,
+    kOpLsr,
+    kOpAsr,
+    kOpRor,
+    kOpNot,
+    kOpAnd,
+    kOpOr,
+    kOpXor,
+    kOpNeg,
+    kOpAdd,
+    kOpAdc,
+    kOpSub,
+    kOpSbc,
+    kOpRsub,
+    kOpMul,
+    kOpDiv,
+    kOpRem,
+    kOpBic,
+    kOpCmn,
+    kOpTst,
+    kOpBkpt,
+    kOpBlx,
+    kOpPush,
+    kOpPop,
+    kOp2Char,
+    kOp2Short,
+    kOp2Byte,
+    kOpCondBr,
+    kOpUncondBr,
+    kOpInvalid,
+} OpKind;
+
+/*
+ * FIXME:
+ * Originally had r4PC as r_S0, rFP as r_S1, rSELF as r_S2, rINST as r_S4
+ * Remap - don't need r4PC, rFP or rINST.  Might make sense to keep
+ * Method* in one of these since we have so many registers to play with.
+ */
+
+#define rSUSPEND r_S0
+#define rSELF r_S1
+#define rSP r_SP
+
+/* FIXME: don't do this - find and fix all rLR's */
+#define rLR r_RA
+
+/*
+ * Annotate special-purpose core registers:
+ */
+
+typedef enum NativeRegisterPool {
+    r_ZERO = 0,
+    r_AT = 1,
+    r_V0 = 2,
+    r_V1 = 3,
+    r_A0 = 4,
+    r_A1 = 5,
+    r_A2 = 6,
+    r_A3 = 7,
+    r_T0 = 8,
+    r_T1 = 9,
+    r_T2 = 10,
+    r_T3 = 11,
+    r_T4 = 12,
+    r_T5 = 13,
+    r_T6 = 14,
+    r_T7 = 15,
+    r_S0 = 16,
+    r_S1 = 17,
+    r_S2 = 18,
+    r_S3 = 19,
+    r_S4 = 20,
+    r_S5 = 21,
+    r_S6 = 22,
+    r_S7 = 23,
+    r_T8 = 24,
+    r_T9 = 25,
+    r_K0 = 26,
+    r_K1 = 27,
+    r_GP = 28,
+    r_SP = 29,
+    r_FP = 30,
+    r_RA = 31,
+
+    r_F0 = 0 + FP_REG_OFFSET,
+    r_F1,
+    r_F2,
+    r_F3,
+    r_F4,
+    r_F5,
+    r_F6,
+    r_F7,
+    r_F8,
+    r_F9,
+    r_F10,
+    r_F11,
+    r_F12,
+    r_F13,
+    r_F14,
+    r_F15,
+#if 0 /* only 16 fp regs supported currently */
+    r_F16,
+    r_F17,
+    r_F18,
+    r_F19,
+    r_F20,
+    r_F21,
+    r_F22,
+    r_F23,
+    r_F24,
+    r_F25,
+    r_F26,
+    r_F27,
+    r_F28,
+    r_F29,
+    r_F30,
+    r_F31,
+#endif
+    r_DF0 = r_F0 + FP_DOUBLE,
+    r_DF1 = r_F2 + FP_DOUBLE,
+    r_DF2 = r_F4 + FP_DOUBLE,
+    r_DF3 = r_F6 + FP_DOUBLE,
+    r_DF4 = r_F8 + FP_DOUBLE,
+    r_DF5 = r_F10 + FP_DOUBLE,
+    r_DF6 = r_F12 + FP_DOUBLE,
+    r_DF7 = r_F14 + FP_DOUBLE,
+#if 0 /* only 16 fp regs supported currently */
+    r_DF8 = r_F16 + FP_DOUBLE,
+    r_DF9 = r_F18 + FP_DOUBLE,
+    r_DF10 = r_F20 + FP_DOUBLE,
+    r_DF11 = r_F22 + FP_DOUBLE,
+    r_DF12 = r_F24 + FP_DOUBLE,
+    r_DF13 = r_F26 + FP_DOUBLE,
+    r_DF14 = r_F28 + FP_DOUBLE,
+    r_DF15 = r_F30 + FP_DOUBLE,
+#endif
+    r_HI = EXTRA_REG_OFFSET,
+    r_LO,
+    r_PC,
+} NativeRegisterPool;
+
+/* Shift encodings */
+typedef enum MipsShiftEncodings {
+    kMipsLsl = 0x0,
+    kMipsLsr = 0x1,
+    kMipsAsr = 0x2,
+    kMipsRor = 0x3
+} MipsShiftEncodings;
+
+/* condition encodings */
+typedef enum MipsConditionCode {
+    kMipsCondEq = 0x0,    /* 0000 */
+    kMipsCondNe = 0x1,    /* 0001 */
+    kMipsCondCs = 0x2,    /* 0010 */
+    kMipsCondCc = 0x3,    /* 0011 */
+    kMipsCondMi = 0x4,    /* 0100 */
+    kMipsCondPl = 0x5,    /* 0101 */
+    kMipsCondVs = 0x6,    /* 0110 */
+    kMipsCondVc = 0x7,    /* 0111 */
+    kMipsCondHi = 0x8,    /* 1000 */
+    kMipsCondLs = 0x9,    /* 1001 */
+    kMipsCondGe = 0xa,    /* 1010 */
+    kMipsCondLt = 0xb,    /* 1011 */
+    kMipsCondGt = 0xc,    /* 1100 */
+    kMipsCondLe = 0xd,    /* 1101 */
+    kMipsCondAl = 0xe,    /* 1110 */
+    kMipsCondNv = 0xf,    /* 1111 */
+} MipsConditionCode;
+
+typedef enum MipsThrowKind {
+    kMipsThrowNullPointer,
+    kMipsThrowDivZero,
+    kMipsThrowArrayBounds,
+    kMipsThrowVerificationError,
+    kMipsThrowNegArraySize,
+    kMipsThrowNoSuchMethod,
+    kMipsThrowStackOverflow,
+} MipsThrowKind;
+
+#define isPseudoOpCode(opCode) ((int)(opCode) < 0)
+
+/*
+ * The following enum defines the list of supported Thumb instructions by the
+ * assembler. Their corresponding snippet positions will be defined in
+ * Assemble.c.
+ */
+typedef enum MipsOpCode {
+    kMipsPseudoSuspendTarget = -15,
+    kMipsPseudoThrowTarget = -14,
+    kMipsPseudoCaseLabel = -13,
+    kMipsPseudoMethodEntry = -12,
+    kMipsPseudoMethodExit = -11,
+    kMipsPseudoBarrier = -10,
+    kMipsPseudoExtended = -9,
+    kMipsPseudoSSARep = -8,
+    kMipsPseudoEntryBlock = -7,
+    kMipsPseudoExitBlock = -6,
+    kMipsPseudoTargetLabel = -5,
+    kMipsPseudoDalvikByteCodeBoundary = -4,
+    kMipsPseudoPseudoAlign4 = -3,
+    kMipsPseudoEHBlockLabel = -2,
+    kMipsPseudoNormalBlockLabel = -1,
+
+    kMipsFirst,
+    kMips32BitData = kMipsFirst, /* data [31..0] */
+    kMipsAddiu,   /* addiu t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0] */
+    kMipsAddu,    /* add d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100001] */
+    kMipsAnd,     /* and d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100100] */
+    kMipsAndi,    /* andi t,s,imm16 [001100] s[25..21] t[20..16] imm16[15..0] */
+    kMipsB,       /* b o   [0001000000000000] o[15..0] */
+    kMipsBal,     /* bal o [0000010000010001] o[15..0] */
+    /* NOTE: the code tests the range kMipsBeq thru kMipsBne, so
+             adding an instruction in this range may require updates */
+    kMipsBeq,     /* beq s,t,o [000100] s[25..21] t[20..16] o[15..0] */
+    kMipsBeqz,    /* beqz s,o [000100] s[25..21] [00000] o[15..0] */
+    kMipsBgez,    /* bgez s,o [000001] s[25..21] [00001] o[15..0] */
+    kMipsBgtz,    /* bgtz s,o [000111] s[25..21] [00000] o[15..0] */
+    kMipsBlez,    /* blez s,o [000110] s[25..21] [00000] o[15..0] */
+    kMipsBltz,    /* bltz s,o [000001] s[25..21] [00000] o[15..0] */
+    kMipsBnez,    /* bnez s,o [000101] s[25..21] [00000] o[15..0] */
+    kMipsBne,     /* bne s,t,o [000101] s[25..21] t[20..16] o[15..0] */
+    kMipsDiv,     /* div s,t [000000] s[25..21] t[20..16] [0000000000011010] */
+#if __mips_isa_rev>=2
+    kMipsExt,     /* ext t,s,p,z [011111] s[25..21] t[20..16] z[15..11] p[10..6] [000000] */
+#endif
+    kMipsJal,     /* jal t [000011] t[25..0] */
+    kMipsJalr,    /* jalr d,s [000000] s[25..21] [00000] d[15..11]
+                                  hint[10..6] [001001] */
+    kMipsJr,      /* jr s [000000] s[25..21] [0000000000] hint[10..6] [001000] */
+    kMipsLahi,    /* lui t,imm16 [00111100000] t[20..16] imm16[15..0] load addr hi */
+    kMipsLalo,    /* ori t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0] load addr lo */
+    kMipsLui,     /* lui t,imm16 [00111100000] t[20..16] imm16[15..0] */
+    kMipsLb,      /* lb t,o(b) [100000] b[25..21] t[20..16] o[15..0] */
+    kMipsLbu,     /* lbu t,o(b) [100100] b[25..21] t[20..16] o[15..0] */
+    kMipsLh,      /* lh t,o(b) [100001] b[25..21] t[20..16] o[15..0] */
+    kMipsLhu,     /* lhu t,o(b) [100101] b[25..21] t[20..16] o[15..0] */
+    kMipsLw,      /* lw t,o(b) [100011] b[25..21] t[20..16] o[15..0] */
+    kMipsMfhi,    /* mfhi d [0000000000000000] d[15..11] [00000010000] */
+    kMipsMflo,    /* mflo d [0000000000000000] d[15..11] [00000010010] */
+    kMipsMove,    /* move d,s [000000] s[25..21] [00000] d[15..11] [00000100101] */
+    kMipsMovz,    /* movz d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000001010] */
+    kMipsMul,     /* mul d,s,t [011100] s[25..21] t[20..16] d[15..11] [00000000010] */
+    kMipsNop,     /* nop [00000000000000000000000000000000] */
+    kMipsNor,     /* nor d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100111] */
+    kMipsOr,      /* or d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100101] */
+    kMipsOri,     /* ori t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0] */
+    kMipsPref,    /* pref h,o(b) [101011] b[25..21] h[20..16] o[15..0] */
+    kMipsSb,      /* sb t,o(b) [101000] b[25..21] t[20..16] o[15..0] */
+#if __mips_isa_rev>=2
+    kMipsSeb,     /* seb d,t [01111100000] t[20..16] d[15..11] [10000100000] */
+    kMipsSeh,     /* seh d,t [01111100000] t[20..16] d[15..11] [11000100000] */
+#endif
+    kMipsSh,      /* sh t,o(b) [101001] b[25..21] t[20..16] o[15..0] */
+    kMipsSll,     /* sll d,t,a [00000000000] t[20..16] d[15..11] a[10..6] [000000] */
+    kMipsSllv,    /* sllv d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000100] */
+    kMipsSlt,     /* slt d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000101010] */
+    kMipsSlti,    /* slti t,s,imm16 [001010] s[25..21] t[20..16] imm16[15..0] */
+    kMipsSltu,    /* sltu d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000101011] */
+    kMipsSra,     /* sra d,s,imm5 [00000000000] t[20..16] d[15..11] imm5[10..6] [000011] */
+    kMipsSrav,    /* srav d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000111] */
+    kMipsSrl,     /* srl d,t,a [00000000000] t[20..16] d[20..16] a[10..6] [000010] */
+    kMipsSrlv,    /* srlv d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000110] */
+    kMipsSubu,    /* subu d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100011] */
+    kMipsSw,      /* sw t,o(b) [101011] b[25..21] t[20..16] o[15..0] */
+    kMipsXor,     /* xor d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100110] */
+    kMipsXori,    /* xori t,s,imm16 [001110] s[25..21] t[20..16] imm16[15..0] */
+#ifdef __mips_hard_float
+    kMipsFadds,   /* add.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000000] */
+    kMipsFsubs,   /* sub.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000001] */
+    kMipsFmuls,   /* mul.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000010] */
+    kMipsFdivs,   /* div.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000011] */
+    kMipsFaddd,   /* add.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000000] */
+    kMipsFsubd,   /* sub.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000001] */
+    kMipsFmuld,   /* mul.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000010] */
+    kMipsFdivd,   /* div.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000011] */
+    kMipsFcvtsd,  /* cvt.s.d d,s [01000110001] [00000] s[15..11] d[10..6] [100000] */
+    kMipsFcvtsw,  /* cvt.s.w d,s [01000110100] [00000] s[15..11] d[10..6] [100000] */
+    kMipsFcvtds,  /* cvt.d.s d,s [01000110000] [00000] s[15..11] d[10..6] [100001] */
+    kMipsFcvtdw,  /* cvt.d.w d,s [01000110100] [00000] s[15..11] d[10..6] [100001] */
+    kMipsFcvtws,  /* cvt.w.d d,s [01000110000] [00000] s[15..11] d[10..6] [100100] */
+    kMipsFcvtwd,  /* cvt.w.d d,s [01000110001] [00000] s[15..11] d[10..6] [100100] */
+    kMipsFmovs,   /* mov.s d,s [01000110000] [00000] s[15..11] d[10..6] [000110] */
+    kMipsFmovd,   /* mov.d d,s [01000110001] [00000] s[15..11] d[10..6] [000110] */
+    kMipsFlwc1,   /* lwc1 t,o(b) [110001] b[25..21] t[20..16] o[15..0] */
+    kMipsFldc1,   /* ldc1 t,o(b) [110101] b[25..21] t[20..16] o[15..0] */
+    kMipsFswc1,   /* swc1 t,o(b) [111001] b[25..21] t[20..16] o[15..0] */
+    kMipsFsdc1,   /* sdc1 t,o(b) [111101] b[25..21] t[20..16] o[15..0] */
+    kMipsMfc1,    /* mfc1 t,s [01000100000] t[20..16] s[15..11] [00000000000] */
+    kMipsMtc1,    /* mtc1 t,s [01000100100] t[20..16] s[15..11] [00000000000] */
+#endif
+    kMipsUndefined,  /* undefined [011001xxxxxxxxxxxxxxxx] */
+    kMipsLast
+} MipsOpCode;
+
+/* Bit flags describing the behavior of each native opcode */
+typedef enum MipsOpFeatureFlags {
+    kIsBranch = 0,
+    kRegDef0,
+    kRegDef1,
+    kRegDefSP,
+    kRegDefLR,
+    kRegDefList0,
+    kRegDefList1,
+    kRegUse0,
+    kRegUse1,
+    kRegUse2,
+    kRegUse3,
+    kRegUseSP,
+    kRegUsePC,
+    kRegUseList0,
+    kRegUseList1,
+    kNoOperand,
+    kIsUnaryOp,
+    kIsBinaryOp,
+    kIsTertiaryOp,
+    kIsQuadOp,
+    kIsIT,
+    kSetsCCodes,
+    kUsesCCodes,
+    kMemLoad,
+    kMemStore,
+} MipsOpFeatureFlags;
+
+#define IS_LOAD         (1 << kMemLoad)
+#define IS_STORE        (1 << kMemStore)
+#define IS_BRANCH       (1 << kIsBranch)
+#define REG_DEF0        (1 << kRegDef0)
+#define REG_DEF1        (1 << kRegDef1)
+#define REG_DEF_SP      (1 << kRegDefSP)
+#define REG_DEF_LR      (1 << kRegDefLR)
+#define REG_DEF_LIST0   (1 << kRegDefList0)
+#define REG_DEF_LIST1   (1 << kRegDefList1)
+#define REG_USE0        (1 << kRegUse0)
+#define REG_USE1        (1 << kRegUse1)
+#define REG_USE2        (1 << kRegUse2)
+#define REG_USE3        (1 << kRegUse3)
+#define REG_USE_SP      (1 << kRegUseSP)
+#define REG_USE_PC      (1 << kRegUsePC)
+#define REG_USE_LIST0   (1 << kRegUseList0)
+#define REG_USE_LIST1   (1 << kRegUseList1)
+#define NO_OPERAND      (1 << kNoOperand)
+#define IS_UNARY_OP     (1 << kIsUnaryOp)
+#define IS_BINARY_OP    (1 << kIsBinaryOp)
+#define IS_TERTIARY_OP  (1 << kIsTertiaryOp)
+#define IS_QUAD_OP      (1 << kIsQuadOp)
+#define IS_IT           (1 << kIsIT)
+#define SETS_CCODES     (1 << kSetsCCodes)
+#define USES_CCODES     (1 << kUsesCCodes)
+
+/* Common combo register usage patterns */
+#define REG_USE01       (REG_USE0 | REG_USE1)
+#define REG_USE02       (REG_USE0 | REG_USE2)
+#define REG_USE012      (REG_USE01 | REG_USE2)
+#define REG_USE12       (REG_USE1 | REG_USE2)
+#define REG_USE23       (REG_USE2 | REG_USE3)
+#define REG_DEF01       (REG_DEF0 | REG_DEF1)
+#define REG_DEF0_USE0   (REG_DEF0 | REG_USE0)
+#define REG_DEF0_USE1   (REG_DEF0 | REG_USE1)
+#define REG_DEF0_USE2   (REG_DEF0 | REG_USE2)
+#define REG_DEF0_USE01  (REG_DEF0 | REG_USE01)
+#define REG_DEF0_USE12  (REG_DEF0 | REG_USE12)
+#define REG_DEF01_USE2  (REG_DEF0 | REG_DEF1 | REG_USE2)
+
+/* Instruction assembly fieldLoc kind */
+typedef enum MipsEncodingKind {
+    kFmtUnused,
+    kFmtBitBlt,        /* Bit string using end/start */
+    kFmtDfp,           /* Double FP reg */
+    kFmtSfp,           /* Single FP reg */
+} MipsEncodingKind;
+
+/* Struct used to define the snippet positions for each Thumb opcode */
+typedef struct MipsEncodingMap {
+    u4 skeleton;
+    struct {
+        MipsEncodingKind kind;
+        int end;   /* end for kFmtBitBlt, 1-bit slice end for FP regs */
+        int start; /* start for kFmtBitBlt, 4-bit slice end for FP regs */
+    } fieldLoc[4];
+    MipsOpCode opcode;
+    int flags;
+    const char *name;
+    const char* fmt;
+    int size;
+} MipsEncodingMap;
+
+/* Keys for target-specific scheduling and other optimization hints */
+typedef enum MipsTargetOptHints {
+    kMaxHoistDistance,
+} MipsTargetOptHints;
+
+extern MipsEncodingMap EncodingMap[kMipsLast];
+
+/*
+ * Each instance of this struct holds a pseudo or real LIR instruction:
+ * - pseudo ones (eg labels and marks) and will be discarded by the assembler.
+ * - real ones will be assembled
+ *
+ * FIXME: notes below are Arm-specific.  We have 32 core registers instead
+ * of 16, and no IT blocks.  Must widen this or overload in order to
+ * support all 32 FP regs.  Perhaps use r0 for ccodes, eliminate IT block
+ * and overload gp with fp status word? (or just use a single bit for
+ * both core and fp condition code/status word?
+ *
+ * Machine resources are encoded into a 64-bit vector, where the encodings are
+ * as following:
+ * - [ 0..15]: general purpose registers including PC, SP, and LR
+ * - [16..47]: floating-point registers where d0 is expanded to s[01] and s0
+ *   starts at bit 16
+ * - [48]: IT block
+ * - [49]: integer condition code
+ * - [50]: floatint-point status word
+ */
+typedef struct MipsLIR {
+    LIR generic;
+    MipsOpCode opcode;
+    int operands[4];            // [0..3] = [dest, src1, src2, extra]
+    struct {
+        bool isNop:1;           // LIR is optimized away
+        bool pcRelFixup:1;      // May need pc-relative fixup
+        unsigned int age:4;     // default is 0, set lazily by the optimizer
+        unsigned int size:3;    // in bytes
+        unsigned int unused:23;
+    } flags;
+    int aliasInfo;              // For Dalvik register access & litpool disambiguation
+    u8 useMask;                 // Resource mask for use
+    u8 defMask;                 // Resource mask for def
+} MipsLIR;
+
+typedef struct SwitchTable {
+    int offset;
+    const u2* table;            // Original dex table
+    int vaddr;                  // Dalvik offset of switch opcode
+    MipsLIR* bxInst;             // Switch indirect branch instruction
+    MipsLIR** targets;           // Array of case targets
+} SwitchTable;
+
+typedef struct FillArrayData {
+    int offset;
+    const u2* table;           // Original dex table
+    int size;
+    int vaddr;                 // Dalvik offset of OP_FILL_ARRAY_DATA opcode
+} FillArrayData;
+
+/* Utility macros to traverse the LIR/MipsLIR list */
+#define NEXT_LIR(lir) ((MipsLIR *) lir->generic.next)
+#define PREV_LIR(lir) ((MipsLIR *) lir->generic.prev)
+
+#define NEXT_LIR_LVALUE(lir) (lir)->generic.next
+#define PREV_LIR_LVALUE(lir) (lir)->generic.prev
+
+#define IS_UIMM16(v) ((0 <= (v)) && ((v) <= 65535))
+#define IS_SIMM16(v) ((-32768 <= (v)) && ((v) <= 32766))
+#define IS_SIMM16_2WORD(v) ((-32764 <= (v)) && ((v) <= 32763)) /* 2 offsets must fit */
+
+}  // namespace art
+
+#endif  // ART_COMPILER_COMPILER_CODEGEN_MIPS_MIPSLIR_H_
diff --git a/src/compiler/codegen/mips/MipsRallocUtil.cc b/src/compiler/codegen/mips/MipsRallocUtil.cc
new file mode 100644
index 0000000..a243415
--- /dev/null
+++ b/src/compiler/codegen/mips/MipsRallocUtil.cc
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains Mips-specific register allocation support.
+ */
+
+#include "../../CompilerUtility.h"
+#include "../../CompilerIR.h"
+#include "../..//Dataflow.h"
+#include "MipsLIR.h"
+#include "Codegen.h"
+#include "../Ralloc.h"
+
+namespace art {
+
+/*
+ * Mark a callee-save fp register as promoted.  Note that
+ * vpush/vpop uses contiguous register lists so we must
+ * include any holes in the mask.  Associate holes with
+ * Dalvik register INVALID_VREG (0xFFFFU).
+ */
+STATIC void markPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
+{
+    UNIMPLEMENTED(FATAL) << "No support yet for promoted FP regs";
+#if 0
+    DCHECK_GE(reg, FP_REG_MASK + FP_CALLEE_SAVE_BASE);
+    reg = (reg & FP_REG_MASK) - FP_CALLEE_SAVE_BASE;
+    // Ensure fpVmapTable is large enough
+    int tableSize = cUnit->fpVmapTable.size();
+    for (int i = tableSize; i < (reg + 1); i++) {
+        cUnit->fpVmapTable.push_back(INVALID_VREG);
+    }
+    // Add the current mapping
+    cUnit->fpVmapTable[reg] = sReg;
+    // Size of fpVmapTable is high-water mark, use to set mask
+    cUnit->numFPSpills = cUnit->fpVmapTable.size();
+    cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << FP_CALLEE_SAVE_BASE;
+#endif
+}
+
+void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
+{
+    RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
+    RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
+    DCHECK(info1 && info2 && info1->pair && info2->pair &&
+           (info1->partner == info2->reg) &&
+           (info2->partner == info1->reg));
+    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
+        if (!(info1->isTemp && info2->isTemp)) {
+            /* Should not happen.  If it does, there's a problem in evalLoc */
+            LOG(FATAL) << "Long half-temp, half-promoted";
+        }
+
+        info1->dirty = false;
+        info2->dirty = false;
+        if (oatS2VReg(cUnit, info2->sReg) <
+            oatS2VReg(cUnit, info1->sReg))
+            info1 = info2;
+        int vReg = oatS2VReg(cUnit, info1->sReg);
+        oatFlushRegWideImpl(cUnit, rSP,
+                                    oatVRegOffset(cUnit, vReg),
+                                    info1->reg, info1->partner);
+    }
+}
+
+void oatFlushReg(CompilationUnit* cUnit, int reg)
+{
+    RegisterInfo* info = oatGetRegInfo(cUnit, reg);
+    if (info->live && info->dirty) {
+        info->dirty = false;
+        int vReg = oatS2VReg(cUnit, info->sReg);
+        oatFlushRegImpl(cUnit, rSP,
+                                oatVRegOffset(cUnit, vReg),
+                                reg, kWord);
+    }
+}
+
+/* Give access to the target-dependent FP register encoding to common code */
+bool oatIsFpReg(int reg) {
+    return FPREG(reg);
+}
+
+uint32_t oatFpRegMask() {
+    return FP_REG_MASK;
+}
+
+/* Clobber all regs that might be used by an external C call */
+extern void oatClobberCalleeSave(CompilationUnit *cUnit)
+{
+    oatClobber(cUnit, r_ZERO);
+    oatClobber(cUnit, r_AT);
+    oatClobber(cUnit, r_V0);
+    oatClobber(cUnit, r_V1);
+    oatClobber(cUnit, r_A0);
+    oatClobber(cUnit, r_A1);
+    oatClobber(cUnit, r_A2);
+    oatClobber(cUnit, r_A3);
+    oatClobber(cUnit, r_T0);
+    oatClobber(cUnit, r_T1);
+    oatClobber(cUnit, r_T2);
+    oatClobber(cUnit, r_T3);
+    oatClobber(cUnit, r_T4);
+    oatClobber(cUnit, r_T5);
+    oatClobber(cUnit, r_T6);
+    oatClobber(cUnit, r_T7);
+    oatClobber(cUnit, r_T8);
+    oatClobber(cUnit, r_T9);
+    oatClobber(cUnit, r_K0);
+    oatClobber(cUnit, r_K1);
+    oatClobber(cUnit, r_GP);
+    oatClobber(cUnit, r_FP);
+    oatClobber(cUnit, r_RA);
+    oatClobber(cUnit, r_HI);
+    oatClobber(cUnit, r_LO);
+    oatClobber(cUnit, r_F0);
+    oatClobber(cUnit, r_F1);
+    oatClobber(cUnit, r_F2);
+    oatClobber(cUnit, r_F3);
+    oatClobber(cUnit, r_F4);
+    oatClobber(cUnit, r_F5);
+    oatClobber(cUnit, r_F6);
+    oatClobber(cUnit, r_F7);
+    oatClobber(cUnit, r_F8);
+    oatClobber(cUnit, r_F9);
+    oatClobber(cUnit, r_F10);
+    oatClobber(cUnit, r_F11);
+    oatClobber(cUnit, r_F12);
+    oatClobber(cUnit, r_F13);
+    oatClobber(cUnit, r_F14);
+    oatClobber(cUnit, r_F15);
+}
+
+extern RegLocation oatGetReturnWide(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE;
+    oatClobber(cUnit, r_V0);
+    oatClobber(cUnit, r_V1);
+    oatMarkInUse(cUnit, r_V0);
+    oatMarkInUse(cUnit, r_V1);
+    oatMarkPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE_ALT;
+    oatClobber(cUnit, r_F0);
+    oatClobber(cUnit, r_F1);
+    oatMarkInUse(cUnit, r_F0);
+    oatMarkInUse(cUnit, r_F1);
+    oatMarkPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+extern RegLocation oatGetReturn(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN;
+    oatClobber(cUnit, r_V0);
+    oatMarkInUse(cUnit, r_V0);
+    return res;
+}
+
+extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN_ALT;
+    oatClobber(cUnit, r_F0);
+    oatMarkInUse(cUnit, r_F0);
+    return res;
+}
+
+extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
+{
+    return FPREG(reg) ? &cUnit->regPool->FPRegs[reg & FP_REG_MASK]
+                      : &cUnit->regPool->coreRegs[reg];
+}
+
+/* To be used when explicitly managing register use */
+extern void oatLockCallTemps(CompilationUnit* cUnit)
+{
+    oatLockTemp(cUnit, r_A0);
+    oatLockTemp(cUnit, r_A1);
+    oatLockTemp(cUnit, r_A2);
+    oatLockTemp(cUnit, r_A3);
+}
+
+/* To be used when explicitly managing register use */
+extern void oatFreeCallTemps(CompilationUnit* cUnit)
+{
+    oatFreeTemp(cUnit, r_A0);
+    oatFreeTemp(cUnit, r_A1);
+    oatFreeTemp(cUnit, r_A2);
+    oatFreeTemp(cUnit, r_A3);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/mips/ArchVariant.cc b/src/compiler/codegen/mips/mips/ArchVariant.cc
new file mode 100644
index 0000000..5eca74b
--- /dev/null
+++ b/src/compiler/codegen/mips/mips/ArchVariant.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+/*
+ * This file is included by Codegen-mips.c, and implements architecture
+ * variant-specific code.
+ */
+
+/*
+ * Determine the initial instruction set to be used for this trace.
+ * Later components may decide to change this.
+ */
+JitInstructionSetType oatInstructionSet(void)
+{
+    return DALVIK_OAT_MIPS;
+}
+
+/* Architecture-specific initializations and checks go here */
+bool oatArchVariantInit(void)
+{
+    return true;
+}
+
+int dvmCompilerTargetOptHint(int key)
+{
+    int res;
+    switch (key) {
+        case kMaxHoistDistance:
+            res = 2;
+            break;
+        default:
+            LOG(FATAL) << "Unknown target optimization hint key: " << key;
+    }
+    return res;
+}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
+{
+#if ANDROID_SMP != 0
+    // FIXME: what to do here for Mips?
+#endif
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/mips/Codegen.cc b/src/compiler/codegen/mips/mips/Codegen.cc
new file mode 100644
index 0000000..2b71b04
--- /dev/null
+++ b/src/compiler/codegen/mips/mips/Codegen.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _CODEGEN_C
+#define TGT_LIR MipsLIR
+
+/* For testing */
+#define __mips_hard_float
+
+#include "../../../Dalvik.h"
+#include "../../../CompilerInternals.h"
+#include "../MipsLIR.h"
+#include "../../Ralloc.h"
+#include "../Codegen.h"
+
+/* Mips codegen building blocks */
+#include "../CodegenCommon.cc"
+
+/* Mips-specific factory utilities */
+#include "../Mips32/Factory.cc"
+/* Target indepedent factory utilities */
+#include "../../CodegenFactory.cc"
+/* Mips-specific factory utilities */
+#include "../ArchFactory.cc"
+
+/* Mips32-specific codegen routines */
+#include "../Mips32/Gen.cc"
+/* FP codegen routines */
+#include "../FP/MipsFP.cc"
+
+/* Mips32-specific register allocation */
+#include "../Mips32/Ralloc.cc"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../../MethodCodegenDriver.cc"
+
+/* Target-independent local optimizations */
+#include "../../LocalOptimizations.cc"
+
+/* Common codegen utility code */
+#include "../../CodegenUtil.cc"
+
+/* Architecture manifest */
+#include "ArchVariant.cc"
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 91c4e3c..59d113d 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -73,6 +73,7 @@
 
   PruneNonImageClasses();  // Remove junk
   ComputeLazyFieldsForImageClasses();  // Add useful information
+  ComputeEagerResolvedStrings();
   Heap::CollectGarbage(false);  // Remove garbage
   Heap::GetAllocSpace()->Trim();  // Trim size of source_space
   if (!AllocMemory()) {
@@ -121,6 +122,35 @@
   return true;
 }
 
+void ImageWriter::ComputeEagerResolvedStringsCallback(Object* obj, void* arg) {
+  if (!obj->GetClass()->IsStringClass()) {
+    return;
+  }
+  String* string = obj->AsString();
+  std::string utf8_string(string->ToModifiedUtf8());
+  ImageWriter* writer = reinterpret_cast<ImageWriter*>(arg);
+  ClassLinker* linker = Runtime::Current()->GetClassLinker();
+  typedef Set::const_iterator CacheIt;  // TODO: C++0x auto
+  for (CacheIt it = writer->dex_caches_.begin(), end = writer->dex_caches_.end(); it != end; ++it) {
+    DexCache* dex_cache = *it;
+    const DexFile& dex_file = linker->FindDexFile(dex_cache);
+    const DexFile::StringId* string_id = dex_file.FindStringId(utf8_string);
+    if (string_id != NULL) {
+      // This string occurs in this dex file, assign the dex cache entry.
+      uint32_t string_idx = dex_file.GetIndexForStringId(*string_id);
+      if (dex_cache->GetResolvedString(string_idx) == NULL) {
+        dex_cache->SetResolvedString(string_idx, string);
+      }
+    }
+  }
+}
+
+void ImageWriter::ComputeEagerResolvedStrings() {
+  HeapBitmap* heap_bitmap = Heap::GetLiveBits();
+  DCHECK(heap_bitmap != NULL);
+  heap_bitmap->Walk(ComputeEagerResolvedStringsCallback, this);  // TODO: add Space-limited Walk
+}
+
 bool ImageWriter::IsImageClass(const Class* klass) {
   if (image_classes_ == NULL) {
     return true;
diff --git a/src/image_writer.h b/src/image_writer.h
index 74a3f94..8db3570 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -110,6 +110,10 @@
   void ComputeLazyFieldsForImageClasses();
   static bool ComputeLazyFieldsForClassesVisitor(Class* klass, void* arg);
 
+  // Wire dex cache resolved strings to strings in the image to avoid runtime resolution
+  void ComputeEagerResolvedStrings();
+  static void ComputeEagerResolvedStringsCallback(Object* obj, void* arg);
+
   void PruneNonImageClasses();
   static bool NonImageClassesVisitor(Class* c, void* arg);
 
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 1b54b24..5b9d271 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -239,7 +239,15 @@
             = down_cast<ObjectArray<Object>*>(image_root_object);
         //  = image_root_object->AsObjectArray<Object>();
         for (int i = 0; i < image_root_object_array->GetLength(); i++) {
-            os << StringPrintf("\t%d: %p\n", i, image_root_object_array->Get(i));
+          Object* value = image_root_object_array->Get(i);
+          if (value != NULL) {
+            os << "\t" << i << ": ";
+            std::string summary;
+            PrettyObjectValue(summary, value->GetClass(), value);
+            os << summary;
+          } else {
+            os << StringPrintf("\t%d: null\n", i);
+          }
         }
       }
     }
@@ -292,6 +300,59 @@
 
   ~ImageDump() {}
 
+  static void PrettyObjectValue(std::string& summary, Class* type, Object* value) {
+    CHECK(type != NULL);
+    if (value == NULL) {
+      StringAppendF(&summary, "null   %s\n", PrettyDescriptor(type).c_str());
+    } else if (type->IsStringClass()) {
+      String* string = value->AsString();
+      StringAppendF(&summary, "%p   String: \"%s\"\n", string, string->ToModifiedUtf8().c_str());
+    } else if (value->IsClass()) {
+      Class* klass = value->AsClass();
+      StringAppendF(&summary, "%p   Class: %s\n", klass, PrettyDescriptor(klass).c_str());
+    } else if (value->IsField()) {
+      Field* field = value->AsField();
+      StringAppendF(&summary, "%p   Field: %s\n", field, PrettyField(field).c_str());
+    } else if (value->IsMethod()) {
+      Method* method = value->AsMethod();
+      StringAppendF(&summary, "%p   Method: %s\n", method, PrettyMethod(method).c_str());
+    } else {
+      StringAppendF(&summary, "%p   %s\n", value, PrettyDescriptor(type).c_str());
+    }
+  }
+
+  static void PrintField(std::string& summary, Field* field, Object* obj) {
+    FieldHelper fh(field);
+    Class* type = fh.GetType();
+    StringAppendF(&summary, "\t%s: ", fh.GetName());
+    if (type->IsPrimitiveLong()) {
+      StringAppendF(&summary, "%lld (0x%llx)\n", field->Get64(obj), field->Get64(obj));
+    } else if (type->IsPrimitiveDouble()) {
+      StringAppendF(&summary, "%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
+    } else if (type->IsPrimitiveFloat()) {
+      StringAppendF(&summary, "%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
+    } else if (type->IsPrimitive()){
+      StringAppendF(&summary, "%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
+    } else {
+      Object* value = field->GetObj(obj);
+      PrettyObjectValue(summary, type, value);
+    }
+  }
+
+  static void DumpFields(std::string& summary, Object* obj, Class* klass) {
+    Class* super = klass->GetSuperClass();
+    if (super != NULL) {
+      DumpFields(summary, obj, super);
+    }
+    ObjectArray<Field>* fields = klass->GetIFields();
+    if (fields != NULL) {
+      for (int32_t i = 0; i < fields->GetLength(); i++) {
+        Field* field = fields->Get(i);
+        PrintField(summary, field, obj);
+      }
+    }
+  }
+
   static void Callback(Object* obj, void* arg) {
     DCHECK(obj != NULL);
     DCHECK(arg != NULL);
@@ -306,59 +367,68 @@
     state->stats_.alignment_bytes += alignment_bytes;
 
     std::string summary;
-    StringAppendF(&summary, "%p: ", obj);
-    if (obj->IsClass()) {
+    Class* obj_class = obj->GetClass();
+    if (obj_class->IsArrayClass()) {
+      StringAppendF(&summary, "%p: %s length:%d\n", obj, PrettyDescriptor(obj_class).c_str(),
+                    obj->AsArray()->GetLength());
+    } else if (obj->IsClass()) {
       Class* klass = obj->AsClass();
-      summary += "CLASS ";
-      summary += ClassHelper(klass).GetDescriptor();
+      StringAppendF(&summary, "%p: java.lang.Class \"%s\" (", obj,
+                    PrettyDescriptor(klass).c_str());
       std::ostringstream ss;
-      ss << " (" << klass->GetStatus() << ")";
+      ss << klass->GetStatus() << ")\n";
       summary += ss.str();
+    } else if (obj->IsField()) {
+      StringAppendF(&summary, "%p: java.lang.reflect.Field %s\n", obj,
+                    PrettyField(obj->AsField()).c_str());
+    } else if (obj->IsMethod()) {
+      StringAppendF(&summary, "%p: java.lang.reflect.Method %s\n", obj,
+                    PrettyMethod(obj->AsMethod()).c_str());
+    } else if (obj_class->IsStringClass()) {
+      StringAppendF(&summary, "%p: java.lang.String \"%s\"\n", obj,
+                    obj->AsString()->ToModifiedUtf8().c_str());
+    } else {
+      StringAppendF(&summary, "%p: %s\n", obj, PrettyDescriptor(obj_class).c_str());
+    }
+    DumpFields(summary, obj, obj_class);
+    if (obj->IsObjectArray()) {
+      ObjectArray<Object>* obj_array = obj->AsObjectArray<Object>();
+      int32_t length = obj_array->GetLength();
+      for (int32_t i = 0; i < length; i++) {
+        Object* value = obj_array->Get(i);
+        size_t run = 0;
+        for (int32_t j = i + 1; j < length; j++) {
+          if (value == obj_array->Get(j)) {
+            run++;
+          } else {
+            break;
+          }
+        }
+        if (run == 0) {
+          StringAppendF(&summary, "\t%d: ", i);
+        } else {
+          StringAppendF(&summary, "\t%d to %d: ", i, i + run);
+          i = i + run;
+        }
+        Class* value_class = value == NULL ? obj_class->GetComponentType() : value->GetClass();
+        PrettyObjectValue(summary, value_class, value);
+      }
+    } else if (obj->IsClass()) {
+      ObjectArray<Field>* sfields = obj->AsClass()->GetSFields();
+      if (sfields != NULL) {
+        summary += "\t\tSTATICS:\n";
+        for (int32_t i = 0; i < sfields->GetLength(); i++) {
+          Field* field = sfields->Get(i);
+          PrintField(summary, field, NULL);
+        }
+      }
     } else if (obj->IsMethod()) {
       Method* method = obj->AsMethod();
-      StringAppendF(&summary, "METHOD %s", PrettyMethod(method).c_str());
-    } else if (obj->IsField()) {
-      Field* field = obj->AsField();
-      StringAppendF(&summary, "FIELD %s", PrettyField(field).c_str());
-    } else if (obj->IsArrayInstance()) {
-      StringAppendF(&summary, "ARRAY %d", obj->AsArray()->GetLength());
-    } else if (obj->GetClass()->IsStringClass()) {
-      StringAppendF(&summary, "STRING %s", obj->AsString()->ToModifiedUtf8().c_str());
-    } else {
-      StringAppendF(&summary, "OBJECT");
-    }
-    StringAppendF(&summary, "\n");
-    std::string descriptor(ClassHelper(obj->GetClass()).GetDescriptor());
-    StringAppendF(&summary, "\tclass %p: %s\n", obj->GetClass(), descriptor.c_str());
-    state->stats_.descriptor_to_bytes[descriptor] += object_bytes;
-    state->stats_.descriptor_to_count[descriptor] += 1;
-    // StringAppendF(&summary, "\tsize %d (alignment padding %d)\n",
-    //               object_bytes, RoundUp(object_bytes, kObjectAlignment) - object_bytes);
-    if (obj->IsMethod()) {
-      Method* method = obj->AsMethod();
-      if (!method->IsCalleeSaveMethod()) {
-        const int8_t* code =reinterpret_cast<const int8_t*>(method->GetCode());
-        StringAppendF(&summary, "\tCODE     %p\n", code);
-
-        const Method::InvokeStub* invoke_stub = method->GetInvokeStub();
-        StringAppendF(&summary, "\tJNI STUB %p\n", invoke_stub);
-      }
       if (method->IsNative()) {
-        if (method->IsRegistered()) {
-          StringAppendF(&summary, "\tNATIVE REGISTERED %p\n", method->GetNativeMethod());
-        } else {
-          StringAppendF(&summary, "\tNATIVE UNREGISTERED\n");
-        }
         DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
         DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
-      } else if (method->IsAbstract()) {
-        StringAppendF(&summary, "\tABSTRACT\n");
-        DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
-        DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
-        DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
-      } else if (method->IsCalleeSaveMethod()) {
-        StringAppendF(&summary, "\tCALLEE SAVE METHOD\n");
+      } else if (method->IsAbstract() || method->IsCalleeSaveMethod()) {
         DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
         DCHECK_EQ(0U, method->GetGcMapLength()) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
@@ -368,20 +438,22 @@
 
         size_t register_map_bytes = method->GetGcMapLength();
         state->stats_.register_map_bytes += register_map_bytes;
-        StringAppendF(&summary, "GC=%zd ", register_map_bytes);
 
         size_t pc_mapping_table_bytes = method->GetMappingTableLength();
         state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
-        StringAppendF(&summary, "Mapping=%zd ", pc_mapping_table_bytes);
 
         const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
         size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
         state->stats_.dex_instruction_bytes += dex_instruction_bytes;
 
-        StringAppendF(&summary, "\tSIZE Code=%zd GC=%zd Mapping=%zd",
+        StringAppendF(&summary, "\t\tSIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
                       dex_instruction_bytes, register_map_bytes, pc_mapping_table_bytes);
       }
     }
+    std::string descriptor(ClassHelper(obj_class).GetDescriptor());
+    state->stats_.descriptor_to_bytes[descriptor] += object_bytes;
+    state->stats_.descriptor_to_count[descriptor] += 1;
+
     state->os_ << summary << std::flush;
   }