Merge "ART: Add a last item in the MIROptimizationFlagPositions enumeration"
diff --git a/Android.mk b/Android.mk
index 92339af..01819ee 100644
--- a/Android.mk
+++ b/Android.mk
@@ -63,7 +63,7 @@
 	rm -f $(2ND_TARGET_OUT_INTERMEDIATES)/JAVA_LIBRARIES/*_intermediates/javalib.odex
 	rm -f $(2ND_TARGET_OUT_INTERMEDIATES)/APPS/*_intermediates/*.odex
 endif
-	rm -rf /tmp/test-*/dalvik-cache/*
+	rm -rf /tmp/$(USER)/test-*/dalvik-cache/*
 	rm -rf /tmp/android-data/dalvik-cache/*
 
 .PHONY: clean-oat-target
diff --git a/build/Android.common.mk b/build/Android.common.mk
index aaa1490..6135571 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -123,6 +123,11 @@
   ART_HOST_CLANG := true
 endif
 
+# enable ART_TARGET_CLANG for ARM64
+ifneq (,$(filter $(TARGET_ARCH),arm64))
+ART_TARGET_CLANG := true
+endif
+
 # directory used for dalvik-cache on device
 ART_DALVIK_CACHE_DIR := /data/dalvik-cache
 
@@ -195,6 +200,14 @@
 	-Wstrict-aliasing \
 	-fstrict-aliasing
 
+# these are necessary for Clang ARM64 ART builds
+ifeq ($(ART_TARGET_CLANG), true)
+art_cflags += \
+	-Wno-implicit-exception-spec-mismatch \
+	-DNVALGRIND \
+	-Wno-unused-value
+endif
+
 ifeq ($(ART_SMALL_MODE),true)
   art_cflags += -DART_SMALL_MODE=1
 endif
@@ -209,7 +222,13 @@
 endif
 
 art_non_debug_cflags := \
-        -O3
+	-O3
+
+# FIXME: upstream LLVM has a vectorizer bug that needs to be fixed
+ifeq ($(ART_TARGET_CLANG),true)
+art_non_debug_cflags += \
+        -fno-vectorize
+endif
 
 art_debug_cflags := \
 	-O1 \
@@ -238,8 +257,9 @@
 ifneq ($(filter 4.6 4.6.%, $(TARGET_GCC_VERSION)),)
   ART_TARGET_CFLAGS += -Wthread-safety
 else
+  # FIXME: add -Wthread-safety when the problem is fixed
   ifeq ($(ART_TARGET_CLANG),true)
-    ART_TARGET_CFLAGS += -Wthread-safety
+    ART_TARGET_CFLAGS +=
   else
     # Warn if -Wthread-safety is not suport and not doing a top-level or 'mma' build.
     ifneq ($(ONE_SHOT_MAKEFILE),)
@@ -304,7 +324,7 @@
 #         Has one argument, the suffix
 define call-art-multi-target
   $(call $(1),$(ART_PHONY_TEST_TARGET_SUFFIX))
-  
+
   ifdef TARGET_2ND_ARCH
     $(call $(1),$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
   endif
@@ -329,10 +349,10 @@
 #         Has one argument, the suffix
 define call-art-multi-target-var
   $(call $(1),$(ART_PHONY_TEST_TARGET_SUFFIX))
-  
+
   ifdef TARGET_2ND_ARCH
     $(call $(1),$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
-    
+
     # Link both together, if it makes sense
     ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
       ifneq ($(2ND_ART_PHONY_TEST_TARGET_SUFFIX),)
@@ -351,10 +371,10 @@
 #       We assume we can link the names together easily...
 define call-art-multi-target-rule
   $(call $(1),$(ART_PHONY_TEST_TARGET_SUFFIX))
-  
+
   ifdef TARGET_2ND_ARCH
     $(call $(1),$(2ND_ART_PHONY_TEST_TARGET_SUFFIX))
-  
+
     # Link both together, if it makes sense
     ifneq ($(ART_PHONY_TEST_TARGET_SUFFIX),)
       ifneq ($(2ND_ART_PHONY_TEST_TARGET_SUFFIX),)
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index ab0e3e5..05ab8ca 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -27,6 +27,15 @@
   kAnyReg,
 };
 
+enum BitsUsed {
+  kSize32Bits,
+  kSize64Bits,
+  kSize128Bits,
+  kSize256Bits,
+  kSize512Bits,
+  kSize1024Bits,
+};
+
 enum SpecialTargetRegister {
   kSelf,            // Thread pointer.
   kSuspend,         // Used to reduce suspend checks for some targets.
@@ -56,17 +65,6 @@
   kLocInvalid
 };
 
-/**
- * Support for vector registers.  Initially used for x86 floats.  This will be used
- * to replace the assumption that a double takes up 2 single FP registers
- */
-enum VectorLengthType {
-  kVectorNotUsed = 0,   // This value is NOT in a vector register.
-  kVectorLength4,       // The value occupies 4 bytes in a vector register.
-  kVectorLength8,       // The value occupies 8 bytes in a vector register.
-  kVectorLength16       // The value occupies 16 bytes in a vector register (unused now).
-};
-
 enum BBType {
   kNullBlock,
   kEntryBlock,
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index ed2ecac..1a9379a 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -40,13 +40,13 @@
 
 /* Default optimizer/debug setting for the compiler. */
 static uint32_t kCompilerOptimizerDisableFlags = 0 |  // Disable specific optimizations
-  (1 << kLoadStoreElimination) |
+  (1 << kLoadStoreElimination) |  // TODO: this pass has been broken for awhile - fix or delete.
   // (1 << kLoadHoisting) |
   // (1 << kSuppressLoads) |
   // (1 << kNullCheckElimination) |
   // (1 << kClassInitCheckElimination) |
   // (1 << kPromoteRegs) |
-  // (1 << kTrackLiveTemps) |
+  (1 << kTrackLiveTemps) |        // FIXME: disable until liveness issue fixed.
   // (1 << kSafeOptimizations) |
   // (1 << kBBOpt) |
   // (1 << kMatch) |
diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc
index 36f1be7..2f17e08 100644
--- a/compiler/dex/mir_dataflow.cc
+++ b/compiler/dex/mir_dataflow.cc
@@ -879,8 +879,8 @@
       new (arena_) ArenaBitVector(arena_, cu_->num_dalvik_registers, false, kBitMapLiveIn);
 
   for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
-    uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
-    DecodedInstruction *d_insn = &mir->dalvikInsn;
+    uint64_t df_attributes = GetDataFlowAttributes(mir);
+    MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
 
     if (df_attributes & DF_HAS_USES) {
       if (df_attributes & DF_UA) {
@@ -949,7 +949,7 @@
 
 /* Look up new SSA names for format_35c instructions */
 void MIRGraph::DataFlowSSAFormat35C(MIR* mir) {
-  DecodedInstruction *d_insn = &mir->dalvikInsn;
+  MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
   int num_uses = d_insn->vA;
   int i;
 
@@ -967,7 +967,7 @@
 
 /* Look up new SSA names for format_3rc instructions */
 void MIRGraph::DataFlowSSAFormat3RC(MIR* mir) {
-  DecodedInstruction *d_insn = &mir->dalvikInsn;
+  MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
   int num_uses = d_insn->vA;
   int i;
 
@@ -994,7 +994,7 @@
         static_cast<struct SSARepresentation *>(arena_->Alloc(sizeof(SSARepresentation),
                                                               kArenaAllocDFInfo));
 
-    uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+    uint64_t df_attributes = GetDataFlowAttributes(mir);
 
       // If not a pseudo-op, note non-leaf or can throw
     if (static_cast<int>(mir->dalvikInsn.opcode) <
@@ -1064,7 +1064,7 @@
                                                               kArenaAllocDFInfo));
     }
 
-    DecodedInstruction *d_insn = &mir->dalvikInsn;
+    MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
 
     if (df_attributes & DF_HAS_USES) {
       num_uses = 0;
@@ -1252,7 +1252,7 @@
       use_counts_.Put(s_reg, use_counts_.Get(s_reg) + weight);
     }
     if (!(cu_->disable_opt & (1 << kPromoteCompilerTemps))) {
-      uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+      uint64_t df_attributes = GetDataFlowAttributes(mir);
       // Implicit use of Method* ? */
       if (df_attributes & DF_UMS) {
         /*
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 8ce4f1f..30d0bc3 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -21,6 +21,7 @@
 #include "base/stl_util.h"
 #include "compiler_internals.h"
 #include "dex_file-inl.h"
+#include "dex_instruction-inl.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "dex/quick/dex_file_method_inliner.h"
 #include "leb128.h"
@@ -106,11 +107,17 @@
 /*
  * Parse an instruction, return the length of the instruction
  */
-int MIRGraph::ParseInsn(const uint16_t* code_ptr, DecodedInstruction* decoded_instruction) {
-  const Instruction* instruction = Instruction::At(code_ptr);
-  *decoded_instruction = DecodedInstruction(instruction);
-
-  return instruction->SizeInCodeUnits();
+int MIRGraph::ParseInsn(const uint16_t* code_ptr, MIR::DecodedInstruction* decoded_instruction) {
+  const Instruction* inst = Instruction::At(code_ptr);
+  decoded_instruction->opcode = inst->Opcode();
+  decoded_instruction->vA = inst->HasVRegA() ? inst->VRegA() : 0;
+  decoded_instruction->vB = inst->HasVRegB() ? inst->VRegB() : 0;
+  decoded_instruction->vB_wide = inst->HasWideVRegB() ? inst->WideVRegB() : 0;
+  decoded_instruction->vC = inst->HasVRegC() ?  inst->VRegC() : 0;
+  if (inst->HasVarArgs()) {
+    inst->GetVarArgs(decoded_instruction->arg);
+  }
+  return inst->SizeInCodeUnits();
 }
 
 
@@ -621,7 +628,7 @@
     int flags = Instruction::FlagsOf(insn->dalvikInsn.opcode);
     int verify_flags = Instruction::VerifyFlagsOf(insn->dalvikInsn.opcode);
 
-    uint64_t df_flags = oat_data_flow_attributes_[insn->dalvikInsn.opcode];
+    uint64_t df_flags = GetDataFlowAttributes(insn);
     merged_df_flags |= df_flags;
 
     if (df_flags & DF_HAS_DEFS) {
@@ -743,6 +750,17 @@
   }
 }
 
+uint64_t MIRGraph::GetDataFlowAttributes(Instruction::Code opcode) {
+  DCHECK_LT((size_t) opcode, (sizeof(oat_data_flow_attributes_) / sizeof(oat_data_flow_attributes_[0])));
+  return oat_data_flow_attributes_[opcode];
+}
+
+uint64_t MIRGraph::GetDataFlowAttributes(MIR* mir) {
+  DCHECK(mir != nullptr);
+  Instruction::Code opcode = mir->dalvikInsn.opcode;
+  return GetDataFlowAttributes(opcode);
+}
+
 // TODO: use a configurable base prefix, and adjust callers to supply pass name.
 /* Dump the CFG into a DOT graph */
 void MIRGraph::DumpCFG(const char* dir_prefix, bool all_blocks, const char *suffix) {
@@ -924,7 +942,7 @@
 }
 
 char* MIRGraph::GetDalvikDisassembly(const MIR* mir) {
-  DecodedInstruction insn = mir->dalvikInsn;
+  MIR::DecodedInstruction insn = mir->dalvikInsn;
   std::string str;
   int flags = 0;
   int opcode = insn.opcode;
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index 2c125f6..c728d84 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -254,7 +254,15 @@
    * additional fields on as-needed basis.  Question: how to support MIR Pseudo-ops; probably
    * need to carry aux data pointer.
    */
-  DecodedInstruction dalvikInsn;
+  struct DecodedInstruction {
+    uint32_t vA;
+    uint32_t vB;
+    uint64_t vB_wide;        /* for k51l */
+    uint32_t vC;
+    uint32_t arg[5];         /* vC/D/E/F/G in invoke or filled-new-array */
+    Instruction::Code opcode;
+  } dalvikInsn;
+
   uint16_t width;                 // Note: width can include switch table or fill array data.
   NarrowDexOffset offset;         // Offset of the instruction in code units.
   uint16_t optimization_flags;
@@ -360,13 +368,10 @@
   unsigned ref:1;       // Something GC cares about.
   unsigned high_word:1;  // High word of pair?
   unsigned home:1;      // Does this represent the home location?
-  VectorLengthType vec_len:3;  // TODO: remove.  Is this value in a vector register, and how big is it?
   RegStorage reg;       // Encoded physical registers.
   int16_t s_reg_low;    // SSA name for low Dalvik word.
   int16_t orig_sreg;    // TODO: remove after Bitcode gen complete
                         // and consolidate usage w/ s_reg_low.
-
-  bool IsVectorScalar() const { return vec_len == kVectorLength4 || vec_len == kVectorLength8;}
 };
 
 /*
@@ -392,8 +397,8 @@
 };
 
 
-const RegLocation bad_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, kVectorNotUsed,
-                             RegStorage(RegStorage::kInvalid), INVALID_SREG, INVALID_SREG};
+const RegLocation bad_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, RegStorage(), INVALID_SREG,
+                             INVALID_SREG};
 
 class MIRGraph {
  public:
@@ -851,6 +856,9 @@
    */
   void CountUses(struct BasicBlock* bb);
 
+  static uint64_t GetDataFlowAttributes(Instruction::Code opcode);
+  static uint64_t GetDataFlowAttributes(MIR* mir);
+
   /**
    * @brief Combine BasicBlocks
    * @param the BasicBlock we are considering
@@ -868,7 +876,6 @@
   RegLocation* reg_location_;                         // Map SSA names to location.
   SafeMap<unsigned int, unsigned int> block_id_map_;  // Block collapse lookup cache.
 
-  static const uint64_t oat_data_flow_attributes_[kMirOpLast];
   static const char* extended_mir_op_names_[kMirOpLast - kMirOpFirst];
   static const uint32_t analysis_attributes_[kMirOpLast];
 
@@ -882,7 +889,7 @@
   void CompilerInitializeSSAConversion();
   bool DoSSAConversion(BasicBlock* bb);
   bool InvokeUsesMethodStar(MIR* mir);
-  int ParseInsn(const uint16_t* code_ptr, DecodedInstruction* decoded_instruction);
+  int ParseInsn(const uint16_t* code_ptr, MIR::DecodedInstruction* decoded_instruction);
   bool ContentIsInsn(const uint16_t* code_ptr);
   BasicBlock* SplitBlock(DexOffset code_offset, BasicBlock* orig_block,
                          BasicBlock** immed_pred_block_p);
@@ -985,6 +992,7 @@
   GrowableArray<MirIFieldLoweringInfo> ifield_lowering_infos_;
   GrowableArray<MirSFieldLoweringInfo> sfield_lowering_infos_;
   GrowableArray<MirMethodLoweringInfo> method_lowering_infos_;
+  static const uint64_t oat_data_flow_attributes_[kMirOpLast];
 
   friend class ClassInitCheckEliminationTest;
   friend class LocalValueNumberingTest;
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 937e258..5c1bdf4 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -43,13 +43,13 @@
 
   for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
     // Skip pass if BB has MIR without SSA representation.
-    if (mir->ssa_rep == NULL) {
+    if (mir->ssa_rep == nullptr) {
        return;
     }
 
-    uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+    uint64_t df_attributes = GetDataFlowAttributes(mir);
 
-    DecodedInstruction *d_insn = &mir->dalvikInsn;
+    MIR::DecodedInstruction* d_insn = &mir->dalvikInsn;
 
     if (!(df_attributes & DF_HAS_DEFS)) continue;
 
@@ -239,7 +239,7 @@
 
 // FIXME - will probably need to revisit all uses of this, as type not defined.
 static const RegLocation temp_loc = {kLocCompilerTemp,
-                                     0, 1 /*defined*/, 0, 0, 0, 0, 0, 1 /*home*/, kVectorNotUsed,
+                                     0, 1 /*defined*/, 0, 0, 0, 0, 0, 1 /*home*/,
                                      RegStorage(), INVALID_SREG, INVALID_SREG};
 
 CompilerTemp* MIRGraph::GetNewCompilerTemp(CompilerTempType ct_type, bool wide) {
@@ -559,7 +559,7 @@
       if (mir->ssa_rep == NULL) {
         continue;
       }
-      uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+      uint64_t df_attributes = GetDataFlowAttributes(mir);
       if (df_attributes & DF_HAS_NULL_CHKS) {
         checkstats_->null_checks++;
         if (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) {
@@ -644,7 +644,7 @@
     MIR* mir = bb->last_mir_insn;
     // Grab the attributes from the paired opcode
     MIR* throw_insn = mir->meta.throw_insn;
-    uint64_t df_attributes = oat_data_flow_attributes_[throw_insn->dalvikInsn.opcode];
+    uint64_t df_attributes = GetDataFlowAttributes(throw_insn);
     bool can_combine = true;
     if (df_attributes & DF_HAS_NULL_CHKS) {
       can_combine &= ((throw_insn->optimization_flags & MIR_IGNORE_NULL_CHECK) != 0);
@@ -796,7 +796,7 @@
       continue;
     }
 
-    uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+    uint64_t df_attributes = GetDataFlowAttributes(mir);
 
     // Might need a null check?
     if (df_attributes & DF_HAS_NULL_CHKS) {
diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc
index 40ced70..891d9fb 100644
--- a/compiler/dex/mir_optimization_test.cc
+++ b/compiler/dex/mir_optimization_test.cc
@@ -172,7 +172,7 @@
       mir->offset = 2 * i;  // All insns need to be at least 2 code units long.
       mir->width = 2u;
       mir->optimization_flags = 0u;
-      merged_df_flags |= MIRGraph::oat_data_flow_attributes_[def->opcode];
+      merged_df_flags |= MIRGraph::GetDataFlowAttributes(def->opcode);
     }
     cu_.mir_graph->merged_df_flags_ = merged_df_flags;
 
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index 70438ec..576e242 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -722,7 +722,7 @@
   /* Prep Src and Dest locations */
   int next_sreg = 0;
   int next_loc = 0;
-  uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode];
+  uint64_t attrs = MirGraph::GetDataFlowAttributes(opcode);
   rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc();
   if (attrs & DF_UA) {
     if (attrs & DF_A_WIDE) {
diff --git a/compiler/dex/quick/arm/arm_lir.h b/compiler/dex/quick/arm/arm_lir.h
index c9acd66..e384f6b 100644
--- a/compiler/dex/quick/arm/arm_lir.h
+++ b/compiler/dex/quick/arm/arm_lir.h
@@ -93,29 +93,8 @@
  * +========================+
  */
 
-// Offset to distingish FP regs.
-#define ARM_FP_REG_OFFSET 32
-// Offset to distinguish DP FP regs.
-#define ARM_FP_DOUBLE 64
 // First FP callee save.
 #define ARM_FP_CALLEE_SAVE_BASE 16
-// Reg types.
-#define ARM_REGTYPE(x) (x & (ARM_FP_REG_OFFSET | ARM_FP_DOUBLE))
-#define ARM_FPREG(x) ((x & ARM_FP_REG_OFFSET) == ARM_FP_REG_OFFSET)
-#define ARM_LOWREG(x) ((x & 0x7) == x)
-#define ARM_DOUBLEREG(x) ((x & ARM_FP_DOUBLE) == ARM_FP_DOUBLE)
-#define ARM_SINGLEREG(x) (ARM_FPREG(x) && !ARM_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 ARM_S2D(x, y) ((x) | ARM_FP_DOUBLE)
-// Mask to strip off fp flags.
-#define ARM_FP_REG_MASK (ARM_FP_REG_OFFSET-1)
 
 enum ArmResourceEncodingPos {
   kArmGPReg0   = 0,
@@ -134,135 +113,197 @@
 #define ENCODE_ARM_REG_FPCS_LIST(N) (static_cast<uint64_t>(N) << kArmFPReg16)
 
 enum ArmNativeRegisterPool {
-  r0   = 0,
-  r1   = 1,
-  r2   = 2,
-  r3   = 3,
-  rARM_SUSPEND = 4,
-  r5   = 5,
-  r6   = 6,
-  r7   = 7,
-  r8   = 8,
-  rARM_SELF  = 9,
-  r10  = 10,
-  r11  = 11,
-  r12  = 12,
-  r13sp  = 13,
-  rARM_SP  = 13,
-  r14lr  = 14,
-  rARM_LR  = 14,
-  r15pc  = 15,
-  rARM_PC  = 15,
-  fr0  =  0 + ARM_FP_REG_OFFSET,
-  fr1  =  1 + ARM_FP_REG_OFFSET,
-  fr2  =  2 + ARM_FP_REG_OFFSET,
-  fr3  =  3 + ARM_FP_REG_OFFSET,
-  fr4  =  4 + ARM_FP_REG_OFFSET,
-  fr5  =  5 + ARM_FP_REG_OFFSET,
-  fr6  =  6 + ARM_FP_REG_OFFSET,
-  fr7  =  7 + ARM_FP_REG_OFFSET,
-  fr8  =  8 + ARM_FP_REG_OFFSET,
-  fr9  =  9 + ARM_FP_REG_OFFSET,
-  fr10 = 10 + ARM_FP_REG_OFFSET,
-  fr11 = 11 + ARM_FP_REG_OFFSET,
-  fr12 = 12 + ARM_FP_REG_OFFSET,
-  fr13 = 13 + ARM_FP_REG_OFFSET,
-  fr14 = 14 + ARM_FP_REG_OFFSET,
-  fr15 = 15 + ARM_FP_REG_OFFSET,
-  fr16 = 16 + ARM_FP_REG_OFFSET,
-  fr17 = 17 + ARM_FP_REG_OFFSET,
-  fr18 = 18 + ARM_FP_REG_OFFSET,
-  fr19 = 19 + ARM_FP_REG_OFFSET,
-  fr20 = 20 + ARM_FP_REG_OFFSET,
-  fr21 = 21 + ARM_FP_REG_OFFSET,
-  fr22 = 22 + ARM_FP_REG_OFFSET,
-  fr23 = 23 + ARM_FP_REG_OFFSET,
-  fr24 = 24 + ARM_FP_REG_OFFSET,
-  fr25 = 25 + ARM_FP_REG_OFFSET,
-  fr26 = 26 + ARM_FP_REG_OFFSET,
-  fr27 = 27 + ARM_FP_REG_OFFSET,
-  fr28 = 28 + ARM_FP_REG_OFFSET,
-  fr29 = 29 + ARM_FP_REG_OFFSET,
-  fr30 = 30 + ARM_FP_REG_OFFSET,
-  fr31 = 31 + ARM_FP_REG_OFFSET,
-  dr0 = fr0 + ARM_FP_DOUBLE,
-  dr1 = fr2 + ARM_FP_DOUBLE,
-  dr2 = fr4 + ARM_FP_DOUBLE,
-  dr3 = fr6 + ARM_FP_DOUBLE,
-  dr4 = fr8 + ARM_FP_DOUBLE,
-  dr5 = fr10 + ARM_FP_DOUBLE,
-  dr6 = fr12 + ARM_FP_DOUBLE,
-  dr7 = fr14 + ARM_FP_DOUBLE,
-  dr8 = fr16 + ARM_FP_DOUBLE,
-  dr9 = fr18 + ARM_FP_DOUBLE,
-  dr10 = fr20 + ARM_FP_DOUBLE,
-  dr11 = fr22 + ARM_FP_DOUBLE,
-  dr12 = fr24 + ARM_FP_DOUBLE,
-  dr13 = fr26 + ARM_FP_DOUBLE,
-  dr14 = fr28 + ARM_FP_DOUBLE,
-  dr15 = fr30 + ARM_FP_DOUBLE,
+  r0           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  0,
+  r1           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  1,
+  r2           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  2,
+  r3           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  3,
+  rARM_SUSPEND = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  4,
+  r5           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  5,
+  r6           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  6,
+  r7           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  7,
+  r8           = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  8,
+  rARM_SELF    = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  9,
+  r10          = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 10,
+  r11          = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 11,
+  r12          = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 12,
+  r13sp        = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 13,
+  rARM_SP      = r13sp,
+  r14lr        = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 14,
+  rARM_LR      = r14lr,
+  r15pc        = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 15,
+  rARM_PC      = r15pc,
+
+  fr0          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  0,
+  fr1          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  1,
+  fr2          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  2,
+  fr3          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  3,
+  fr4          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  4,
+  fr5          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  5,
+  fr6          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  6,
+  fr7          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  7,
+  fr8          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  8,
+  fr9          = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  9,
+  fr10         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 10,
+  fr11         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 11,
+  fr12         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 12,
+  fr13         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 13,
+  fr14         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 14,
+  fr15         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 15,
+  fr16         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 16,
+  fr17         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 17,
+  fr18         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 18,
+  fr19         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 19,
+  fr20         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 20,
+  fr21         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 21,
+  fr22         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 22,
+  fr23         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 23,
+  fr24         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 24,
+  fr25         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 25,
+  fr26         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 26,
+  fr27         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 27,
+  fr28         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 28,
+  fr29         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 29,
+  fr30         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 30,
+  fr31         = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 31,
+
+  dr0          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
+  dr1          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  1,
+  dr2          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
+  dr3          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  3,
+  dr4          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
+  dr5          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  5,
+  dr6          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
+  dr7          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  7,
+  dr8          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
+  dr9          = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  9,
+  dr10         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+  dr11         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
+  dr12         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+  dr13         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
+  dr14         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+  dr15         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
+#if 0
+  // Enable when def/use and runtime able to handle these.
+  dr16         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
+  dr17         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 17,
+  dr18         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
+  dr19         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 19,
+  dr20         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
+  dr21         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 21,
+  dr22         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
+  dr23         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 23,
+  dr24         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
+  dr25         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 25,
+  dr26         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
+  dr27         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 27,
+  dr28         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
+  dr29         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 29,
+  dr30         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
+  dr31         = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 31,
+#endif
 };
 
-// TODO: clean this up; reduce use of or eliminate macros
+constexpr RegStorage rs_r0(RegStorage::kValid | r0);
+constexpr RegStorage rs_r1(RegStorage::kValid | r1);
+constexpr RegStorage rs_r2(RegStorage::kValid | r2);
+constexpr RegStorage rs_r3(RegStorage::kValid | r3);
+constexpr RegStorage rs_rARM_SUSPEND(RegStorage::kValid | rARM_SUSPEND);
+constexpr RegStorage rs_r5(RegStorage::kValid | r5);
+constexpr RegStorage rs_r6(RegStorage::kValid | r6);
+constexpr RegStorage rs_r7(RegStorage::kValid | r7);
+constexpr RegStorage rs_r8(RegStorage::kValid | r8);
+constexpr RegStorage rs_rARM_SELF(RegStorage::kValid | rARM_SELF);
+constexpr RegStorage rs_r10(RegStorage::kValid | r10);
+constexpr RegStorage rs_r11(RegStorage::kValid | r11);
+constexpr RegStorage rs_r12(RegStorage::kValid | r12);
+constexpr RegStorage rs_r13sp(RegStorage::kValid | r13sp);
+constexpr RegStorage rs_rARM_SP(RegStorage::kValid | rARM_SP);
+constexpr RegStorage rs_r14lr(RegStorage::kValid | r14lr);
+constexpr RegStorage rs_rARM_LR(RegStorage::kValid | rARM_LR);
+constexpr RegStorage rs_r15pc(RegStorage::kValid | r15pc);
+constexpr RegStorage rs_rARM_PC(RegStorage::kValid | rARM_PC);
+constexpr RegStorage rs_invalid(RegStorage::kInvalid);
 
-const RegStorage rs_r0(RegStorage::k32BitSolo, r0);
-const RegStorage rs_r1(RegStorage::k32BitSolo, r1);
-const RegStorage rs_r2(RegStorage::k32BitSolo, r2);
-const RegStorage rs_r3(RegStorage::k32BitSolo, r3);
-const RegStorage rs_rARM_SUSPEND(RegStorage::k32BitSolo, rARM_SUSPEND);
-const RegStorage rs_r5(RegStorage::k32BitSolo, r5);
-const RegStorage rs_r6(RegStorage::k32BitSolo, r6);
-const RegStorage rs_r7(RegStorage::k32BitSolo, r7);
-const RegStorage rs_r8(RegStorage::k32BitSolo, r8);
-const RegStorage rs_rARM_SELF(RegStorage::k32BitSolo, rARM_SELF);
-const RegStorage rs_r10(RegStorage::k32BitSolo, r10);
-const RegStorage rs_r11(RegStorage::k32BitSolo, r11);
-const RegStorage rs_r12(RegStorage::k32BitSolo, r12);
-const RegStorage rs_r13sp(RegStorage::k32BitSolo, r13sp);
-const RegStorage rs_rARM_SP(RegStorage::k32BitSolo, rARM_SP);
-const RegStorage rs_r14lr(RegStorage::k32BitSolo, r14lr);
-const RegStorage rs_rARM_LR(RegStorage::k32BitSolo, rARM_LR);
-const RegStorage rs_r15pc(RegStorage::k32BitSolo, r15pc);
-const RegStorage rs_rARM_PC(RegStorage::k32BitSolo, rARM_PC);
-const RegStorage rs_invalid(RegStorage::kInvalid);
+constexpr RegStorage rs_fr0(RegStorage::kValid | fr0);
+constexpr RegStorage rs_fr1(RegStorage::kValid | fr1);
+constexpr RegStorage rs_fr2(RegStorage::kValid | fr2);
+constexpr RegStorage rs_fr3(RegStorage::kValid | fr3);
+constexpr RegStorage rs_fr4(RegStorage::kValid | fr4);
+constexpr RegStorage rs_fr5(RegStorage::kValid | fr5);
+constexpr RegStorage rs_fr6(RegStorage::kValid | fr6);
+constexpr RegStorage rs_fr7(RegStorage::kValid | fr7);
+constexpr RegStorage rs_fr8(RegStorage::kValid | fr8);
+constexpr RegStorage rs_fr9(RegStorage::kValid | fr9);
+constexpr RegStorage rs_fr10(RegStorage::kValid | fr10);
+constexpr RegStorage rs_fr11(RegStorage::kValid | fr11);
+constexpr RegStorage rs_fr12(RegStorage::kValid | fr12);
+constexpr RegStorage rs_fr13(RegStorage::kValid | fr13);
+constexpr RegStorage rs_fr14(RegStorage::kValid | fr14);
+constexpr RegStorage rs_fr15(RegStorage::kValid | fr15);
+constexpr RegStorage rs_fr16(RegStorage::kValid | fr16);
+constexpr RegStorage rs_fr17(RegStorage::kValid | fr17);
+constexpr RegStorage rs_fr18(RegStorage::kValid | fr18);
+constexpr RegStorage rs_fr19(RegStorage::kValid | fr19);
+constexpr RegStorage rs_fr20(RegStorage::kValid | fr20);
+constexpr RegStorage rs_fr21(RegStorage::kValid | fr21);
+constexpr RegStorage rs_fr22(RegStorage::kValid | fr22);
+constexpr RegStorage rs_fr23(RegStorage::kValid | fr23);
+constexpr RegStorage rs_fr24(RegStorage::kValid | fr24);
+constexpr RegStorage rs_fr25(RegStorage::kValid | fr25);
+constexpr RegStorage rs_fr26(RegStorage::kValid | fr26);
+constexpr RegStorage rs_fr27(RegStorage::kValid | fr27);
+constexpr RegStorage rs_fr28(RegStorage::kValid | fr28);
+constexpr RegStorage rs_fr29(RegStorage::kValid | fr29);
+constexpr RegStorage rs_fr30(RegStorage::kValid | fr30);
+constexpr RegStorage rs_fr31(RegStorage::kValid | fr31);
 
-// Target-independent aliases.
-#define rARM_ARG0 r0
-#define rs_rARM_ARG0 rs_r0
-#define rARM_ARG1 r1
-#define rs_rARM_ARG1 rs_r1
-#define rARM_ARG2 r2
-#define rs_rARM_ARG2 rs_r2
-#define rARM_ARG3 r3
-#define rs_rARM_ARG3 rs_r3
-#define rARM_FARG0 r0
-#define rs_ARM_FARG0 rs_r0
-#define rARM_FARG1 r1
-#define rs_rARM_FARG1 rs_r1
-#define rARM_FARG2 r2
-#define rs_rARM_FARG2 rs_r2
-#define rARM_FARG3 r3
-#define rs_rARM_FARG3 rs_r3
-#define rARM_RET0 r0
-#define rs_rARM_RET0 rs_r0
-#define rARM_RET1 r1
-#define rs_rARM_RET1 rs_r1
-#define rARM_INVOKE_TGT rARM_LR
-#define rs_rARM_INVOKE_TGT rs_rARM_LR
-#define rARM_COUNT RegStorage::kInvalidRegVal
+constexpr RegStorage rs_dr0(RegStorage::kValid | dr0);
+constexpr RegStorage rs_dr1(RegStorage::kValid | dr1);
+constexpr RegStorage rs_dr2(RegStorage::kValid | dr2);
+constexpr RegStorage rs_dr3(RegStorage::kValid | dr3);
+constexpr RegStorage rs_dr4(RegStorage::kValid | dr4);
+constexpr RegStorage rs_dr5(RegStorage::kValid | dr5);
+constexpr RegStorage rs_dr6(RegStorage::kValid | dr6);
+constexpr RegStorage rs_dr7(RegStorage::kValid | dr7);
+constexpr RegStorage rs_dr8(RegStorage::kValid | dr8);
+constexpr RegStorage rs_dr9(RegStorage::kValid | dr9);
+constexpr RegStorage rs_dr10(RegStorage::kValid | dr10);
+constexpr RegStorage rs_dr11(RegStorage::kValid | dr11);
+constexpr RegStorage rs_dr12(RegStorage::kValid | dr12);
+constexpr RegStorage rs_dr13(RegStorage::kValid | dr13);
+constexpr RegStorage rs_dr14(RegStorage::kValid | dr14);
+constexpr RegStorage rs_dr15(RegStorage::kValid | dr15);
+#if 0
+constexpr RegStorage rs_dr16(RegStorage::kValid | dr16);
+constexpr RegStorage rs_dr17(RegStorage::kValid | dr17);
+constexpr RegStorage rs_dr18(RegStorage::kValid | dr18);
+constexpr RegStorage rs_dr19(RegStorage::kValid | dr19);
+constexpr RegStorage rs_dr20(RegStorage::kValid | dr20);
+constexpr RegStorage rs_dr21(RegStorage::kValid | dr21);
+constexpr RegStorage rs_dr22(RegStorage::kValid | dr22);
+constexpr RegStorage rs_dr23(RegStorage::kValid | dr23);
+constexpr RegStorage rs_dr24(RegStorage::kValid | dr24);
+constexpr RegStorage rs_dr25(RegStorage::kValid | dr25);
+constexpr RegStorage rs_dr26(RegStorage::kValid | dr26);
+constexpr RegStorage rs_dr27(RegStorage::kValid | dr27);
+constexpr RegStorage rs_dr28(RegStorage::kValid | dr28);
+constexpr RegStorage rs_dr29(RegStorage::kValid | dr29);
+constexpr RegStorage rs_dr30(RegStorage::kValid | dr30);
+constexpr RegStorage rs_dr31(RegStorage::kValid | dr31);
+#endif
 
 // RegisterLocation templates return values (r0, or r0/r1).
 const RegLocation arm_loc_c_return
-    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
      RegStorage(RegStorage::k32BitSolo, r0), INVALID_SREG, INVALID_SREG};
 const RegLocation arm_loc_c_return_wide
-    {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
      RegStorage(RegStorage::k64BitPair, r0, r1), INVALID_SREG, INVALID_SREG};
 const RegLocation arm_loc_c_return_float
-    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
      RegStorage(RegStorage::k32BitSolo, r0), INVALID_SREG, INVALID_SREG};
 const RegLocation arm_loc_c_return_double
-    {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
      RegStorage(RegStorage::k64BitPair, r0, r1), INVALID_SREG, INVALID_SREG};
 
 enum ArmShiftEncodings {
diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc
index f77b0a6..cac766d 100644
--- a/compiler/dex/quick/arm/assemble_arm.cc
+++ b/compiler/dex/quick/arm/assemble_arm.cc
@@ -1137,24 +1137,25 @@
                 bits |= value;
                 break;
               case kFmtDfp: {
-                DCHECK(ARM_DOUBLEREG(operand));
-                DCHECK_EQ((operand & 0x1), 0U);
-                uint32_t reg_name = (operand & ARM_FP_REG_MASK) >> 1;
+                DCHECK(RegStorage::IsDouble(operand)) << ", Operand = 0x" << std::hex << operand;
+                uint32_t reg_num = RegStorage::RegNum(operand);
                 /* Snag the 1-bit slice and position it */
-                value = ((reg_name & 0x10) >> 4) << encoder->field_loc[i].end;
+                value = ((reg_num & 0x10) >> 4) << encoder->field_loc[i].end;
                 /* Extract and position the 4-bit slice */
-                value |= (reg_name & 0x0f) << encoder->field_loc[i].start;
+                value |= (reg_num & 0x0f) << encoder->field_loc[i].start;
                 bits |= value;
                 break;
               }
-              case kFmtSfp:
-                DCHECK(ARM_SINGLEREG(operand));
+              case kFmtSfp: {
+                DCHECK(RegStorage::IsSingle(operand)) << ", Operand = 0x" << std::hex << operand;
+                uint32_t reg_num = RegStorage::RegNum(operand);
                 /* Snag the 1-bit slice and position it */
-                value = (operand & 0x1) << encoder->field_loc[i].end;
+                value = (reg_num & 0x1) << encoder->field_loc[i].end;
                 /* Extract and position the 4-bit slice */
-                value |= ((operand & 0x1e) >> 1) << encoder->field_loc[i].start;
+                value |= ((reg_num & 0x1e) >> 1) << encoder->field_loc[i].start;
                 bits |= value;
                 break;
+              }
               case kFmtImm12:
               case kFmtModImm:
                 value = ((operand & 0x800) >> 11) << 26;
@@ -1217,8 +1218,8 @@
   AssignDataOffsets();
 
   /*
-   * Note: generation must be 1 on first pass (to distinguish from initialized state of 0 for non-visited nodes).
-   * Start at zero here, and bit will be flipped to 1 on entry to the loop.
+   * Note: generation must be 1 on first pass (to distinguish from initialized state of 0 for
+   * non-visited nodes).  Start at zero here, and bit will be flipped to 1 on entry to the loop.
    */
   int generation = 0;
   while (true) {
@@ -1244,7 +1245,7 @@
         case kFixupNone:
           break;
         case kFixupVLoad:
-          if (lir->operands[1] != r15pc) {
+          if (lir->operands[1] != rs_r15pc.GetReg()) {
             break;
           }
           // NOTE: intentional fallthrough.
@@ -1285,7 +1286,8 @@
              * happens.
              */
             int base_reg = ((lir->opcode == kThumb2LdrdPcRel8) ||
-                            (lir->opcode == kThumb2LdrPcRel12)) ?  lir->operands[0] : rARM_LR;
+                            (lir->opcode == kThumb2LdrPcRel12)) ?  lir->operands[0] :
+                            rs_rARM_LR.GetReg();
 
             // Add new Adr to generate the address.
             LIR* new_adr = RawLIR(lir->dalvik_offset, kThumb2Adr,
@@ -1500,7 +1502,8 @@
           EmbeddedData *tab_rec = reinterpret_cast<EmbeddedData*>(UnwrapPointer(lir->operands[2]));
           LIR* target = lir->target;
           int32_t target_disp = (tab_rec != NULL) ?  tab_rec->offset + offset_adjustment
-              : target->offset + ((target->flags.generation == lir->flags.generation) ? 0 : offset_adjustment);
+              : target->offset + ((target->flags.generation == lir->flags.generation) ? 0 :
+              offset_adjustment);
           int32_t disp = target_disp - ((lir->offset + 4) & ~3);
           if (disp < 4096) {
             lir->operands[1] = disp;
@@ -1533,12 +1536,12 @@
             prev_lir = new_mov16H;  // Now we've got a new prev.
 
             offset_adjustment -= lir->flags.size;
-            if (ARM_LOWREG(lir->operands[0])) {
+            if (RegStorage::RegNum(lir->operands[0]) < 8) {
               lir->opcode = kThumbAddRRLH;
             } else {
               lir->opcode = kThumbAddRRHH;
             }
-            lir->operands[1] = rARM_PC;
+            lir->operands[1] = rs_rARM_PC.GetReg();
             lir->flags.size = EncodingMap[lir->opcode].size;
             offset_adjustment += lir->flags.size;
             // Must stay in fixup list and have offset updated; will be used by LST/HSP pair.
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 9cb56cf..163c0fe 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -54,8 +54,7 @@
   tab_rec->table = table;
   tab_rec->vaddr = current_dalvik_offset_;
   uint32_t size = table[1];
-  tab_rec->targets = static_cast<LIR**>(arena_->Alloc(size * sizeof(LIR*),
-                                                     kArenaAllocLIR));
+  tab_rec->targets = static_cast<LIR**>(arena_->Alloc(size * sizeof(LIR*), kArenaAllocLIR));
   switch_tables_.Insert(tab_rec);
 
   // Get the switch value
@@ -78,7 +77,7 @@
   // Establish loop branch target
   LIR* target = NewLIR0(kPseudoTargetLabel);
   // Load next key/disp
-  NewLIR2(kThumb2LdmiaWB, r_base.GetReg(), (1 << r_key.GetReg()) | (1 << r_disp.GetReg()));
+  NewLIR2(kThumb2LdmiaWB, r_base.GetReg(), (1 << r_key.GetRegNum()) | (1 << r_disp.GetRegNum()));
   OpRegReg(kOpCmp, r_key, rl_src.reg);
   // Go if match. NOTE: No instruction set switch here - must stay Thumb2
   LIR* it = OpIT(kCondEq, "");
@@ -168,7 +167,7 @@
   LoadWordDisp(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pHandleFillArrayData).Int32Value(),
                rs_rARM_LR);
   // Materialize a pointer to the fill data image
-  NewLIR3(kThumb2Adr, r1, 0, WrapPointer(tab_rec));
+  NewLIR3(kThumb2Adr, rs_r1.GetReg(), 0, WrapPointer(tab_rec));
   ClobberCallerSave();
   LIR* call_inst = OpReg(kOpBlx, rs_rARM_LR);
   MarkSafepointPC(call_inst);
@@ -195,10 +194,12 @@
       }
     }
     Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2);
-    NewLIR3(kThumb2Ldrex, r1, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
+    NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(),
+        mirror::Object::MonitorOffset().Int32Value() >> 2);
     MarkPossibleNullPointerException(opt_flags);
     LIR* not_unlocked_branch = OpCmpImmBranch(kCondNe, rs_r1, 0, NULL);
-    NewLIR4(kThumb2Strex, r1, r2, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
+    NewLIR4(kThumb2Strex, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(),
+        mirror::Object::MonitorOffset().Int32Value() >> 2);
     LIR* lock_success_branch = OpCmpImmBranch(kCondEq, rs_r1, 0, NULL);
 
 
@@ -221,16 +222,19 @@
     // Explicit null-check as slow-path is entered using an IT.
     GenNullCheck(rs_r0, opt_flags);
     Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2);
-    NewLIR3(kThumb2Ldrex, r1, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
+    NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(),
+        mirror::Object::MonitorOffset().Int32Value() >> 2);
     MarkPossibleNullPointerException(opt_flags);
     OpRegImm(kOpCmp, rs_r1, 0);
     LIR* it = OpIT(kCondEq, "");
-    NewLIR4(kThumb2Strex/*eq*/, r1, r2, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
+    NewLIR4(kThumb2Strex/*eq*/, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(),
+        mirror::Object::MonitorOffset().Int32Value() >> 2);
     OpEndIT(it);
     OpRegImm(kOpCmp, rs_r1, 0);
     it = OpIT(kCondNe, "T");
     // Go expensive route - artLockObjectFromCode(self, obj);
-    LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(), rs_rARM_LR);
+    LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(),
+                       rs_rARM_LR);
     ClobberCallerSave();
     LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
     OpEndIT(it);
@@ -339,10 +343,10 @@
    * expanding the frame or flushing.  This leaves the utility
    * code with a single temp: r12.  This should be enough.
    */
-  LockTemp(r0);
-  LockTemp(r1);
-  LockTemp(r2);
-  LockTemp(r3);
+  LockTemp(rs_r0);
+  LockTemp(rs_r1);
+  LockTemp(rs_r2);
+  LockTemp(rs_r3);
 
   /*
    * We can safely skip the stack overflow check if we're
@@ -433,10 +437,10 @@
 
   FlushIns(ArgLocs, rl_method);
 
-  FreeTemp(r0);
-  FreeTemp(r1);
-  FreeTemp(r2);
-  FreeTemp(r3);
+  FreeTemp(rs_r0);
+  FreeTemp(rs_r1);
+  FreeTemp(rs_r2);
+  FreeTemp(rs_r3);
 }
 
 void ArmMir2Lir::GenExitSequence() {
@@ -445,8 +449,8 @@
    * In the exit path, r0/r1 are live - make sure they aren't
    * allocated by the register utilities as temps.
    */
-  LockTemp(r0);
-  LockTemp(r1);
+  LockTemp(rs_r0);
+  LockTemp(rs_r1);
 
   NewLIR0(kPseudoMethodExit);
   OpRegImm(kOpAdd, rs_rARM_SP, frame_size_ - (spill_count * 4));
@@ -454,20 +458,20 @@
   if (num_fp_spills_) {
     NewLIR1(kThumb2VPopCS, num_fp_spills_);
   }
-  if (core_spill_mask_ & (1 << rARM_LR)) {
+  if (core_spill_mask_ & (1 << rs_rARM_LR.GetRegNum())) {
     /* Unspill rARM_LR to rARM_PC */
-    core_spill_mask_ &= ~(1 << rARM_LR);
-    core_spill_mask_ |= (1 << rARM_PC);
+    core_spill_mask_ &= ~(1 << rs_rARM_LR.GetRegNum());
+    core_spill_mask_ |= (1 << rs_rARM_PC.GetRegNum());
   }
   NewLIR1(kThumb2Pop, core_spill_mask_);
-  if (!(core_spill_mask_ & (1 << rARM_PC))) {
+  if (!(core_spill_mask_ & (1 << rs_rARM_PC.GetRegNum()))) {
     /* We didn't pop to rARM_PC, so must do a bv rARM_LR */
-    NewLIR1(kThumbBx, rARM_LR);
+    NewLIR1(kThumbBx, rs_rARM_LR.GetReg());
   }
 }
 
 void ArmMir2Lir::GenSpecialExitSequence() {
-  NewLIR1(kThumbBx, rARM_LR);
+  NewLIR1(kThumbBx, rs_rARM_LR.GetReg());
 }
 
 }  // namespace art
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 646859c..9d1723a 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -38,7 +38,7 @@
     LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
                          OpSize size);
     LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
-                             RegStorage r_dest, RegStorage r_dest_hi, OpSize size, int s_reg);
+                             RegStorage r_dest, OpSize size, int s_reg);
     LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
     LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
     LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
@@ -46,16 +46,12 @@
     LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
                           OpSize size);
     LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
-                              RegStorage r_src, RegStorage r_src_hi, OpSize size, int s_reg);
+                              RegStorage r_src, OpSize size, int s_reg);
     void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
 
     // Required for target - register utilities.
-    bool IsFpReg(int reg);
-    bool IsFpReg(RegStorage reg);
-    bool SameRegType(int reg1, int reg2);
     RegStorage AllocTypedTemp(bool fp_hint, int reg_class);
     RegStorage AllocTypedTempWide(bool fp_hint, int reg_class);
-    int S2d(int low_reg, int high_reg);
     RegStorage TargetReg(SpecialTargetRegister reg);
     RegStorage GetArgMappingToPhysicalReg(int arg_num);
     RegLocation GetReturnAlt();
@@ -64,17 +60,16 @@
     RegLocation LocCReturnDouble();
     RegLocation LocCReturnFloat();
     RegLocation LocCReturnWide();
-    uint32_t FpRegMask();
-    uint64_t GetRegMaskCommon(int reg);
+    uint64_t GetRegMaskCommon(RegStorage reg);
     void AdjustSpillMask();
     void ClobberCallerSave();
-    void FlushReg(RegStorage reg);
-    void FlushRegWide(RegStorage reg);
     void FreeCallTemps();
     void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
     void LockCallTemps();
-    void MarkPreservedSingle(int v_reg, int reg);
+    void MarkPreservedSingle(int v_reg, RegStorage reg);
+    void MarkPreservedDouble(int v_reg, RegStorage reg);
     void CompilerInitializeRegAlloc();
+    RegStorage AllocPreservedDouble(int s_reg);
 
     // Required for target - miscellaneous.
     void AssembleLIR();
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc
index d72f596..bb02f74 100644
--- a/compiler/dex/quick/arm/fp_arm.cc
+++ b/compiler/dex/quick/arm/fp_arm.cc
@@ -111,13 +111,11 @@
   rl_result = EvalLoc(rl_dest, kFPReg, true);
   DCHECK(rl_dest.wide);
   DCHECK(rl_result.wide);
-  NewLIR3(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg()),
-          S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+  NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
   StoreValueWide(rl_dest, rl_result);
 }
 
-void ArmMir2Lir::GenConversion(Instruction::Code opcode,
-                               RegLocation rl_dest, RegLocation rl_src) {
+void ArmMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src) {
   int op = kThumbBkpt;
   int src_reg;
   RegLocation rl_result;
@@ -143,19 +141,16 @@
       break;
     case Instruction::LONG_TO_DOUBLE: {
       rl_src = LoadValueWide(rl_src, kFPReg);
-      src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
+      RegStorage src_low = rl_src.reg.DoubleToLowSingle();
+      RegStorage src_high = rl_src.reg.DoubleToHighSingle();
       rl_result = EvalLoc(rl_dest, kFPReg, true);
-      // TODO: fix AllocTempDouble to return a k64BitSolo double reg and lose the ARM_FP_DOUBLE.
       RegStorage tmp1 = AllocTempDouble();
       RegStorage tmp2 = AllocTempDouble();
 
-      // FIXME: needs 64-bit register cleanup.
-      NewLIR2(kThumb2VcvtF64S32, tmp1.GetLowReg() | ARM_FP_DOUBLE, (src_reg & ~ARM_FP_DOUBLE) + 1);
-      NewLIR2(kThumb2VcvtF64U32, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
-              (src_reg & ~ARM_FP_DOUBLE));
+      NewLIR2(kThumb2VcvtF64S32, tmp1.GetReg(), src_high.GetReg());
+      NewLIR2(kThumb2VcvtF64U32, rl_result.reg.GetReg(), src_low.GetReg());
       LoadConstantWide(tmp2, 0x41f0000000000000LL);
-      NewLIR3(kThumb2VmlaF64, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
-              tmp1.GetLowReg() | ARM_FP_DOUBLE, tmp2.GetLowReg() | ARM_FP_DOUBLE);
+      NewLIR3(kThumb2VmlaF64, rl_result.reg.GetReg(), tmp1.GetReg(), tmp2.GetReg());
       FreeTemp(tmp1);
       FreeTemp(tmp2);
       StoreValueWide(rl_dest, rl_result);
@@ -166,23 +161,20 @@
       return;
     case Instruction::LONG_TO_FLOAT: {
       rl_src = LoadValueWide(rl_src, kFPReg);
-      src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
+      RegStorage src_low = rl_src.reg.DoubleToLowSingle();
+      RegStorage src_high = rl_src.reg.DoubleToHighSingle();
       rl_result = EvalLoc(rl_dest, kFPReg, true);
       // Allocate temp registers.
       RegStorage high_val = AllocTempDouble();
       RegStorage low_val = AllocTempDouble();
       RegStorage const_val = AllocTempDouble();
       // Long to double.
-      NewLIR2(kThumb2VcvtF64S32, high_val.GetLowReg() | ARM_FP_DOUBLE,
-              (src_reg & ~ARM_FP_DOUBLE) + 1);
-      NewLIR2(kThumb2VcvtF64U32, low_val.GetLowReg() | ARM_FP_DOUBLE,
-              (src_reg & ~ARM_FP_DOUBLE));
+      NewLIR2(kThumb2VcvtF64S32, high_val.GetReg(), src_high.GetReg());
+      NewLIR2(kThumb2VcvtF64U32, low_val.GetReg(), src_low.GetReg());
       LoadConstantWide(const_val, INT64_C(0x41f0000000000000));
-      NewLIR3(kThumb2VmlaF64, low_val.GetLowReg() | ARM_FP_DOUBLE,
-              high_val.GetLowReg() | ARM_FP_DOUBLE,
-              const_val.GetLowReg() | ARM_FP_DOUBLE);
+      NewLIR3(kThumb2VmlaF64, low_val.GetReg(), high_val.GetReg(), const_val.GetReg());
       // Double to float.
-      NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetLowReg() | ARM_FP_DOUBLE);
+      NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetReg());
       // Free temp registers.
       FreeTemp(high_val);
       FreeTemp(low_val);
@@ -199,14 +191,14 @@
   }
   if (rl_src.wide) {
     rl_src = LoadValueWide(rl_src, kFPReg);
-    src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
+    src_reg = rl_src.reg.GetReg();
   } else {
     rl_src = LoadValue(rl_src, kFPReg);
     src_reg = rl_src.reg.GetReg();
   }
   if (rl_dest.wide) {
     rl_result = EvalLoc(rl_dest, kFPReg, true);
-    NewLIR2(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), src_reg);
+    NewLIR2(op, rl_result.reg.GetReg(), src_reg);
     StoreValueWide(rl_dest, rl_result);
   } else {
     rl_result = EvalLoc(rl_dest, kFPReg, true);
@@ -225,8 +217,7 @@
     rl_src2 = mir_graph_->GetSrcWide(mir, 2);
     rl_src1 = LoadValueWide(rl_src1, kFPReg);
     rl_src2 = LoadValueWide(rl_src2, kFPReg);
-    NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetLowReg(), rl_src2.reg.GetHighReg()),
-            S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+    NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
   } else {
     rl_src1 = mir_graph_->GetSrc(mir, 0);
     rl_src2 = mir_graph_->GetSrc(mir, 1);
@@ -300,8 +291,7 @@
     ClobberSReg(rl_dest.s_reg_low);
     rl_result = EvalLoc(rl_dest, kCoreReg, true);
     LoadConstant(rl_result.reg, default_result);
-    NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetLowReg(), rl_src2.reg.GetHighReg()),
-            S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+    NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
   } else {
     rl_src1 = LoadValue(rl_src1, kFPReg);
     rl_src2 = LoadValue(rl_src2, kFPReg);
@@ -311,7 +301,7 @@
     LoadConstant(rl_result.reg, default_result);
     NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
   }
-  DCHECK(!ARM_FPREG(rl_result.reg.GetReg()));
+  DCHECK(!rl_result.reg.IsFloat());
   NewLIR0(kThumb2Fmstat);
 
   LIR* it = OpIT((default_result == -1) ? kCondGt : kCondMi, "");
@@ -338,8 +328,7 @@
   RegLocation rl_result;
   rl_src = LoadValueWide(rl_src, kFPReg);
   rl_result = EvalLoc(rl_dest, kFPReg, true);
-  NewLIR2(kThumb2Vnegd, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
-          S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
+  NewLIR2(kThumb2Vnegd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
   StoreValueWide(rl_dest, rl_result);
 }
 
@@ -350,19 +339,16 @@
   RegLocation rl_dest = InlineTargetWide(info);  // double place for result
   rl_src = LoadValueWide(rl_src, kFPReg);
   RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
-  // TODO: shouldn't need S2d once 64bitSolo has proper double tag bit.
-  NewLIR2(kThumb2Vsqrtd, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
-          S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
-  NewLIR2(kThumb2Vcmpd, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
-          S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()));
+  NewLIR2(kThumb2Vsqrtd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
+  NewLIR2(kThumb2Vcmpd, rl_result.reg.GetReg(), rl_result.reg.GetReg());
   NewLIR0(kThumb2Fmstat);
   branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
   ClobberCallerSave();
   LockCallTemps();  // Using fixed registers
   RegStorage r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pSqrt));
-  NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
+  NewLIR3(kThumb2Fmrrd, rs_r0.GetReg(), rs_r1.GetReg(), rl_src.reg.GetReg());
   NewLIR1(kThumbBlxR, r_tgt.GetReg());
-  NewLIR3(kThumb2Fmdrr, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), r0, r1);
+  NewLIR3(kThumb2Fmdrr, rl_result.reg.GetReg(), rs_r0.GetReg(), rs_r1.GetReg());
   branch->target = NewLIR0(kPseudoTargetLabel);
   StoreValueWide(rl_dest, rl_result);
   return true;
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index a2d6373..8391c03 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -322,7 +322,7 @@
    */
   bool skip = ((target != NULL) && (target->opcode == kPseudoThrowTarget));
   skip &= ((cu_->code_item->insns_size_in_code_units_ - current_dalvik_offset_) > 64);
-  if (!skip && (ARM_LOWREG(reg.GetReg())) && (check_value == 0) &&
+  if (!skip && reg.Low8() && (check_value == 0) &&
      ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) {
     branch = NewLIR2((arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
                      reg.GetReg(), 0);
@@ -344,13 +344,13 @@
   if (r_src.IsPair()) {
     r_src = r_src.GetLow();
   }
-  if (ARM_FPREG(r_dest.GetReg()) || ARM_FPREG(r_src.GetReg()))
+  if (r_dest.IsFloat() || r_src.IsFloat())
     return OpFpRegCopy(r_dest, r_src);
-  if (ARM_LOWREG(r_dest.GetReg()) && ARM_LOWREG(r_src.GetReg()))
+  if (r_dest.Low8() && r_src.Low8())
     opcode = kThumbMovRR;
-  else if (!ARM_LOWREG(r_dest.GetReg()) && !ARM_LOWREG(r_src.GetReg()))
+  else if (!r_dest.Low8() && !r_src.Low8())
      opcode = kThumbMovRR_H2H;
-  else if (ARM_LOWREG(r_dest.GetReg()))
+  else if (r_dest.Low8())
      opcode = kThumbMovRR_H2L;
   else
      opcode = kThumbMovRR_L2H;
@@ -370,21 +370,19 @@
 
 void ArmMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
   if (r_dest != r_src) {
-    bool dest_fp = ARM_FPREG(r_dest.GetLowReg());
-    bool src_fp = ARM_FPREG(r_src.GetLowReg());
+    bool dest_fp = r_dest.IsFloat();
+    bool src_fp = r_src.IsFloat();
+    DCHECK(r_dest.Is64Bit());
+    DCHECK(r_src.Is64Bit());
     if (dest_fp) {
       if (src_fp) {
-        // FIXME: handle 64-bit solo's here.
-        OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
-                  RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
+        OpRegCopy(r_dest, r_src);
       } else {
-        NewLIR3(kThumb2Fmdrr, S2d(r_dest.GetLowReg(), r_dest.GetHighReg()),
-                r_src.GetLowReg(), r_src.GetHighReg());
+        NewLIR3(kThumb2Fmdrr, r_dest.GetReg(), r_src.GetLowReg(), r_src.GetHighReg());
       }
     } else {
       if (src_fp) {
-        NewLIR3(kThumb2Fmrrd, r_dest.GetLowReg(), r_dest.GetHighReg(), S2d(r_src.GetLowReg(),
-                r_src.GetHighReg()));
+        NewLIR3(kThumb2Fmrrd, r_dest.GetLowReg(), r_dest.GetHighReg(), r_src.GetReg());
       } else {
         // Handle overlap
         if (r_src.GetHighReg() == r_dest.GetLowReg()) {
@@ -747,16 +745,18 @@
   // around the potentially locked temp by using LR for r_ptr, unconditionally.
   // TODO: Pass information about the need for more temps to the stack frame generation
   // code so that we can rely on being able to allocate enough temps.
-  DCHECK(!reg_pool_->core_regs[rARM_LR].is_temp);
-  MarkTemp(rARM_LR);
-  FreeTemp(rARM_LR);
-  LockTemp(rARM_LR);
+  DCHECK(!GetRegInfo(rs_rARM_LR)->IsTemp());
+  MarkTemp(rs_rARM_LR);
+  FreeTemp(rs_rARM_LR);
+  LockTemp(rs_rARM_LR);
   bool load_early = true;
   if (is_long) {
-    int expected_reg = is_long ? rl_src_expected.reg.GetLowReg() : rl_src_expected.reg.GetReg();
-    int new_val_reg = is_long ? rl_src_new_value.reg.GetLowReg() : rl_src_new_value.reg.GetReg();
-    bool expected_is_core_reg = rl_src_expected.location == kLocPhysReg && !IsFpReg(expected_reg);
-    bool new_value_is_core_reg = rl_src_new_value.location == kLocPhysReg && !IsFpReg(new_val_reg);
+    RegStorage expected_reg = rl_src_expected.reg.IsPair() ? rl_src_expected.reg.GetLow() :
+        rl_src_expected.reg;
+    RegStorage new_val_reg = rl_src_new_value.reg.IsPair() ? rl_src_new_value.reg.GetLow() :
+        rl_src_new_value.reg;
+    bool expected_is_core_reg = rl_src_expected.location == kLocPhysReg && !expected_reg.IsFloat();
+    bool new_value_is_core_reg = rl_src_new_value.location == kLocPhysReg && !new_val_reg.IsFloat();
     bool expected_is_good_reg = expected_is_core_reg && !IsTemp(expected_reg);
     bool new_value_is_good_reg = new_value_is_core_reg && !IsTemp(new_val_reg);
 
@@ -802,9 +802,9 @@
 
   // Free now unneeded rl_object and rl_offset to give more temps.
   ClobberSReg(rl_object.s_reg_low);
-  FreeTemp(rl_object.reg.GetReg());
+  FreeTemp(rl_object.reg);
   ClobberSReg(rl_offset.s_reg_low);
-  FreeTemp(rl_offset.reg.GetReg());
+  FreeTemp(rl_offset.reg);
 
   RegLocation rl_expected;
   if (!is_long) {
@@ -813,9 +813,9 @@
     rl_expected = LoadValueWide(rl_src_expected, kCoreReg);
   } else {
     // NOTE: partially defined rl_expected & rl_new_value - but we just want the regs.
-    int low_reg = AllocTemp().GetReg();
-    int high_reg = AllocTemp().GetReg();
-    rl_new_value.reg = RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
+    RegStorage low_reg = AllocTemp();
+    RegStorage high_reg = AllocTemp();
+    rl_new_value.reg = RegStorage::MakeRegPair(low_reg, high_reg);
     rl_expected = rl_new_value;
   }
 
@@ -840,7 +840,7 @@
       LoadValueDirectWide(rl_src_new_value, rl_new_value.reg);
     }
     // Make sure we use ORR that sets the ccode
-    if (ARM_LOWREG(r_tmp.GetReg()) && ARM_LOWREG(r_tmp_high.GetReg())) {
+    if (r_tmp.Low8() && r_tmp_high.Low8()) {
       NewLIR2(kThumbOrr, r_tmp.GetReg(), r_tmp_high.GetReg());
     } else {
       NewLIR4(kThumb2OrrRRRs, r_tmp.GetReg(), r_tmp.GetReg(), r_tmp_high.GetReg(), 0);
@@ -881,8 +881,8 @@
   StoreValue(rl_dest, rl_result);
 
   // Now, restore lr to its non-temp status.
-  Clobber(rARM_LR);
-  UnmarkTemp(rARM_LR);
+  Clobber(rs_rARM_LR);
+  UnmarkTemp(rs_rARM_LR);
   return true;
 }
 
@@ -891,11 +891,11 @@
 }
 
 LIR* ArmMir2Lir::OpVldm(RegStorage r_base, int count) {
-  return NewLIR3(kThumb2Vldms, r_base.GetReg(), fr0, count);
+  return NewLIR3(kThumb2Vldms, r_base.GetReg(), rs_fr0.GetReg(), count);
 }
 
 LIR* ArmMir2Lir::OpVstm(RegStorage r_base, int count) {
-  return NewLIR3(kThumb2Vstms, r_base.GetReg(), fr0, count);
+  return NewLIR3(kThumb2Vstms, r_base.GetReg(), rs_fr0.GetReg(), count);
 }
 
 void ArmMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
@@ -918,7 +918,7 @@
 
 // Test suspend flag, return target of taken suspend branch
 LIR* ArmMir2Lir::OpTestSuspend(LIR* target) {
-  NewLIR2(kThumbSubRI8, rARM_SUSPEND, 1);
+  NewLIR2(kThumbSubRI8, rs_rARM_SUSPEND.GetReg(), 1);
   return OpCondBranch((target == NULL) ? kCondEq : kCondNe, target);
 }
 
@@ -1012,9 +1012,9 @@
     RegStorage res_lo;
     RegStorage res_hi;
     bool dest_promoted = rl_dest.location == kLocPhysReg && rl_dest.reg.Valid() &&
-        !IsTemp(rl_dest.reg.GetLowReg()) && !IsTemp(rl_dest.reg.GetHighReg());
-    bool src1_promoted = !IsTemp(rl_src1.reg.GetLowReg()) && !IsTemp(rl_src1.reg.GetHighReg());
-    bool src2_promoted = !IsTemp(rl_src2.reg.GetLowReg()) && !IsTemp(rl_src2.reg.GetHighReg());
+        !IsTemp(rl_dest.reg.GetLow()) && !IsTemp(rl_dest.reg.GetHigh());
+    bool src1_promoted = !IsTemp(rl_src1.reg.GetLow()) && !IsTemp(rl_src1.reg.GetHigh());
+    bool src2_promoted = !IsTemp(rl_src2.reg.GetLow()) && !IsTemp(rl_src2.reg.GetHigh());
     // Check if rl_dest is *not* either operand and we have enough temp registers.
     if ((rl_dest.s_reg_low != rl_src1.s_reg_low && rl_dest.s_reg_low != rl_src2.s_reg_low) &&
         (dest_promoted || src1_promoted || src2_promoted)) {
@@ -1036,10 +1036,10 @@
     }
 
     // Temporarily add LR to the temp pool, and assign it to tmp1
-    MarkTemp(rARM_LR);
-    FreeTemp(rARM_LR);
+    MarkTemp(rs_rARM_LR);
+    FreeTemp(rs_rARM_LR);
     RegStorage tmp1 = rs_rARM_LR;
-    LockTemp(rARM_LR);
+    LockTemp(rs_rARM_LR);
 
     if (rl_src1.reg == rl_src2.reg) {
       DCHECK(res_hi.Valid());
@@ -1054,7 +1054,7 @@
         DCHECK(!res_hi.Valid());
         DCHECK_NE(rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
         DCHECK_NE(rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
-        FreeTemp(rl_src1.reg.GetHighReg());
+        FreeTemp(rl_src1.reg.GetHigh());
         res_hi = AllocTemp();
       }
       DCHECK(res_hi.Valid());
@@ -1073,8 +1073,8 @@
 
     // Now, restore lr to its non-temp status.
     FreeTemp(tmp1);
-    Clobber(rARM_LR);
-    UnmarkTemp(rARM_LR);
+    Clobber(rs_rARM_LR);
+    UnmarkTemp(rs_rARM_LR);
 
     if (reg_status != 0) {
       // We had manually allocated registers for rl_result.
@@ -1116,7 +1116,7 @@
  */
 void ArmMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_dest, int scale) {
-  RegisterClass reg_class = oat_reg_class_by_size(size);
+  RegisterClass reg_class = RegClassBySize(size);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   int data_offset;
   RegLocation rl_result;
@@ -1158,7 +1158,7 @@
       // No special indexed operation, lea + load w/ displacement
       reg_ptr = AllocTemp();
       OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kArmLsl, scale));
-      FreeTemp(rl_index.reg.GetReg());
+      FreeTemp(rl_index.reg);
     }
     rl_result = EvalLoc(rl_dest, reg_class, true);
 
@@ -1189,7 +1189,7 @@
     // Offset base, then use indexed load
     RegStorage reg_ptr = AllocTemp();
     OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
-    FreeTemp(rl_array.reg.GetReg());
+    FreeTemp(rl_array.reg);
     rl_result = EvalLoc(rl_dest, reg_class, true);
 
     if (needs_range_check) {
@@ -1209,7 +1209,7 @@
  */
 void ArmMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
-  RegisterClass reg_class = oat_reg_class_by_size(size);
+  RegisterClass reg_class = RegClassBySize(size);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   bool constant_index = rl_index.is_const;
 
@@ -1234,8 +1234,8 @@
   bool allocated_reg_ptr_temp = false;
   if (constant_index) {
     reg_ptr = rl_array.reg;
-  } else if (IsTemp(rl_array.reg.GetReg()) && !card_mark) {
-    Clobber(rl_array.reg.GetReg());
+  } else if (IsTemp(rl_array.reg) && !card_mark) {
+    Clobber(rl_array.reg);
     reg_ptr = rl_array.reg;
   } else {
     allocated_reg_ptr_temp = true;
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 305e89b..f59720b 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -25,16 +25,41 @@
 
 namespace art {
 
-static int core_regs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10,
-                         r11, r12, rARM_SP, rARM_LR, rARM_PC};
-static int ReservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC};
-static int FpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
-                       fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
-                       fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
-                       fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
-static int core_temps[] = {r0, r1, r2, r3, r12};
-static int fp_temps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
-                        fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
+// TODO: rework this when c++11 support allows.
+static const RegStorage core_regs_arr[] =
+    {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
+     rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
+static const RegStorage sp_regs_arr[] =
+    {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
+     rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
+     rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
+     rs_fr31};
+static const RegStorage dp_regs_arr[] =
+    {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
+     rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
+static const RegStorage reserved_regs_arr[] =
+    {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
+static const RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
+static const RegStorage sp_temps_arr[] =
+    {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
+     rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
+static const RegStorage dp_temps_arr[] =
+    {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
+
+static const std::vector<RegStorage> core_regs(core_regs_arr,
+    core_regs_arr + sizeof(core_regs_arr) / sizeof(core_regs_arr[0]));
+static const std::vector<RegStorage> sp_regs(sp_regs_arr,
+    sp_regs_arr + sizeof(sp_regs_arr) / sizeof(sp_regs_arr[0]));
+static const std::vector<RegStorage> dp_regs(dp_regs_arr,
+    dp_regs_arr + sizeof(dp_regs_arr) / sizeof(dp_regs_arr[0]));
+static const std::vector<RegStorage> reserved_regs(reserved_regs_arr,
+    reserved_regs_arr + sizeof(reserved_regs_arr) / sizeof(reserved_regs_arr[0]));
+static const std::vector<RegStorage> core_temps(core_temps_arr,
+    core_temps_arr + sizeof(core_temps_arr) / sizeof(core_temps_arr[0]));
+static const std::vector<RegStorage> sp_temps(sp_temps_arr,
+    sp_temps_arr + sizeof(sp_temps_arr) / sizeof(sp_temps_arr[0]));
+static const std::vector<RegStorage> dp_temps(dp_temps_arr,
+    dp_temps_arr + sizeof(dp_temps_arr) / sizeof(dp_temps_arr[0]));
 
 RegLocation ArmMir2Lir::LocCReturn() {
   return arm_loc_c_return;
@@ -54,74 +79,61 @@
 
 // Return a target-dependent special register.
 RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
-  int res_reg = RegStorage::kInvalidRegVal;
+  RegStorage res_reg = RegStorage::InvalidReg();
   switch (reg) {
-    case kSelf: res_reg = rARM_SELF; break;
-    case kSuspend: res_reg =  rARM_SUSPEND; break;
-    case kLr: res_reg =  rARM_LR; break;
-    case kPc: res_reg =  rARM_PC; break;
-    case kSp: res_reg =  rARM_SP; break;
-    case kArg0: res_reg = rARM_ARG0; break;
-    case kArg1: res_reg = rARM_ARG1; break;
-    case kArg2: res_reg = rARM_ARG2; break;
-    case kArg3: res_reg = rARM_ARG3; break;
-    case kFArg0: res_reg = rARM_FARG0; break;
-    case kFArg1: res_reg = rARM_FARG1; break;
-    case kFArg2: res_reg = rARM_FARG2; break;
-    case kFArg3: res_reg = rARM_FARG3; break;
-    case kRet0: res_reg = rARM_RET0; break;
-    case kRet1: res_reg = rARM_RET1; break;
-    case kInvokeTgt: res_reg = rARM_INVOKE_TGT; break;
-    case kHiddenArg: res_reg = r12; break;
-    case kHiddenFpArg: res_reg = RegStorage::kInvalidRegVal; break;
-    case kCount: res_reg = rARM_COUNT; break;
+    case kSelf: res_reg = rs_rARM_SELF; break;
+    case kSuspend: res_reg =  rs_rARM_SUSPEND; break;
+    case kLr: res_reg =  rs_rARM_LR; break;
+    case kPc: res_reg =  rs_rARM_PC; break;
+    case kSp: res_reg =  rs_rARM_SP; break;
+    case kArg0: res_reg = rs_r0; break;
+    case kArg1: res_reg = rs_r1; break;
+    case kArg2: res_reg = rs_r2; break;
+    case kArg3: res_reg = rs_r3; break;
+    case kFArg0: res_reg = rs_r0; break;
+    case kFArg1: res_reg = rs_r1; break;
+    case kFArg2: res_reg = rs_r2; break;
+    case kFArg3: res_reg = rs_r3; break;
+    case kRet0: res_reg = rs_r0; break;
+    case kRet1: res_reg = rs_r1; break;
+    case kInvokeTgt: res_reg = rs_rARM_LR; break;
+    case kHiddenArg: res_reg = rs_r12; break;
+    case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
+    case kCount: res_reg = RegStorage::InvalidReg(); break;
   }
-  return RegStorage::Solo32(res_reg);
+  return res_reg;
 }
 
 RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
   // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
   switch (arg_num) {
     case 0:
-      return rs_rARM_ARG1;
+      return rs_r1;
     case 1:
-      return rs_rARM_ARG2;
+      return rs_r2;
     case 2:
-      return rs_rARM_ARG3;
+      return rs_r3;
     default:
       return RegStorage::InvalidReg();
   }
 }
 
-// Create a double from a pair of singles.
-int ArmMir2Lir::S2d(int low_reg, int high_reg) {
-  return ARM_S2D(low_reg, high_reg);
-}
-
-// Return mask to strip off fp reg flags and bias.
-uint32_t ArmMir2Lir::FpRegMask() {
-  return ARM_FP_REG_MASK;
-}
-
-// True if both regs single, both core or both double.
-bool ArmMir2Lir::SameRegType(int reg1, int reg2) {
-  return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
-}
-
 /*
  * Decode the register id.
  */
-uint64_t ArmMir2Lir::GetRegMaskCommon(int reg) {
+uint64_t ArmMir2Lir::GetRegMaskCommon(RegStorage reg) {
   uint64_t seed;
   int shift;
-  int reg_id;
-
-
-  reg_id = reg & 0x1f;
+  int reg_id = reg.GetRegNum();
   /* Each double register is equal to a pair of single-precision FP registers */
-  seed = ARM_DOUBLEREG(reg) ? 3 : 1;
+  if (reg.IsDouble()) {
+    seed = 0x3;
+    reg_id = reg_id << 1;
+  } else {
+    seed = 1;
+  }
   /* FP register starts at bit position 16 */
-  shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
+  shift = reg.IsFloat() ? kArmFPReg0 : 0;
   /* Expand the double register id into single offset */
   shift += reg_id;
   return (seed << shift);
@@ -196,7 +208,7 @@
     }
     /* Fixup for kThumbPush/lr and kThumbPop/pc */
     if (opcode == kThumbPush || opcode == kThumbPop) {
-      uint64_t r8Mask = GetRegMaskCommon(r8);
+      uint64_t r8Mask = GetRegMaskCommon(rs_r8);
       if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
         lir->u.m.use_mask &= ~r8Mask;
         lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
@@ -274,9 +286,9 @@
     if (vector & 0x1) {
       int reg_id = i;
       if (opcode == kThumbPush && i == 8) {
-        reg_id = r14lr;
+        reg_id = rs_rARM_LR.GetRegNum();
       } else if (opcode == kThumbPop && i == 8) {
-        reg_id = r15pc;
+        reg_id = rs_rARM_PC.GetRegNum();
       }
       if (printed) {
         snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
@@ -391,10 +403,10 @@
              snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
              break;
            case 's':
-             snprintf(tbuf, arraysize(tbuf), "s%d", operand & ARM_FP_REG_MASK);
+             snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
              break;
            case 'S':
-             snprintf(tbuf, arraysize(tbuf), "d%d", (operand & ARM_FP_REG_MASK) >> 1);
+             snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
              break;
            case 'h':
              snprintf(tbuf, arraysize(tbuf), "%04x", operand);
@@ -404,6 +416,7 @@
              snprintf(tbuf, arraysize(tbuf), "%d", operand);
              break;
            case 'C':
+             operand = RegStorage::RegNum(operand);
              DCHECK_LT(operand, static_cast<int>(
                  sizeof(core_reg_names)/sizeof(core_reg_names[0])));
              snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
@@ -539,48 +552,46 @@
 
 RegStorage ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
   if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
-    return AllocTempFloat();
+    return AllocTempSingle();
   return AllocTemp();
 }
 
 void ArmMir2Lir::CompilerInitializeRegAlloc() {
-  int num_regs = sizeof(core_regs)/sizeof(*core_regs);
-  int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
-  int num_temps = sizeof(core_temps)/sizeof(*core_temps);
-  int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
-  int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
-  reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
-                                                       kArenaAllocRegAlloc));
-  reg_pool_->num_core_regs = num_regs;
-  reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
-      (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc));
-  reg_pool_->num_fp_regs = num_fp_regs;
-  reg_pool_->FPRegs = static_cast<RegisterInfo*>
-      (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc));
-  CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
-  CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
+  reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, sp_regs, dp_regs, reserved_regs,
+                                        core_temps, sp_temps, dp_temps);
 
-  // Keep special registers from being allocated
-  // Don't reserve the r4 if we are doing implicit suspend checks.
+  // Target-specific adjustments.
+
+  // Alias single precision floats to appropriate half of overlapping double.
+  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    int sp_reg_num = info->GetReg().GetRegNum();
+    int dp_reg_num = sp_reg_num >> 1;
+    RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
+    RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
+    // Double precision register's master storage should refer to itself.
+    DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
+    // Redirect single precision's master storage to master.
+    info->SetMaster(dp_reg_info);
+    // Singles should show a single 32-bit mask bit, at first referring to the low half.
+    DCHECK_EQ(info->StorageMask(), 0x1U);
+    if (sp_reg_num & 1) {
+      // For odd singles, change to user the high word of the backing double.
+      info->SetStorageMask(0x2);
+    }
+  }
+
   // TODO: re-enable this when we can safely save r4 over the suspension code path.
   bool no_suspend = NO_SUSPEND;  // || !Runtime::Current()->ExplicitSuspendChecks();
-  for (int i = 0; i < num_reserved; i++) {
-    if (no_suspend && (ReservedRegs[i] == rARM_SUSPEND)) {
-      // Don't reserve the suspend register.
-      continue;
-    }
-    MarkInUse(ReservedRegs[i]);
-  }
-  // Mark temp regs - all others not in use can be used for promotion
-  for (int i = 0; i < num_temps; i++) {
-    MarkTemp(core_temps[i]);
-  }
-  for (int i = 0; i < num_fp_temps; i++) {
-    MarkTemp(fp_temps[i]);
+  if (no_suspend) {
+    GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
   }
 
-  // Start allocation at r2 in an attempt to avoid clobbering return values
-  reg_pool_->next_core_reg = r2;
+  // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
+  // TODO: adjust when we roll to hard float calling convention.
+  reg_pool_->next_core_reg_ = 2;
+  reg_pool_->next_sp_reg_ = 0;
+  reg_pool_->next_dp_reg_ = 0;
 }
 
 void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
@@ -602,7 +613,7 @@
  */
 
 void ArmMir2Lir::AdjustSpillMask() {
-  core_spill_mask_ |= (1 << rARM_LR);
+  core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
   num_core_spills_++;
 }
 
@@ -612,123 +623,99 @@
  * include any holes in the mask.  Associate holes with
  * Dalvik register INVALID_VREG (0xFFFFU).
  */
-void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
-  DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
-  reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
+void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
+  DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
+  int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
   // Ensure fp_vmap_table is large enough
   int table_size = fp_vmap_table_.size();
-  for (int i = table_size; i < (reg + 1); i++) {
+  for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
     fp_vmap_table_.push_back(INVALID_VREG);
   }
   // Add the current mapping
-  fp_vmap_table_[reg] = v_reg;
+  fp_vmap_table_[adjusted_reg_num] = v_reg;
   // Size of fp_vmap_table is high-water mark, use to set mask
   num_fp_spills_ = fp_vmap_table_.size();
   fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
 }
 
-void ArmMir2Lir::FlushRegWide(RegStorage reg) {
-  RegisterInfo* info1 = GetRegInfo(reg.GetLowReg());
-  RegisterInfo* info2 = GetRegInfo(reg.GetHighReg());
-  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->is_temp && info2->is_temp)) {
-      /* Should not happen.  If it does, there's a problem in eval_loc */
-      LOG(FATAL) << "Long half-temp, half-promoted";
-    }
-
-    info1->dirty = false;
-    info2->dirty = false;
-    if (mir_graph_->SRegToVReg(info2->s_reg) <
-      mir_graph_->SRegToVReg(info1->s_reg))
-      info1 = info2;
-    int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
-    StoreBaseDispWide(rs_rARM_SP, VRegOffset(v_reg),
-                      RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner));
-  }
-}
-
-void ArmMir2Lir::FlushReg(RegStorage reg) {
-  DCHECK(!reg.IsPair());
-  RegisterInfo* info = GetRegInfo(reg.GetReg());
-  if (info->live && info->dirty) {
-    info->dirty = false;
-    int v_reg = mir_graph_->SRegToVReg(info->s_reg);
-    StoreBaseDisp(rs_rARM_SP, VRegOffset(v_reg), reg, k32);
-  }
-}
-
-/* Give access to the target-dependent FP register encoding to common code */
-bool ArmMir2Lir::IsFpReg(int reg) {
-  return ARM_FPREG(reg);
-}
-
-bool ArmMir2Lir::IsFpReg(RegStorage reg) {
-  return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg());
+void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
+  // TEMP: perform as 2 singles.
+  int reg_num = reg.GetRegNum() << 1;
+  RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
+  RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
+  MarkPreservedSingle(v_reg, lo);
+  MarkPreservedSingle(v_reg + 1, hi);
 }
 
 /* Clobber all regs that might be used by an external C call */
 void ArmMir2Lir::ClobberCallerSave() {
-  Clobber(r0);
-  Clobber(r1);
-  Clobber(r2);
-  Clobber(r3);
-  Clobber(r12);
-  Clobber(r14lr);
-  Clobber(fr0);
-  Clobber(fr1);
-  Clobber(fr2);
-  Clobber(fr3);
-  Clobber(fr4);
-  Clobber(fr5);
-  Clobber(fr6);
-  Clobber(fr7);
-  Clobber(fr8);
-  Clobber(fr9);
-  Clobber(fr10);
-  Clobber(fr11);
-  Clobber(fr12);
-  Clobber(fr13);
-  Clobber(fr14);
-  Clobber(fr15);
+  // TODO: rework this - it's gotten even more ugly.
+  Clobber(rs_r0);
+  Clobber(rs_r1);
+  Clobber(rs_r2);
+  Clobber(rs_r3);
+  Clobber(rs_r12);
+  Clobber(rs_r14lr);
+  Clobber(rs_fr0);
+  Clobber(rs_fr1);
+  Clobber(rs_fr2);
+  Clobber(rs_fr3);
+  Clobber(rs_fr4);
+  Clobber(rs_fr5);
+  Clobber(rs_fr6);
+  Clobber(rs_fr7);
+  Clobber(rs_fr8);
+  Clobber(rs_fr9);
+  Clobber(rs_fr10);
+  Clobber(rs_fr11);
+  Clobber(rs_fr12);
+  Clobber(rs_fr13);
+  Clobber(rs_fr14);
+  Clobber(rs_fr15);
+  Clobber(rs_dr0);
+  Clobber(rs_dr1);
+  Clobber(rs_dr2);
+  Clobber(rs_dr3);
+  Clobber(rs_dr4);
+  Clobber(rs_dr5);
+  Clobber(rs_dr6);
+  Clobber(rs_dr7);
 }
 
 RegLocation ArmMir2Lir::GetReturnWideAlt() {
   RegLocation res = LocCReturnWide();
-  res.reg.SetReg(r2);
-  res.reg.SetHighReg(r3);
-  Clobber(r2);
-  Clobber(r3);
-  MarkInUse(r2);
-  MarkInUse(r3);
-  MarkPair(res.reg.GetLowReg(), res.reg.GetHighReg());
+  res.reg.SetLowReg(rs_r2.GetReg());
+  res.reg.SetHighReg(rs_r3.GetReg());
+  Clobber(rs_r2);
+  Clobber(rs_r3);
+  MarkInUse(rs_r2);
+  MarkInUse(rs_r3);
+  MarkWide(res.reg);
   return res;
 }
 
 RegLocation ArmMir2Lir::GetReturnAlt() {
   RegLocation res = LocCReturn();
-  res.reg.SetReg(r1);
-  Clobber(r1);
-  MarkInUse(r1);
+  res.reg.SetReg(rs_r1.GetReg());
+  Clobber(rs_r1);
+  MarkInUse(rs_r1);
   return res;
 }
 
 /* To be used when explicitly managing register use */
 void ArmMir2Lir::LockCallTemps() {
-  LockTemp(r0);
-  LockTemp(r1);
-  LockTemp(r2);
-  LockTemp(r3);
+  LockTemp(rs_r0);
+  LockTemp(rs_r1);
+  LockTemp(rs_r2);
+  LockTemp(rs_r3);
 }
 
 /* To be used when explicitly managing register use */
 void ArmMir2Lir::FreeCallTemps() {
-  FreeTemp(r0);
-  FreeTemp(r1);
-  FreeTemp(r2);
-  FreeTemp(r3);
+  FreeTemp(rs_r0);
+  FreeTemp(rs_r1);
+  FreeTemp(rs_r2);
+  FreeTemp(rs_r3);
 }
 
 RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
@@ -758,4 +745,59 @@
   return ArmMir2Lir::EncodingMap[opcode].fmt;
 }
 
+/*
+ * Somewhat messy code here.  We want to allocate a pair of contiguous
+ * physical single-precision floating point registers starting with
+ * an even numbered reg.  It is possible that the paired s_reg (s_reg+1)
+ * has already been allocated - try to fit if possible.  Fail to
+ * allocate if we can't meet the requirements for the pair of
+ * s_reg<=sX[even] & (s_reg+1)<= sX+1.
+ */
+// TODO: needs rewrite to support non-backed 64-bit float regs.
+RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
+  RegStorage res;
+  int v_reg = mir_graph_->SRegToVReg(s_reg);
+  int p_map_idx = SRegToPMap(s_reg);
+  if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
+    // Upper reg is already allocated.  Can we fit?
+    int high_reg = promotion_map_[p_map_idx+1].FpReg;
+    if ((high_reg & 1) == 0) {
+      // High reg is even - fail.
+      return res;  // Invalid.
+    }
+    // Is the low reg of the pair free?
+    // FIXME: rework.
+    RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
+    if (p->InUse() || p->IsTemp()) {
+      // Already allocated or not preserved - fail.
+      return res;  // Invalid.
+    }
+    // OK - good to go.
+    res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
+    p->MarkInUse();
+    MarkPreservedSingle(v_reg, p->GetReg());
+  } else {
+    /*
+     * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
+     * different underlying physical registers.
+     */
+    GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
+    for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+      if (!info->IsTemp() && !info->InUse()) {
+        res = info->GetReg();
+        info->MarkInUse();
+        MarkPreservedDouble(v_reg, info->GetReg());
+        break;
+      }
+    }
+  }
+  if (res.Valid()) {
+    promotion_map_[p_map_idx].fp_location = kLocPhysReg;
+    promotion_map_[p_map_idx].FpReg = res.DoubleToLowSingle().GetReg();
+    promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
+    promotion_map_[p_map_idx+1].FpReg = res.DoubleToHighSingle().GetReg();
+  }
+  return res;
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 2e64f74..08acef7 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -69,7 +69,7 @@
 }
 
 LIR* ArmMir2Lir::LoadFPConstantValue(int r_dest, int value) {
-  DCHECK(ARM_SINGLEREG(r_dest));
+  DCHECK(RegStorage::IsSingle(r_dest));
   if (value == 0) {
     // TODO: we need better info about the target CPU.  a vector exclusive or
     //       would probably be better here if we could rely on its existance.
@@ -88,7 +88,7 @@
     data_target = AddWordData(&literal_list_, value);
   }
   LIR* load_pc_rel = RawLIR(current_dalvik_offset_, kThumb2Vldrs,
-                          r_dest, r15pc, 0, 0, 0, data_target);
+                          r_dest, rs_r15pc.GetReg(), 0, 0, 0, data_target);
   SetMemRefType(load_pc_rel, true, kLiteral);
   AppendLIR(load_pc_rel);
   return load_pc_rel;
@@ -173,12 +173,12 @@
   LIR* res;
   int mod_imm;
 
-  if (ARM_FPREG(r_dest.GetReg())) {
+  if (r_dest.IsFloat()) {
     return LoadFPConstantValue(r_dest.GetReg(), value);
   }
 
   /* See if the value can be constructed cheaply */
-  if (ARM_LOWREG(r_dest.GetReg()) && (value >= 0) && (value <= 255)) {
+  if (r_dest.Low8() && (value >= 0) && (value <= 255)) {
     return NewLIR2(kThumbMovImm, r_dest.GetReg(), value);
   }
   /* Check Modified immediate special cases */
@@ -204,7 +204,7 @@
 }
 
 LIR* ArmMir2Lir::OpUnconditionalBranch(LIR* target) {
-  LIR* res = NewLIR1(kThumbBUncond, 0 /* offset to be patched  during assembly*/);
+  LIR* res = NewLIR1(kThumbBUncond, 0 /* offset to be patched  during assembly */);
   res->target = target;
   return res;
 }
@@ -237,7 +237,7 @@
 LIR* ArmMir2Lir::OpRegRegShift(OpKind op, RegStorage r_dest_src1, RegStorage r_src2,
                                int shift) {
   bool thumb_form =
-      ((shift == 0) && ARM_LOWREG(r_dest_src1.GetReg()) && ARM_LOWREG(r_src2.GetReg()));
+      ((shift == 0) && r_dest_src1.Low8() && r_src2.Low8());
   ArmOpcode opcode = kThumbBkpt;
   switch (op) {
     case kOpAdc:
@@ -256,9 +256,9 @@
     case kOpCmp:
       if (thumb_form)
         opcode = kThumbCmpRR;
-      else if ((shift == 0) && !ARM_LOWREG(r_dest_src1.GetReg()) && !ARM_LOWREG(r_src2.GetReg()))
+      else if ((shift == 0) && !r_dest_src1.Low8() && !r_src2.Low8())
         opcode = kThumbCmpHH;
-      else if ((shift == 0) && ARM_LOWREG(r_dest_src1.GetReg()))
+      else if ((shift == 0) && r_dest_src1.Low8())
         opcode = kThumbCmpLH;
       else if (shift == 0)
         opcode = kThumbCmpHL;
@@ -270,11 +270,11 @@
       break;
     case kOpMov:
       DCHECK_EQ(shift, 0);
-      if (ARM_LOWREG(r_dest_src1.GetReg()) && ARM_LOWREG(r_src2.GetReg()))
+      if (r_dest_src1.Low8() && r_src2.Low8())
         opcode = kThumbMovRR;
-      else if (!ARM_LOWREG(r_dest_src1.GetReg()) && !ARM_LOWREG(r_src2.GetReg()))
+      else if (!r_dest_src1.Low8() && !r_src2.Low8())
         opcode = kThumbMovRR_H2H;
-      else if (ARM_LOWREG(r_dest_src1.GetReg()))
+      else if (r_dest_src1.Low8())
         opcode = kThumbMovRR_H2L;
       else
         opcode = kThumbMovRR_L2H;
@@ -389,8 +389,7 @@
 LIR* ArmMir2Lir::OpRegRegRegShift(OpKind op, RegStorage r_dest, RegStorage r_src1,
                                   RegStorage r_src2, int shift) {
   ArmOpcode opcode = kThumbBkpt;
-  bool thumb_form = (shift == 0) && ARM_LOWREG(r_dest.GetReg()) && ARM_LOWREG(r_src1.GetReg()) &&
-      ARM_LOWREG(r_src2.GetReg());
+  bool thumb_form = (shift == 0) && r_dest.Low8() && r_src1.Low8() && r_src2.Low8();
   switch (op) {
     case kOpAdd:
       opcode = (thumb_form) ? kThumbAddRRR : kThumb2AddRRR;
@@ -466,7 +465,7 @@
   int32_t abs_value = (neg) ? -value : value;
   ArmOpcode opcode = kThumbBkpt;
   ArmOpcode alt_opcode = kThumbBkpt;
-  bool all_low_regs = (ARM_LOWREG(r_dest.GetReg()) && ARM_LOWREG(r_src1.GetReg()));
+  bool all_low_regs = r_dest.Low8() && r_src1.Low8();
   int32_t mod_imm = ModifiedImmediate(value);
 
   switch (op) {
@@ -488,10 +487,9 @@
     case kOpRor:
       return NewLIR3(kThumb2RorRRI5, r_dest.GetReg(), r_src1.GetReg(), value);
     case kOpAdd:
-      if (ARM_LOWREG(r_dest.GetReg()) && (r_src1 == rs_r13sp) &&
-        (value <= 1020) && ((value & 0x3) == 0)) {
+      if (r_dest.Low8() && (r_src1 == rs_r13sp) && (value <= 1020) && ((value & 0x3) == 0)) {
         return NewLIR3(kThumbAddSpRel, r_dest.GetReg(), r_src1.GetReg(), value >> 2);
-      } else if (ARM_LOWREG(r_dest.GetReg()) && (r_src1 == rs_r15pc) &&
+      } else if (r_dest.Low8() && (r_src1 == rs_r15pc) &&
           (value <= 1020) && ((value & 0x3) == 0)) {
         return NewLIR3(kThumbAddPcRel, r_dest.GetReg(), r_src1.GetReg(), value >> 2);
       }
@@ -601,7 +599,7 @@
 LIR* ArmMir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
   bool neg = (value < 0);
   int32_t abs_value = (neg) ? -value : value;
-  bool short_form = (((abs_value & 0xff) == abs_value) && ARM_LOWREG(r_dest_src1.GetReg()));
+  bool short_form = (((abs_value & 0xff) == abs_value) && r_dest_src1.Low8());
   ArmOpcode opcode = kThumbBkpt;
   switch (op) {
     case kOpAdd:
@@ -643,22 +641,24 @@
   LIR* res = NULL;
   int32_t val_lo = Low32Bits(value);
   int32_t val_hi = High32Bits(value);
-  int target_reg = S2d(r_dest.GetLowReg(), r_dest.GetHighReg());
-  if (ARM_FPREG(r_dest.GetLowReg())) {
+  if (r_dest.IsFloat()) {
+    DCHECK(!r_dest.IsPair());
     if ((val_lo == 0) && (val_hi == 0)) {
       // TODO: we need better info about the target CPU.  a vector exclusive or
       //       would probably be better here if we could rely on its existance.
       // Load an immediate +2.0 (which encodes to 0)
-      NewLIR2(kThumb2Vmovd_IMM8, target_reg, 0);
+      NewLIR2(kThumb2Vmovd_IMM8, r_dest.GetReg(), 0);
       // +0.0 = +2.0 - +2.0
-      res = NewLIR3(kThumb2Vsubd, target_reg, target_reg, target_reg);
+      res = NewLIR3(kThumb2Vsubd, r_dest.GetReg(), r_dest.GetReg(), r_dest.GetReg());
     } else {
       int encoded_imm = EncodeImmDouble(value);
       if (encoded_imm >= 0) {
-        res = NewLIR2(kThumb2Vmovd_IMM8, target_reg, encoded_imm);
+        res = NewLIR2(kThumb2Vmovd_IMM8, r_dest.GetReg(), encoded_imm);
       }
     }
   } else {
+    // NOTE: Arm32 assumption here.
+    DCHECK(r_dest.IsPair());
     if ((InexpensiveConstantInt(val_lo) && (InexpensiveConstantInt(val_hi)))) {
       res = LoadConstantNoClobber(r_dest.GetLow(), val_lo);
       LoadConstantNoClobber(r_dest.GetHigh(), val_hi);
@@ -670,13 +670,13 @@
     if (data_target == NULL) {
       data_target = AddWideData(&literal_list_, val_lo, val_hi);
     }
-    if (ARM_FPREG(r_dest.GetLowReg())) {
+    if (r_dest.IsFloat()) {
       res = RawLIR(current_dalvik_offset_, kThumb2Vldrd,
-                   target_reg, r15pc, 0, 0, 0, data_target);
+                   r_dest.GetReg(), rs_r15pc.GetReg(), 0, 0, 0, data_target);
     } else {
       DCHECK(r_dest.IsPair());
       res = RawLIR(current_dalvik_offset_, kThumb2LdrdPcRel8,
-                   r_dest.GetLowReg(), r_dest.GetHighReg(), r15pc, 0, 0, data_target);
+                   r_dest.GetLowReg(), r_dest.GetHighReg(), rs_r15pc.GetReg(), 0, 0, data_target);
     }
     SetMemRefType(res, true, kLiteral);
     AppendLIR(res);
@@ -690,22 +690,20 @@
 
 LIR* ArmMir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
                                  int scale, OpSize size) {
-  bool all_low_regs = ARM_LOWREG(r_base.GetReg()) && ARM_LOWREG(r_index.GetReg()) &&
-      ARM_LOWREG(r_dest.GetReg());
+  bool all_low_regs = r_base.Low8() && r_index.Low8() && r_dest.Low8();
   LIR* load;
   ArmOpcode opcode = kThumbBkpt;
   bool thumb_form = (all_low_regs && (scale == 0));
   RegStorage reg_ptr;
 
-  if (ARM_FPREG(r_dest.GetReg())) {
-    if (ARM_SINGLEREG(r_dest.GetReg())) {
+  if (r_dest.IsFloat()) {
+    if (r_dest.IsSingle()) {
       DCHECK((size == k32) || (size == kSingle) || (size == kReference));
       opcode = kThumb2Vldrs;
       size = kSingle;
     } else {
-      DCHECK(ARM_DOUBLEREG(r_dest.GetReg()));
+      DCHECK(r_dest.IsDouble());
       DCHECK((size == k64) || (size == kDouble));
-      DCHECK_EQ((r_dest.GetReg() & 0x1), 0);
       opcode = kThumb2Vldrd;
       size = kDouble;
     }
@@ -758,20 +756,19 @@
 
 LIR* ArmMir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
                                   int scale, OpSize size) {
-  bool all_low_regs = ARM_LOWREG(r_base.GetReg()) && ARM_LOWREG(r_index.GetReg()) &&
-      ARM_LOWREG(r_src.GetReg());
+  bool all_low_regs = r_base.Low8() && r_index.Low8() && r_src.Low8();
   LIR* store = NULL;
   ArmOpcode opcode = kThumbBkpt;
   bool thumb_form = (all_low_regs && (scale == 0));
   RegStorage reg_ptr;
 
-  if (ARM_FPREG(r_src.GetReg())) {
-    if (ARM_SINGLEREG(r_src.GetReg())) {
+  if (r_src.IsFloat()) {
+    if (r_src.IsSingle()) {
       DCHECK((size == k32) || (size == kSingle) || (size == kReference));
       opcode = kThumb2Vstrs;
       size = kSingle;
     } else {
-      DCHECK(ARM_DOUBLEREG(r_src.GetReg()));
+      DCHECK(r_src.IsDouble());
       DCHECK((size == k64) || (size == kDouble));
       DCHECK_EQ((r_src.GetReg() & 0x1), 0);
       opcode = kThumb2Vstrd;
@@ -833,21 +830,16 @@
   ArmOpcode opcode = kThumbBkpt;
   bool short_form = false;
   bool thumb2Form = (displacement < 4092 && displacement >= 0);
-  bool all_low = r_dest.Is32Bit() && ARM_LOWREG(r_base.GetReg() && ARM_LOWREG(r_dest.GetReg()));
+  bool all_low = r_dest.Is32Bit() && r_base.Low8() && r_dest.Low8();
   int encoded_disp = displacement;
   bool already_generated = false;
-  int dest_low_reg = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg();
   bool null_pointer_safepoint = false;
   switch (size) {
     case kDouble:
     // Intentional fall-though.
     case k64:
-      if (ARM_FPREG(dest_low_reg)) {
-        // Note: following change to avoid using pairs for doubles, replace conversion w/ DCHECK.
-        if (r_dest.IsPair()) {
-          DCHECK(ARM_FPREG(r_dest.GetHighReg()));
-          r_dest = RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg()));
-        }
+      if (r_dest.IsFloat()) {
+        DCHECK(!r_dest.IsPair());
         opcode = kThumb2Vldrd;
         if (displacement <= 1020) {
           short_form = true;
@@ -870,7 +862,7 @@
     case k32:
     // Intentional fall-though.
     case kReference:
-      if (ARM_FPREG(r_dest.GetReg())) {
+      if (r_dest.IsFloat()) {
         opcode = kThumb2Vldrs;
         if (displacement <= 1020) {
           short_form = true;
@@ -878,13 +870,13 @@
         }
         break;
       }
-      if (ARM_LOWREG(r_dest.GetReg()) && (r_base.GetReg() == r15pc) &&
-          (displacement <= 1020) && (displacement >= 0)) {
+      if (r_dest.Low8() && (r_base == rs_rARM_PC) && (displacement <= 1020) &&
+          (displacement >= 0)) {
         short_form = true;
         encoded_disp >>= 2;
         opcode = kThumbLdrPcRel;
-      } else if (ARM_LOWREG(r_dest.GetReg()) && (r_base.GetReg() == r13sp) &&
-          (displacement <= 1020) && (displacement >= 0)) {
+      } else if (r_dest.Low8() && (r_base == rs_rARM_SP) && (displacement <= 1020) &&
+                 (displacement >= 0)) {
         short_form = true;
         encoded_disp >>= 2;
         opcode = kThumbLdrSpRel;
@@ -940,7 +932,7 @@
     } else {
       RegStorage reg_offset = AllocTemp();
       LoadConstant(reg_offset, encoded_disp);
-      if (ARM_FPREG(dest_low_reg)) {
+      if (r_dest.IsFloat()) {
         // No index ops - must use a long sequence.  Turn the offset into a direct pointer.
         OpRegReg(kOpAdd, reg_offset, r_base);
         load = LoadBaseDispBody(reg_offset, 0, r_dest, size, s_reg);
@@ -985,15 +977,14 @@
   ArmOpcode opcode = kThumbBkpt;
   bool short_form = false;
   bool thumb2Form = (displacement < 4092 && displacement >= 0);
-  bool all_low = r_src.Is32Bit() && (ARM_LOWREG(r_base.GetReg()) && ARM_LOWREG(r_src.GetReg()));
+  bool all_low = r_src.Is32Bit() && r_base.Low8() && r_src.Low8();
   int encoded_disp = displacement;
   bool already_generated = false;
-  int src_low_reg = r_src.IsPair() ? r_src.GetLowReg() : r_src.GetReg();
   bool null_pointer_safepoint = false;
   switch (size) {
     case k64:
     case kDouble:
-      if (!ARM_FPREG(src_low_reg)) {
+      if (!r_src.IsFloat()) {
         if (displacement <= 1020) {
           store = NewLIR4(kThumb2StrdI8, r_src.GetLowReg(), r_src.GetHighReg(), r_base.GetReg(),
                           displacement >> 2);
@@ -1004,11 +995,7 @@
         }
         already_generated = true;
       } else {
-        // Note: following change to avoid using pairs for doubles, replace conversion w/ DCHECK.
-        if (r_src.IsPair()) {
-          DCHECK(ARM_FPREG(r_src.GetHighReg()));
-          r_src = RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg()));
-        }
+        DCHECK(!r_src.IsPair());
         opcode = kThumb2Vstrd;
         if (displacement <= 1020) {
           short_form = true;
@@ -1017,10 +1004,12 @@
       }
       break;
     case kSingle:
+    // Intentional fall-through.
     case k32:
+    // Intentional fall-through.
     case kReference:
-      if (ARM_FPREG(r_src.GetReg())) {
-        DCHECK(ARM_SINGLEREG(r_src.GetReg()));
+      if (r_src.IsFloat()) {
+        DCHECK(r_src.IsSingle());
         opcode = kThumb2Vstrs;
         if (displacement <= 1020) {
           short_form = true;
@@ -1028,8 +1017,7 @@
         }
         break;
       }
-      if (ARM_LOWREG(r_src.GetReg()) && (r_base == rs_r13sp) &&
-          (displacement <= 1020) && (displacement >= 0)) {
+      if (r_src.Low8() && (r_base == rs_r13sp) && (displacement <= 1020) && (displacement >= 0)) {
         short_form = true;
         encoded_disp >>= 2;
         opcode = kThumbStrSpRel;
@@ -1074,7 +1062,7 @@
     } else {
       RegStorage r_scratch = AllocTemp();
       LoadConstant(r_scratch, encoded_disp);
-      if (ARM_FPREG(src_low_reg)) {
+      if (r_src.IsFloat()) {
         // No index ops - must use a long sequence.  Turn the offset into a direct pointer.
         OpRegReg(kOpAdd, r_scratch, r_base);
         store = StoreBaseDispBody(r_scratch, 0, r_src, size);
@@ -1113,14 +1101,14 @@
 
 LIR* ArmMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
   int opcode;
-  DCHECK_EQ(ARM_DOUBLEREG(r_dest.GetReg()), ARM_DOUBLEREG(r_src.GetReg()));
-  if (ARM_DOUBLEREG(r_dest.GetReg())) {
+  DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
+  if (r_dest.IsDouble()) {
     opcode = kThumb2Vmovd;
   } else {
-    if (ARM_SINGLEREG(r_dest.GetReg())) {
-      opcode = ARM_SINGLEREG(r_src.GetReg()) ? kThumb2Vmovs : kThumb2Fmsr;
+    if (r_dest.IsSingle()) {
+      opcode = r_src.IsSingle() ? kThumb2Vmovs : kThumb2Fmsr;
     } else {
-      DCHECK(ARM_SINGLEREG(r_src.GetReg()));
+      DCHECK(r_src.IsSingle());
       opcode = kThumb2Fmrs;
     }
   }
@@ -1142,8 +1130,7 @@
 }
 
 LIR* ArmMir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
-                                      int displacement, RegStorage r_src, RegStorage r_src_hi,
-                                      OpSize size, int s_reg) {
+                                      int displacement, RegStorage r_src, OpSize size, int s_reg) {
   LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for Arm";
   return NULL;
 }
@@ -1154,8 +1141,7 @@
 }
 
 LIR* ArmMir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
-                                     int displacement, RegStorage r_dest, RegStorage r_dest_hi,
-                                     OpSize size, int s_reg) {
+                                     int displacement, RegStorage r_dest, OpSize size, int s_reg) {
   LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for Arm";
   return NULL;
 }
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 0596d4f..9f84e09 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -254,7 +254,7 @@
     PromotionMap v_reg_map = promotion_map_[i];
     std::string buf;
     if (v_reg_map.fp_location == kLocPhysReg) {
-      StringAppendF(&buf, " : s%d", v_reg_map.FpReg & FpRegMask());
+      StringAppendF(&buf, " : s%d", RegStorage::RegNum(v_reg_map.FpReg));
     }
 
     std::string buf3;
@@ -942,7 +942,7 @@
       switch_tables_(arena, 4, kGrowableArraySwitchTables),
       fill_array_data_(arena, 4, kGrowableArrayFillArrayData),
       tempreg_info_(arena, 20, kGrowableArrayMisc),
-      reginfo_map_(arena, 64, kGrowableArrayMisc),
+      reginfo_map_(arena, RegStorage::kMaxRegs, kGrowableArrayMisc),
       pointer_storage_(arena, 128, kGrowableArrayMisc),
       data_offset_(0),
       total_size_(0),
@@ -1050,10 +1050,11 @@
 int Mir2Lir::ComputeFrameSize() {
   /* Figure out the frame size */
   static const uint32_t kAlignMask = kStackAlignment - 1;
-  uint32_t size = ((num_core_spills_ + num_fp_spills_ +
-                   1 /* filler word */ + cu_->num_regs + cu_->num_outs)
-                   * sizeof(uint32_t)) +
-                   GetNumBytesForCompilerTempSpillRegion();
+  uint32_t size = num_core_spills_ * GetBytesPerGprSpillLocation(cu_->instruction_set)
+                  + num_fp_spills_ * GetBytesPerFprSpillLocation(cu_->instruction_set)
+                  + sizeof(uint32_t)  // Filler.
+                  + (cu_->num_regs + cu_->num_outs) * sizeof(uint32_t)
+                  + GetNumBytesForCompilerTempSpillRegion();
   /* Align and set */
   return (size + kAlignMask) & ~(kAlignMask);
 }
@@ -1185,8 +1186,19 @@
 
 RegLocation Mir2Lir::NarrowRegLoc(RegLocation loc) {
   loc.wide = false;
-  if (loc.reg.IsPair()) {
-    loc.reg = loc.reg.GetLow();
+  if (loc.location == kLocPhysReg) {
+    if (loc.reg.IsPair()) {
+      loc.reg = loc.reg.GetLow();
+    } else {
+      // FIXME: temp workaround.
+      // Issue here: how do we narrow to a 32-bit value in 64-bit container?
+      // Probably the wrong thing to narrow the RegStorage container here.  That
+      // should be a target decision.  At the RegLocation level, we're only
+      // modifying the view of the Dalvik value - this is orthogonal to the storage
+      // container size.  Consider this a temp workaround.
+      DCHECK(loc.reg.IsDouble());
+      loc.reg = loc.reg.DoubleToLowSingle();
+    }
   }
   return loc;
 }
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 8b9a686..2cd17cc 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -330,9 +330,10 @@
     bool is_type_initialized;  // Ignored as an array does not have an initializer.
     bool use_direct_type_ptr;
     uintptr_t direct_type_ptr;
+    bool is_finalizable;
     if (kEmbedClassInCode &&
-        driver->CanEmbedTypeInCode(*dex_file, type_idx,
-                                   &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
+        driver->CanEmbedTypeInCode(*dex_file, type_idx, &is_type_initialized, &use_direct_type_ptr,
+                                   &direct_type_ptr, &is_finalizable)) {
       // The fast path.
       if (!use_direct_type_ptr) {
         LoadClassType(type_idx, kArg0);
@@ -700,7 +701,7 @@
   cu_->compiler_driver->ProcessedInstanceField(field_info.FastGet());
   if (field_info.FastGet() && !SLOW_FIELD_PATH) {
     RegLocation rl_result;
-    RegisterClass reg_class = oat_reg_class_by_size(size);
+    RegisterClass reg_class = RegClassBySize(size);
     DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
     rl_obj = LoadValue(rl_obj, kCoreReg);
     if (is_long_or_double) {
@@ -773,7 +774,7 @@
   const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir);
   cu_->compiler_driver->ProcessedInstanceField(field_info.FastPut());
   if (field_info.FastPut() && !SLOW_FIELD_PATH) {
-    RegisterClass reg_class = oat_reg_class_by_size(size);
+    RegisterClass reg_class = RegClassBySize(size);
     DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
     rl_obj = LoadValue(rl_obj, kCoreReg);
     if (is_long_or_double) {
@@ -980,9 +981,11 @@
     bool is_type_initialized;
     bool use_direct_type_ptr;
     uintptr_t direct_type_ptr;
+    bool is_finalizable;
     if (kEmbedClassInCode &&
-        driver->CanEmbedTypeInCode(*dex_file, type_idx,
-                                   &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
+        driver->CanEmbedTypeInCode(*dex_file, type_idx, &is_type_initialized, &use_direct_type_ptr,
+                                   &direct_type_ptr, &is_finalizable) &&
+                                   !is_finalizable) {
       // The fast path.
       if (!use_direct_type_ptr) {
         LoadClassType(type_idx, kArg0);
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 93a23a6..9c1fbe4 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -22,12 +22,16 @@
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "invoke_type.h"
 #include "mirror/array.h"
+#include "mirror/object_array-inl.h"
 #include "mirror/string.h"
 #include "mir_to_lir-inl.h"
 #include "x86/codegen_x86.h"
 
 namespace art {
 
+// Shortcuts to repeatedly used long types.
+typedef mirror::ObjectArray<mirror::Object> ObjArray;
+
 /*
  * This source files contains "gen" codegen routines that should
  * be applicable to most targets.  Only mid-level support utilities
@@ -358,7 +362,7 @@
   rl_src.location = kLocPhysReg;
   rl_src.reg = TargetReg(kArg0);
   rl_src.home = false;
-  MarkLive(rl_src.reg, rl_src.s_reg_low);
+  MarkLive(rl_src);
   if (rl_method.wide) {
     StoreValueWide(rl_method, rl_src);
   } else {
@@ -494,8 +498,8 @@
     case 2:  // Grab target method*
       CHECK_EQ(cu->dex_file, target_method.dex_file);
       cg->LoadRefDisp(cg->TargetReg(kArg0),
-                      mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
-                      (target_method.dex_method_index * 4), cg->TargetReg(kArg0));
+                      ObjArray::OffsetOfElement(target_method.dex_method_index).Int32Value(),
+                      cg->TargetReg(kArg0));
       break;
     case 3:  // Grab the code from the method*
       if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
@@ -548,8 +552,8 @@
                       cg->TargetReg(kInvokeTgt));
       break;
     case 3:  // Get target method [use kInvokeTgt, set kArg0]
-      cg->LoadRefDisp(cg->TargetReg(kInvokeTgt), (method_idx * 4) +
-                      mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
+      cg->LoadRefDisp(cg->TargetReg(kInvokeTgt),
+                      ObjArray::OffsetOfElement(method_idx).Int32Value(),
                       cg->TargetReg(kArg0));
       break;
     case 4:  // Get the compiled code address [uses kArg0, sets kInvokeTgt]
@@ -605,8 +609,8 @@
       break;
     case 4:  // Get target method [use kInvokeTgt, set kArg0]
       // NOTE: native pointer.
-      cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), ((method_idx % ClassLinker::kImtSize) * 4) +
-                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
+      cg->LoadRefDisp(cg->TargetReg(kInvokeTgt),
+                       ObjArray::OffsetOfElement(method_idx % ClassLinker::kImtSize).Int32Value(),
                        cg->TargetReg(kArg0));
       break;
     case 5:  // Get the compiled code address [use kArg0, set kInvokeTgt]
@@ -753,7 +757,8 @@
       // Wide spans, we need the 2nd half of uses[2].
       rl_arg = UpdateLocWide(rl_use2);
       if (rl_arg.location == kLocPhysReg) {
-        reg = rl_arg.reg.GetHigh();
+        // NOTE: not correct for 64-bit core regs, but this needs rewriting for hard-float.
+        reg = rl_arg.reg.IsPair() ? rl_arg.reg.GetHigh() : rl_arg.reg.DoubleToHighSingle();
       } else {
         // kArg2 & rArg3 can safely be used here
         reg = TargetReg(kArg3);
@@ -768,34 +773,28 @@
     }
     // Loop through the rest
     while (next_use < info->num_arg_words) {
-      RegStorage low_reg;
-      RegStorage high_reg;
+      RegStorage arg_reg;
       rl_arg = info->args[next_use];
       rl_arg = UpdateRawLoc(rl_arg);
       if (rl_arg.location == kLocPhysReg) {
-        if (rl_arg.wide) {
-          low_reg = rl_arg.reg.GetLow();
-          high_reg = rl_arg.reg.GetHigh();
-        } else {
-          low_reg = rl_arg.reg;
-        }
+        arg_reg = rl_arg.reg;
       } else {
-        low_reg = TargetReg(kArg2);
+        arg_reg = rl_arg.wide ? RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)) :
+            TargetReg(kArg2);
         if (rl_arg.wide) {
-          high_reg = TargetReg(kArg3);
-          LoadValueDirectWideFixed(rl_arg, RegStorage::MakeRegPair(low_reg, high_reg));
+          LoadValueDirectWideFixed(rl_arg, arg_reg);
         } else {
-          LoadValueDirectFixed(rl_arg, low_reg);
+          LoadValueDirectFixed(rl_arg, arg_reg);
         }
         call_state = next_call_insn(cu_, info, call_state, target_method,
                                     vtable_idx, direct_code, direct_method, type);
       }
       int outs_offset = (next_use + 1) * 4;
       if (rl_arg.wide) {
-        StoreBaseDispWide(TargetReg(kSp), outs_offset, RegStorage::MakeRegPair(low_reg, high_reg));
+        StoreBaseDispWide(TargetReg(kSp), outs_offset, arg_reg);
         next_use += 2;
       } else {
-        Store32Disp(TargetReg(kSp), outs_offset, low_reg);
+        Store32Disp(TargetReg(kSp), outs_offset, arg_reg);
         next_use++;
       }
       call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
@@ -926,7 +925,7 @@
         // Allocate a free xmm temp. Since we are working through the calling sequence,
         // we expect to have an xmm temporary available.
         RegStorage temp = AllocTempDouble();
-        CHECK_GT(temp.GetLowReg(), 0);
+        DCHECK(temp.Valid());
 
         LIR* ld1 = nullptr;
         LIR* ld2 = nullptr;
@@ -989,9 +988,7 @@
         }
 
         // Free the temporary used for the data movement.
-        // CLEANUP: temp is currently a bogus pair, elmiminate extra free when updated.
-        FreeTemp(temp.GetLow());
-        FreeTemp(temp.GetHigh());
+        FreeTemp(temp);
       } else {
         // Moving 32-bits via general purpose register.
         bytes_to_move = sizeof(uint32_t);
@@ -1136,8 +1133,8 @@
   if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) {
     LoadBaseIndexed(reg_ptr, reg_off, rl_result.reg, 1, kUnsignedHalf);
   } else {
-    LoadBaseIndexedDisp(reg_ptr, reg_off, 1, data_offset, rl_result.reg,
-                        RegStorage::InvalidReg(), kUnsignedHalf, INVALID_SREG);
+    LoadBaseIndexedDisp(reg_ptr, reg_off, 1, data_offset, rl_result.reg, kUnsignedHalf,
+                        INVALID_SREG);
   }
   FreeTemp(reg_off);
   FreeTemp(reg_ptr);
@@ -1409,7 +1406,7 @@
     Load32Disp(TargetReg(kSelf), offset.Int32Value(), rl_result.reg);
   } else {
     CHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
-    reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.reg.GetReg(), offset);
+    reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.reg, offset);
   }
   StoreValue(rl_dest, rl_result);
   return true;
@@ -1432,13 +1429,12 @@
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (is_long) {
     if (cu_->instruction_set == kX86) {
-      LoadBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_result.reg.GetLow(),
-                          rl_result.reg.GetHigh(), k64, INVALID_SREG);
+      LoadBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_result.reg, k64, INVALID_SREG);
     } else {
       RegStorage rl_temp_offset = AllocTemp();
       OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg);
       LoadBaseDispWide(rl_temp_offset, 0, rl_result.reg, INVALID_SREG);
-      FreeTemp(rl_temp_offset.GetReg());
+      FreeTemp(rl_temp_offset);
     }
   } else {
     LoadBaseIndexed(rl_object.reg, rl_offset.reg, rl_result.reg, 0, k32);
@@ -1480,13 +1476,12 @@
   if (is_long) {
     rl_value = LoadValueWide(rl_src_value, kCoreReg);
     if (cu_->instruction_set == kX86) {
-      StoreBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_value.reg.GetLow(),
-                           rl_value.reg.GetHigh(), k64, INVALID_SREG);
+      StoreBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_value.reg, k64, INVALID_SREG);
     } else {
       RegStorage rl_temp_offset = AllocTemp();
       OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg);
       StoreBaseDispWide(rl_temp_offset, 0, rl_value.reg);
-      FreeTemp(rl_temp_offset.GetReg());
+      FreeTemp(rl_temp_offset);
     }
   } else {
     rl_value = LoadValue(rl_src_value, kCoreReg);
@@ -1494,7 +1489,7 @@
   }
 
   // Free up the temp early, to ensure x86 doesn't run out of temporaries in MarkGCCard.
-  FreeTemp(rl_offset.reg.GetReg());
+  FreeTemp(rl_offset.reg);
 
   if (is_volatile) {
     // A load might follow the volatile store so insert a StoreLoad barrier.
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index 9808f7f..e6911cd 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -143,7 +143,7 @@
   if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
     LoadValueDirect(rl_src, rl_src.reg);
     rl_src.location = kLocPhysReg;
-    MarkLive(rl_src.reg, rl_src.s_reg_low);
+    MarkLive(rl_src);
   }
   return rl_src;
 }
@@ -184,12 +184,12 @@
   }
 
   // Dest is now live and dirty (until/if we flush it to home location)
-  MarkLive(rl_dest.reg, rl_dest.s_reg_low);
+  MarkLive(rl_dest);
   MarkDirty(rl_dest);
 
 
   ResetDefLoc(rl_dest);
-  if (IsDirty(rl_dest.reg) && oat_live_out(rl_dest.s_reg_low)) {
+  if (IsDirty(rl_dest.reg) && LiveOut(rl_dest.s_reg_low)) {
     def_start = last_lir_insn_;
     Store32Disp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg);
     MarkClean(rl_dest);
@@ -207,13 +207,7 @@
   if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
     LoadValueDirectWide(rl_src, rl_src.reg);
     rl_src.location = kLocPhysReg;
-    MarkLive(rl_src.reg.GetLow(), rl_src.s_reg_low);
-    if (rl_src.reg.GetLowReg() != rl_src.reg.GetHighReg()) {
-      MarkLive(rl_src.reg.GetHigh(), GetSRegHi(rl_src.s_reg_low));
-    } else {
-      // This must be an x86 vector register value.
-      DCHECK(IsFpReg(rl_src.reg) && (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64));
-    }
+    MarkLive(rl_src);
   }
   return rl_src;
 }
@@ -254,24 +248,13 @@
   }
 
   // Dest is now live and dirty (until/if we flush it to home location)
-  MarkLive(rl_dest.reg.GetLow(), rl_dest.s_reg_low);
-
-  // Does this wide value live in two registers (or one vector one)?
-  // FIXME: wide reg update.
-  if (rl_dest.reg.GetLowReg() != rl_dest.reg.GetHighReg()) {
-    MarkLive(rl_dest.reg.GetHigh(), GetSRegHi(rl_dest.s_reg_low));
-    MarkDirty(rl_dest);
-    MarkPair(rl_dest.reg.GetLowReg(), rl_dest.reg.GetHighReg());
-  } else {
-    // This must be an x86 vector register value,
-    DCHECK(IsFpReg(rl_dest.reg) && (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64));
-    MarkDirty(rl_dest);
-  }
-
+  MarkLive(rl_dest);
+  MarkWide(rl_dest.reg);
+  MarkDirty(rl_dest);
 
   ResetDefLocWide(rl_dest);
-  if (IsDirty(rl_dest.reg) && (oat_live_out(rl_dest.s_reg_low) ||
-      oat_live_out(GetSRegHi(rl_dest.s_reg_low)))) {
+  if (IsDirty(rl_dest.reg) && (LiveOut(rl_dest.s_reg_low) ||
+      LiveOut(GetSRegHi(rl_dest.s_reg_low)))) {
     def_start = last_lir_insn_;
     DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
               mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
@@ -295,13 +278,12 @@
   }
 
   // Dest is now live and dirty (until/if we flush it to home location)
-  MarkLive(rl_dest.reg, rl_dest.s_reg_low);
+  MarkLive(rl_dest);
   MarkDirty(rl_dest);
 
 
   ResetDefLoc(rl_dest);
-  if (IsDirty(rl_dest.reg) &&
-      oat_live_out(rl_dest.s_reg_low)) {
+  if (IsDirty(rl_dest.reg) && LiveOut(rl_dest.s_reg_low)) {
     LIR *def_start = last_lir_insn_;
     Store32Disp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg);
     MarkClean(rl_dest);
@@ -314,7 +296,6 @@
 }
 
 void Mir2Lir::StoreFinalValueWide(RegLocation rl_dest, RegLocation rl_src) {
-  DCHECK_EQ(IsFpReg(rl_src.reg.GetLowReg()), IsFpReg(rl_src.reg.GetHighReg()));
   DCHECK(rl_dest.wide);
   DCHECK(rl_src.wide);
   DCHECK_EQ(rl_src.location, kLocPhysReg);
@@ -325,28 +306,17 @@
     // Just re-assign the registers.  Dest gets Src's regs.
     rl_dest.location = kLocPhysReg;
     rl_dest.reg = rl_src.reg;
-    Clobber(rl_src.reg.GetLowReg());
-    Clobber(rl_src.reg.GetHighReg());
+    Clobber(rl_src.reg);
   }
 
   // Dest is now live and dirty (until/if we flush it to home location).
-  MarkLive(rl_dest.reg.GetLow(), rl_dest.s_reg_low);
-
-  // Does this wide value live in two registers (or one vector one)?
-  // FIXME: wide reg.
-  if (rl_dest.reg.GetLowReg() != rl_dest.reg.GetHighReg()) {
-    MarkLive(rl_dest.reg.GetHigh(), GetSRegHi(rl_dest.s_reg_low));
-    MarkDirty(rl_dest);
-    MarkPair(rl_dest.reg.GetLowReg(), rl_dest.reg.GetHighReg());
-  } else {
-    // This must be an x86 vector register value,
-    DCHECK(IsFpReg(rl_dest.reg) && (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64));
-    MarkDirty(rl_dest);
-  }
+  MarkLive(rl_dest);
+  MarkWide(rl_dest.reg);
+  MarkDirty(rl_dest);
 
   ResetDefLocWide(rl_dest);
-  if (IsDirty(rl_dest.reg) && (oat_live_out(rl_dest.s_reg_low) ||
-      oat_live_out(GetSRegHi(rl_dest.s_reg_low)))) {
+  if (IsDirty(rl_dest.reg) && (LiveOut(rl_dest.s_reg_low) ||
+      LiveOut(GetSRegHi(rl_dest.s_reg_low)))) {
     LIR *def_start = last_lir_insn_;
     DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
               mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
@@ -369,7 +339,7 @@
 RegLocation Mir2Lir::ForceTemp(RegLocation loc) {
   DCHECK(!loc.wide);
   DCHECK(loc.location == kLocPhysReg);
-  DCHECK(!IsFpReg(loc.reg));
+  DCHECK(!loc.reg.IsFloat());
   if (IsTemp(loc.reg)) {
     Clobber(loc.reg);
   } else {
@@ -383,21 +353,20 @@
   return loc;
 }
 
-// FIXME: wide regs.
+// FIXME: will need an update for 64-bit core regs.
 RegLocation Mir2Lir::ForceTempWide(RegLocation loc) {
   DCHECK(loc.wide);
   DCHECK(loc.location == kLocPhysReg);
-  DCHECK(!IsFpReg(loc.reg.GetLowReg()));
-  DCHECK(!IsFpReg(loc.reg.GetHighReg()));
-  if (IsTemp(loc.reg.GetLowReg())) {
-    Clobber(loc.reg.GetLowReg());
+  DCHECK(!loc.reg.IsFloat());
+  if (IsTemp(loc.reg.GetLow())) {
+    Clobber(loc.reg.GetLow());
   } else {
     RegStorage temp_low = AllocTemp();
     OpRegCopy(temp_low, loc.reg.GetLow());
     loc.reg.SetLowReg(temp_low.GetReg());
   }
-  if (IsTemp(loc.reg.GetHighReg())) {
-    Clobber(loc.reg.GetHighReg());
+  if (IsTemp(loc.reg.GetHigh())) {
+    Clobber(loc.reg.GetHigh());
   } else {
     RegStorage temp_high = AllocTemp();
     OpRegCopy(temp_high, loc.reg.GetHigh());
diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc
index 4bdc9fa..4a918a1 100644
--- a/compiler/dex/quick/local_optimizations.cc
+++ b/compiler/dex/quick/local_optimizations.cc
@@ -163,7 +163,7 @@
           DCHECK(!(check_flags & IS_STORE));
           /* Same value && same register type */
           if (check_lir->flags.alias_info == this_lir->flags.alias_info &&
-              SameRegType(check_lir->operands[0], native_reg_id)) {
+              RegStorage::SameRegType(check_lir->operands[0], native_reg_id)) {
             /*
              * Different destination register - insert
              * a move
@@ -179,7 +179,7 @@
           /* Must alias */
           if (check_lir->flags.alias_info == this_lir->flags.alias_info) {
             /* Only optimize compatible registers */
-            bool reg_compatible = SameRegType(check_lir->operands[0], native_reg_id);
+            bool reg_compatible = RegStorage::SameRegType(check_lir->operands[0], native_reg_id);
             if ((is_this_lir_load && is_check_lir_load) ||
                 (!is_this_lir_load && is_check_lir_load)) {
               /* RAR or RAW */
diff --git a/compiler/dex/quick/mips/README.mips b/compiler/dex/quick/mips/README.mips
index 061c157..ff561fa 100644
--- a/compiler/dex/quick/mips/README.mips
+++ b/compiler/dex/quick/mips/README.mips
@@ -17,7 +17,7 @@
       code generation for switch tables, fill array data, 64-bit
       data handling and the register usage conventions.
 
-    o The memory model.  Verify that oatGenMemoryBarrier() generates the
+    o The memory model.  Verify that GenMemoryBarrier() generates the
       appropriate flavor of sync.
 
 Register promotion
diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc
index a579254..baae319 100644
--- a/compiler/dex/quick/mips/assemble_mips.cc
+++ b/compiler/dex/quick/mips/assemble_mips.cc
@@ -672,16 +672,17 @@
           bits |= (value << encoder->field_loc[i].end);
           break;
         case kFmtDfp: {
-          DCHECK(MIPS_DOUBLEREG(operand));
+          // TODO: do we need to adjust now that we're using 64BitSolo?
+          DCHECK(RegStorage::IsDouble(operand)) << ", Operand = 0x" << std::hex << operand;
           DCHECK_EQ((operand & 0x1), 0U);
-          value = ((operand & MIPS_FP_REG_MASK) << encoder->field_loc[i].start) &
+          value = (RegStorage::RegNum(operand) << encoder->field_loc[i].start) &
               ((1 << (encoder->field_loc[i].end + 1)) - 1);
           bits |= value;
           break;
         }
         case kFmtSfp:
-          DCHECK(MIPS_SINGLEREG(operand));
-          value = ((operand & MIPS_FP_REG_MASK) << encoder->field_loc[i].start) &
+          DCHECK(RegStorage::IsSingle(operand)) << ", Operand = 0x" << std::hex << operand;
+          value = (RegStorage::RegNum(operand) << encoder->field_loc[i].start) &
               ((1 << (encoder->field_loc[i].end + 1)) - 1);
           bits |= value;
           break;
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index df13882..3af3715 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -295,10 +295,10 @@
    * expanding the frame or flushing.  This leaves the utility
    * code with a single temp: r12.  This should be enough.
    */
-  LockTemp(rMIPS_ARG0);
-  LockTemp(rMIPS_ARG1);
-  LockTemp(rMIPS_ARG2);
-  LockTemp(rMIPS_ARG3);
+  LockTemp(rs_rMIPS_ARG0);
+  LockTemp(rs_rMIPS_ARG1);
+  LockTemp(rs_rMIPS_ARG2);
+  LockTemp(rs_rMIPS_ARG3);
 
   /*
    * We can safely skip the stack overflow check if we're
@@ -351,10 +351,10 @@
 
   FlushIns(ArgLocs, rl_method);
 
-  FreeTemp(rMIPS_ARG0);
-  FreeTemp(rMIPS_ARG1);
-  FreeTemp(rMIPS_ARG2);
-  FreeTemp(rMIPS_ARG3);
+  FreeTemp(rs_rMIPS_ARG0);
+  FreeTemp(rs_rMIPS_ARG1);
+  FreeTemp(rs_rMIPS_ARG2);
+  FreeTemp(rs_rMIPS_ARG3);
 }
 
 void MipsMir2Lir::GenExitSequence() {
@@ -362,8 +362,8 @@
    * In the exit path, rMIPS_RET0/rMIPS_RET1 are live - make sure they aren't
    * allocated by the register utilities as temps.
    */
-  LockTemp(rMIPS_RET0);
-  LockTemp(rMIPS_RET1);
+  LockTemp(rs_rMIPS_RET0);
+  LockTemp(rs_rMIPS_RET1);
 
   NewLIR0(kPseudoMethodExit);
   UnSpillCoreRegs();
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 81d6782..7a8376e 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -39,7 +39,7 @@
     LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
                          OpSize size);
     LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
-                             RegStorage r_dest, RegStorage r_dest_hi, OpSize size, int s_reg);
+                             RegStorage r_dest, OpSize size, int s_reg);
     LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
     LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
     LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
@@ -47,16 +47,12 @@
     LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
                           OpSize size);
     LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
-                              RegStorage r_src, RegStorage r_src_hi, OpSize size, int s_reg);
+                              RegStorage r_src, OpSize size, int s_reg);
     void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
 
     // Required for target - register utilities.
-    bool IsFpReg(int reg);
-    bool IsFpReg(RegStorage reg);
-    bool SameRegType(int reg1, int reg2);
     RegStorage AllocTypedTemp(bool fp_hint, int reg_class);
     RegStorage AllocTypedTempWide(bool fp_hint, int reg_class);
-    int S2d(int low_reg, int high_reg);
     RegStorage TargetReg(SpecialTargetRegister reg);
     RegStorage GetArgMappingToPhysicalReg(int arg_num);
     RegLocation GetReturnAlt();
@@ -65,16 +61,14 @@
     RegLocation LocCReturnDouble();
     RegLocation LocCReturnFloat();
     RegLocation LocCReturnWide();
-    uint32_t FpRegMask();
-    uint64_t GetRegMaskCommon(int reg);
+    uint64_t GetRegMaskCommon(RegStorage reg);
     void AdjustSpillMask();
     void ClobberCallerSave();
-    void FlushReg(RegStorage reg);
-    void FlushRegWide(RegStorage reg);
     void FreeCallTemps();
     void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
     void LockCallTemps();
-    void MarkPreservedSingle(int v_reg, int reg);
+    void MarkPreservedSingle(int v_reg, RegStorage reg);
+    void MarkPreservedDouble(int v_reg, RegStorage reg);
     void CompilerInitializeRegAlloc();
 
     // Required for target - miscellaneous.
diff --git a/compiler/dex/quick/mips/fp_mips.cc b/compiler/dex/quick/mips/fp_mips.cc
index a479dc7..9fffb2f 100644
--- a/compiler/dex/quick/mips/fp_mips.cc
+++ b/compiler/dex/quick/mips/fp_mips.cc
@@ -111,15 +111,13 @@
   rl_result = EvalLoc(rl_dest, kFPReg, true);
   DCHECK(rl_dest.wide);
   DCHECK(rl_result.wide);
-  NewLIR3(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg()),
-          S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+  NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
   StoreValueWide(rl_dest, rl_result);
 }
 
 void MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
                                 RegLocation rl_src) {
   int op = kMipsNop;
-  int src_reg;
   RegLocation rl_result;
   switch (opcode) {
     case Instruction::INT_TO_FLOAT:
@@ -157,18 +155,14 @@
   }
   if (rl_src.wide) {
     rl_src = LoadValueWide(rl_src, kFPReg);
-    src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
   } else {
     rl_src = LoadValue(rl_src, kFPReg);
-    src_reg = rl_src.reg.GetReg();
   }
+  rl_result = EvalLoc(rl_dest, kFPReg, true);
+  NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
   if (rl_dest.wide) {
-    rl_result = EvalLoc(rl_dest, kFPReg, true);
-    NewLIR2(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), src_reg);
     StoreValueWide(rl_dest, rl_result);
   } else {
-    rl_result = EvalLoc(rl_dest, kFPReg, true);
-    NewLIR2(op, rl_result.reg.GetReg(), src_reg);
     StoreValue(rl_dest, rl_result);
   }
 }
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 7c0becd..1410e14 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -44,16 +44,16 @@
                              RegLocation rl_src2) {
   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
-  int t0 = AllocTemp().GetReg();
-  int t1 = AllocTemp().GetReg();
+  RegStorage t0 = AllocTemp();
+  RegStorage t1 = AllocTemp();
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
-  NewLIR3(kMipsSlt, t0, rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
-  NewLIR3(kMipsSlt, t1, rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
-  NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1, t0);
+  NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
+  NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
+  NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
   LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL);
-  NewLIR3(kMipsSltu, t0, rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
-  NewLIR3(kMipsSltu, t1, rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
-  NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1, t0);
+  NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
+  NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
+  NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
   FreeTemp(t0);
   FreeTemp(t1);
   LIR* target = NewLIR0(kPseudoTargetLabel);
@@ -114,13 +114,13 @@
   if (cmp_zero) {
     branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
   } else {
-    int t_reg = AllocTemp().GetReg();
+    RegStorage t_reg = AllocTemp();
     if (swapped) {
-      NewLIR3(slt_op, t_reg, src2.GetReg(), src1.GetReg());
+      NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
     } else {
-      NewLIR3(slt_op, t_reg, src1.GetReg(), src2.GetReg());
+      NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
     }
-    branch = NewLIR1(br_op, t_reg);
+    branch = NewLIR1(br_op, t_reg.GetReg());
     FreeTemp(t_reg);
   }
   branch->target = target;
@@ -167,7 +167,7 @@
   if (r_src.IsPair()) {
     r_src = r_src.GetLow();
   }
-  if (MIPS_FPREG(r_dest.GetReg()) || MIPS_FPREG(r_src.GetReg()))
+  if (r_dest.IsFloat() || r_src.IsFloat())
     return OpFpRegCopy(r_dest, r_src);
   LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
             r_dest.GetReg(), r_src.GetReg());
@@ -186,17 +186,15 @@
 
 void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
   if (r_dest != r_src) {
-    bool dest_fp = MIPS_FPREG(r_dest.GetLowReg());
-    bool src_fp = MIPS_FPREG(r_src.GetLowReg());
+    bool dest_fp = r_dest.IsFloat();
+    bool src_fp = r_src.IsFloat();
     if (dest_fp) {
       if (src_fp) {
-        // FIXME: handle this here - reserve OpRegCopy for 32-bit copies.
-        OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
-                  RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
-        } else {
-          /* note the operands are swapped for the mtc1 instr */
-          NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
-          NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
+        OpRegCopy(r_dest, r_src);
+      } else {
+         /* note the operands are swapped for the mtc1 instr */
+        NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
+        NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
       }
     } else {
       if (src_fp) {
@@ -238,9 +236,9 @@
 
 RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit,
                                        bool is_div) {
-  int t_reg = AllocTemp().GetReg();
-  NewLIR3(kMipsAddiu, t_reg, rZERO, lit);
-  NewLIR2(kMipsDiv, reg1.GetReg(), t_reg);
+  RegStorage t_reg = AllocTemp();
+  NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
+  NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg());
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (is_div) {
     NewLIR1(kMipsMflo, rl_result.reg.GetReg());
@@ -470,7 +468,7 @@
  */
 void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                           RegLocation rl_index, RegLocation rl_dest, int scale) {
-  RegisterClass reg_class = oat_reg_class_by_size(size);
+  RegisterClass reg_class = RegClassBySize(size);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   int data_offset;
   RegLocation rl_result;
@@ -496,7 +494,7 @@
   }
   /* reg_ptr -> array data */
   OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
-  FreeTemp(rl_array.reg.GetReg());
+  FreeTemp(rl_array.reg);
   if ((size == k64) || (size == kDouble)) {
     if (scale) {
       RegStorage r_new_index = AllocTemp();
@@ -537,7 +535,7 @@
  */
 void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
                           RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
-  RegisterClass reg_class = oat_reg_class_by_size(size);
+  RegisterClass reg_class = RegClassBySize(size);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   int data_offset;
 
@@ -551,8 +549,8 @@
   rl_index = LoadValue(rl_index, kCoreReg);
   RegStorage reg_ptr;
   bool allocated_reg_ptr_temp = false;
-  if (IsTemp(rl_array.reg.GetReg()) && !card_mark) {
-    Clobber(rl_array.reg.GetReg());
+  if (IsTemp(rl_array.reg) && !card_mark) {
+    Clobber(rl_array.reg);
     reg_ptr = rl_array.reg;
   } else {
     reg_ptr = AllocTemp();
diff --git a/compiler/dex/quick/mips/mips_lir.h b/compiler/dex/quick/mips/mips_lir.h
index c5150ee..5b2cb9d 100644
--- a/compiler/dex/quick/mips/mips_lir.h
+++ b/compiler/dex/quick/mips/mips_lir.h
@@ -86,26 +86,6 @@
  * +========================+
  */
 
-// Offset to distingish FP regs.
-#define MIPS_FP_REG_OFFSET 32
-// Offset to distinguish DP FP regs.
-#define MIPS_FP_DOUBLE 64
-// Reg types.
-#define MIPS_REGTYPE(x) (x & (MIPS_FP_REG_OFFSET | MIPS_FP_DOUBLE))
-#define MIPS_FPREG(x) ((x & MIPS_FP_REG_OFFSET) == MIPS_FP_REG_OFFSET)
-#define MIPS_DOUBLEREG(x) ((x & MIPS_FP_DOUBLE) == MIPS_FP_DOUBLE)
-#define MIPS_SINGLEREG(x) (MIPS_FPREG(x) && !MIPS_DOUBLEREG(x))
-// FIXME: out of date comment.
-/*
- * 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 MIPS_S2D(x, y) ((x) | MIPS_FP_DOUBLE)
-// Mask to strip off fp flags.
-#define MIPS_FP_REG_MASK (MIPS_FP_REG_OFFSET-1)
 
 #define LOWORD_OFFSET 0
 #define HIWORD_OFFSET 4
@@ -159,135 +139,159 @@
 #define ENCODE_MIPS_REG_LO           (1ULL << kMipsRegLO)
 
 enum MipsNativeRegisterPool {
-  rZERO = 0,
-  rAT = 1,
-  rV0 = 2,
-  rV1 = 3,
-  rA0 = 4,
-  rA1 = 5,
-  rA2 = 6,
-  rA3 = 7,
-  rT0 = 8,
-  rT1 = 9,
-  rT2 = 10,
-  rT3 = 11,
-  rT4 = 12,
-  rT5 = 13,
-  rT6 = 14,
-  rT7 = 15,
-  rS0 = 16,
-  rS1 = 17,
-  rS2 = 18,
-  rS3 = 19,
-  rS4 = 20,
-  rS5 = 21,
-  rS6 = 22,
-  rS7 = 23,
-  rT8 = 24,
-  rT9 = 25,
-  rK0 = 26,
-  rK1 = 27,
-  rGP = 28,
-  rSP = 29,
-  rFP = 30,
-  rRA = 31,
+  rZERO = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  0,
+  rAT   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  1,
+  rV0   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  2,
+  rV1   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  3,
+  rA0   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  4,
+  rA1   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  5,
+  rA2   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  6,
+  rA3   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  7,
+  rT0   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  8,
+  rT1   = RegStorage::k32BitSolo | RegStorage::kCoreRegister |  9,
+  rT2   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 10,
+  rT3   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 11,
+  rT4   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 12,
+  rT5   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 13,
+  rT6   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 14,
+  rT7   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 15,
+  rS0   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 16,
+  rS1   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 17,
+  rS2   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 18,
+  rS3   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 19,
+  rS4   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 20,
+  rS5   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 21,
+  rS6   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 22,
+  rS7   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 23,
+  rT8   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 24,
+  rT9   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 25,
+  rK0   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 26,
+  rK1   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 27,
+  rGP   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 28,
+  rSP   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 29,
+  rFP   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 30,
+  rRA   = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 31,
 
-  rF0 = 0 + MIPS_FP_REG_OFFSET,
-  rF1,
-  rF2,
-  rF3,
-  rF4,
-  rF5,
-  rF6,
-  rF7,
-  rF8,
-  rF9,
-  rF10,
-  rF11,
-  rF12,
-  rF13,
-  rF14,
-  rF15,
+  rF0  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  0,
+  rF1  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  1,
+  rF2  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  2,
+  rF3  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  3,
+  rF4  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  4,
+  rF5  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  5,
+  rF6  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  6,
+  rF7  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  7,
+  rF8  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  8,
+  rF9  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint |  9,
+  rF10 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 10,
+  rF11 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 11,
+  rF12 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 12,
+  rF13 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 13,
+  rF14 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 14,
+  rF15 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 15,
 #if 0
   /*
    * TODO: The shared resource mask doesn't have enough bit positions to describe all
    * MIPS registers.  Expand it and enable use of fp registers 16 through 31.
    */
-  rF16,
-  rF17,
-  rF18,
-  rF19,
-  rF20,
-  rF21,
-  rF22,
-  rF23,
-  rF24,
-  rF25,
-  rF26,
-  rF27,
-  rF28,
-  rF29,
-  rF30,
-  rF31,
+  rF16 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 16,
+  rF17 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 17,
+  rF18 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 18,
+  rF19 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 19,
+  rF20 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 20,
+  rF21 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 21,
+  rF22 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 22,
+  rF23 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 23,
+  rF24 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 24,
+  rF25 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 25,
+  rF26 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 26,
+  rF27 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 27,
+  rF28 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 28,
+  rF29 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 29,
+  rF30 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 30,
+  rF31 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 31,
 #endif
-  rDF0 = rF0 + MIPS_FP_DOUBLE,
-  rDF1 = rF2 + MIPS_FP_DOUBLE,
-  rDF2 = rF4 + MIPS_FP_DOUBLE,
-  rDF3 = rF6 + MIPS_FP_DOUBLE,
-  rDF4 = rF8 + MIPS_FP_DOUBLE,
-  rDF5 = rF10 + MIPS_FP_DOUBLE,
-  rDF6 = rF12 + MIPS_FP_DOUBLE,
-  rDF7 = rF14 + MIPS_FP_DOUBLE,
+  rD0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
+  rD1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  1,
+  rD2  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
+  rD3  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  3,
+  rD4  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
+  rD5  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  5,
+  rD6  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
+  rD7  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  7,
 #if 0  // TODO: expand resource mask to enable use of all MIPS fp registers.
-  rDF8 = rF16 + MIPS_FP_DOUBLE,
-  rDF9 = rF18 + MIPS_FP_DOUBLE,
-  rDF10 = rF20 + MIPS_FP_DOUBLE,
-  rDF11 = rF22 + MIPS_FP_DOUBLE,
-  rDF12 = rF24 + MIPS_FP_DOUBLE,
-  rDF13 = rF26 + MIPS_FP_DOUBLE,
-  rDF14 = rF28 + MIPS_FP_DOUBLE,
-  rDF15 = rF30 + MIPS_FP_DOUBLE,
+  rD8  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
+  rD9  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  9,
+  rD10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+  rD11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
+  rD12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+  rD13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
+  rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+  rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
 #endif
 };
 
-const RegStorage rs_rZERO(RegStorage::k32BitSolo, rZERO);
-const RegStorage rs_rAT(RegStorage::k32BitSolo, rAT);
-const RegStorage rs_rV0(RegStorage::k32BitSolo, rV0);
-const RegStorage rs_rV1(RegStorage::k32BitSolo, rV1);
-const RegStorage rs_rA0(RegStorage::k32BitSolo, rA0);
-const RegStorage rs_rA1(RegStorage::k32BitSolo, rA1);
-const RegStorage rs_rA2(RegStorage::k32BitSolo, rA2);
-const RegStorage rs_rA3(RegStorage::k32BitSolo, rA3);
-const RegStorage rs_rT0(RegStorage::k32BitSolo, rT0);
-const RegStorage rs_rT1(RegStorage::k32BitSolo, rT1);
-const RegStorage rs_rT2(RegStorage::k32BitSolo, rT2);
-const RegStorage rs_rT3(RegStorage::k32BitSolo, rT3);
-const RegStorage rs_rT4(RegStorage::k32BitSolo, rT4);
-const RegStorage rs_rT5(RegStorage::k32BitSolo, rT5);
-const RegStorage rs_rT6(RegStorage::k32BitSolo, rT6);
-const RegStorage rs_rT7(RegStorage::k32BitSolo, rT7);
-const RegStorage rs_rS0(RegStorage::k32BitSolo, rS0);
-const RegStorage rs_rS1(RegStorage::k32BitSolo, rS1);
-const RegStorage rs_rS2(RegStorage::k32BitSolo, rS2);
-const RegStorage rs_rS3(RegStorage::k32BitSolo, rS3);
-const RegStorage rs_rS4(RegStorage::k32BitSolo, rS4);
-const RegStorage rs_rS5(RegStorage::k32BitSolo, rS5);
-const RegStorage rs_rS6(RegStorage::k32BitSolo, rS6);
-const RegStorage rs_rS7(RegStorage::k32BitSolo, rS7);
-const RegStorage rs_rT8(RegStorage::k32BitSolo, rT8);
-const RegStorage rs_rT9(RegStorage::k32BitSolo, rT9);
-const RegStorage rs_rK0(RegStorage::k32BitSolo, rK0);
-const RegStorage rs_rK1(RegStorage::k32BitSolo, rK1);
-const RegStorage rs_rGP(RegStorage::k32BitSolo, rGP);
-const RegStorage rs_rSP(RegStorage::k32BitSolo, rSP);
-const RegStorage rs_rFP(RegStorage::k32BitSolo, rFP);
-const RegStorage rs_rRA(RegStorage::k32BitSolo, rRA);
-const RegStorage rs_rF12(RegStorage::k32BitSolo, rF12);
-const RegStorage rs_rF13(RegStorage::k32BitSolo, rF13);
-const RegStorage rs_rF14(RegStorage::k32BitSolo, rF14);
-const RegStorage rs_rF15(RegStorage::k32BitSolo, rF15);
-const RegStorage rs_rF0(RegStorage::k32BitSolo, rF0);
-const RegStorage rs_rF1(RegStorage::k32BitSolo, rF1);
+constexpr RegStorage rs_rZERO(RegStorage::kValid | rZERO);
+constexpr RegStorage rs_rAT(RegStorage::kValid | rAT);
+constexpr RegStorage rs_rV0(RegStorage::kValid | rV0);
+constexpr RegStorage rs_rV1(RegStorage::kValid | rV1);
+constexpr RegStorage rs_rA0(RegStorage::kValid | rA0);
+constexpr RegStorage rs_rA1(RegStorage::kValid | rA1);
+constexpr RegStorage rs_rA2(RegStorage::kValid | rA2);
+constexpr RegStorage rs_rA3(RegStorage::kValid | rA3);
+constexpr RegStorage rs_rT0(RegStorage::kValid | rT0);
+constexpr RegStorage rs_rT1(RegStorage::kValid | rT1);
+constexpr RegStorage rs_rT2(RegStorage::kValid | rT2);
+constexpr RegStorage rs_rT3(RegStorage::kValid | rT3);
+constexpr RegStorage rs_rT4(RegStorage::kValid | rT4);
+constexpr RegStorage rs_rT5(RegStorage::kValid | rT5);
+constexpr RegStorage rs_rT6(RegStorage::kValid | rT6);
+constexpr RegStorage rs_rT7(RegStorage::kValid | rT7);
+constexpr RegStorage rs_rS0(RegStorage::kValid | rS0);
+constexpr RegStorage rs_rS1(RegStorage::kValid | rS1);
+constexpr RegStorage rs_rS2(RegStorage::kValid | rS2);
+constexpr RegStorage rs_rS3(RegStorage::kValid | rS3);
+constexpr RegStorage rs_rS4(RegStorage::kValid | rS4);
+constexpr RegStorage rs_rS5(RegStorage::kValid | rS5);
+constexpr RegStorage rs_rS6(RegStorage::kValid | rS6);
+constexpr RegStorage rs_rS7(RegStorage::kValid | rS7);
+constexpr RegStorage rs_rT8(RegStorage::kValid | rT8);
+constexpr RegStorage rs_rT9(RegStorage::kValid | rT9);
+constexpr RegStorage rs_rK0(RegStorage::kValid | rK0);
+constexpr RegStorage rs_rK1(RegStorage::kValid | rK1);
+constexpr RegStorage rs_rGP(RegStorage::kValid | rGP);
+constexpr RegStorage rs_rSP(RegStorage::kValid | rSP);
+constexpr RegStorage rs_rFP(RegStorage::kValid | rFP);
+constexpr RegStorage rs_rRA(RegStorage::kValid | rRA);
+
+constexpr RegStorage rs_rMIPS_LR(RegStorage::kInvalid);     // Not used for MIPS.
+constexpr RegStorage rs_rMIPS_PC(RegStorage::kInvalid);     // Not used for MIPS.
+constexpr RegStorage rs_rMIPS_COUNT(RegStorage::kInvalid);  // Not used for MIPS.
+
+constexpr RegStorage rs_rF0(RegStorage::kValid | rF0);
+constexpr RegStorage rs_rF1(RegStorage::kValid | rF1);
+constexpr RegStorage rs_rF2(RegStorage::kValid | rF2);
+constexpr RegStorage rs_rF3(RegStorage::kValid | rF3);
+constexpr RegStorage rs_rF4(RegStorage::kValid | rF4);
+constexpr RegStorage rs_rF5(RegStorage::kValid | rF5);
+constexpr RegStorage rs_rF6(RegStorage::kValid | rF6);
+constexpr RegStorage rs_rF7(RegStorage::kValid | rF7);
+constexpr RegStorage rs_rF8(RegStorage::kValid | rF8);
+constexpr RegStorage rs_rF9(RegStorage::kValid | rF9);
+constexpr RegStorage rs_rF10(RegStorage::kValid | rF10);
+constexpr RegStorage rs_rF11(RegStorage::kValid | rF11);
+constexpr RegStorage rs_rF12(RegStorage::kValid | rF12);
+constexpr RegStorage rs_rF13(RegStorage::kValid | rF13);
+constexpr RegStorage rs_rF14(RegStorage::kValid | rF14);
+constexpr RegStorage rs_rF15(RegStorage::kValid | rF15);
+
+constexpr RegStorage rs_rD0(RegStorage::kValid | rD0);
+constexpr RegStorage rs_rD1(RegStorage::kValid | rD1);
+constexpr RegStorage rs_rD2(RegStorage::kValid | rD2);
+constexpr RegStorage rs_rD3(RegStorage::kValid | rD3);
+constexpr RegStorage rs_rD4(RegStorage::kValid | rD4);
+constexpr RegStorage rs_rD5(RegStorage::kValid | rD5);
+constexpr RegStorage rs_rD6(RegStorage::kValid | rD6);
+constexpr RegStorage rs_rD7(RegStorage::kValid | rD7);
 
 // TODO: reduce/eliminate use of these.
 #define rMIPS_SUSPEND rS0
@@ -311,9 +315,9 @@
 #define rMIPS_FARG2 rFARG2
 #define rs_rMIPS_FARG2 rs_rFARG2
 #define rMIPS_FARG3 rFARG3
-#define rs_MIPS_FARG3 rs_rFARG3
+#define rs_rMIPS_FARG3 rs_rFARG3
 #define rMIPS_RET0 rRESULT0
-#define rs_MIPS_RET0 rs_rRESULT0
+#define rs_rMIPS_RET0 rs_rRESULT0
 #define rMIPS_RET1 rRESULT1
 #define rs_rMIPS_RET1 rs_rRESULT1
 #define rMIPS_INVOKE_TGT rT9
@@ -322,16 +326,17 @@
 
 // RegisterLocation templates return values (r_V0, or r_V0/r_V1).
 const RegLocation mips_loc_c_return
-    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
      RegStorage(RegStorage::k32BitSolo, rV0), INVALID_SREG, INVALID_SREG};
 const RegLocation mips_loc_c_return_wide
-    {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
      RegStorage(RegStorage::k64BitPair, rV0, rV1), INVALID_SREG, INVALID_SREG};
 const RegLocation mips_loc_c_return_float
-    {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1,
      RegStorage(RegStorage::k32BitSolo, rF0), INVALID_SREG, INVALID_SREG};
+// FIXME: move MIPS to k64Bitsolo for doubles
 const RegLocation mips_loc_c_return_double
-    {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1,
      RegStorage(RegStorage::k64BitPair, rF0, rF1), INVALID_SREG, INVALID_SREG};
 
 enum MipsShiftEncodings {
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 7f4cd5e..8d91aba 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -26,18 +26,40 @@
 
 namespace art {
 
-static int core_regs[] = {rZERO, rAT, rV0, rV1, rA0, rA1, rA2, rA3,
-                          rT0, rT1, rT2, rT3, rT4, rT5, rT6, rT7,
-                          rS0, rS1, rS2, rS3, rS4, rS5, rS6, rS7, rT8,
-                          rT9, rK0, rK1, rGP, rSP, rFP, rRA};
-static int ReservedRegs[] = {rZERO, rAT, rS0, rS1, rK0, rK1, rGP, rSP,
-                             rRA};
-static int core_temps[] = {rV0, rV1, rA0, rA1, rA2, rA3, rT0, rT1, rT2,
-                           rT3, rT4, rT5, rT6, rT7, rT8};
-static int FpRegs[] = {rF0, rF1, rF2, rF3, rF4, rF5, rF6, rF7,
-                       rF8, rF9, rF10, rF11, rF12, rF13, rF14, rF15};
-static int fp_temps[] = {rF0, rF1, rF2, rF3, rF4, rF5, rF6, rF7,
-                         rF8, rF9, rF10, rF11, rF12, rF13, rF14, rF15};
+static const RegStorage core_regs_arr[] =
+    {rs_rZERO, rs_rAT, rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2,
+     rs_rT3, rs_rT4, rs_rT5, rs_rT6, rs_rT7, rs_rS0, rs_rS1, rs_rS2, rs_rS3, rs_rS4, rs_rS5,
+     rs_rS6, rs_rS7, rs_rT8, rs_rT9, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rFP, rs_rRA};
+static RegStorage sp_regs_arr[] =
+    {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
+     rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
+static RegStorage dp_regs_arr[] =
+    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+static const RegStorage reserved_regs_arr[] =
+    {rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
+static RegStorage core_temps_arr[] =
+    {rs_rV0, rs_rV1, rs_rA0, rs_rA1, rs_rA2, rs_rA3, rs_rT0, rs_rT1, rs_rT2, rs_rT3, rs_rT4,
+     rs_rT5, rs_rT6, rs_rT7, rs_rT8};
+static RegStorage sp_temps_arr[] =
+    {rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
+     rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
+static RegStorage dp_temps_arr[] =
+    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+
+static const std::vector<RegStorage> core_regs(core_regs_arr,
+    core_regs_arr + sizeof(core_regs_arr) / sizeof(core_regs_arr[0]));
+static const std::vector<RegStorage> sp_regs(sp_regs_arr,
+    sp_regs_arr + sizeof(sp_regs_arr) / sizeof(sp_regs_arr[0]));
+static const std::vector<RegStorage> dp_regs(dp_regs_arr,
+    dp_regs_arr + sizeof(dp_regs_arr) / sizeof(dp_regs_arr[0]));
+static const std::vector<RegStorage> reserved_regs(reserved_regs_arr,
+    reserved_regs_arr + sizeof(reserved_regs_arr) / sizeof(reserved_regs_arr[0]));
+static const std::vector<RegStorage> core_temps(core_temps_arr,
+    core_temps_arr + sizeof(core_temps_arr) / sizeof(core_temps_arr[0]));
+static const std::vector<RegStorage> sp_temps(sp_temps_arr,
+    sp_temps_arr + sizeof(sp_temps_arr) / sizeof(sp_temps_arr[0]));
+static const std::vector<RegStorage> dp_temps(dp_temps_arr,
+    dp_temps_arr + sizeof(dp_temps_arr) / sizeof(dp_temps_arr[0]));
 
 RegLocation MipsMir2Lir::LocCReturn() {
   return mips_loc_c_return;
@@ -57,29 +79,29 @@
 
 // Return a target-dependent special register.
 RegStorage MipsMir2Lir::TargetReg(SpecialTargetRegister reg) {
-  int res_reg = RegStorage::kInvalidRegVal;
+  RegStorage res_reg;
   switch (reg) {
-    case kSelf: res_reg = rMIPS_SELF; break;
-    case kSuspend: res_reg =  rMIPS_SUSPEND; break;
-    case kLr: res_reg =  rMIPS_LR; break;
-    case kPc: res_reg =  rMIPS_PC; break;
-    case kSp: res_reg =  rMIPS_SP; break;
-    case kArg0: res_reg = rMIPS_ARG0; break;
-    case kArg1: res_reg = rMIPS_ARG1; break;
-    case kArg2: res_reg = rMIPS_ARG2; break;
-    case kArg3: res_reg = rMIPS_ARG3; break;
-    case kFArg0: res_reg = rMIPS_FARG0; break;
-    case kFArg1: res_reg = rMIPS_FARG1; break;
-    case kFArg2: res_reg = rMIPS_FARG2; break;
-    case kFArg3: res_reg = rMIPS_FARG3; break;
-    case kRet0: res_reg = rMIPS_RET0; break;
-    case kRet1: res_reg = rMIPS_RET1; break;
-    case kInvokeTgt: res_reg = rMIPS_INVOKE_TGT; break;
-    case kHiddenArg: res_reg = rT0; break;
-    case kHiddenFpArg: res_reg = RegStorage::kInvalidRegVal; break;
-    case kCount: res_reg = rMIPS_COUNT; break;
+    case kSelf: res_reg = rs_rMIPS_SELF; break;
+    case kSuspend: res_reg =  rs_rMIPS_SUSPEND; break;
+    case kLr: res_reg =  rs_rMIPS_LR; break;
+    case kPc: res_reg =  rs_rMIPS_PC; break;
+    case kSp: res_reg =  rs_rMIPS_SP; break;
+    case kArg0: res_reg = rs_rMIPS_ARG0; break;
+    case kArg1: res_reg = rs_rMIPS_ARG1; break;
+    case kArg2: res_reg = rs_rMIPS_ARG2; break;
+    case kArg3: res_reg = rs_rMIPS_ARG3; break;
+    case kFArg0: res_reg = rs_rMIPS_FARG0; break;
+    case kFArg1: res_reg = rs_rMIPS_FARG1; break;
+    case kFArg2: res_reg = rs_rMIPS_FARG2; break;
+    case kFArg3: res_reg = rs_rMIPS_FARG3; break;
+    case kRet0: res_reg = rs_rMIPS_RET0; break;
+    case kRet1: res_reg = rs_rMIPS_RET1; break;
+    case kInvokeTgt: res_reg = rs_rMIPS_INVOKE_TGT; break;
+    case kHiddenArg: res_reg = rs_rT0; break;
+    case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
+    case kCount: res_reg = rs_rMIPS_COUNT; break;
   }
-  return RegStorage::Solo32(res_reg);
+  return res_reg;
 }
 
 RegStorage MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
@@ -96,35 +118,22 @@
   }
 }
 
-// Create a double from a pair of singles.
-int MipsMir2Lir::S2d(int low_reg, int high_reg) {
-  return MIPS_S2D(low_reg, high_reg);
-}
-
-// Return mask to strip off fp reg flags and bias.
-uint32_t MipsMir2Lir::FpRegMask() {
-  return MIPS_FP_REG_MASK;
-}
-
-// True if both regs single, both core or both double.
-bool MipsMir2Lir::SameRegType(int reg1, int reg2) {
-  return (MIPS_REGTYPE(reg1) == MIPS_REGTYPE(reg2));
-}
-
 /*
  * Decode the register id.
  */
-uint64_t MipsMir2Lir::GetRegMaskCommon(int reg) {
+uint64_t MipsMir2Lir::GetRegMaskCommon(RegStorage reg) {
   uint64_t seed;
   int shift;
-  int reg_id;
-
-
-  reg_id = reg & 0x1f;
+  int reg_id = reg.GetRegNum();
   /* Each double register is equal to a pair of single-precision FP registers */
-  seed = MIPS_DOUBLEREG(reg) ? 3 : 1;
-  /* FP register starts at bit position 16 */
-  shift = MIPS_FPREG(reg) ? kMipsFPReg0 : 0;
+  if (reg.IsDouble()) {
+    seed = 0x3;
+    reg_id = reg_id << 1;
+  } else {
+    seed = 1;
+  }
+  /* FP register starts at bit position 32 */
+  shift = reg.IsFloat() ? kMipsFPReg0 : 0;
   /* Expand the double register id into single offset */
   shift += reg_id;
   return (seed << shift);
@@ -209,11 +218,11 @@
              }
              break;
            case 's':
-             snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
+             snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
              break;
            case 'S':
-             DCHECK_EQ(((operand & MIPS_FP_REG_MASK) & 1), 0);
-             snprintf(tbuf, arraysize(tbuf), "$f%d", operand & MIPS_FP_REG_MASK);
+             DCHECK_EQ(RegStorage::RegNum(operand) & 1, 0);
+             snprintf(tbuf, arraysize(tbuf), "$f%d", RegStorage::RegNum(operand));
              break;
            case 'h':
              snprintf(tbuf, arraysize(tbuf), "%04x", operand);
@@ -327,7 +336,7 @@
  */
 
 void MipsMir2Lir::AdjustSpillMask() {
-  core_spill_mask_ |= (1 << rRA);
+  core_spill_mask_ |= (1 << rs_rRA.GetRegNum());
   num_core_spills_++;
 }
 
@@ -337,92 +346,63 @@
  * include any holes in the mask.  Associate holes with
  * Dalvik register INVALID_VREG (0xFFFFU).
  */
-void MipsMir2Lir::MarkPreservedSingle(int s_reg, int reg) {
+void MipsMir2Lir::MarkPreservedSingle(int s_reg, RegStorage reg) {
   LOG(FATAL) << "No support yet for promoted FP regs";
 }
 
-void MipsMir2Lir::FlushRegWide(RegStorage reg) {
-  RegisterInfo* info1 = GetRegInfo(reg.GetLowReg());
-  RegisterInfo* info2 = GetRegInfo(reg.GetHighReg());
-  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->is_temp && info2->is_temp)) {
-      /* Should not happen.  If it does, there's a problem in eval_loc */
-      LOG(FATAL) << "Long half-temp, half-promoted";
-    }
-
-    info1->dirty = false;
-    info2->dirty = false;
-    if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
-      info1 = info2;
-    int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
-    StoreBaseDispWide(rs_rMIPS_SP, VRegOffset(v_reg),
-                      RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner));
-  }
-}
-
-void MipsMir2Lir::FlushReg(RegStorage reg) {
-  DCHECK(!reg.IsPair());
-  RegisterInfo* info = GetRegInfo(reg.GetReg());
-  if (info->live && info->dirty) {
-    info->dirty = false;
-    int v_reg = mir_graph_->SRegToVReg(info->s_reg);
-    Store32Disp(rs_rMIPS_SP, VRegOffset(v_reg), reg);
-  }
-}
-
-/* Give access to the target-dependent FP register encoding to common code */
-bool MipsMir2Lir::IsFpReg(int reg) {
-  return MIPS_FPREG(reg);
-}
-
-bool MipsMir2Lir::IsFpReg(RegStorage reg) {
-  return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg());
+void MipsMir2Lir::MarkPreservedDouble(int s_reg, RegStorage reg) {
+  LOG(FATAL) << "No support yet for promoted FP regs";
 }
 
 /* Clobber all regs that might be used by an external C call */
 void MipsMir2Lir::ClobberCallerSave() {
-  Clobber(rZERO);
-  Clobber(rAT);
-  Clobber(rV0);
-  Clobber(rV1);
-  Clobber(rA0);
-  Clobber(rA1);
-  Clobber(rA2);
-  Clobber(rA3);
-  Clobber(rT0);
-  Clobber(rT1);
-  Clobber(rT2);
-  Clobber(rT3);
-  Clobber(rT4);
-  Clobber(rT5);
-  Clobber(rT6);
-  Clobber(rT7);
-  Clobber(rT8);
-  Clobber(rT9);
-  Clobber(rK0);
-  Clobber(rK1);
-  Clobber(rGP);
-  Clobber(rFP);
-  Clobber(rRA);
-  Clobber(rF0);
-  Clobber(rF1);
-  Clobber(rF2);
-  Clobber(rF3);
-  Clobber(rF4);
-  Clobber(rF5);
-  Clobber(rF6);
-  Clobber(rF7);
-  Clobber(rF8);
-  Clobber(rF9);
-  Clobber(rF10);
-  Clobber(rF11);
-  Clobber(rF12);
-  Clobber(rF13);
-  Clobber(rF14);
-  Clobber(rF15);
+  Clobber(rs_rZERO);
+  Clobber(rs_rAT);
+  Clobber(rs_rV0);
+  Clobber(rs_rV1);
+  Clobber(rs_rA0);
+  Clobber(rs_rA1);
+  Clobber(rs_rA2);
+  Clobber(rs_rA3);
+  Clobber(rs_rT0);
+  Clobber(rs_rT1);
+  Clobber(rs_rT2);
+  Clobber(rs_rT3);
+  Clobber(rs_rT4);
+  Clobber(rs_rT5);
+  Clobber(rs_rT6);
+  Clobber(rs_rT7);
+  Clobber(rs_rT8);
+  Clobber(rs_rT9);
+  Clobber(rs_rK0);
+  Clobber(rs_rK1);
+  Clobber(rs_rGP);
+  Clobber(rs_rFP);
+  Clobber(rs_rRA);
+  Clobber(rs_rF0);
+  Clobber(rs_rF1);
+  Clobber(rs_rF2);
+  Clobber(rs_rF3);
+  Clobber(rs_rF4);
+  Clobber(rs_rF5);
+  Clobber(rs_rF6);
+  Clobber(rs_rF7);
+  Clobber(rs_rF8);
+  Clobber(rs_rF9);
+  Clobber(rs_rF10);
+  Clobber(rs_rF11);
+  Clobber(rs_rF12);
+  Clobber(rs_rF13);
+  Clobber(rs_rF14);
+  Clobber(rs_rF15);
+  Clobber(rs_rD0);
+  Clobber(rs_rD1);
+  Clobber(rs_rD2);
+  Clobber(rs_rD3);
+  Clobber(rs_rD4);
+  Clobber(rs_rD5);
+  Clobber(rs_rD6);
+  Clobber(rs_rD7);
 }
 
 RegLocation MipsMir2Lir::GetReturnWideAlt() {
@@ -439,18 +419,18 @@
 
 /* To be used when explicitly managing register use */
 void MipsMir2Lir::LockCallTemps() {
-  LockTemp(rMIPS_ARG0);
-  LockTemp(rMIPS_ARG1);
-  LockTemp(rMIPS_ARG2);
-  LockTemp(rMIPS_ARG3);
+  LockTemp(rs_rMIPS_ARG0);
+  LockTemp(rs_rMIPS_ARG1);
+  LockTemp(rs_rMIPS_ARG2);
+  LockTemp(rs_rMIPS_ARG3);
 }
 
 /* To be used when explicitly managing register use */
 void MipsMir2Lir::FreeCallTemps() {
-  FreeTemp(rMIPS_ARG0);
-  FreeTemp(rMIPS_ARG1);
-  FreeTemp(rMIPS_ARG2);
-  FreeTemp(rMIPS_ARG3);
+  FreeTemp(rs_rMIPS_ARG0);
+  FreeTemp(rs_rMIPS_ARG1);
+  FreeTemp(rs_rMIPS_ARG2);
+  FreeTemp(rs_rMIPS_ARG3);
 }
 
 void MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
@@ -461,56 +441,52 @@
 
 // Alloc a pair of core registers, or a double.
 RegStorage MipsMir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) {
-  int high_reg;
-  int low_reg;
-
   if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
     return AllocTempDouble();
   }
 
-  low_reg = AllocTemp().GetReg();
-  high_reg = AllocTemp().GetReg();
-  return RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
+  RegStorage low_reg = AllocTemp();
+  RegStorage high_reg = AllocTemp();
+  return RegStorage::MakeRegPair(low_reg, high_reg);
 }
 
 RegStorage MipsMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
   if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
-    return AllocTempFloat();
-}
+    return AllocTempSingle();
+  }
   return AllocTemp();
 }
 
 void MipsMir2Lir::CompilerInitializeRegAlloc() {
-  int num_regs = sizeof(core_regs)/sizeof(*core_regs);
-  int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
-  int num_temps = sizeof(core_temps)/sizeof(*core_temps);
-  int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
-  int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
-  reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
-                                                       kArenaAllocRegAlloc));
-  reg_pool_->num_core_regs = num_regs;
-  reg_pool_->core_regs = static_cast<RegisterInfo*>
-     (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc));
-  reg_pool_->num_fp_regs = num_fp_regs;
-  reg_pool_->FPRegs = static_cast<RegisterInfo*>
-      (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc));
-  CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
-  CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
-  // Keep special registers from being allocated
-  for (int i = 0; i < num_reserved; i++) {
-    if (NO_SUSPEND && (ReservedRegs[i] == rMIPS_SUSPEND)) {
-      // To measure cost of suspend check
-      continue;
+  reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, sp_regs, dp_regs, reserved_regs,
+                                        core_temps, sp_temps, dp_temps);
+
+  // Target-specific adjustments.
+
+  // Alias single precision floats to appropriate half of overlapping double.
+  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    int sp_reg_num = info->GetReg().GetRegNum();
+    int dp_reg_num = sp_reg_num >> 1;
+    RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
+    RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
+    // Double precision register's master storage should refer to itself.
+    DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
+    // Redirect single precision's master storage to master.
+    info->SetMaster(dp_reg_info);
+    // Singles should show a single 32-bit mask bit, at first referring to the low half.
+    DCHECK_EQ(info->StorageMask(), 0x1U);
+    if (sp_reg_num & 1) {
+      // For odd singles, change to user the high word of the backing double.
+      info->SetStorageMask(0x2);
     }
-    MarkInUse(ReservedRegs[i]);
   }
-  // Mark temp regs - all others not in use can be used for promotion
-  for (int i = 0; i < num_temps; i++) {
-    MarkTemp(core_temps[i]);
-  }
-  for (int i = 0; i < num_fp_temps; i++) {
-    MarkTemp(fp_temps[i]);
-  }
+
+  // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
+  // TODO: adjust when we roll to hard float calling convention.
+  reg_pool_->next_core_reg_ = 2;
+  reg_pool_->next_sp_reg_ = 2;
+  reg_pool_->next_dp_reg_ = 1;
 }
 
 void MipsMir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index a865430..50b945a 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -24,12 +24,12 @@
 LIR* MipsMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
   int opcode;
   /* must be both DOUBLE or both not DOUBLE */
-  DCHECK_EQ(MIPS_DOUBLEREG(r_dest.GetReg()), MIPS_DOUBLEREG(r_src.GetReg()));
-  if (MIPS_DOUBLEREG(r_dest.GetReg())) {
+  DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
+  if (r_dest.IsDouble()) {
     opcode = kMipsFmovd;
   } else {
-    if (MIPS_SINGLEREG(r_dest.GetReg())) {
-      if (MIPS_SINGLEREG(r_src.GetReg())) {
+    if (r_dest.IsSingle()) {
+      if (r_src.IsSingle()) {
         opcode = kMipsFmovs;
       } else {
         /* note the operands are swapped for the mtc1 instr */
@@ -39,7 +39,7 @@
         opcode = kMipsMtc1;
       }
     } else {
-      DCHECK(MIPS_SINGLEREG(r_src.GetReg()));
+      DCHECK(r_src.IsSingle());
       opcode = kMipsMfc1;
     }
   }
@@ -79,9 +79,9 @@
   LIR *res;
 
   RegStorage r_dest_save = r_dest;
-  int is_fp_reg = MIPS_FPREG(r_dest.GetReg());
+  int is_fp_reg = r_dest.IsFloat();
   if (is_fp_reg) {
-    DCHECK(MIPS_SINGLEREG(r_dest.GetReg()));
+    DCHECK(r_dest.IsSingle());
     r_dest = AllocTemp();
   }
 
@@ -355,8 +355,8 @@
   MipsOpCode opcode = kMipsNop;
   RegStorage t_reg = AllocTemp();
 
-  if (MIPS_FPREG(r_dest.GetReg())) {
-    DCHECK(MIPS_SINGLEREG(r_dest.GetReg()));
+  if (r_dest.IsFloat()) {
+    DCHECK(r_dest.IsSingle());
     DCHECK((size == k32) || (size == kSingle) || (size == kReference));
     size = kSingle;
   } else {
@@ -407,8 +407,8 @@
   MipsOpCode opcode = kMipsNop;
   RegStorage t_reg = AllocTemp();
 
-  if (MIPS_FPREG(r_src.GetReg())) {
-    DCHECK(MIPS_SINGLEREG(r_src.GetReg()));
+  if (r_src.IsFloat()) {
+    DCHECK(r_src.IsSingle());
     DCHECK((size == k32) || (size == kSingle) || (size == kReference));
     size = kSingle;
   } else {
@@ -469,16 +469,16 @@
     case kDouble:
       pair = true;
       opcode = kMipsLw;
-      if (MIPS_FPREG(r_dest.GetReg())) {
+      if (r_dest.IsFloat()) {
         opcode = kMipsFlwc1;
-        if (MIPS_DOUBLEREG(r_dest.GetReg())) {
-          // TODO: rework to use k64BitSolo
-          r_dest.SetReg(r_dest.GetReg() - MIPS_FP_DOUBLE);
+        if (r_dest.IsDouble()) {
+          int reg_num = (r_dest.GetRegNum() << 1) | RegStorage::kFloatingPoint;
+          r_dest = RegStorage(RegStorage::k64BitSolo, reg_num, reg_num + 1);
         } else {
-          DCHECK(MIPS_FPREG(r_dest_hi.GetReg()));
+          DCHECK(r_dest_hi.IsFloat());
           DCHECK_EQ(r_dest.GetReg(), r_dest_hi.GetReg() - 1);
+          r_dest_hi.SetReg(r_dest.GetReg() + 1);
         }
-        r_dest_hi.SetReg(r_dest.GetReg() + 1);
       }
       short_form = IS_SIMM16_2WORD(displacement);
       DCHECK_EQ((displacement & 0x3), 0);
@@ -487,9 +487,9 @@
     case kSingle:
     case kReference:
       opcode = kMipsLw;
-      if (MIPS_FPREG(r_dest.GetReg())) {
+      if (r_dest.IsFloat()) {
         opcode = kMipsFlwc1;
-        DCHECK(MIPS_SINGLEREG(r_dest.GetReg()));
+        DCHECK(r_dest.IsSingle());
       }
       DCHECK_EQ((displacement & 0x3), 0);
       break;
@@ -567,22 +567,22 @@
   LIR *store2 = NULL;
   MipsOpCode opcode = kMipsNop;
   bool short_form = IS_SIMM16(displacement);
-  bool pair = false;
+  bool pair = r_src.IsPair();
 
   switch (size) {
     case k64:
     case kDouble:
-      pair = true;
       opcode = kMipsSw;
-      if (MIPS_FPREG(r_src.GetReg())) {
+      if (r_src.IsFloat()) {
         opcode = kMipsFswc1;
-        if (MIPS_DOUBLEREG(r_src.GetReg())) {
-          r_src.SetReg(r_src.GetReg() - MIPS_FP_DOUBLE);
+        if (r_src.IsDouble()) {
+          int reg_num = (r_src.GetRegNum() << 1) | RegStorage::kFloatingPoint;
+          r_src = RegStorage(RegStorage::k64BitPair, reg_num, reg_num + 1);
         } else {
-          DCHECK(MIPS_FPREG(r_src_hi.GetReg()));
+          DCHECK(r_src_hi.IsFloat());
           DCHECK_EQ(r_src.GetReg(), (r_src_hi.GetReg() - 1));
+          r_src_hi.SetReg(r_src.GetReg() + 1);
         }
-        r_src_hi.SetReg(r_src.GetReg() + 1);
       }
       short_form = IS_SIMM16_2WORD(displacement);
       DCHECK_EQ((displacement & 0x3), 0);
@@ -591,9 +591,9 @@
     case kSingle:
     case kReference:
       opcode = kMipsSw;
-      if (MIPS_FPREG(r_src.GetReg())) {
+      if (r_src.IsFloat()) {
         opcode = kMipsFswc1;
-        DCHECK(MIPS_SINGLEREG(r_src.GetReg()));
+        DCHECK(r_src.IsSingle());
       }
       DCHECK_EQ((displacement & 0x3), 0);
       break;
@@ -665,8 +665,7 @@
 }
 
 LIR* MipsMir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
-                                       int displacement, RegStorage r_src, RegStorage r_src_hi,
-                                       OpSize size, int s_reg) {
+                                       int displacement, RegStorage r_src, OpSize size, int s_reg) {
   LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for MIPS";
   return NULL;
 }
@@ -677,8 +676,7 @@
 }
 
 LIR* MipsMir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
-                                      int displacement, RegStorage r_dest, RegStorage r_dest_hi,
-                                      OpSize size, int s_reg) {
+                                      int displacement, RegStorage r_dest, OpSize size, int s_reg) {
   LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for MIPS";
   return NULL;
 }
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index b2362fc..f5d71c4 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -25,20 +25,21 @@
 
 /* Mark a temp register as dead.  Does not affect allocation state. */
 inline void Mir2Lir::ClobberBody(RegisterInfo* p) {
-  if (p->is_temp) {
-    DCHECK(!(p->live && p->dirty))  << "Live & dirty temp in clobber";
-    p->live = false;
-    p->s_reg = INVALID_SREG;
-    p->def_start = NULL;
-    p->def_end = NULL;
-    if (p->pair) {
-      p->pair = false;
-      p = GetRegInfo(p->partner);
-      p->pair = false;
-      p->live = false;
-      p->s_reg = INVALID_SREG;
-      p->def_start = NULL;
-      p->def_end = NULL;
+  if (p->IsTemp()) {
+    DCHECK(!(p->IsLive() && p->IsDirty()))  << "Live & dirty temp in clobber";
+    p->SetIsLive(false);
+    p->SetSReg(INVALID_SREG);
+    p->ResetDefBody();
+    if (p->IsWide()) {
+      p->SetIsWide(false);
+      if (p->GetReg() != p->Partner()) {
+        // Register pair - deal with the other half.
+        p = GetRegInfo(p->Partner());
+        p->SetIsWide(false);
+        p->SetIsLive(false);
+        p->SetSReg(INVALID_SREG);
+        p->ResetDefBody();
+      }
     }
   }
 }
@@ -143,7 +144,9 @@
  * Mark the corresponding bit(s).
  */
 inline void Mir2Lir::SetupRegMask(uint64_t* mask, int reg) {
-  *mask |= GetRegMaskCommon(reg);
+  DCHECK_EQ((reg & ~RegStorage::kRegValMask), 0);
+  DCHECK(reginfo_map_.Get(reg) != nullptr) << "No info for 0x" << reg;
+  *mask |= reginfo_map_.Get(reg)->DefUseMask();
 }
 
 /*
@@ -228,9 +231,11 @@
   SetupTargetResourceMasks(lir, flags);
 }
 
-inline art::Mir2Lir::RegisterInfo* Mir2Lir::GetRegInfo(int reg) {
-  DCHECK(reginfo_map_.Get(reg) != NULL);
-  return reginfo_map_.Get(reg);
+inline art::Mir2Lir::RegisterInfo* Mir2Lir::GetRegInfo(RegStorage reg) {
+  RegisterInfo* res = reg.IsPair() ? reginfo_map_.Get(reg.GetLowReg()) :
+      reginfo_map_.Get(reg.GetReg());
+  DCHECK(res != nullptr);
+  return res;
 }
 
 }  // namespace art
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 6c5279e..c9e1950 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -286,7 +286,7 @@
   // Prep Src and Dest locations.
   int next_sreg = 0;
   int next_loc = 0;
-  uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode];
+  uint64_t attrs = MIRGraph::GetDataFlowAttributes(opcode);
   rl_src[0] = rl_src[1] = rl_src[2] = mir_graph_->GetBadLoc();
   if (attrs & DF_UA) {
     if (attrs & DF_A_WIDE) {
@@ -991,8 +991,7 @@
     if (cu_->disable_opt & (1 << kTrackLiveTemps)) {
       ClobberAllRegs();
       // Reset temp allocation to minimize differences when A/B testing.
-      reg_pool_->next_core_reg = 0;
-      reg_pool_->next_fp_reg = 0;
+      reg_pool_->ResetNextTemp();
     }
 
     if (cu_->disable_opt & (1 << kSuppressLoads)) {
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 9283a29..cb4396f 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -241,32 +241,151 @@
     };
 
     /*
-     * 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.
+     * Data structure tracking the mapping detween a Dalvik value (32 or 64 bits)
+     * and native register storage.  The primary purpose is to reuse previuosly
+     * loaded values, if possible, and otherwise to keep the value in register
+     * storage as long as possible.
+     *
+     * NOTE 1: wide_value refers to the width of the Dalvik value contained in
+     * this register (or pair).  For example, a 64-bit register containing a 32-bit
+     * Dalvik value would have wide_value==false even though the storage container itself
+     * is wide.  Similarly, a 32-bit register containing half of a 64-bit Dalvik value
+     * would have wide_value==true (and additionally would have its partner field set to the
+     * other half whose wide_value field would also be true.
+     *
+     * NOTE 2: In the case of a register pair, you can determine which of the partners
+     * is the low half by looking at the s_reg names.  The high s_reg will equal low_sreg + 1.
+     *
+     * NOTE 3: In the case of a 64-bit register holding a Dalvik wide value, wide_value
+     * will be true and partner==self.  s_reg refers to the low-order word of the Dalvik
+     * value, and the s_reg of the high word is implied (s_reg + 1).
+     *
+     * NOTE 4: The reg and is_temp fields should always be correct.  If is_temp is false no
+     * other fields have meaning. [perhaps not true, wide should work for promoted regs?]
+     * If is_temp==true and live==false, no other fields have
+     * meaning.  If is_temp==true and live==true, wide_value, partner, dirty, s_reg, def_start
+     * and def_end describe the relationship between the temp register/register pair and
+     * the Dalvik value[s] described by s_reg/s_reg+1.
+     *
+     * The fields used_storage, master_storage and storage_mask are used to track allocation
+     * in light of potential aliasing.  For example, consider Arm's d2, which overlaps s4 & s5.
+     * d2's storage mask would be 0x00000003, the two low-order bits denoting 64 bits of
+     * storage use.  For s4, it would be 0x0000001; for s5 0x00000002.  These values should not
+     * change once initialized.  The "used_storage" field tracks current allocation status.
+     * Although each record contains this field, only the field from the largest member of
+     * an aliased group is used.  In our case, it would be d2's.  The master_storage pointer
+     * of d2, s4 and s5 would all point to d2's used_storage field.  Each bit in a used_storage
+     * represents 32 bits of storage.  d2's used_storage would be initialized to 0xfffffffc.
+     * Then, if we wanted to determine whether s4 could be allocated, we would "and"
+     * s4's storage_mask with s4's *master_storage.  If the result is zero, s4 is free and
+     * to allocate: *master_storage |= storage_mask.  To free, *master_storage &= ~storage_mask.
+     *
+     * For an X86 vector register example, storage_mask would be:
+     *    0x00000001 for 32-bit view of xmm1
+     *    0x00000003 for 64-bit view of xmm1
+     *    0x0000000f for 128-bit view of xmm1
+     *    0x000000ff for 256-bit view of ymm1   // future expansion, if needed
+     *    0x0000ffff for 512-bit view of ymm1   // future expansion, if needed
+     *    0xffffffff for 1024-bit view of ymm1  // future expansion, if needed
+     *
+     * NOTE: the x86 usage is still somewhat in flux.  There are competing notions of how
+     * to treat xmm registers:
+     *     1. Treat them all as 128-bits wide, but denote how much data used via bytes field.
+     *         o This more closely matches reality, but means you'd need to be able to get
+     *           to the associated RegisterInfo struct to figure out how it's being used.
+     *         o This is how 64-bit core registers will be used - always 64 bits, but the
+     *           "bytes" field will be 4 for 32-bit usage and 8 for 64-bit usage.
+     *     2. View the xmm registers based on contents.
+     *         o A single in a xmm2 register would be k32BitVector, while a double in xmm2 would
+     *           be a k64BitVector.
+     *         o Note that the two uses above would be considered distinct registers (but with
+     *           the aliasing mechanism, we could detect interference).
+     *         o This is how aliased double and single float registers will be handled on
+     *           Arm and MIPS.
+     * Working plan is, for all targets, to follow mechanism 1 for 64-bit core registers, and
+     * mechanism 2 for aliased float registers and x86 vector registers.
      */
-    struct RegisterInfo {
-      int reg;                    // Reg number
-      bool in_use;                // Has it been allocated?
-      bool is_temp;               // 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 s_reg;                  // Name of live value.
-      LIR *def_start;             // Starting inst in last def sequence.
-      LIR *def_end;               // Ending inst in last def sequence.
+    class RegisterInfo {
+     public:
+      RegisterInfo(RegStorage r, uint64_t mask = ENCODE_ALL);
+      ~RegisterInfo() {}
+      static void* operator new(size_t size, ArenaAllocator* arena) {
+        return arena->Alloc(size, kArenaAllocRegAlloc);
+      }
+
+      bool InUse() { return (storage_mask_ & master_->used_storage_) != 0; }
+      void MarkInUse() { master_->used_storage_ |= storage_mask_; }
+      void MarkFree() { master_->used_storage_ &= ~storage_mask_; }
+      RegStorage GetReg() { return reg_; }
+      void SetReg(RegStorage reg) { reg_ = reg; }
+      bool IsTemp() { return is_temp_; }
+      void SetIsTemp(bool val) { is_temp_ = val; }
+      bool IsWide() { return wide_value_; }
+      void SetIsWide(bool val) { wide_value_ = val; }
+      bool IsLive() { return live_; }
+      void SetIsLive(bool val) { live_ = val; }
+      bool IsDirty() { return dirty_; }
+      void SetIsDirty(bool val) { dirty_ = val; }
+      RegStorage Partner() { return partner_; }
+      void SetPartner(RegStorage partner) { partner_ = partner; }
+      int SReg() { return s_reg_; }
+      void SetSReg(int s_reg) { s_reg_ = s_reg; }
+      uint64_t DefUseMask() { return def_use_mask_; }
+      void SetDefUseMask(uint64_t def_use_mask) { def_use_mask_ = def_use_mask; }
+      RegisterInfo* Master() { return master_; }
+      void SetMaster(RegisterInfo* master) { master_ = master; }
+      uint32_t StorageMask() { return storage_mask_; }
+      void SetStorageMask(uint32_t storage_mask) { storage_mask_ = storage_mask; }
+      LIR* DefStart() { return def_start_; }
+      void SetDefStart(LIR* def_start) { def_start_ = def_start; }
+      LIR* DefEnd() { return def_end_; }
+      void SetDefEnd(LIR* def_end) { def_end_ = def_end; }
+      void ResetDefBody() { def_start_ = def_end_ = nullptr; }
+
+
+     private:
+      RegStorage reg_;
+      bool is_temp_;               // Can allocate as temp?
+      bool wide_value_;            // Holds a Dalvik wide value (either itself, or part of a pair).
+      bool live_;                  // Is there an associated SSA name?
+      bool dirty_;                 // If live, is it dirty?
+      RegStorage partner_;         // If wide_value, other reg of pair or self if 64-bit register.
+      int s_reg_;                  // Name of live value.
+      uint64_t def_use_mask_;      // Resources for this element.
+      uint32_t used_storage_;      // 1 bit per 4 bytes of storage. Unused by aliases.
+      RegisterInfo* master_;       // Pointer to controlling storage mask.
+      uint32_t storage_mask_;      // Track allocation of sub-units.
+      LIR *def_start_;             // Starting inst in last def sequence.
+      LIR *def_end_;               // Ending inst in last def sequence.
     };
 
-    struct RegisterPool {
-       int num_core_regs;
-       RegisterInfo *core_regs;
-       int next_core_reg;
-       int num_fp_regs;
-       RegisterInfo *FPRegs;
-       int next_fp_reg;
-     };
+    class RegisterPool {
+     public:
+      RegisterPool(Mir2Lir* m2l, ArenaAllocator* arena, const std::vector<RegStorage>& core_regs,
+                   const std::vector<RegStorage>& sp_regs, const std::vector<RegStorage>& dp_regs,
+                   const std::vector<RegStorage>& reserved_regs,
+                   const std::vector<RegStorage>& core_temps,
+                   const std::vector<RegStorage>& sp_temps,
+                   const std::vector<RegStorage>& dp_temps);
+      ~RegisterPool() {}
+      static void* operator new(size_t size, ArenaAllocator* arena) {
+        return arena->Alloc(size, kArenaAllocRegAlloc);
+      }
+      void ResetNextTemp() {
+        next_core_reg_ = 0;
+        next_sp_reg_ = 0;
+        next_dp_reg_ = 0;
+      }
+      GrowableArray<RegisterInfo*> core_regs_;
+      int next_core_reg_;
+      GrowableArray<RegisterInfo*> sp_regs_;    // Single precision float.
+      int next_sp_reg_;
+      GrowableArray<RegisterInfo*> dp_regs_;    // Double precision float.
+      int next_dp_reg_;
+
+     private:
+      Mir2Lir* const m2l_;
+    };
 
     struct PromotionMap {
       RegLocationType core_location:3;
@@ -339,7 +458,14 @@
       return *reinterpret_cast<const int32_t*>(switch_data);
     }
 
-    RegisterClass oat_reg_class_by_size(OpSize size) {
+    /*
+     * TODO: this is a trace JIT vestige, and its use should be reconsidered.  At the time
+     * it was introduced, it was intended to be a quick best guess of type without having to
+     * take the time to do type analysis.  Currently, though, we have a much better idea of
+     * the types of Dalvik virtual registers.  Instead of using this for a best guess, why not
+     * just use our knowledge of type to select the most appropriate register class?
+     */
+    RegisterClass RegClassBySize(OpSize size) {
       return (size == kUnsignedHalf || size == kSignedHalf || size == kUnsignedByte ||
               size == kSignedByte) ? kCoreReg : kAnyReg;
     }
@@ -459,75 +585,63 @@
 
     // Shared by all targets - implemented in ralloc_util.cc
     int GetSRegHi(int lowSreg);
-    bool oat_live_out(int s_reg);
-    int oatSSASrc(MIR* mir, int num);
+    bool LiveOut(int s_reg);
     void SimpleRegAlloc();
     void ResetRegPool();
-    void CompilerInitPool(RegisterInfo* regs, int* reg_nums, int num);
-    void DumpRegPool(RegisterInfo* p, int num_regs);
+    void CompilerInitPool(RegisterInfo* info, RegStorage* regs, int num);
+    void DumpRegPool(GrowableArray<RegisterInfo*>* regs);
     void DumpCoreRegPool();
     void DumpFpRegPool();
+    void DumpRegPools();
     /* Mark a temp register as dead.  Does not affect allocation state. */
-    void Clobber(int reg) {
-      ClobberBody(GetRegInfo(reg));
-    }
     void Clobber(RegStorage reg);
-    void ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg);
+    void ClobberSRegBody(GrowableArray<RegisterInfo*>* regs, int s_reg);
     void ClobberSReg(int s_reg);
     int SRegToPMap(int s_reg);
     void RecordCorePromotion(RegStorage reg, int s_reg);
     RegStorage AllocPreservedCoreReg(int s_reg);
-    void RecordFpPromotion(RegStorage reg, int s_reg);
+    void RecordSinglePromotion(RegStorage reg, int s_reg);
+    void RecordDoublePromotion(RegStorage reg, int s_reg);
     RegStorage AllocPreservedSingle(int s_reg);
-    RegStorage AllocPreservedDouble(int s_reg);
-    RegStorage AllocTempBody(RegisterInfo* p, int num_regs, int* next_temp, bool required);
-    virtual RegStorage AllocTempDouble();
+    virtual RegStorage AllocPreservedDouble(int s_reg);
+    RegStorage AllocTempBody(GrowableArray<RegisterInfo*> &regs, int* next_temp, bool required);
     RegStorage AllocFreeTemp();
     RegStorage AllocTemp();
-    RegStorage AllocTempFloat();
-    RegisterInfo* AllocLiveBody(RegisterInfo* p, int num_regs, int s_reg);
-    RegisterInfo* AllocLive(int s_reg, int reg_class);
-    void FreeTemp(int reg);
+    RegStorage AllocTempSingle();
+    RegStorage AllocTempDouble();
+    void FlushReg(RegStorage reg);
+    void FlushRegWide(RegStorage reg);
+    RegStorage AllocLiveReg(int s_reg, int reg_class, bool wide);
+    RegStorage FindLiveReg(GrowableArray<RegisterInfo*> &regs, int s_reg);
     void FreeTemp(RegStorage reg);
-    RegisterInfo* IsLive(int reg);
     bool IsLive(RegStorage reg);
-    RegisterInfo* IsTemp(int reg);
     bool IsTemp(RegStorage reg);
-    RegisterInfo* IsPromoted(int reg);
     bool IsPromoted(RegStorage reg);
-    bool IsDirty(int reg);
     bool IsDirty(RegStorage reg);
-    void LockTemp(int reg);
     void LockTemp(RegStorage reg);
-    void ResetDef(int reg);
     void ResetDef(RegStorage reg);
-    void NullifyRange(LIR *start, LIR *finish, int s_reg1, int s_reg2);
+    void NullifyRange(RegStorage reg, int s_reg);
     void MarkDef(RegLocation rl, LIR *start, LIR *finish);
     void MarkDefWide(RegLocation rl, LIR *start, LIR *finish);
     RegLocation WideToNarrow(RegLocation rl);
     void ResetDefLoc(RegLocation rl);
-    virtual void ResetDefLocWide(RegLocation rl);
+    void ResetDefLocWide(RegLocation rl);
     void ResetDefTracking();
     void ClobberAllRegs();
     void FlushSpecificReg(RegisterInfo* info);
-    void FlushAllRegsBody(RegisterInfo* info, int num_regs);
     void FlushAllRegs();
     bool RegClassMatches(int reg_class, RegStorage reg);
-    void MarkLive(RegStorage reg, int s_reg);
-    void MarkTemp(int reg);
+    void MarkLive(RegLocation loc);
+    void MarkLiveReg(RegStorage reg, int s_reg);
     void MarkTemp(RegStorage reg);
-    void UnmarkTemp(int reg);
     void UnmarkTemp(RegStorage reg);
-    void MarkPair(int low_reg, int high_reg);
+    void MarkWide(RegStorage reg);
     void MarkClean(RegLocation loc);
     void MarkDirty(RegLocation loc);
-    void MarkInUse(int reg);
     void MarkInUse(RegStorage reg);
-    void CopyRegInfo(int new_reg, int old_reg);
-    void CopyRegInfo(RegStorage new_reg, RegStorage old_reg);
     bool CheckCorePoolSanity();
     RegLocation UpdateLoc(RegLocation loc);
-    virtual RegLocation UpdateLocWide(RegLocation loc);
+    RegLocation UpdateLocWide(RegLocation loc);
     RegLocation UpdateRawLoc(RegLocation loc);
 
     /**
@@ -538,7 +652,7 @@
      * @param update Whether the liveness information should be updated.
      * @return Returns the properly typed temporary in physical register pairs.
      */
-    virtual RegLocation EvalLocWide(RegLocation loc, int reg_class, bool update);
+    RegLocation EvalLocWide(RegLocation loc, int reg_class, bool update);
 
     /**
      * @brief Used to load register location into a typed temporary.
@@ -547,7 +661,7 @@
      * @param update Whether the liveness information should be updated.
      * @return Returns the properly typed temporary in physical register.
      */
-    virtual RegLocation EvalLoc(RegLocation loc, int reg_class, bool update);
+    RegLocation EvalLoc(RegLocation loc, int reg_class, bool update);
 
     void CountRefs(RefCounts* core_counts, RefCounts* fp_counts, size_t num_regs);
     void DumpCounts(const RefCounts* arr, int size, const char* msg);
@@ -556,7 +670,7 @@
     int SRegOffset(int s_reg);
     RegLocation GetReturnWide(bool is_double);
     RegLocation GetReturn(bool is_float);
-    RegisterInfo* GetRegInfo(int reg);
+    RegisterInfo* GetRegInfo(RegStorage reg);
 
     // Shared by all targets - implemented in gen_common.cc.
     void AddIntrinsicSlowPath(CallInfo* info, LIR* branch, LIR* resume = nullptr);
@@ -868,8 +982,8 @@
     virtual LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
                                  int scale, OpSize size) = 0;
     virtual LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
-                                     int displacement, RegStorage r_dest, RegStorage r_dest_hi,
-                                     OpSize size, int s_reg) = 0;
+                                     int displacement, RegStorage r_dest, OpSize size,
+                                     int s_reg) = 0;
     virtual LIR* LoadConstantNoClobber(RegStorage r_dest, int value) = 0;
     virtual LIR* LoadConstantWide(RegStorage r_dest, int64_t value) = 0;
     virtual LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
@@ -878,18 +992,13 @@
     virtual LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
                                   int scale, OpSize size) = 0;
     virtual LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
-                                      int displacement, RegStorage r_src, RegStorage r_src_hi,
-                                      OpSize size, int s_reg) = 0;
+                                      int displacement, RegStorage r_src, OpSize size,
+                                      int s_reg) = 0;
     virtual void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) = 0;
 
     // Required for target - register utilities.
-    virtual bool IsFpReg(int reg) = 0;
-    virtual bool IsFpReg(RegStorage reg) = 0;
-    virtual bool SameRegType(int reg1, int reg2) = 0;
     virtual RegStorage AllocTypedTemp(bool fp_hint, int reg_class) = 0;
     virtual RegStorage AllocTypedTempWide(bool fp_hint, int reg_class) = 0;
-    // TODO: elminate S2d.
-    virtual int S2d(int low_reg, int high_reg) = 0;
     virtual RegStorage TargetReg(SpecialTargetRegister reg) = 0;
     virtual RegStorage GetArgMappingToPhysicalReg(int arg_num) = 0;
     virtual RegLocation GetReturnAlt() = 0;
@@ -898,17 +1007,14 @@
     virtual RegLocation LocCReturnDouble() = 0;
     virtual RegLocation LocCReturnFloat() = 0;
     virtual RegLocation LocCReturnWide() = 0;
-    // TODO: use to reduce/eliminate xx_FPREG() macro use.
-    virtual uint32_t FpRegMask() = 0;
-    virtual uint64_t GetRegMaskCommon(int reg) = 0;
+    virtual uint64_t GetRegMaskCommon(RegStorage reg) = 0;
     virtual void AdjustSpillMask() = 0;
     virtual void ClobberCallerSave() = 0;
-    virtual void FlushReg(RegStorage reg) = 0;
-    virtual void FlushRegWide(RegStorage reg) = 0;
     virtual void FreeCallTemps() = 0;
     virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) = 0;
     virtual void LockCallTemps() = 0;
-    virtual void MarkPreservedSingle(int v_reg, int reg) = 0;
+    virtual void MarkPreservedSingle(int v_reg, RegStorage reg) = 0;
+    virtual void MarkPreservedDouble(int v_reg, RegStorage reg) = 0;
     virtual void CompilerInitializeRegAlloc() = 0;
 
     // Required for target - miscellaneous.
@@ -1199,11 +1305,6 @@
 
   private:
     void ClobberBody(RegisterInfo* p);
-    void ResetDefBody(RegisterInfo* p) {
-      p->def_start = NULL;
-      p->def_end = NULL;
-    }
-
     void SetCurrentDexPc(DexOffset dexpc) {
       current_dalvik_offset_ = dexpc;
     }
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 6455572..a39611e 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -30,7 +30,7 @@
 void Mir2Lir::ResetRegPool() {
   GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
   for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
-    info->in_use = false;
+    info->MarkFree();
   }
   // Reset temp tracking sanity check.
   if (kIsDebugBuild) {
@@ -38,66 +38,124 @@
   }
 }
 
- /*
-  * Set up temp & preserved register pools specialized by target.
-  * Note: num_regs may be zero.
-  */
-void Mir2Lir::CompilerInitPool(RegisterInfo* regs, int* reg_nums, int num) {
-  for (int i = 0; i < num; i++) {
-    uint32_t reg_number = reg_nums[i];
-    regs[i].reg = reg_number;
-    regs[i].in_use = false;
-    regs[i].is_temp = false;
-    regs[i].pair = false;
-    regs[i].live = false;
-    regs[i].dirty = false;
-    regs[i].s_reg = INVALID_SREG;
-    size_t map_size = reginfo_map_.Size();
-    if (reg_number >= map_size) {
-      for (uint32_t i = 0; i < ((reg_number - map_size) + 1); i++) {
-        reginfo_map_.Insert(NULL);
-      }
-    }
-    reginfo_map_.Put(reg_number, &regs[i]);
+Mir2Lir::RegisterInfo::RegisterInfo(RegStorage r, uint64_t mask)
+  : reg_(r), is_temp_(false), wide_value_(false), live_(false),
+    dirty_(false), partner_(r), s_reg_(INVALID_SREG), def_use_mask_(mask), master_(this) {
+  switch (r.StorageSize()) {
+    case 0: storage_mask_ = 0xffffffff; break;
+    case 4: storage_mask_ = 0x00000001; break;
+    case 8: storage_mask_ = 0x00000003; break;
+    case 16: storage_mask_ = 0x0000000f; break;
+    case 32: storage_mask_ = 0x000000ff; break;
+    case 64: storage_mask_ = 0x0000ffff; break;
+    case 128: storage_mask_ = 0xffffffff; break;
   }
+  used_storage_ = r.Valid() ? ~storage_mask_ : storage_mask_;
 }
 
-void Mir2Lir::DumpRegPool(RegisterInfo* p, int num_regs) {
+Mir2Lir::RegisterPool::RegisterPool(Mir2Lir* m2l, ArenaAllocator* arena,
+                                    const std::vector<RegStorage>& core_regs,
+                                    const std::vector<RegStorage>& sp_regs,
+                                    const std::vector<RegStorage>& dp_regs,
+                                    const std::vector<RegStorage>& reserved_regs,
+                                    const std::vector<RegStorage>& core_temps,
+                                    const std::vector<RegStorage>& sp_temps,
+                                    const std::vector<RegStorage>& dp_temps) :
+    core_regs_(arena, core_regs.size()), next_core_reg_(0), sp_regs_(arena, sp_regs.size()),
+    next_sp_reg_(0), dp_regs_(arena, dp_regs.size()), next_dp_reg_(0), m2l_(m2l)  {
+  // Initialize the fast lookup map.
+  m2l_->reginfo_map_.Reset();
+  m2l_->reginfo_map_.Resize(RegStorage::kMaxRegs);
+  for (unsigned i = 0; i < RegStorage::kMaxRegs; i++) {
+    m2l_->reginfo_map_.Insert(nullptr);
+  }
+
+  // Construct the register pool.
+  for (RegStorage reg : core_regs) {
+    RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg));
+    m2l_->reginfo_map_.Put(reg.GetReg(), info);
+    core_regs_.Insert(info);
+  }
+  for (RegStorage reg : sp_regs) {
+    RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg));
+    m2l_->reginfo_map_.Put(reg.GetReg(), info);
+    sp_regs_.Insert(info);
+  }
+  for (RegStorage reg : dp_regs) {
+    RegisterInfo* info = new (arena) RegisterInfo(reg, m2l_->GetRegMaskCommon(reg));
+    m2l_->reginfo_map_.Put(reg.GetReg(), info);
+    dp_regs_.Insert(info);
+  }
+
+  // Keep special registers from being allocated.
+  for (RegStorage reg : reserved_regs) {
+    m2l_->MarkInUse(reg);
+  }
+
+  // Mark temp regs - all others not in use can be used for promotion
+  for (RegStorage reg : core_temps) {
+    m2l_->MarkTemp(reg);
+  }
+  for (RegStorage reg : sp_temps) {
+    m2l_->MarkTemp(reg);
+  }
+  for (RegStorage reg : dp_temps) {
+    m2l_->MarkTemp(reg);
+  }
+
+  // Add an entry for InvalidReg with zero'd mask.
+  RegisterInfo* invalid_reg = new (arena) RegisterInfo(RegStorage::InvalidReg(), 0);
+  m2l_->reginfo_map_.Put(RegStorage::InvalidReg().GetReg(), invalid_reg);
+}
+
+void Mir2Lir::DumpRegPool(GrowableArray<RegisterInfo*>* regs) {
   LOG(INFO) << "================================================";
-  for (int i = 0; i < num_regs; i++) {
+  GrowableArray<RegisterInfo*>::Iterator it(regs);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
     LOG(INFO) << StringPrintf(
-        "R[%d]: T:%d, U:%d, P:%d, p:%d, LV:%d, D:%d, SR:%d",
-        p[i].reg, p[i].is_temp, p[i].in_use, p[i].pair, p[i].partner,
-        p[i].live, p[i].dirty, p[i].s_reg);
+        "R[%d:%d:%c]: T:%d, U:%d, W:%d, p:%d, LV:%d, D:%d, SR:%d, DEF:%d",
+        info->GetReg().GetReg(), info->GetReg().GetRegNum(), info->GetReg().IsFloat() ?  'f' : 'c',
+        info->IsTemp(), info->InUse(), info->IsWide(), info->Partner().GetReg(), info->IsLive(),
+        info->IsDirty(), info->SReg(), info->DefStart() != nullptr);
   }
   LOG(INFO) << "================================================";
 }
 
 void Mir2Lir::DumpCoreRegPool() {
-  DumpRegPool(reg_pool_->core_regs, reg_pool_->num_core_regs);
+  DumpRegPool(&reg_pool_->core_regs_);
 }
 
 void Mir2Lir::DumpFpRegPool() {
-  DumpRegPool(reg_pool_->FPRegs, reg_pool_->num_fp_regs);
+  DumpRegPool(&reg_pool_->sp_regs_);
+  DumpRegPool(&reg_pool_->dp_regs_);
+}
+
+void Mir2Lir::DumpRegPools() {
+  LOG(INFO) << "Core registers";
+  DumpCoreRegPool();
+  LOG(INFO) << "FP registers";
+  DumpFpRegPool();
 }
 
 void Mir2Lir::Clobber(RegStorage reg) {
   if (reg.IsPair()) {
-    ClobberBody(GetRegInfo(reg.GetLowReg()));
-    ClobberBody(GetRegInfo(reg.GetHighReg()));
+    ClobberBody(GetRegInfo(reg.GetLow()));
+    ClobberBody(GetRegInfo(reg.GetHigh()));
   } else {
-    ClobberBody(GetRegInfo(reg.GetReg()));
+    ClobberBody(GetRegInfo(reg));
   }
 }
 
-void Mir2Lir::ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg) {
-  for (int i = 0; i< num_regs; i++) {
-    if (p[i].s_reg == s_reg) {
-      if (p[i].is_temp) {
-        p[i].live = false;
+void Mir2Lir::ClobberSRegBody(GrowableArray<RegisterInfo*>* regs, int s_reg) {
+  GrowableArray<RegisterInfo*>::Iterator it(regs);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    if ((info->SReg() == s_reg)  ||
+        (info->IsWide() && (GetRegInfo(info->Partner())->SReg() == s_reg))) {
+      // NOTE: a single s_reg may appear multiple times, so we can't short-circuit.
+      if (info->IsTemp()) {
+        info->SetIsLive(false);
       }
-      p[i].def_start = NULL;
-      p[i].def_end = NULL;
+      info->ResetDefBody();
     }
   }
 }
@@ -114,14 +172,17 @@
  * addressed.
  */
 void Mir2Lir::ClobberSReg(int s_reg) {
-  /* Reset live temp tracking sanity checker */
-  if (kIsDebugBuild) {
-    if (s_reg == live_sreg_) {
-      live_sreg_ = INVALID_SREG;
+  if (s_reg != INVALID_SREG) {
+    /* Reset live temp tracking sanity checker */
+    if (kIsDebugBuild) {
+      if (s_reg == live_sreg_) {
+        live_sreg_ = INVALID_SREG;
+      }
     }
+    ClobberSRegBody(&reg_pool_->core_regs_, s_reg);
+    ClobberSRegBody(&reg_pool_->sp_regs_, s_reg);
+    ClobberSRegBody(&reg_pool_->dp_regs_, s_reg);
   }
-  ClobberSRegBody(reg_pool_->core_regs, reg_pool_->num_core_regs, s_reg);
-  ClobberSRegBody(reg_pool_->FPRegs, reg_pool_->num_fp_regs, s_reg);
 }
 
 /*
@@ -153,11 +214,12 @@
   }
 }
 
+// TODO: refactor following Alloc/Record routines - much commonality.
 void Mir2Lir::RecordCorePromotion(RegStorage reg, int s_reg) {
   int p_map_idx = SRegToPMap(s_reg);
   int v_reg = mir_graph_->SRegToVReg(s_reg);
-  int reg_num = reg.GetReg();
-  GetRegInfo(reg_num)->in_use = true;
+  int reg_num = reg.GetRegNum();
+  GetRegInfo(reg)->MarkInUse();
   core_spill_mask_ |= (1 << reg_num);
   // Include reg for later sort
   core_vmap_table_.push_back(reg_num << VREG_NUM_WIDTH | (v_reg & ((1 << VREG_NUM_WIDTH) - 1)));
@@ -166,13 +228,13 @@
   promotion_map_[p_map_idx].core_reg = reg_num;
 }
 
-/* Reserve a callee-save register.  Return -1 if none available */
+/* Reserve a callee-save register.  Return InvalidReg if none available */
 RegStorage Mir2Lir::AllocPreservedCoreReg(int s_reg) {
   RegStorage res;
-  RegisterInfo* core_regs = reg_pool_->core_regs;
-  for (int i = 0; i < reg_pool_->num_core_regs; i++) {
-    if (!core_regs[i].is_temp && !core_regs[i].in_use) {
-      res = RegStorage::Solo32(core_regs[i].reg);
+  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->core_regs_);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    if (!info->IsTemp() && !info->InUse()) {
+      res = info->GetReg();
       RecordCorePromotion(res, s_reg);
       break;
     }
@@ -180,100 +242,66 @@
   return res;
 }
 
-void Mir2Lir::RecordFpPromotion(RegStorage reg, int s_reg) {
+void Mir2Lir::RecordSinglePromotion(RegStorage reg, int s_reg) {
   int p_map_idx = SRegToPMap(s_reg);
   int v_reg = mir_graph_->SRegToVReg(s_reg);
-  int reg_num = reg.GetReg();
-  GetRegInfo(reg_num)->in_use = true;
-  MarkPreservedSingle(v_reg, reg_num);
+  GetRegInfo(reg)->MarkInUse();
+  MarkPreservedSingle(v_reg, reg);
   promotion_map_[p_map_idx].fp_location = kLocPhysReg;
-  promotion_map_[p_map_idx].FpReg = reg_num;
+  promotion_map_[p_map_idx].FpReg = reg.GetReg();
 }
 
-// Reserve a callee-save fp single register.
+// Reserve a callee-save sp single register.
 RegStorage Mir2Lir::AllocPreservedSingle(int s_reg) {
   RegStorage res;
-  RegisterInfo* FPRegs = reg_pool_->FPRegs;
-  for (int i = 0; i < reg_pool_->num_fp_regs; i++) {
-    if (!FPRegs[i].is_temp && !FPRegs[i].in_use) {
-      res = RegStorage::Solo32(FPRegs[i].reg);
-      RecordFpPromotion(res, s_reg);
+  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    if (!info->IsTemp() && !info->InUse()) {
+      res = info->GetReg();
+      RecordSinglePromotion(res, s_reg);
       break;
     }
   }
   return res;
 }
 
-/*
- * Somewhat messy code here.  We want to allocate a pair of contiguous
- * physical single-precision floating point registers starting with
- * an even numbered reg.  It is possible that the paired s_reg (s_reg+1)
- * has already been allocated - try to fit if possible.  Fail to
- * allocate if we can't meet the requirements for the pair of
- * s_reg<=sX[even] & (s_reg+1)<= sX+1.
- */
-// TODO: needs rewrite to support non-backed 64-bit float regs.
+void Mir2Lir::RecordDoublePromotion(RegStorage reg, int s_reg) {
+  int p_map_idx = SRegToPMap(s_reg);
+  int v_reg = mir_graph_->SRegToVReg(s_reg);
+  GetRegInfo(reg)->MarkInUse();
+  MarkPreservedDouble(v_reg, reg);
+  promotion_map_[p_map_idx].fp_location = kLocPhysReg;
+  promotion_map_[p_map_idx].FpReg = reg.GetReg();
+}
+
+// Reserve a callee-save dp solo register.
 RegStorage Mir2Lir::AllocPreservedDouble(int s_reg) {
   RegStorage res;
-  int v_reg = mir_graph_->SRegToVReg(s_reg);
-  int p_map_idx = SRegToPMap(s_reg);
-  if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
-    // Upper reg is already allocated.  Can we fit?
-    int high_reg = promotion_map_[p_map_idx+1].FpReg;
-    if ((high_reg & 1) == 0) {
-      // High reg is even - fail.
-      return res;  // Invalid.
+  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    if (!info->IsTemp() && !info->InUse()) {
+      res = info->GetReg();
+      RecordDoublePromotion(res, s_reg);
+      break;
     }
-    // Is the low reg of the pair free?
-    RegisterInfo* p = GetRegInfo(high_reg-1);
-    if (p->in_use || p->is_temp) {
-      // Already allocated or not preserved - fail.
-      return res;  // Invalid.
-    }
-    // OK - good to go.
-    res = RegStorage(RegStorage::k64BitPair, p->reg, p->reg + 1);
-    p->in_use = true;
-    DCHECK_EQ((res.GetReg() & 1), 0);
-    MarkPreservedSingle(v_reg, res.GetReg());
-  } else {
-    RegisterInfo* FPRegs = reg_pool_->FPRegs;
-    for (int i = 0; i < reg_pool_->num_fp_regs; i++) {
-      if (!FPRegs[i].is_temp && !FPRegs[i].in_use &&
-        ((FPRegs[i].reg & 0x1) == 0x0) &&
-        !FPRegs[i+1].is_temp && !FPRegs[i+1].in_use &&
-        ((FPRegs[i+1].reg & 0x1) == 0x1) &&
-        (FPRegs[i].reg + 1) == FPRegs[i+1].reg) {
-        res = RegStorage(RegStorage::k64BitPair, FPRegs[i].reg, FPRegs[i].reg+1);
-        FPRegs[i].in_use = true;
-        MarkPreservedSingle(v_reg, res.GetLowReg());
-        FPRegs[i+1].in_use = true;
-        DCHECK_EQ(res.GetLowReg() + 1, FPRegs[i+1].reg);
-        MarkPreservedSingle(v_reg+1, res.GetLowReg() + 1);
-        break;
-      }
-    }
-  }
-  if (res.Valid()) {
-    promotion_map_[p_map_idx].fp_location = kLocPhysReg;
-    promotion_map_[p_map_idx].FpReg = res.GetLowReg();
-    promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
-    promotion_map_[p_map_idx+1].FpReg = res.GetLowReg() + 1;
   }
   return res;
 }
 
-RegStorage Mir2Lir::AllocTempBody(RegisterInfo* p, int num_regs, int* next_temp,
-                                  bool required) {
+
+RegStorage Mir2Lir::AllocTempBody(GrowableArray<RegisterInfo*> &regs, int* next_temp, bool required) {
+  int num_regs = regs.Size();
   int next = *next_temp;
   for (int i = 0; i< num_regs; i++) {
     if (next >= num_regs)
       next = 0;
-    if (p[next].is_temp && !p[next].in_use && !p[next].live) {
-      Clobber(p[next].reg);
-      p[next].in_use = true;
-      p[next].pair = false;
+    RegisterInfo* info = regs.Get(next);
+    if (info->IsTemp() && !info->InUse() && !info->IsLive()) {
+      Clobber(info->GetReg());
+      info->MarkInUse();
+      info->SetIsWide(false);
       *next_temp = next + 1;
-      return RegStorage::Solo32(p[next].reg);
+      return info->GetReg();
     }
     next++;
   }
@@ -281,201 +309,166 @@
   for (int i = 0; i< num_regs; i++) {
     if (next >= num_regs)
       next = 0;
-    if (p[next].is_temp && !p[next].in_use) {
-      Clobber(p[next].reg);
-      p[next].in_use = true;
-      p[next].pair = false;
+    RegisterInfo* info = regs.Get(next);
+    if (info->IsTemp() && !info->InUse()) {
+      Clobber(info->GetReg());
+      info->MarkInUse();
+      info->SetIsWide(false);
       *next_temp = next + 1;
-      return RegStorage::Solo32(p[next].reg);
+      return info->GetReg();
     }
     next++;
   }
   if (required) {
     CodegenDump();
-    DumpRegPool(reg_pool_->core_regs,
-          reg_pool_->num_core_regs);
+    DumpRegPools();
     LOG(FATAL) << "No free temp registers";
   }
   return RegStorage::InvalidReg();  // No register available
 }
 
-// REDO: too many assumptions.
-// Virtualize - this is target dependent.
-RegStorage Mir2Lir::AllocTempDouble() {
-  RegisterInfo* p = reg_pool_->FPRegs;
-  int num_regs = reg_pool_->num_fp_regs;
-  /* Start looking at an even reg */
-  int next = reg_pool_->next_fp_reg & ~0x1;
-
-  // First try to avoid allocating live registers
-  for (int i = 0; i < num_regs; i+=2) {
-    if (next >= num_regs)
-      next = 0;
-    if ((p[next].is_temp && !p[next].in_use && !p[next].live) &&
-      (p[next+1].is_temp && !p[next+1].in_use && !p[next+1].live)) {
-      Clobber(p[next].reg);
-      Clobber(p[next+1].reg);
-      p[next].in_use = true;
-      p[next+1].in_use = true;
-      DCHECK_EQ((p[next].reg+1), p[next+1].reg);
-      DCHECK_EQ((p[next].reg & 0x1), 0);
-      reg_pool_->next_fp_reg = next + 2;
-      if (reg_pool_->next_fp_reg >= num_regs) {
-        reg_pool_->next_fp_reg = 0;
-      }
-      // FIXME: should return k64BitSolo.
-      return RegStorage(RegStorage::k64BitPair, p[next].reg, p[next+1].reg);
-    }
-    next += 2;
-  }
-  next = reg_pool_->next_fp_reg & ~0x1;
-
-  // No choice - find a pair and kill it.
-  for (int i = 0; i < num_regs; i+=2) {
-    if (next >= num_regs)
-      next = 0;
-    if (p[next].is_temp && !p[next].in_use && p[next+1].is_temp &&
-      !p[next+1].in_use) {
-      Clobber(p[next].reg);
-      Clobber(p[next+1].reg);
-      p[next].in_use = true;
-      p[next+1].in_use = true;
-      DCHECK_EQ((p[next].reg+1), p[next+1].reg);
-      DCHECK_EQ((p[next].reg & 0x1), 0);
-      reg_pool_->next_fp_reg = next + 2;
-      if (reg_pool_->next_fp_reg >= num_regs) {
-        reg_pool_->next_fp_reg = 0;
-      }
-      return RegStorage(RegStorage::k64BitPair, p[next].reg, p[next+1].reg);
-    }
-    next += 2;
-  }
-  LOG(FATAL) << "No free temp registers (pair)";
-  return RegStorage::InvalidReg();
-}
-
 /* Return a temp if one is available, -1 otherwise */
 RegStorage Mir2Lir::AllocFreeTemp() {
-  return AllocTempBody(reg_pool_->core_regs,
-             reg_pool_->num_core_regs,
-             &reg_pool_->next_core_reg, false);
+  return AllocTempBody(reg_pool_->core_regs_, &reg_pool_->next_core_reg_, false);
 }
 
 RegStorage Mir2Lir::AllocTemp() {
-  return AllocTempBody(reg_pool_->core_regs,
-             reg_pool_->num_core_regs,
-             &reg_pool_->next_core_reg, true);
+  return AllocTempBody(reg_pool_->core_regs_, &reg_pool_->next_core_reg_, true);
 }
 
-RegStorage Mir2Lir::AllocTempFloat() {
-  return AllocTempBody(reg_pool_->FPRegs,
-             reg_pool_->num_fp_regs,
-             &reg_pool_->next_fp_reg, true);
+RegStorage Mir2Lir::AllocTempSingle() {
+  RegStorage res = AllocTempBody(reg_pool_->sp_regs_, &reg_pool_->next_sp_reg_, true);
+  DCHECK(res.IsSingle()) << "Reg: 0x" << std::hex << res.GetRawBits();
+  return res;
 }
 
-Mir2Lir::RegisterInfo* Mir2Lir::AllocLiveBody(RegisterInfo* p, int num_regs, int s_reg) {
-  if (s_reg == -1)
-    return NULL;
-  for (int i = 0; i < num_regs; i++) {
-    if ((p[i].s_reg == s_reg) && p[i].live) {
-      if (p[i].is_temp)
-        p[i].in_use = true;
-      return &p[i];
+RegStorage Mir2Lir::AllocTempDouble() {
+  RegStorage res = AllocTempBody(reg_pool_->dp_regs_, &reg_pool_->next_dp_reg_, true);
+  DCHECK(res.IsDouble()) << "Reg: 0x" << std::hex << res.GetRawBits();
+  return res;
+}
+
+RegStorage Mir2Lir::FindLiveReg(GrowableArray<RegisterInfo*> &regs, int s_reg) {
+  RegStorage res;
+  GrowableArray<RegisterInfo*>::Iterator it(&regs);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    if ((info->SReg() == s_reg) && info->IsLive()) {
+      res = info->GetReg();
+      break;
     }
   }
-  return NULL;
-}
-
-Mir2Lir::RegisterInfo* Mir2Lir::AllocLive(int s_reg, int reg_class) {
-  RegisterInfo* res = NULL;
-  switch (reg_class) {
-    case kAnyReg:
-      res = AllocLiveBody(reg_pool_->FPRegs,
-                reg_pool_->num_fp_regs, s_reg);
-      if (res)
-        break;
-      /* Intentional fallthrough */
-    case kCoreReg:
-      res = AllocLiveBody(reg_pool_->core_regs,
-                reg_pool_->num_core_regs, s_reg);
-      break;
-    case kFPReg:
-      res = AllocLiveBody(reg_pool_->FPRegs,
-                reg_pool_->num_fp_regs, s_reg);
-      break;
-    default:
-      LOG(FATAL) << "Invalid register type";
-  }
   return res;
 }
 
-void Mir2Lir::FreeTemp(int reg) {
-  RegisterInfo* p = GetRegInfo(reg);
-  if (p->is_temp) {
-    p->in_use = false;
+RegStorage Mir2Lir::AllocLiveReg(int s_reg, int reg_class, bool wide) {
+  RegStorage reg;
+  // TODO: might be worth a sanity check here to verify at most 1 live reg per s_reg.
+  if ((reg_class == kAnyReg) || (reg_class == kFPReg)) {
+    reg = FindLiveReg(wide ? reg_pool_->dp_regs_ : reg_pool_->sp_regs_, s_reg);
   }
-  p->pair = false;
+  if (!reg.Valid() && (reg_class != kFPReg)) {
+    reg = FindLiveReg(reg_pool_->core_regs_, s_reg);
+  }
+  if (reg.Valid()) {
+    if (wide && reg.Is32Bit() && !reg.IsFloat()) {
+      // Only allow reg pairs for Core.
+      RegStorage high_reg = FindLiveReg(reg_pool_->core_regs_, s_reg + 1);
+      if (high_reg.Valid()) {
+        RegisterInfo* info_lo = GetRegInfo(reg);
+        RegisterInfo* info_hi = GetRegInfo(high_reg);
+        if (info_lo->IsTemp()) {
+          info_lo->MarkInUse();
+        }
+        if (info_hi->IsTemp()) {
+          info_hi->MarkInUse();
+        }
+        reg = RegStorage::MakeRegPair(reg, high_reg);
+        MarkWide(reg);
+      } else {
+        // Only half available - clobber.
+        Clobber(reg);
+        reg = RegStorage::InvalidReg();
+      }
+    }
+    if (reg.Valid() && !reg.IsPair()) {
+      RegisterInfo* info = GetRegInfo(reg);
+      if (info->IsTemp()) {
+        info->MarkInUse();
+      }
+    }
+    if (reg.Valid() && (wide != GetRegInfo(reg)->IsWide())) {
+      // Width mismatch - don't try to reuse.
+      Clobber(reg);
+      reg = RegStorage::InvalidReg();
+    }
+  }
+  return reg;
 }
 
 void Mir2Lir::FreeTemp(RegStorage reg) {
   if (reg.IsPair()) {
-    FreeTemp(reg.GetLowReg());
-    FreeTemp(reg.GetHighReg());
+    FreeTemp(reg.GetLow());
+    FreeTemp(reg.GetHigh());
   } else {
-    FreeTemp(reg.GetReg());
+    RegisterInfo* p = GetRegInfo(reg);
+    if (p->IsTemp()) {
+      p->MarkFree();
+      p->SetIsWide(false);
+      p->SetPartner(reg);
+    }
   }
 }
 
-Mir2Lir::RegisterInfo* Mir2Lir::IsLive(int reg) {
-  RegisterInfo* p = GetRegInfo(reg);
-  return p->live ? p : NULL;
-}
-
 bool Mir2Lir::IsLive(RegStorage reg) {
+  bool res;
   if (reg.IsPair()) {
-    return IsLive(reg.GetLowReg()) || IsLive(reg.GetHighReg());
+    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+    res = p_lo->IsLive() || p_hi->IsLive();
   } else {
-    return IsLive(reg.GetReg());
+    RegisterInfo* p = GetRegInfo(reg);
+    res = p->IsLive();
   }
-}
-
-Mir2Lir::RegisterInfo* Mir2Lir::IsTemp(int reg) {
-  RegisterInfo* p = GetRegInfo(reg);
-  return (p->is_temp) ? p : NULL;
+  return res;
 }
 
 bool Mir2Lir::IsTemp(RegStorage reg) {
+  bool res;
   if (reg.IsPair()) {
-    return IsTemp(reg.GetLowReg()) || IsTemp(reg.GetHighReg());
+    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+    res = p_lo->IsTemp() || p_hi->IsTemp();
   } else {
-    return IsTemp(reg.GetReg());
+    RegisterInfo* p = GetRegInfo(reg);
+    res = p->IsTemp();
   }
-}
-
-Mir2Lir::RegisterInfo* Mir2Lir::IsPromoted(int reg) {
-  RegisterInfo* p = GetRegInfo(reg);
-  return (p->is_temp) ? NULL : p;
+  return res;
 }
 
 bool Mir2Lir::IsPromoted(RegStorage reg) {
+  bool res;
   if (reg.IsPair()) {
-    return IsPromoted(reg.GetLowReg()) || IsPromoted(reg.GetHighReg());
+    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+    res = !p_lo->IsTemp() || !p_hi->IsTemp();
   } else {
-    return IsPromoted(reg.GetReg());
+    RegisterInfo* p = GetRegInfo(reg);
+    res = !p->IsTemp();
   }
-}
-
-bool Mir2Lir::IsDirty(int reg) {
-  RegisterInfo* p = GetRegInfo(reg);
-  return p->dirty;
+  return res;
 }
 
 bool Mir2Lir::IsDirty(RegStorage reg) {
+  bool res;
   if (reg.IsPair()) {
-    return IsDirty(reg.GetLowReg()) || IsDirty(reg.GetHighReg());
+    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+    res = p_lo->IsDirty() || p_hi->IsDirty();
   } else {
-    return IsDirty(reg.GetReg());
+    RegisterInfo* p = GetRegInfo(reg);
+    res = p->IsDirty();
   }
+  return res;
 }
 
 /*
@@ -483,35 +476,44 @@
  * register.  No check is made to see if the register was previously
  * allocated.  Use with caution.
  */
-void Mir2Lir::LockTemp(int reg) {
-  RegisterInfo* p = GetRegInfo(reg);
-  DCHECK(p->is_temp);
-  p->in_use = true;
-  p->live = false;
-}
-
 void Mir2Lir::LockTemp(RegStorage reg) {
-  DCHECK(!reg.IsPair());
-  LockTemp(reg.GetReg());
-}
-
-void Mir2Lir::ResetDef(int reg) {
-  ResetDefBody(GetRegInfo(reg));
+  DCHECK(IsTemp(reg));
+  if (reg.IsPair()) {
+    RegisterInfo* p_lo = GetRegInfo(reg.GetLow());
+    RegisterInfo* p_hi = GetRegInfo(reg.GetHigh());
+    p_lo->MarkInUse();
+    p_lo->SetIsLive(false);
+    p_hi->MarkInUse();
+    p_hi->SetIsLive(false);
+  } else {
+    RegisterInfo* p = GetRegInfo(reg);
+    p->MarkInUse();
+    p->SetIsLive(false);
+  }
 }
 
 void Mir2Lir::ResetDef(RegStorage reg) {
-  DCHECK(!reg.IsPair());  // Is this done?  If so, do on both low and high.
-  ResetDef(reg.GetReg());
+  if (reg.IsPair()) {
+    GetRegInfo(reg.GetLow())->ResetDefBody();
+    GetRegInfo(reg.GetHigh())->ResetDefBody();
+  } else {
+    GetRegInfo(reg)->ResetDefBody();
+  }
 }
 
-void Mir2Lir::NullifyRange(LIR *start, LIR *finish, int s_reg1, int s_reg2) {
-  if (start && finish) {
-    LIR *p;
-    DCHECK_EQ(s_reg1, s_reg2);
-    for (p = start; ; p = p->next) {
+void Mir2Lir::NullifyRange(RegStorage reg, int s_reg) {
+  RegisterInfo* info = nullptr;
+  RegStorage rs = reg.IsPair() ? reg.GetLow() : reg;
+  if (IsTemp(rs)) {
+    info = GetRegInfo(reg);
+  }
+  if ((info != nullptr) && (info->DefStart() != nullptr) && (info->DefEnd() != nullptr)) {
+    DCHECK_EQ(info->SReg(), s_reg);  // Make sure we're on the same page.
+    for (LIR* p = info->DefStart();; p = p->next) {
       NopLIR(p);
-      if (p == finish)
+      if (p == info->DefEnd()) {
         break;
+      }
     }
   }
 }
@@ -525,9 +527,9 @@
   DCHECK(!rl.wide);
   DCHECK(start && start->next);
   DCHECK(finish);
-  RegisterInfo* p = GetRegInfo(rl.reg.GetReg());
-  p->def_start = start->next;
-  p->def_end = finish;
+  RegisterInfo* p = GetRegInfo(rl.reg);
+  p->SetDefStart(start->next);
+  p->SetDefEnd(finish);
 }
 
 /*
@@ -539,28 +541,33 @@
   DCHECK(rl.wide);
   DCHECK(start && start->next);
   DCHECK(finish);
-  RegisterInfo* p = GetRegInfo(rl.reg.GetLowReg());
-  ResetDef(rl.reg.GetHighReg());  // Only track low of pair
-  p->def_start = start->next;
-  p->def_end = finish;
+  RegisterInfo* p;
+  if (rl.reg.IsPair()) {
+    p = GetRegInfo(rl.reg.GetLow());
+    ResetDef(rl.reg.GetHigh());  // Only track low of pair
+  } else {
+    p = GetRegInfo(rl.reg);
+  }
+  p->SetDefStart(start->next);
+  p->SetDefEnd(finish);
 }
 
 RegLocation Mir2Lir::WideToNarrow(RegLocation rl) {
   DCHECK(rl.wide);
   if (rl.location == kLocPhysReg) {
-    RegisterInfo* info_lo = GetRegInfo(rl.reg.GetLowReg());
-    RegisterInfo* info_hi = GetRegInfo(rl.reg.GetHighReg());
-    if (info_lo->is_temp) {
-      info_lo->pair = false;
-      info_lo->def_start = NULL;
-      info_lo->def_end = NULL;
+    if (rl.reg.IsPair()) {
+      RegisterInfo* info_lo = GetRegInfo(rl.reg.GetLow());
+      RegisterInfo* info_hi = GetRegInfo(rl.reg.GetHigh());
+      if (info_lo->IsTemp()) {
+        info_lo->SetIsWide(false);
+        info_lo->ResetDefBody();
+      }
+      if (info_hi->IsTemp()) {
+        info_hi->SetIsWide(false);
+        info_hi->ResetDefBody();
+      }
+      rl.reg = rl.reg.GetLow();
     }
-    if (info_hi->is_temp) {
-      info_hi->pair = false;
-      info_hi->def_start = NULL;
-      info_hi->def_end = NULL;
-    }
-    rl.reg = RegStorage::Solo32(rl.reg.GetLowReg());
   }
   rl.wide = false;
   return rl;
@@ -568,220 +575,244 @@
 
 void Mir2Lir::ResetDefLoc(RegLocation rl) {
   DCHECK(!rl.wide);
-  RegisterInfo* p = IsTemp(rl.reg.GetReg());
-  if (p && !(cu_->disable_opt & (1 << kSuppressLoads))) {
-    DCHECK(!p->pair);
-    NullifyRange(p->def_start, p->def_end, p->s_reg, rl.s_reg_low);
+  if (IsTemp(rl.reg) && !(cu_->disable_opt & (1 << kSuppressLoads))) {
+    NullifyRange(rl.reg, rl.s_reg_low);
   }
-  ResetDef(rl.reg.GetReg());
+  ResetDef(rl.reg);
 }
 
 void Mir2Lir::ResetDefLocWide(RegLocation rl) {
   DCHECK(rl.wide);
-  RegisterInfo* p_low = IsTemp(rl.reg.GetLowReg());
-  RegisterInfo* p_high = IsTemp(rl.reg.GetHighReg());
-  if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) {
-    DCHECK(p_low->pair);
-    NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low);
+  // If pair, only track low reg of pair.
+  RegStorage rs = rl.reg.IsPair() ? rl.reg.GetLow() : rl.reg;
+  if (IsTemp(rs) && !(cu_->disable_opt & (1 << kSuppressLoads))) {
+    NullifyRange(rs, rl.s_reg_low);
   }
-  if (p_high && !(cu_->disable_opt & (1 << kSuppressLoads))) {
-    DCHECK(p_high->pair);
-  }
-  ResetDef(rl.reg.GetLowReg());
-  ResetDef(rl.reg.GetHighReg());
+  ResetDef(rs);
 }
 
 void Mir2Lir::ResetDefTracking() {
-  for (int i = 0; i< reg_pool_->num_core_regs; i++) {
-    ResetDefBody(&reg_pool_->core_regs[i]);
+  GrowableArray<RegisterInfo*>::Iterator core_it(&reg_pool_->core_regs_);
+  for (RegisterInfo* info = core_it.Next(); info != nullptr; info = core_it.Next()) {
+    info->ResetDefBody();
   }
-  for (int i = 0; i< reg_pool_->num_fp_regs; i++) {
-    ResetDefBody(&reg_pool_->FPRegs[i]);
+  GrowableArray<RegisterInfo*>::Iterator sp_it(&reg_pool_->core_regs_);
+  for (RegisterInfo* info = sp_it.Next(); info != nullptr; info = sp_it.Next()) {
+    info->ResetDefBody();
+  }
+  GrowableArray<RegisterInfo*>::Iterator dp_it(&reg_pool_->core_regs_);
+  for (RegisterInfo* info = dp_it.Next(); info != nullptr; info = dp_it.Next()) {
+    info->ResetDefBody();
   }
 }
 
 void Mir2Lir::ClobberAllRegs() {
   GrowableArray<RegisterInfo*>::Iterator iter(&tempreg_info_);
   for (RegisterInfo* info = iter.Next(); info != NULL; info = iter.Next()) {
-    info->live = false;
-    info->s_reg = INVALID_SREG;
-    info->def_start = NULL;
-    info->def_end = NULL;
-    info->pair = false;
+    info->SetIsLive(false);
+    info->SetSReg(INVALID_SREG);
+    info->ResetDefBody();
+    info->SetIsWide(false);
+  }
+}
+
+void Mir2Lir::FlushRegWide(RegStorage reg) {
+  if (reg.IsPair()) {
+    RegisterInfo* info1 = GetRegInfo(reg.GetLow());
+    RegisterInfo* info2 = GetRegInfo(reg.GetHigh());
+    DCHECK(info1 && info2 && info1->IsWide() && info2->IsWide() &&
+         (info1->Partner() == info2->GetReg()) && (info2->Partner() == info1->GetReg()));
+    if ((info1->IsLive() && info1->IsDirty()) || (info2->IsLive() && info2->IsDirty())) {
+      if (!(info1->IsTemp() && info2->IsTemp())) {
+        /* Should not happen.  If it does, there's a problem in eval_loc */
+        LOG(FATAL) << "Long half-temp, half-promoted";
+      }
+
+      info1->SetIsDirty(false);
+      info2->SetIsDirty(false);
+      if (mir_graph_->SRegToVReg(info2->SReg()) < mir_graph_->SRegToVReg(info1->SReg())) {
+        info1 = info2;
+      }
+      int v_reg = mir_graph_->SRegToVReg(info1->SReg());
+      StoreBaseDispWide(TargetReg(kSp), VRegOffset(v_reg), reg);
+    }
+  } else {
+    RegisterInfo* info = GetRegInfo(reg);
+    if (info->IsLive() && info->IsDirty()) {
+      info->SetIsDirty(false);
+      int v_reg = mir_graph_->SRegToVReg(info->SReg());
+      StoreBaseDispWide(TargetReg(kSp), VRegOffset(v_reg), reg);
+    }
+  }
+}
+
+void Mir2Lir::FlushReg(RegStorage reg) {
+  DCHECK(!reg.IsPair());
+  RegisterInfo* info = GetRegInfo(reg);
+  if (info->IsLive() && info->IsDirty()) {
+    info->SetIsDirty(false);
+    int v_reg = mir_graph_->SRegToVReg(info->SReg());
+    StoreBaseDisp(TargetReg(kSp), VRegOffset(v_reg), reg, kWord);
   }
 }
 
 void Mir2Lir::FlushSpecificReg(RegisterInfo* info) {
-  if (info->pair) {
-    FlushRegWide(RegStorage(RegStorage::k64BitPair, info->reg, info->partner));
+  if (info->IsWide()) {
+    FlushRegWide(info->GetReg());
   } else {
-    FlushReg(RegStorage::Solo32(info->reg));
-  }
-}
-
-// Make sure nothing is live and dirty
-void Mir2Lir::FlushAllRegsBody(RegisterInfo* info, int num_regs) {
-  for (int i = 0; i < num_regs; i++) {
-    if (info[i].live && info[i].dirty) {
-      FlushSpecificReg(&info[i]);
-    }
+    FlushReg(info->GetReg());
   }
 }
 
 void Mir2Lir::FlushAllRegs() {
-  FlushAllRegsBody(reg_pool_->core_regs,
-           reg_pool_->num_core_regs);
-  FlushAllRegsBody(reg_pool_->FPRegs,
-           reg_pool_->num_fp_regs);
-  ClobberAllRegs();
+  GrowableArray<RegisterInfo*>::Iterator it(&tempreg_info_);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    if (info->IsLive() && info->IsDirty()) {
+      FlushSpecificReg(info);
+    }
+    DCHECK(info->IsTemp());
+    info->SetIsLive(false);
+    info->SetSReg(INVALID_SREG);
+    info->ResetDefBody();
+    info->SetIsWide(false);
+  }
 }
 
 
-// TUNING: rewrite all of this reg stuff.  Probably use an attribute table
 bool Mir2Lir::RegClassMatches(int reg_class, RegStorage reg) {
-  int reg_num = reg.IsPair() ? reg.GetLowReg() : reg.GetReg();
   if (reg_class == kAnyReg) {
     return true;
   } else if (reg_class == kCoreReg) {
-    return !IsFpReg(reg_num);
+    return !reg.IsFloat();
   } else {
-    return IsFpReg(reg_num);
+    return reg.IsFloat();
   }
 }
 
-void Mir2Lir::MarkLive(RegStorage reg, int s_reg) {
-  DCHECK(!reg.IsPair());   // Could be done - but would that be meaningful?
-  RegisterInfo* info = GetRegInfo(reg.GetReg());
-  if ((info->s_reg == s_reg) && info->live) {
-    return;  /* already live */
-  } else if (s_reg != INVALID_SREG) {
+void Mir2Lir::MarkLiveReg(RegStorage reg, int s_reg) {
+  RegisterInfo* info = GetRegInfo(reg);
+  if ((info->SReg() == s_reg) && info->IsLive()) {
+    return;  // Already live.
+  }
+  if (s_reg != INVALID_SREG) {
     ClobberSReg(s_reg);
-    if (info->is_temp) {
-      info->live = true;
+    if (info->IsTemp()) {
+      info->SetIsLive(true);
     }
   } else {
-    /* Can't be live if no associated s_reg */
-    DCHECK(info->is_temp);
-    info->live = false;
+    // Can't be live if no associated s_reg.
+    DCHECK(info->IsTemp());
+    info->SetIsLive(false);
   }
-  info->s_reg = s_reg;
+  info->SetSReg(s_reg);
 }
 
-void Mir2Lir::MarkTemp(int reg) {
-  RegisterInfo* info = GetRegInfo(reg);
-  tempreg_info_.Insert(info);
-  info->is_temp = true;
+void Mir2Lir::MarkLive(RegLocation loc) {
+  RegStorage reg = loc.reg;
+  int s_reg = loc.s_reg_low;
+  if (reg.IsPair()) {
+    MarkLiveReg(reg.GetLow(), s_reg);
+    MarkLiveReg(reg.GetHigh(), s_reg+1);
+  } else {
+    if (loc.wide) {
+      ClobberSReg(s_reg + 1);
+    }
+    MarkLiveReg(reg, s_reg);
+  }
 }
 
 void Mir2Lir::MarkTemp(RegStorage reg) {
   DCHECK(!reg.IsPair());
-  MarkTemp(reg.GetReg());
-}
-
-void Mir2Lir::UnmarkTemp(int reg) {
   RegisterInfo* info = GetRegInfo(reg);
-  tempreg_info_.Delete(info);
-  info->is_temp = false;
+  tempreg_info_.Insert(info);
+  info->SetIsTemp(true);
 }
 
 void Mir2Lir::UnmarkTemp(RegStorage reg) {
   DCHECK(!reg.IsPair());
-  UnmarkTemp(reg.GetReg());
+  RegisterInfo* info = GetRegInfo(reg);
+  tempreg_info_.Delete(info);
+  info->SetIsTemp(false);
 }
 
-void Mir2Lir::MarkPair(int low_reg, int high_reg) {
-  DCHECK_NE(low_reg, high_reg);
-  RegisterInfo* info_lo = GetRegInfo(low_reg);
-  RegisterInfo* info_hi = GetRegInfo(high_reg);
-  info_lo->pair = info_hi->pair = true;
-  info_lo->partner = high_reg;
-  info_hi->partner = low_reg;
-}
-
-void Mir2Lir::MarkClean(RegLocation loc) {
-  if (loc.wide) {
-    RegisterInfo* info = GetRegInfo(loc.reg.GetLowReg());
-    info->dirty = false;
-    info = GetRegInfo(loc.reg.GetHighReg());
-    info->dirty = false;
+void Mir2Lir::MarkWide(RegStorage reg) {
+  if (reg.IsPair()) {
+    RegisterInfo* info_lo = GetRegInfo(reg.GetLow());
+    RegisterInfo* info_hi = GetRegInfo(reg.GetHigh());
+    info_lo->SetIsWide(true);
+    info_hi->SetIsWide(true);
+    info_lo->SetPartner(reg.GetHigh());
+    info_hi->SetPartner(reg.GetLow());
   } else {
-    RegisterInfo* info = GetRegInfo(loc.reg.GetReg());
-    info->dirty = false;
+    RegisterInfo* info = GetRegInfo(reg);
+    info->SetIsWide(true);
+    info->SetPartner(reg);
   }
 }
 
+void Mir2Lir::MarkClean(RegLocation loc) {
+  if (loc.reg.IsPair()) {
+    RegisterInfo* info = GetRegInfo(loc.reg.GetLow());
+    info->SetIsDirty(false);
+    info = GetRegInfo(loc.reg.GetHigh());
+    info->SetIsDirty(false);
+  } else {
+    RegisterInfo* info = GetRegInfo(loc.reg);
+    info->SetIsDirty(false);
+  }
+}
+
+// FIXME: need to verify rules/assumptions about how wide values are treated in 64BitSolos.
 void Mir2Lir::MarkDirty(RegLocation loc) {
   if (loc.home) {
     // If already home, can't be dirty
     return;
   }
-  if (loc.wide) {
-    RegisterInfo* info = GetRegInfo(loc.reg.GetLowReg());
-    info->dirty = true;
-    info = GetRegInfo(loc.reg.GetHighReg());
-    info->dirty = true;
+  if (loc.reg.IsPair()) {
+    RegisterInfo* info = GetRegInfo(loc.reg.GetLow());
+    info->SetIsDirty(true);
+    info = GetRegInfo(loc.reg.GetHigh());
+    info->SetIsDirty(true);
   } else {
-    RegisterInfo* info = GetRegInfo(loc.reg.GetReg());
-    info->dirty = true;
+    RegisterInfo* info = GetRegInfo(loc.reg);
+    info->SetIsDirty(true);
   }
 }
 
-void Mir2Lir::MarkInUse(int reg) {
-    RegisterInfo* info = GetRegInfo(reg);
-    info->in_use = true;
-}
-
 void Mir2Lir::MarkInUse(RegStorage reg) {
   if (reg.IsPair()) {
-    MarkInUse(reg.GetLowReg());
-    MarkInUse(reg.GetHighReg());
+    GetRegInfo(reg.GetLow())->MarkInUse();
+    GetRegInfo(reg.GetHigh())->MarkInUse();
   } else {
-    MarkInUse(reg.GetReg());
+    GetRegInfo(reg)->MarkInUse();
   }
 }
 
-void Mir2Lir::CopyRegInfo(int new_reg, int old_reg) {
-  RegisterInfo* new_info = GetRegInfo(new_reg);
-  RegisterInfo* old_info = GetRegInfo(old_reg);
-  // Target temp, live, dirty status must not change
-  bool is_temp = new_info->is_temp;
-  bool live = new_info->live;
-  bool dirty = new_info->dirty;
-  *new_info = *old_info;
-  // Restore target's temp, live, dirty status
-  new_info->is_temp = is_temp;
-  new_info->live = live;
-  new_info->dirty = dirty;
-  new_info->reg = new_reg;
-}
-
-void Mir2Lir::CopyRegInfo(RegStorage new_reg, RegStorage old_reg) {
-  DCHECK(!new_reg.IsPair());
-  DCHECK(!old_reg.IsPair());
-  CopyRegInfo(new_reg.GetReg(), old_reg.GetReg());
-}
-
 bool Mir2Lir::CheckCorePoolSanity() {
-  for (static int i = 0; i < reg_pool_->num_core_regs; i++) {
-    if (reg_pool_->core_regs[i].pair) {
-      static int my_reg = reg_pool_->core_regs[i].reg;
-      static int my_sreg = reg_pool_->core_regs[i].s_reg;
-      static int partner_reg = reg_pool_->core_regs[i].partner;
-      static RegisterInfo* partner = GetRegInfo(partner_reg);
+  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->core_regs_);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    RegStorage my_reg = info->GetReg();
+    if (info->IsWide() && my_reg.IsPair()) {
+      int my_sreg = info->SReg();
+      RegStorage partner_reg = info->Partner();
+      RegisterInfo* partner = GetRegInfo(partner_reg);
       DCHECK(partner != NULL);
-      DCHECK(partner->pair);
-      DCHECK_EQ(my_reg, partner->partner);
-      static int partner_sreg = partner->s_reg;
+      DCHECK(partner->IsWide());
+      DCHECK_EQ(my_reg.GetReg(), partner->Partner().GetReg());
+      int partner_sreg = partner->SReg();
       if (my_sreg == INVALID_SREG) {
         DCHECK_EQ(partner_sreg, INVALID_SREG);
       } else {
         int diff = my_sreg - partner_sreg;
-        DCHECK((diff == -1) || (diff == 1));
+        DCHECK((diff == 0) || (diff == -1) || (diff == 1));
       }
+    } else {
+      // TODO: add whatever sanity checks might be useful for 64BitSolo regs here.
+      // TODO: sanity checks for floating point pools?
     }
-    if (!reg_pool_->core_regs[i].live) {
-      DCHECK(reg_pool_->core_regs[i].def_start == NULL);
-      DCHECK(reg_pool_->core_regs[i].def_end == NULL);
+    if (!info->IsLive()) {
+      DCHECK(info->DefStart() == NULL);
+      DCHECK(info->DefEnd() == NULL);
     }
   }
   return true;
@@ -796,80 +827,64 @@
  * is a bit complex when dealing with FP regs.  Examine code to see
  * if it's worthwhile trying to be more clever here.
  */
-
 RegLocation Mir2Lir::UpdateLoc(RegLocation loc) {
   DCHECK(!loc.wide);
   DCHECK(CheckCorePoolSanity());
   if (loc.location != kLocPhysReg) {
     DCHECK((loc.location == kLocDalvikFrame) ||
          (loc.location == kLocCompilerTemp));
-    RegisterInfo* info_lo = AllocLive(loc.s_reg_low, kAnyReg);
-    if (info_lo) {
-      if (info_lo->pair) {
-        Clobber(info_lo->reg);
-        Clobber(info_lo->partner);
-        FreeTemp(info_lo->reg);
-      } else {
-        loc.reg = RegStorage::Solo32(info_lo->reg);
+    RegStorage reg = AllocLiveReg(loc.s_reg_low, kAnyReg, false);
+    if (reg.Valid()) {
+      bool match = true;
+      RegisterInfo* info = GetRegInfo(reg);
+      match &= !reg.IsPair();
+      match &= !info->IsWide();
+      if (match) {
         loc.location = kLocPhysReg;
+        loc.reg = reg;
+      } else {
+        Clobber(reg);
+        FreeTemp(reg);
       }
     }
   }
   return loc;
 }
 
-/* see comments for update_loc */
 RegLocation Mir2Lir::UpdateLocWide(RegLocation loc) {
   DCHECK(loc.wide);
   DCHECK(CheckCorePoolSanity());
   if (loc.location != kLocPhysReg) {
     DCHECK((loc.location == kLocDalvikFrame) ||
          (loc.location == kLocCompilerTemp));
-    // Are the dalvik regs already live in physical registers?
-    RegisterInfo* info_lo = AllocLive(loc.s_reg_low, kAnyReg);
-    RegisterInfo* info_hi = AllocLive(GetSRegHi(loc.s_reg_low), kAnyReg);
-    bool match = true;
-    match = match && (info_lo != NULL);
-    match = match && (info_hi != NULL);
-    // Are they both core or both FP?
-    match = match && (IsFpReg(info_lo->reg) == IsFpReg(info_hi->reg));
-    // If a pair of floating point singles, are they properly aligned?
-    if (match && IsFpReg(info_lo->reg)) {
-      match &= ((info_lo->reg & 0x1) == 0);
-      match &= ((info_hi->reg - info_lo->reg) == 1);
-    }
-    // If previously used as a pair, it is the same pair?
-    if (match && (info_lo->pair || info_hi->pair)) {
-      match = (info_lo->pair == info_hi->pair);
-      match &= ((info_lo->reg == info_hi->partner) &&
-            (info_hi->reg == info_lo->partner));
-    }
-    if (match) {
-      // Can reuse - update the register usage info
-      loc.location = kLocPhysReg;
-      loc.reg = RegStorage(RegStorage::k64BitPair, info_lo->reg, info_hi->reg);
-      MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
-      DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
-      return loc;
-    }
-    // Can't easily reuse - clobber and free any overlaps
-    if (info_lo) {
-      Clobber(info_lo->reg);
-      FreeTemp(info_lo->reg);
-      if (info_lo->pair)
-        Clobber(info_lo->partner);
-    }
-    if (info_hi) {
-      Clobber(info_hi->reg);
-      FreeTemp(info_hi->reg);
-      if (info_hi->pair)
-        Clobber(info_hi->partner);
+    RegStorage reg = AllocLiveReg(loc.s_reg_low, kAnyReg, true);
+    if (reg.Valid()) {
+      bool match = true;
+      if (reg.IsPair()) {
+        // If we've got a register pair, make sure that it was last used as the same pair.
+        RegisterInfo* info_lo = GetRegInfo(reg.GetLow());
+        RegisterInfo* info_hi = GetRegInfo(reg.GetHigh());
+        match &= info_lo->IsWide();
+        match &= info_hi->IsWide();
+        match &= (info_lo->Partner() == info_hi->GetReg());
+        match &= (info_hi->Partner() == info_lo->GetReg());
+      } else {
+        RegisterInfo* info = GetRegInfo(reg);
+        match &= info->IsWide();
+        match &= (info->GetReg() == info->Partner());
+      }
+      if (match) {
+        loc.location = kLocPhysReg;
+        loc.reg = reg;
+      } else {
+        Clobber(reg);
+        FreeTemp(reg);
+      }
     }
   }
   return loc;
 }
 
-
 /* For use in cases we don't know (or care) width */
 RegLocation Mir2Lir::UpdateRawLoc(RegLocation loc) {
   if (loc.wide)
@@ -885,18 +900,15 @@
 
   /* If already in registers, we can assume proper form.  Right reg class? */
   if (loc.location == kLocPhysReg) {
-    DCHECK_EQ(IsFpReg(loc.reg.GetLowReg()), IsFpReg(loc.reg.GetHighReg()));
-    DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
     if (!RegClassMatches(reg_class, loc.reg)) {
       /* Wrong register class.  Reallocate and copy */
       RegStorage new_regs = AllocTypedTempWide(loc.fp, reg_class);
       OpRegCopyWide(new_regs, loc.reg);
-      CopyRegInfo(new_regs.GetLowReg(), loc.reg.GetLowReg());
-      CopyRegInfo(new_regs.GetHighReg(), loc.reg.GetHighReg());
+      // Associate the old sreg with the new register and clobber the old register.
+      GetRegInfo(new_regs)->SetSReg(GetRegInfo(loc.reg)->SReg());
       Clobber(loc.reg);
       loc.reg = new_regs;
-      MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
-      DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
+      MarkWide(loc.reg);
     }
     return loc;
   }
@@ -905,23 +917,19 @@
   DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG);
 
   loc.reg = AllocTypedTempWide(loc.fp, reg_class);
+  MarkWide(loc.reg);
 
-  MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
   if (update) {
     loc.location = kLocPhysReg;
-    MarkLive(loc.reg.GetLow(), loc.s_reg_low);
-    // Does this wide value live in two registers or one vector register?
-    if (loc.reg.GetLowReg() != loc.reg.GetHighReg()) {
-      MarkLive(loc.reg.GetHigh(), GetSRegHi(loc.s_reg_low));
-    }
+    MarkLive(loc);
   }
-  DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
   return loc;
 }
 
 RegLocation Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) {
-  if (loc.wide)
+  if (loc.wide) {
     return EvalLocWide(loc, reg_class, update);
+  }
 
   loc = UpdateLoc(loc);
 
@@ -930,7 +938,8 @@
       /* Wrong register class.  Realloc, copy and transfer ownership */
       RegStorage new_reg = AllocTypedTemp(loc.fp, reg_class);
       OpRegCopy(new_reg, loc.reg);
-      CopyRegInfo(new_reg, loc.reg);
+      // Associate the old sreg with the new register and clobber the old register.
+      GetRegInfo(new_reg)->SetSReg(GetRegInfo(loc.reg)->SReg());
       Clobber(loc.reg);
       loc.reg = new_reg;
     }
@@ -943,7 +952,7 @@
 
   if (update) {
     loc.location = kLocPhysReg;
-    MarkLive(loc.reg, loc.s_reg_low);
+    MarkLive(loc);
   }
   return loc;
 }
@@ -1115,9 +1124,14 @@
           int low_reg = promotion_map_[p_map_idx].FpReg;
           int high_reg = promotion_map_[p_map_idx+1].FpReg;
           // Doubles require pair of singles starting at even reg
+          // TODO: move target-specific restrictions out of here.
           if (((low_reg & 0x1) == 0) && ((low_reg + 1) == high_reg)) {
             curr->location = kLocPhysReg;
-            curr->reg = RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
+            if (cu_->instruction_set == kThumb2) {
+              curr->reg = RegStorage::FloatSolo64(RegStorage::RegNum(low_reg) >> 1);
+            } else {
+              curr->reg = RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
+            }
             curr->home = true;
           }
         }
@@ -1155,13 +1169,18 @@
   RegLocation gpr_res = LocCReturnWide();
   RegLocation fpr_res = LocCReturnDouble();
   RegLocation res = is_double ? fpr_res : gpr_res;
-  Clobber(res.reg.GetLowReg());
-  Clobber(res.reg.GetHighReg());
-  LockTemp(res.reg.GetLowReg());
-  LockTemp(res.reg.GetHighReg());
-  // Does this wide value live in two registers or one vector register?
-  if (res.reg.GetLowReg() != res.reg.GetHighReg()) {
-    MarkPair(res.reg.GetLowReg(), res.reg.GetHighReg());
+  if (res.reg.IsPair()) {
+    Clobber(res.reg);
+    LockTemp(res.reg);
+    // Does this wide value live in two registers or one vector register?
+    if (res.reg.GetLowReg() != res.reg.GetHighReg()) {
+      // FIXME: I think we want to mark these as wide as well.
+      MarkWide(res.reg);
+    }
+  } else {
+    Clobber(res.reg);
+    LockTemp(res.reg);
+    MarkWide(res.reg);
   }
   return res;
 }
@@ -1170,11 +1189,11 @@
   RegLocation gpr_res = LocCReturn();
   RegLocation fpr_res = LocCReturnFloat();
   RegLocation res = is_float ? fpr_res : gpr_res;
-  Clobber(res.reg.GetReg());
+  Clobber(res.reg);
   if (cu_->instruction_set == kMips) {
-    MarkInUse(res.reg.GetReg());
+    MarkInUse(res.reg);
   } else {
-    LockTemp(res.reg.GetReg());
+    LockTemp(res.reg);
   }
   return res;
 }
@@ -1204,14 +1223,9 @@
   return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
 }
 
-bool Mir2Lir::oat_live_out(int s_reg) {
+bool Mir2Lir::LiveOut(int s_reg) {
   // For now.
   return true;
 }
 
-int Mir2Lir::oatSSASrc(MIR* mir, int num) {
-  DCHECK_GT(mir->ssa_rep->num_uses, num);
-  return mir->ssa_rep->uses[num];
-}
-
 }  // namespace art
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index e7a1a69..58e2f42 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -175,7 +175,7 @@
   { kX86Mov32AI, kArrayImm,  IS_STORE | IS_QUIN_OP     | REG_USE01,      { 0,             0, 0xC7, 0, 0, 0, 0, 4 }, "Mov32AI", "[!0r+!1r<<!2d+!3d],!4d" },
   { kX86Mov32TI, kThreadImm, IS_STORE | IS_BINARY_OP,                    { THREAD_PREFIX, 0, 0xC7, 0, 0, 0, 0, 4 }, "Mov32TI", "fs:[!0d],!1d" },
 
-  { kX86Lea32RM, kRegMem, IS_TERTIARY_OP | IS_LOAD | REG_DEF0_USE12, { 0, 0, 0x8D, 0, 0, 0, 0, 0 }, "Lea32RM", "!0r,[!1r+!2d]" },
+  { kX86Lea32RM, kRegMem, IS_TERTIARY_OP | IS_LOAD | REG_DEF0_USE1, { 0, 0, 0x8D, 0, 0, 0, 0, 0 }, "Lea32RM", "!0r,[!1r+!2d]" },
 
   { kX86Lea32RA, kRegArray, IS_QUIN_OP | REG_DEF0_USE12, { 0, 0, 0x8D, 0, 0, 0, 0, 0 }, "Lea32RA", "!0r,[!1r+!2r<<!3d+!4d]" },
 
@@ -388,11 +388,11 @@
     }
   }
   ++size;  // modrm
-  if (has_sib || base == rX86_SP) {
+  if (has_sib || RegStorage::RegNum(base) == rs_rX86_SP.GetRegNum()) {
     // SP requires a SIB byte.
     ++size;
   }
-  if (displacement != 0 || base == rBP) {
+  if (displacement != 0 || RegStorage::RegNum(base) == rs_rBP.GetRegNum()) {
     // BP requires an explicit displacement, even when it's 0.
     if (entry->opcode != kX86Lea32RA) {
       DCHECK_NE(entry->flags & (IS_LOAD | IS_STORE), 0ULL) << entry->name;
@@ -446,7 +446,7 @@
       } else {
         // AX opcodes don't require the modrm byte.
         int reg = lir->operands[0];
-        return size - (reg == rAX ? 1 : 0);
+        return size - (RegStorage::RegNum(reg) == rs_rAX.GetRegNum() ? 1 : 0);
       }
     }
     case kMemImm:  // lir operands - 0: base, 1: disp, 2: immediate
@@ -533,7 +533,7 @@
       DCHECK_EQ(lir->opcode, static_cast<int>(kX86StartOfMethod));
       return 5 /* call opcode + 4 byte displacement */ + 1 /* pop reg */ +
           ComputeSize(&X86Mir2Lir::EncodingMap[kX86Sub32RI], 0, 0, false) -
-          (lir->operands[0] == rAX  ? 1 : 0);  // shorter ax encoding
+          (RegStorage::RegNum(lir->operands[0]) == rs_rAX.GetRegNum()  ? 1 : 0);  // shorter ax encoding
     default:
       break;
   }
@@ -574,7 +574,7 @@
 
 static uint8_t ModrmForDisp(int base, int disp) {
   // BP requires an explicit disp, so do not omit it in the 0 case
-  if (disp == 0 && base != rBP) {
+  if (disp == 0 && RegStorage::RegNum(base) != rs_rBP.GetRegNum()) {
     return 0;
   } else if (IS_SIMM8(disp)) {
     return 1;
@@ -585,7 +585,7 @@
 
 void X86Mir2Lir::EmitDisp(uint8_t base, int disp) {
   // BP requires an explicit disp, so do not omit it in the 0 case
-  if (disp == 0 && base != rBP) {
+  if (disp == 0 && RegStorage::RegNum(base) != rs_rBP.GetRegNum()) {
     return;
   } else if (IS_SIMM8(disp)) {
     code_buffer_.push_back(disp & 0xFF);
@@ -598,26 +598,28 @@
 }
 
 void X86Mir2Lir::EmitModrmDisp(uint8_t reg_or_opcode, uint8_t base, int disp) {
-  DCHECK_LT(reg_or_opcode, 8);
-  DCHECK_LT(base, 8);
-  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | base;
+  DCHECK_LT(RegStorage::RegNum(reg_or_opcode), 8);
+  DCHECK_LT(RegStorage::RegNum(base), 8);
+  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (RegStorage::RegNum(reg_or_opcode) << 3) |
+     RegStorage::RegNum(base);
   code_buffer_.push_back(modrm);
-  if (base == rX86_SP) {
+  if (RegStorage::RegNum(base) == rs_rX86_SP.GetRegNum()) {
     // Special SIB for SP base
-    code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP);
+    code_buffer_.push_back(0 << 6 | rs_rX86_SP.GetRegNum() << 3 | rs_rX86_SP.GetRegNum());
   }
   EmitDisp(base, disp);
 }
 
 void X86Mir2Lir::EmitModrmSibDisp(uint8_t reg_or_opcode, uint8_t base, uint8_t index,
                                   int scale, int disp) {
-  DCHECK_LT(reg_or_opcode, 8);
-  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | rX86_SP;
+  DCHECK_LT(RegStorage::RegNum(reg_or_opcode), 8);
+  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | RegStorage::RegNum(reg_or_opcode) << 3 |
+      rs_rX86_SP.GetRegNum();
   code_buffer_.push_back(modrm);
   DCHECK_LT(scale, 4);
-  DCHECK_LT(index, 8);
-  DCHECK_LT(base, 8);
-  uint8_t sib = (scale << 6) | (index << 3) | base;
+  DCHECK_LT(RegStorage::RegNum(index), 8);
+  DCHECK_LT(RegStorage::RegNum(base), 8);
+  uint8_t sib = (scale << 6) | (RegStorage::RegNum(index) << 3) | RegStorage::RegNum(base);
   code_buffer_.push_back(sib);
   EmitDisp(base, disp);
 }
@@ -651,24 +653,22 @@
   // There's no 3-byte instruction with +rd
   DCHECK(entry->skeleton.opcode != 0x0F ||
          (entry->skeleton.extra_opcode1 != 0x38 && entry->skeleton.extra_opcode1 != 0x3A));
-  DCHECK(!X86_FPREG(reg));
-  DCHECK_LT(reg, 8);
-  code_buffer_.back() += reg;
+  DCHECK(!RegStorage::IsFloat(reg));
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
+  code_buffer_.back() += RegStorage::RegNum(reg);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
   DCHECK_EQ(0, entry->skeleton.immediate_bytes);
 }
 
 void X86Mir2Lir::EmitOpReg(const X86EncodingMap* entry, uint8_t reg) {
   EmitPrefixAndOpcode(entry);
-  if (X86_FPREG(reg)) {
-    reg = reg & X86_FP_REG_MASK;
-  }
-  if (reg >= 4) {
-    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
+  if (RegStorage::RegNum(reg) >= 4) {
+    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " "
+        << static_cast<int>(RegStorage::RegNum(reg))
         << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
   }
-  DCHECK_LT(reg, 8);
-  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
+  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
   code_buffer_.push_back(modrm);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
   DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -696,13 +696,10 @@
 void X86Mir2Lir::EmitMemReg(const X86EncodingMap* entry,
                        uint8_t base, int disp, uint8_t reg) {
   EmitPrefixAndOpcode(entry);
-  if (X86_FPREG(reg)) {
-    reg = reg & X86_FP_REG_MASK;
-  }
-  if (reg >= 4) {
+  if (RegStorage::RegNum(reg) >= 4) {
     DCHECK(strchr(entry->name, '8') == NULL ||
            entry->opcode == kX86Movzx8RM || entry->opcode == kX86Movsx8RM)
-        << entry->name << " " << static_cast<int>(reg)
+        << entry->name << " " << static_cast<int>(RegStorage::RegNum(reg))
         << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
   }
   EmitModrmDisp(reg, base, disp);
@@ -720,17 +717,14 @@
 void X86Mir2Lir::EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index,
                               int scale, int disp) {
   EmitPrefixAndOpcode(entry);
-  if (X86_FPREG(reg)) {
-    reg = reg & X86_FP_REG_MASK;
-  }
   EmitModrmSibDisp(reg, base, index, scale, disp);
   DCHECK_EQ(0, entry->skeleton.modrm_opcode);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
   DCHECK_EQ(0, entry->skeleton.immediate_bytes);
 }
 
-void X86Mir2Lir::EmitArrayReg(const X86EncodingMap* entry, uint8_t base, uint8_t index, int scale, int disp,
-                  uint8_t reg) {
+void X86Mir2Lir::EmitArrayReg(const X86EncodingMap* entry, uint8_t base, uint8_t index, int scale,
+                              int disp, uint8_t reg) {
   // Opcode will flip operands.
   EmitRegArray(entry, reg, base, index, scale, disp);
 }
@@ -738,15 +732,13 @@
 void X86Mir2Lir::EmitRegThread(const X86EncodingMap* entry, uint8_t reg, int disp) {
   DCHECK_NE(entry->skeleton.prefix1, 0);
   EmitPrefixAndOpcode(entry);
-  if (X86_FPREG(reg)) {
-    reg = reg & X86_FP_REG_MASK;
-  }
-  if (reg >= 4) {
-    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
+  if (RegStorage::RegNum(reg) >= 4) {
+    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " "
+        << static_cast<int>(RegStorage::RegNum(reg))
         << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
   }
-  DCHECK_LT(reg, 8);
-  uint8_t modrm = (0 << 6) | (reg << 3) | rBP;
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
+  uint8_t modrm = (0 << 6) | (RegStorage::RegNum(reg) << 3) | rs_rBP.GetRegNum();
   code_buffer_.push_back(modrm);
   code_buffer_.push_back(disp & 0xFF);
   code_buffer_.push_back((disp >> 8) & 0xFF);
@@ -759,15 +751,9 @@
 
 void X86Mir2Lir::EmitRegReg(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2) {
   EmitPrefixAndOpcode(entry);
-  if (X86_FPREG(reg1)) {
-    reg1 = reg1 & X86_FP_REG_MASK;
-  }
-  if (X86_FPREG(reg2)) {
-    reg2 = reg2 & X86_FP_REG_MASK;
-  }
-  DCHECK_LT(reg1, 8);
-  DCHECK_LT(reg2, 8);
-  uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
+  DCHECK_LT(RegStorage::RegNum(reg1), 8);
+  DCHECK_LT(RegStorage::RegNum(reg2), 8);
+  uint8_t modrm = (3 << 6) | (RegStorage::RegNum(reg1) << 3) | RegStorage::RegNum(reg2);
   code_buffer_.push_back(modrm);
   DCHECK_EQ(0, entry->skeleton.modrm_opcode);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
@@ -777,15 +763,9 @@
 void X86Mir2Lir::EmitRegRegImm(const X86EncodingMap* entry,
                           uint8_t reg1, uint8_t reg2, int32_t imm) {
   EmitPrefixAndOpcode(entry);
-  if (X86_FPREG(reg1)) {
-    reg1 = reg1 & X86_FP_REG_MASK;
-  }
-  if (X86_FPREG(reg2)) {
-    reg2 = reg2 & X86_FP_REG_MASK;
-  }
-  DCHECK_LT(reg1, 8);
-  DCHECK_LT(reg2, 8);
-  uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
+  DCHECK_LT(RegStorage::RegNum(reg1), 8);
+  DCHECK_LT(RegStorage::RegNum(reg2), 8);
+  uint8_t modrm = (3 << 6) | (RegStorage::RegNum(reg1) << 3) | RegStorage::RegNum(reg2);
   code_buffer_.push_back(modrm);
   DCHECK_EQ(0, entry->skeleton.modrm_opcode);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
@@ -800,8 +780,8 @@
 void X86Mir2Lir::EmitRegMemImm(const X86EncodingMap* entry,
                                uint8_t reg, uint8_t base, int disp, int32_t imm) {
   EmitPrefixAndOpcode(entry);
-  DCHECK(!X86_FPREG(reg));
-  DCHECK_LT(reg, 8);
+  DCHECK(!RegStorage::IsFloat(reg));
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
   EmitModrmDisp(reg, base, disp);
   DCHECK_EQ(0, entry->skeleton.modrm_opcode);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
@@ -817,14 +797,11 @@
   } else {
     DCHECK_EQ(0, entry->skeleton.prefix2);
   }
-  if (reg == rAX && entry->skeleton.ax_opcode != 0) {
+  if (RegStorage::RegNum(reg) == rs_rAX.GetRegNum() && entry->skeleton.ax_opcode != 0) {
     code_buffer_.push_back(entry->skeleton.ax_opcode);
   } else {
     EmitOpcode(entry);
-    if (X86_FPREG(reg)) {
-      reg = reg & X86_FP_REG_MASK;
-    }
-    uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+    uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
     code_buffer_.push_back(modrm);
   }
   EmitImm(entry, imm);
@@ -839,7 +816,7 @@
 
 void X86Mir2Lir::EmitThreadImm(const X86EncodingMap* entry, int disp, int imm) {
   EmitPrefixAndOpcode(entry);
-  uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
+  uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rs_rBP.GetRegNum();
   code_buffer_.push_back(modrm);
   code_buffer_.push_back(disp & 0xFF);
   code_buffer_.push_back((disp >> 8) & 0xFF);
@@ -850,8 +827,8 @@
 }
 
 void X86Mir2Lir::EmitMovRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) {
-  DCHECK_LT(reg, 8);
-  code_buffer_.push_back(0xB8 + reg);
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
+  code_buffer_.push_back(0xB8 + RegStorage::RegNum(reg));
   code_buffer_.push_back(imm & 0xFF);
   code_buffer_.push_back((imm >> 8) & 0xFF);
   code_buffer_.push_back((imm >> 16) & 0xFF);
@@ -869,12 +846,13 @@
   DCHECK_NE(0x0F, entry->skeleton.opcode);
   DCHECK_EQ(0, entry->skeleton.extra_opcode1);
   DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  if (reg >= 4) {
-    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
+  if (RegStorage::RegNum(reg) >= 4) {
+    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " "
+        << static_cast<int>(RegStorage::RegNum(reg))
         << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
   }
-  DCHECK_LT(reg, 8);
-  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
+  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
   code_buffer_.push_back(modrm);
   if (imm != 1) {
     DCHECK_EQ(entry->skeleton.immediate_bytes, 1);
@@ -884,14 +862,14 @@
 }
 
 void X86Mir2Lir::EmitShiftRegCl(const X86EncodingMap* entry, uint8_t reg, uint8_t cl) {
-  DCHECK_EQ(cl, static_cast<uint8_t>(rCX));
+  DCHECK_EQ(cl, static_cast<uint8_t>(rs_rCX.GetReg()));
   EmitPrefix(entry);
   code_buffer_.push_back(entry->skeleton.opcode);
   DCHECK_NE(0x0F, entry->skeleton.opcode);
   DCHECK_EQ(0, entry->skeleton.extra_opcode1);
   DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  DCHECK_LT(reg, 8);
-  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
+  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
   code_buffer_.push_back(modrm);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
   DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -899,13 +877,13 @@
 
 void X86Mir2Lir::EmitShiftMemCl(const X86EncodingMap* entry, uint8_t base,
                                 int displacement, uint8_t cl) {
-  DCHECK_EQ(cl, static_cast<uint8_t>(rCX));
+  DCHECK_EQ(cl, static_cast<uint8_t>(rs_rCX.GetReg()));
   EmitPrefix(entry);
   code_buffer_.push_back(entry->skeleton.opcode);
   DCHECK_NE(0x0F, entry->skeleton.opcode);
   DCHECK_EQ(0, entry->skeleton.extra_opcode1);
   DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  DCHECK_LT(base, 8);
+  DCHECK_LT(RegStorage::RegNum(base), 8);
   EmitModrmDisp(entry->skeleton.modrm_opcode, base, displacement);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
   DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -926,13 +904,14 @@
   DCHECK_EQ(0x90, entry->skeleton.extra_opcode1);
   code_buffer_.push_back(0x90 | condition);
   DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  DCHECK_LT(reg, 8);
-  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
+  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
   code_buffer_.push_back(modrm);
   DCHECK_EQ(entry->skeleton.immediate_bytes, 0);
 }
 
-void X86Mir2Lir::EmitRegRegCond(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2, uint8_t condition) {
+void X86Mir2Lir::EmitRegRegCond(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2,
+                                uint8_t condition) {
   // Generate prefix and opcode without the condition
   EmitPrefixAndOpcode(entry);
 
@@ -945,14 +924,14 @@
   DCHECK_EQ(0, entry->skeleton.modrm_opcode);
 
   // Check that registers requested for encoding are sane.
-  DCHECK_LT(reg1, 8);
-  DCHECK_LT(reg2, 8);
+  DCHECK_LT(RegStorage::RegNum(reg1), 8);
+  DCHECK_LT(RegStorage::RegNum(reg2), 8);
 
   // For register to register encoding, the mod is 3.
   const uint8_t mod = (3 << 6);
 
   // Encode the ModR/M byte now.
-  const uint8_t modrm = mod | (reg1 << 3) | reg2;
+  const uint8_t modrm = mod | (RegStorage::RegNum(reg1) << 3) | RegStorage::RegNum(reg2);
   code_buffer_.push_back(modrm);
 }
 
@@ -975,8 +954,8 @@
     DCHECK(entry->opcode == kX86JmpR);
     code_buffer_.push_back(entry->skeleton.opcode);
     uint8_t reg = static_cast<uint8_t>(rel);
-    DCHECK_LT(reg, 8);
-    uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+    DCHECK_LT(RegStorage::RegNum(reg), 8);
+    uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | RegStorage::RegNum(reg);
     code_buffer_.push_back(modrm);
   }
 }
@@ -1018,7 +997,7 @@
 void X86Mir2Lir::EmitCallThread(const X86EncodingMap* entry, int disp) {
   DCHECK_NE(entry->skeleton.prefix1, 0);
   EmitPrefixAndOpcode(entry);
-  uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
+  uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rs_rBP.GetRegNum();
   code_buffer_.push_back(modrm);
   code_buffer_.push_back(disp & 0xFF);
   code_buffer_.push_back((disp >> 8) & 0xFF);
@@ -1042,26 +1021,23 @@
     disp = tab_rec->offset;
   }
   EmitPrefix(entry);
-  if (X86_FPREG(reg)) {
-    reg = reg & X86_FP_REG_MASK;
-  }
-  DCHECK_LT(reg, 8);
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
   if (entry->opcode == kX86PcRelLoadRA) {
     code_buffer_.push_back(entry->skeleton.opcode);
     DCHECK_NE(0x0F, entry->skeleton.opcode);
     DCHECK_EQ(0, entry->skeleton.extra_opcode1);
     DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    uint8_t modrm = (2 << 6) | (reg << 3) | rX86_SP;
+    uint8_t modrm = (2 << 6) | (RegStorage::RegNum(reg) << 3) | rs_rX86_SP.GetRegNum();
     code_buffer_.push_back(modrm);
     DCHECK_LT(scale, 4);
-    DCHECK_LT(index, 8);
-    DCHECK_LT(base_or_table, 8);
+    DCHECK_LT(RegStorage::RegNum(index), 8);
+    DCHECK_LT(RegStorage::RegNum(base_or_table), 8);
     uint8_t base = static_cast<uint8_t>(base_or_table);
-    uint8_t sib = (scale << 6) | (index << 3) | base;
+    uint8_t sib = (scale << 6) | (RegStorage::RegNum(index) << 3) | RegStorage::RegNum(base);
     code_buffer_.push_back(sib);
     DCHECK_EQ(0, entry->skeleton.immediate_bytes);
   } else {
-    code_buffer_.push_back(entry->skeleton.opcode + reg);
+    code_buffer_.push_back(entry->skeleton.opcode + RegStorage::RegNum(reg));
   }
   code_buffer_.push_back(disp & 0xFF);
   code_buffer_.push_back((disp >> 8) & 0xFF);
@@ -1079,10 +1055,11 @@
   code_buffer_.push_back(0);
   code_buffer_.push_back(0);
 
-  DCHECK_LT(reg, 8);
-  code_buffer_.push_back(0x58 + reg);  // pop reg
+  DCHECK_LT(RegStorage::RegNum(reg), 8);
+  code_buffer_.push_back(0x58 + RegStorage::RegNum(reg));  // pop reg
 
-  EmitRegImm(&X86Mir2Lir::EncodingMap[kX86Sub32RI], reg, offset + 5 /* size of call +0 */);
+  EmitRegImm(&X86Mir2Lir::EncodingMap[kX86Sub32RI], RegStorage::RegNum(reg),
+             offset + 5 /* size of call +0 */);
 }
 
 void X86Mir2Lir::EmitUnimplemented(const X86EncodingMap* entry, LIR* lir) {
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 06cc861..f701a1f 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -152,10 +152,10 @@
     LoadValueDirect(rl_method, rs_rX86_ARG2);
     store_method_addr_used_ = true;
   } else {
-    NewLIR1(kX86StartOfMethod, rX86_ARG2);
+    NewLIR1(kX86StartOfMethod, rs_rX86_ARG2.GetReg());
   }
-  NewLIR2(kX86PcRelAdr, rX86_ARG1, WrapPointer(tab_rec));
-  NewLIR2(kX86Add32RR, rX86_ARG1, rX86_ARG2);
+  NewLIR2(kX86PcRelAdr, rs_rX86_ARG1.GetReg(), WrapPointer(tab_rec));
+  NewLIR2(kX86Add32RR, rs_rX86_ARG1.GetReg(), rs_rX86_ARG2.GetReg());
   CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pHandleFillArrayData), rs_rX86_ARG0,
                           rs_rX86_ARG1, true);
 }
@@ -191,9 +191,9 @@
    * expanding the frame or flushing.  This leaves the utility
    * code with no spare temps.
    */
-  LockTemp(rX86_ARG0);
-  LockTemp(rX86_ARG1);
-  LockTemp(rX86_ARG2);
+  LockTemp(rs_rX86_ARG0);
+  LockTemp(rs_rX86_ARG1);
+  LockTemp(rs_rX86_ARG2);
 
   /* Build frame, return address already on stack */
   // TODO: 64 bit.
@@ -240,7 +240,7 @@
     // in case a signal comes in that's not using an alternate signal stack and the large frame may
     // have moved us outside of the reserved area at the end of the stack.
     // cmp rX86_SP, fs:[stack_end_]; jcc throw_slowpath
-    OpRegThreadMem(kOpCmp, rX86_SP, Thread::StackEndOffset<4>());
+    OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<4>());
     LIR* branch = OpCondBranch(kCondUlt, nullptr);
     AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, frame_size_ - 4));
   }
@@ -249,15 +249,15 @@
 
   if (base_of_code_ != nullptr) {
     // We have been asked to save the address of the method start for later use.
-    setup_method_address_[0] = NewLIR1(kX86StartOfMethod, rX86_ARG0);
+    setup_method_address_[0] = NewLIR1(kX86StartOfMethod, rs_rX86_ARG0.GetReg());
     int displacement = SRegOffset(base_of_code_->s_reg_low);
     // Native pointer - must be natural word size.
     setup_method_address_[1] = StoreWordDisp(rs_rX86_SP, displacement, rs_rX86_ARG0);
   }
 
-  FreeTemp(rX86_ARG0);
-  FreeTemp(rX86_ARG1);
-  FreeTemp(rX86_ARG2);
+  FreeTemp(rs_rX86_ARG0);
+  FreeTemp(rs_rX86_ARG1);
+  FreeTemp(rs_rX86_ARG2);
 }
 
 void X86Mir2Lir::GenExitSequence() {
@@ -265,8 +265,8 @@
    * In the exit path, rX86_RET0/rX86_RET1 are live - make sure they aren't
    * allocated by the register utilities as temps.
    */
-  LockTemp(rX86_RET0);
-  LockTemp(rX86_RET1);
+  LockTemp(rs_rX86_RET0);
+  LockTemp(rs_rX86_RET1);
 
   NewLIR0(kPseudoMethodExit);
   UnSpillCoreRegs();
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 760290c..c3ea55f 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -37,27 +37,21 @@
     LIR* LoadBaseDispWide(RegStorage r_base, int displacement, RegStorage r_dest, int s_reg);
     LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
                          OpSize size);
-    // TODO: collapse r_dest, r_dest_hi
     LIR* LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
-                             RegStorage r_dest, RegStorage r_dest_hi, OpSize size, int s_reg);
+                             RegStorage r_dest, OpSize size, int s_reg);
     LIR* LoadConstantNoClobber(RegStorage r_dest, int value);
     LIR* LoadConstantWide(RegStorage r_dest, int64_t value);
     LIR* StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size);
     LIR* StoreBaseDispWide(RegStorage r_base, int displacement, RegStorage r_src);
     LIR* StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src, int scale,
                           OpSize size);
-    // TODO: collapse r_src, r_src_hi
     LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
-                              RegStorage r_src, RegStorage r_src_hi, OpSize size, int s_reg);
+                              RegStorage r_src, OpSize size, int s_reg);
     void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
 
     // Required for target - register utilities.
-    bool IsFpReg(int reg);
-    bool IsFpReg(RegStorage reg);
-    bool SameRegType(int reg1, int reg2);
     RegStorage AllocTypedTemp(bool fp_hint, int reg_class);
     RegStorage AllocTypedTempWide(bool fp_hint, int reg_class);
-    int S2d(int low_reg, int high_reg);
     RegStorage TargetReg(SpecialTargetRegister reg);
     RegStorage GetArgMappingToPhysicalReg(int arg_num);
     RegLocation GetReturnAlt();
@@ -66,16 +60,14 @@
     RegLocation LocCReturnDouble();
     RegLocation LocCReturnFloat();
     RegLocation LocCReturnWide();
-    uint32_t FpRegMask();
-    uint64_t GetRegMaskCommon(int reg);
+    uint64_t GetRegMaskCommon(RegStorage reg);
     void AdjustSpillMask();
     void ClobberCallerSave();
-    void FlushReg(RegStorage reg);
-    void FlushRegWide(RegStorage reg);
     void FreeCallTemps();
     void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
     void LockCallTemps();
-    void MarkPreservedSingle(int v_reg, int reg);
+    void MarkPreservedSingle(int v_reg, RegStorage reg);
+    void MarkPreservedDouble(int v_reg, RegStorage reg);
     void CompilerInitializeRegAlloc();
 
     // Required for target - miscellaneous.
@@ -252,7 +244,7 @@
     void OpRegCopyWide(RegStorage dest, RegStorage src);
     void OpTlsCmp(ThreadOffset<4> offset, int val);
 
-    void OpRegThreadMem(OpKind op, int r_dest, ThreadOffset<4> thread_offset);
+    void OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<4> thread_offset);
     void SpillCoreRegs();
     void UnSpillCoreRegs();
     static const X86EncodingMap EncodingMap[kX86Last];
@@ -261,12 +253,6 @@
     bool InexpensiveConstantLong(int64_t value);
     bool InexpensiveConstantDouble(int64_t value);
 
-    RegLocation UpdateLocWide(RegLocation loc);
-    RegLocation EvalLocWide(RegLocation loc, int reg_class, bool update);
-    RegLocation EvalLoc(RegLocation loc, int reg_class, bool update);
-    RegStorage AllocTempDouble();
-    void ResetDefLocWide(RegLocation rl);
-
     /*
      * @brief x86 specific codegen for int operations.
      * @param opcode Operation to perform.
@@ -379,7 +365,6 @@
     void EmitUnimplemented(const X86EncodingMap* entry, LIR* lir);
     void GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
                                   int64_t val, ConditionCode ccode);
-    void OpVectorRegCopyWide(uint8_t fp_reg, uint8_t low_reg, uint8_t high_reg);
     void GenConstWide(RegLocation rl_dest, int64_t value);
 
     static bool ProvidesFullMemoryBarrier(X86OpCode opcode);
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index f7b0c9d..1ed0b63 100644
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -67,7 +67,7 @@
   RegStorage r_src1 = rl_src1.reg;
   RegStorage r_src2 = rl_src2.reg;
   if (r_dest == r_src2) {
-    r_src2 = AllocTempFloat();
+    r_src2 = AllocTempSingle();
     OpRegCopy(r_src2, r_dest);
   }
   OpRegCopy(r_dest, r_src1);
@@ -77,6 +77,12 @@
 
 void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
                                   RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
+  DCHECK(rl_dest.wide);
+  DCHECK(rl_dest.fp);
+  DCHECK(rl_src1.wide);
+  DCHECK(rl_src1.fp);
+  DCHECK(rl_src2.wide);
+  DCHECK(rl_src2.fp);
   X86OpCode op = kX86Nop;
   RegLocation rl_result;
 
@@ -112,22 +118,14 @@
       LOG(FATAL) << "Unexpected opcode: " << opcode;
   }
   rl_src1 = LoadValueWide(rl_src1, kFPReg);
-  DCHECK(rl_src1.wide);
   rl_src2 = LoadValueWide(rl_src2, kFPReg);
-  DCHECK(rl_src2.wide);
   rl_result = EvalLoc(rl_dest, kFPReg, true);
-  DCHECK(rl_dest.wide);
-  DCHECK(rl_result.wide);
-  // TODO: update with direct 64-bit reg.
-  int r_dest = S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg());
-  int r_src1 = S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg());
-  int r_src2 = S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg());
-  if (r_dest == r_src2) {
-    r_src2 = AllocTempDouble().GetLowReg() | X86_FP_DOUBLE;
-    OpRegCopy(RegStorage::Solo64(r_src2), RegStorage::Solo64(r_dest));
+  if (rl_result.reg == rl_src2.reg) {
+    rl_src2.reg = AllocTempDouble();
+    OpRegCopy(rl_src2.reg, rl_result.reg);
   }
-  OpRegCopy(RegStorage::Solo64(r_dest), RegStorage::Solo64(r_src1));
-  NewLIR2(op, r_dest, r_src2);
+  OpRegCopy(rl_result.reg, rl_src1.reg);
+  NewLIR2(op, rl_result.reg.GetReg(), rl_src2.reg.GetReg());
   StoreValueWide(rl_dest, rl_result);
 }
 
@@ -141,16 +139,13 @@
 
   // If the source is in physical register, then put it in its location on stack.
   if (rl_src.location == kLocPhysReg) {
-    RegisterInfo* lo_info = GetRegInfo(rl_src.reg.GetLowReg());
+    RegisterInfo* reg_info = GetRegInfo(rl_src.reg);
 
-    if (lo_info != nullptr && lo_info->is_temp) {
+    if (reg_info != nullptr && reg_info->IsTemp()) {
       // Calling FlushSpecificReg because it will only write back VR if it is dirty.
-      FlushSpecificReg(lo_info);
-      // ResetDef for low/high to prevent NullifyRange from removing stores.
-      ResetDef(rl_src.reg.GetLowReg());
-      if (rl_src.reg.GetLowReg() != rl_src.reg.GetHighReg() && GetRegInfo(rl_src.reg.GetHighReg()) != nullptr) {
-        ResetDef(rl_src.reg.GetHighReg());
-      }
+      FlushSpecificReg(reg_info);
+      // ResetDef to prevent NullifyRange from removing stores.
+      ResetDef(rl_src.reg);
     } else {
       // It must have been register promoted if it is not a temp but is still in physical
       // register. Since we need it to be in memory to convert, we place it there now.
@@ -159,9 +154,10 @@
   }
 
   // Push the source virtual register onto the x87 stack.
-  LIR *fild64 = NewLIR2NoDest(kX86Fild64M, TargetReg(kSp).GetReg(), src_v_reg_offset + LOWORD_OFFSET);
+  LIR *fild64 = NewLIR2NoDest(kX86Fild64M, TargetReg(kSp).GetReg(),
+                              src_v_reg_offset + LOWORD_OFFSET);
   AnnotateDalvikRegAccess(fild64, (src_v_reg_offset + LOWORD_OFFSET) >> 2,
-      true /* is_load */, true /* is64bit */);
+                          true /* is_load */, true /* is64bit */);
 
   // Now pop off x87 stack and store it in the destination VR's stack location.
   int opcode = is_double ? kX86Fstp64M : kX86Fstp32M;
@@ -204,7 +200,6 @@
                                RegLocation rl_src) {
   RegisterClass rcSrc = kFPReg;
   X86OpCode op = kX86Nop;
-  int src_reg;
   RegLocation rl_result;
   switch (opcode) {
     case Instruction::INT_TO_FLOAT:
@@ -225,18 +220,17 @@
       break;
     case Instruction::FLOAT_TO_INT: {
       rl_src = LoadValue(rl_src, kFPReg);
-      src_reg = rl_src.reg.GetReg();
       // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
       ClobberSReg(rl_dest.s_reg_low);
       rl_result = EvalLoc(rl_dest, kCoreReg, true);
-      int temp_reg = AllocTempFloat().GetReg();
+      RegStorage temp_reg = AllocTempSingle();
 
       LoadConstant(rl_result.reg, 0x7fffffff);
-      NewLIR2(kX86Cvtsi2ssRR, temp_reg, rl_result.reg.GetReg());
-      NewLIR2(kX86ComissRR, src_reg, temp_reg);
+      NewLIR2(kX86Cvtsi2ssRR, temp_reg.GetReg(), rl_result.reg.GetReg());
+      NewLIR2(kX86ComissRR, rl_src.reg.GetReg(), temp_reg.GetReg());
       LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
       LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
-      NewLIR2(kX86Cvttss2siRR, rl_result.reg.GetReg(), src_reg);
+      NewLIR2(kX86Cvttss2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
       LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
       branch_na_n->target = NewLIR0(kPseudoTargetLabel);
       NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
@@ -247,18 +241,17 @@
     }
     case Instruction::DOUBLE_TO_INT: {
       rl_src = LoadValueWide(rl_src, kFPReg);
-      src_reg = rl_src.reg.GetLowReg();
       // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
       ClobberSReg(rl_dest.s_reg_low);
       rl_result = EvalLoc(rl_dest, kCoreReg, true);
-      int temp_reg = AllocTempDouble().GetLowReg() | X86_FP_DOUBLE;
+      RegStorage temp_reg = AllocTempDouble();
 
       LoadConstant(rl_result.reg, 0x7fffffff);
-      NewLIR2(kX86Cvtsi2sdRR, temp_reg, rl_result.reg.GetReg());
-      NewLIR2(kX86ComisdRR, src_reg, temp_reg);
+      NewLIR2(kX86Cvtsi2sdRR, temp_reg.GetReg(), rl_result.reg.GetReg());
+      NewLIR2(kX86ComisdRR, rl_src.reg.GetReg(), temp_reg.GetReg());
       LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
       LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
-      NewLIR2(kX86Cvttsd2siRR, rl_result.reg.GetReg(), src_reg);
+      NewLIR2(kX86Cvttsd2siRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
       LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
       branch_na_n->target = NewLIR0(kPseudoTargetLabel);
       NewLIR2(kX86Xor32RR, rl_result.reg.GetReg(), rl_result.reg.GetReg());
@@ -282,20 +275,18 @@
     default:
       LOG(INFO) << "Unexpected opcode: " << opcode;
   }
+  // At this point, target will be either float or double.
+  DCHECK(rl_dest.fp);
   if (rl_src.wide) {
     rl_src = LoadValueWide(rl_src, rcSrc);
-    src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
   } else {
     rl_src = LoadValue(rl_src, rcSrc);
-    src_reg = rl_src.reg.GetReg();
   }
+  rl_result = EvalLoc(rl_dest, kFPReg, true);
+  NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
   if (rl_dest.wide) {
-    rl_result = EvalLoc(rl_dest, kFPReg, true);
-    NewLIR2(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), src_reg);
     StoreValueWide(rl_dest, rl_result);
   } else {
-    rl_result = EvalLoc(rl_dest, kFPReg, true);
-    NewLIR2(op, rl_result.reg.GetReg(), src_reg);
     StoreValue(rl_dest, rl_result);
   }
 }
@@ -304,34 +295,28 @@
                           RegLocation rl_src1, RegLocation rl_src2) {
   bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
   bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
-  int src_reg1;
-  int src_reg2;
   if (single) {
     rl_src1 = LoadValue(rl_src1, kFPReg);
-    src_reg1 = rl_src1.reg.GetReg();
     rl_src2 = LoadValue(rl_src2, kFPReg);
-    src_reg2 = rl_src2.reg.GetReg();
   } else {
     rl_src1 = LoadValueWide(rl_src1, kFPReg);
-    src_reg1 = S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg());
     rl_src2 = LoadValueWide(rl_src2, kFPReg);
-    src_reg2 = S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg());
   }
   // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
   ClobberSReg(rl_dest.s_reg_low);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   LoadConstantNoClobber(rl_result.reg, unordered_gt ? 1 : 0);
   if (single) {
-    NewLIR2(kX86UcomissRR, src_reg1, src_reg2);
+    NewLIR2(kX86UcomissRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
   } else {
-    NewLIR2(kX86UcomisdRR, src_reg1, src_reg2);
+    NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
   }
   LIR* branch = NULL;
   if (unordered_gt) {
     branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
   }
   // If the result reg can't be byte accessed, use a jump and move instead of a set.
-  if (rl_result.reg.GetReg() >= 4) {
+  if (rl_result.reg.GetReg() >= rs_rX86_SP.GetReg()) {
     LIR* branch2 = NULL;
     if (unordered_gt) {
       branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
@@ -363,8 +348,7 @@
     rl_src2 = mir_graph_->GetSrcWide(mir, 2);
     rl_src1 = LoadValueWide(rl_src1, kFPReg);
     rl_src2 = LoadValueWide(rl_src2, kFPReg);
-    NewLIR2(kX86UcomisdRR, S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg()),
-            S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
+    NewLIR2(kX86UcomisdRR, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
   } else {
     rl_src1 = mir_graph_->GetSrc(mir, 0);
     rl_src2 = mir_graph_->GetSrc(mir, 1);
@@ -442,8 +426,7 @@
   RegLocation rl_dest = InlineTargetWide(info);  // double place for result
   rl_src = LoadValueWide(rl_src, kFPReg);
   RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
-  NewLIR2(kX86SqrtsdRR, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
-          S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
+  NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
   StoreValueWide(rl_dest, rl_result);
   return true;
 }
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 96c4cbe..4446f43 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -33,18 +33,18 @@
                             RegLocation rl_src2) {
   FlushAllRegs();
   LockCallTemps();  // Prepare for explicit register usage
-  RegStorage r_tmp1(RegStorage::k64BitPair, r0, r1);
-  RegStorage r_tmp2(RegStorage::k64BitPair, r2, r3);
+  RegStorage r_tmp1 = RegStorage::MakeRegPair(rs_r0, rs_r1);
+  RegStorage r_tmp2 = RegStorage::MakeRegPair(rs_r2, rs_r3);
   LoadValueDirectWideFixed(rl_src1, r_tmp1);
   LoadValueDirectWideFixed(rl_src2, r_tmp2);
   // Compute (r1:r0) = (r1:r0) - (r3:r2)
   OpRegReg(kOpSub, rs_r0, rs_r2);  // r0 = r0 - r2
   OpRegReg(kOpSbc, rs_r1, rs_r3);  // r1 = r1 - r3 - CF
-  NewLIR2(kX86Set8R, r2, kX86CondL);  // r2 = (r1:r0) < (r3:r2) ? 1 : 0
-  NewLIR2(kX86Movzx8RR, r2, r2);
+  NewLIR2(kX86Set8R, rs_r2.GetReg(), kX86CondL);  // r2 = (r1:r0) < (r3:r2) ? 1 : 0
+  NewLIR2(kX86Movzx8RR, rs_r2.GetReg(), rs_r2.GetReg());
   OpReg(kOpNeg, rs_r2);         // r2 = -r2
   OpRegReg(kOpOr, rs_r0, rs_r1);   // r0 = high | low - sets ZF
-  NewLIR2(kX86Set8R, r0, kX86CondNz);  // r0 = (r1:r0) != (r3:r2) ? 1 : 0
+  NewLIR2(kX86Set8R, rs_r0.GetReg(), kX86CondNz);  // r0 = (r1:r0) != (r3:r2) ? 1 : 0
   NewLIR2(kX86Movzx8RR, r0, r0);
   OpRegReg(kOpOr, rs_r0, rs_r2);   // r0 = r0 | r2
   RegLocation rl_result = LocCReturn();
@@ -106,7 +106,7 @@
   if (r_src.IsPair()) {
     r_src = r_src.GetLow();
   }
-  if (X86_FPREG(r_dest.GetReg()) || X86_FPREG(r_src.GetReg()))
+  if (r_dest.IsFloat() || r_src.IsFloat())
     return OpFpRegCopy(r_dest, r_src);
   LIR* res = RawLIR(current_dalvik_offset_, kX86Mov32RR,
                     r_dest.GetReg(), r_src.GetReg());
@@ -125,31 +125,28 @@
 
 void X86Mir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
   if (r_dest != r_src) {
-    // FIXME: handle k64BitSolo when we start using them.
-    DCHECK(r_dest.IsPair());
-    DCHECK(r_src.IsPair());
-    bool dest_fp = X86_FPREG(r_dest.GetLowReg());
-    bool src_fp = X86_FPREG(r_src.GetLowReg());
+    bool dest_fp = r_dest.IsFloat();
+    bool src_fp = r_src.IsFloat();
     if (dest_fp) {
       if (src_fp) {
-        // TODO: we ought to handle this case here - reserve OpRegCopy for 32-bit copies.
-        OpRegCopy(RegStorage::Solo64(S2d(r_dest.GetLowReg(), r_dest.GetHighReg())),
-                  RegStorage::Solo64(S2d(r_src.GetLowReg(), r_src.GetHighReg())));
+        OpRegCopy(r_dest, r_src);
       } else {
         // TODO: Prevent this from happening in the code. The result is often
         // unused or could have been loaded more easily from memory.
-        NewLIR2(kX86MovdxrRR, r_dest.GetLowReg(), r_src.GetLowReg());
+        NewLIR2(kX86MovdxrRR, r_dest.GetReg(), r_src.GetLowReg());
         RegStorage r_tmp = AllocTempDouble();
-        NewLIR2(kX86MovdxrRR, r_tmp.GetLowReg(), r_src.GetHighReg());
-        NewLIR2(kX86PunpckldqRR, r_dest.GetLowReg(), r_tmp.GetLowReg());
+        NewLIR2(kX86MovdxrRR, r_tmp.GetReg(), r_src.GetHighReg());
+        NewLIR2(kX86PunpckldqRR, r_dest.GetReg(), r_tmp.GetReg());
         FreeTemp(r_tmp);
       }
     } else {
       if (src_fp) {
-        NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetLowReg());
-        NewLIR2(kX86PsrlqRI, r_src.GetLowReg(), 32);
-        NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), r_src.GetLowReg());
+        NewLIR2(kX86MovdrxRR, r_dest.GetLowReg(), r_src.GetReg());
+        NewLIR2(kX86PsrlqRI, r_src.GetReg(), 32);
+        NewLIR2(kX86MovdrxRR, r_dest.GetHighReg(), r_src.GetReg());
       } else {
+        DCHECK(r_dest.IsPair());
+        DCHECK(r_src.IsPair());
         // Handle overlap
         if (r_src.GetHighReg() == r_dest.GetLowReg() && r_src.GetLowReg() == r_dest.GetHighReg()) {
           // Deal with cycles.
@@ -289,8 +286,8 @@
 
   FlushAllRegs();
   LockCallTemps();  // Prepare for explicit register usage
-  RegStorage r_tmp1(RegStorage::k64BitPair, r0, r1);
-  RegStorage r_tmp2(RegStorage::k64BitPair, r2, r3);
+  RegStorage r_tmp1 = RegStorage::MakeRegPair(rs_r0, rs_r1);
+  RegStorage r_tmp2 = RegStorage::MakeRegPair(rs_r2, rs_r3);
   LoadValueDirectWideFixed(rl_src1, r_tmp1);
   LoadValueDirectWideFixed(rl_src2, r_tmp2);
   // Swap operands and condition code to prevent use of zero flag.
@@ -452,8 +449,7 @@
   LockCallTemps();  // Prepare for explicit register usage.
 
   // Assume that the result will be in EDX.
-  RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, rs_r2,
-                           INVALID_SREG, INVALID_SREG};
+  RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, rs_r2, INVALID_SREG, INVALID_SREG};
 
   // handle div/rem by 1 special case.
   if (imm == 1) {
@@ -516,7 +512,7 @@
       // We will need the value later.
       if (rl_src.location == kLocPhysReg) {
         // We can use it directly.
-        DCHECK(rl_src.reg.GetReg() != r0 && rl_src.reg.GetReg() != r2);
+        DCHECK(rl_src.reg.GetReg() != rs_r0.GetReg() && rl_src.reg.GetReg() != rs_r2.GetReg());
         numerator_reg = rl_src.reg;
       } else {
         numerator_reg = rs_r1;
@@ -532,21 +528,21 @@
     LoadConstantNoClobber(rs_r2, magic);
 
     // EDX:EAX = magic & dividend.
-    NewLIR1(kX86Imul32DaR, r2);
+    NewLIR1(kX86Imul32DaR, rs_r2.GetReg());
 
     if (imm > 0 && magic < 0) {
       // Add numerator to EDX.
       DCHECK(numerator_reg.Valid());
-      NewLIR2(kX86Add32RR, r2, numerator_reg.GetReg());
+      NewLIR2(kX86Add32RR, rs_r2.GetReg(), numerator_reg.GetReg());
     } else if (imm < 0 && magic > 0) {
       DCHECK(numerator_reg.Valid());
-      NewLIR2(kX86Sub32RR, r2, numerator_reg.GetReg());
+      NewLIR2(kX86Sub32RR, rs_r2.GetReg(), numerator_reg.GetReg());
     }
 
     // Do we need the shift?
     if (shift != 0) {
       // Shift EDX by 'shift' bits.
-      NewLIR2(kX86Sar32RI, r2, shift);
+      NewLIR2(kX86Sar32RI, rs_r2.GetReg(), shift);
     }
 
     // Add 1 to EDX if EDX < 0.
@@ -555,10 +551,10 @@
     OpRegCopy(rs_r0, rs_r2);
 
     // Move sign bit to bit 0, zeroing the rest.
-    NewLIR2(kX86Shr32RI, r2, 31);
+    NewLIR2(kX86Shr32RI, rs_r2.GetReg(), 31);
 
     // EDX = EDX + EAX.
-    NewLIR2(kX86Add32RR, r2, r0);
+    NewLIR2(kX86Add32RR, rs_r2.GetReg(), rs_r0.GetReg());
 
     // Quotient is in EDX.
     if (!is_div) {
@@ -571,7 +567,7 @@
       OpRegRegImm(kOpMul, rs_r2, rs_r2, imm);
 
       // EDX -= EAX.
-      NewLIR2(kX86Sub32RR, r0, r2);
+      NewLIR2(kX86Sub32RR, rs_r0.GetReg(), rs_r2.GetReg());
 
       // For this case, return the result in EAX.
       rl_result.reg.SetReg(r0);
@@ -625,12 +621,11 @@
   // Expected case.
   minus_one_branch->target = NewLIR0(kPseudoTargetLabel);
   minint_branch->target = minus_one_branch->target;
-  NewLIR1(kX86Idivmod32DaR, r1);
+  NewLIR1(kX86Idivmod32DaR, rs_r1.GetReg());
   done->target = NewLIR0(kPseudoTargetLabel);
 
   // Result is in EAX for div and EDX for rem.
-  RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, rs_r0,
-                           INVALID_SREG, INVALID_SREG};
+  RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, rs_r0, INVALID_SREG, INVALID_SREG};
   if (!is_div) {
     rl_result.reg.SetReg(r2);
   }
@@ -741,16 +736,16 @@
     // TODO: CFI support.
     FlushAllRegs();
     LockCallTemps();
-    RegStorage r_tmp1(RegStorage::k64BitPair, rAX, rDX);
-    RegStorage r_tmp2(RegStorage::k64BitPair, rBX, rCX);
+    RegStorage r_tmp1 = RegStorage::MakeRegPair(rs_rAX, rs_rDX);
+    RegStorage r_tmp2 = RegStorage::MakeRegPair(rs_rBX, rs_rCX);
     LoadValueDirectWideFixed(rl_src_expected, r_tmp1);
     LoadValueDirectWideFixed(rl_src_new_value, r_tmp2);
-    NewLIR1(kX86Push32R, rDI);
-    MarkTemp(rDI);
-    LockTemp(rDI);
-    NewLIR1(kX86Push32R, rSI);
-    MarkTemp(rSI);
-    LockTemp(rSI);
+    NewLIR1(kX86Push32R, rs_rDI.GetReg());
+    MarkTemp(rs_rDI);
+    LockTemp(rs_rDI);
+    NewLIR1(kX86Push32R, rs_rSI.GetReg());
+    MarkTemp(rs_rSI);
+    LockTemp(rs_rSI);
     const int push_offset = 4 /* push edi */ + 4 /* push esi */;
     int srcObjSp = IsInReg(this, rl_src_obj, rs_rSI) ? 0
                 : (IsInReg(this, rl_src_obj, rs_rDI) ? 4
@@ -761,22 +756,23 @@
                    : (IsInReg(this, rl_src_offset, rs_rDI) ? 4
                    : (SRegOffset(rl_src_offset.s_reg_low) + push_offset));
     LoadWordDisp(TargetReg(kSp), srcOffsetSp, rs_rSI);
-    NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0);
+    NewLIR4(kX86LockCmpxchg8bA, rs_rDI.GetReg(), rs_rSI.GetReg(), 0, 0);
 
     // After a store we need to insert barrier in case of potential load. Since the
     // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
     GenMemBarrier(kStoreLoad);
 
-    FreeTemp(rSI);
-    UnmarkTemp(rSI);
-    NewLIR1(kX86Pop32R, rSI);
-    FreeTemp(rDI);
-    UnmarkTemp(rDI);
-    NewLIR1(kX86Pop32R, rDI);
+    FreeTemp(rs_rSI);
+    UnmarkTemp(rs_rSI);
+    NewLIR1(kX86Pop32R, rs_rSI.GetReg());
+    FreeTemp(rs_rDI);
+    UnmarkTemp(rs_rDI);
+    NewLIR1(kX86Pop32R, rs_rDI.GetReg());
     FreeCallTemps();
   } else {
     // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX.
     FlushReg(rs_r0);
+    Clobber(rs_r0);
     LockTemp(rs_r0);
 
     RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
@@ -784,9 +780,9 @@
 
     if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
       // Mark card for object assuming new value is stored.
-      FreeTemp(r0);  // Temporarily release EAX for MarkGCCard().
+      FreeTemp(rs_r0);  // Temporarily release EAX for MarkGCCard().
       MarkGCCard(rl_new_value.reg, rl_object.reg);
-      LockTemp(r0);
+      LockTemp(rs_r0);
     }
 
     RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
@@ -797,7 +793,7 @@
     // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
     GenMemBarrier(kStoreLoad);
 
-    FreeTemp(r0);
+    FreeTemp(rs_r0);
   }
 
   // Convert ZF to boolean
@@ -1003,8 +999,8 @@
       LoadBaseDisp(rs_rX86_SP, displacement, dest, k32, sreg);
       break;
     default:
-      m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest.GetReg(), rX86_SP,
-                  displacement, val);
+      m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest.GetReg(),
+                  rs_rX86_SP.GetReg(), displacement, val);
       AnnotateDalvikRegAccess(m, displacement >> 2, true /* is_load */, true /* is_64bit */);
       break;
   }
@@ -1062,7 +1058,7 @@
     }
 
     // ECX <- ECX + EAX  (2H * 1L) + (1H * 2L)
-    NewLIR2(kX86Add32RR, r1, r0);
+    NewLIR2(kX86Add32RR, rs_r1.GetReg(), rs_r0.GetReg());
 
     // EAX <- 2L
     LoadConstantNoClobber(rs_r0, val_lo);
@@ -1071,18 +1067,17 @@
     if (src1_in_reg) {
       NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
     } else {
-      LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET);
+      LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP.GetReg(), displacement + LOWORD_OFFSET);
       AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                               true /* is_load */, true /* is_64bit */);
     }
 
     // EDX <- EDX + ECX (add high words)
-    NewLIR2(kX86Add32RR, r2, r1);
+    NewLIR2(kX86Add32RR, rs_r2.GetReg(), rs_r1.GetReg());
 
     // Result is EDX:EAX
-    RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
-                             RegStorage::MakeRegPair(rs_r0, rs_r2),
-                             INVALID_SREG, INVALID_SREG};
+    RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
+                             RegStorage::MakeRegPair(rs_r0, rs_r2), INVALID_SREG, INVALID_SREG};
     StoreValueWide(rl_dest, rl_result);
     return;
   }
@@ -1103,7 +1098,7 @@
 
   // ECX <- 1H
   if (src1_in_reg) {
-    NewLIR2(kX86Mov32RR, r1, rl_src1.reg.GetHighReg());
+    NewLIR2(kX86Mov32RR, rs_r1.GetReg(), rl_src1.reg.GetHighReg());
   } else {
     LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src1.s_reg_low) + HIWORD_OFFSET, rs_r1,
                  k32, GetSRegHi(rl_src1.s_reg_low));
@@ -1113,20 +1108,21 @@
     // Take advantage of the fact that the values are the same.
     // ECX <- ECX * 2L  (1H * 2L)
     if (src2_in_reg) {
-      NewLIR2(kX86Imul32RR, r1, rl_src2.reg.GetLowReg());
+      NewLIR2(kX86Imul32RR, rs_r1.GetReg(), rl_src2.reg.GetLowReg());
     } else {
       int displacement = SRegOffset(rl_src2.s_reg_low);
-      LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
+      LIR *m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP.GetReg(),
+                       displacement + LOWORD_OFFSET);
       AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                               true /* is_load */, true /* is_64bit */);
     }
 
     // ECX <- 2*ECX (2H * 1L) + (1H * 2L)
-    NewLIR2(kX86Add32RR, r1, r1);
+    NewLIR2(kX86Add32RR, rs_r1.GetReg(), rs_r1.GetReg());
   } else {
     // EAX <- 2H
     if (src2_in_reg) {
-      NewLIR2(kX86Mov32RR, r0, rl_src2.reg.GetHighReg());
+      NewLIR2(kX86Mov32RR, rs_r0.GetReg(), rl_src2.reg.GetHighReg());
     } else {
       LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, rs_r0,
                    k32, GetSRegHi(rl_src2.s_reg_low));
@@ -1134,31 +1130,33 @@
 
     // EAX <- EAX * 1L  (2H * 1L)
     if (src1_in_reg) {
-      NewLIR2(kX86Imul32RR, r0, rl_src1.reg.GetLowReg());
+      NewLIR2(kX86Imul32RR, rs_r0.GetReg(), rl_src1.reg.GetLowReg());
     } else {
       int displacement = SRegOffset(rl_src1.s_reg_low);
-      LIR *m = NewLIR3(kX86Imul32RM, r0, rX86_SP, displacement + LOWORD_OFFSET);
+      LIR *m = NewLIR3(kX86Imul32RM, rs_r0.GetReg(), rs_rX86_SP.GetReg(),
+                       displacement + LOWORD_OFFSET);
       AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                               true /* is_load */, true /* is_64bit */);
     }
 
     // ECX <- ECX * 2L  (1H * 2L)
     if (src2_in_reg) {
-      NewLIR2(kX86Imul32RR, r1, rl_src2.reg.GetLowReg());
+      NewLIR2(kX86Imul32RR, rs_r1.GetReg(), rl_src2.reg.GetLowReg());
     } else {
       int displacement = SRegOffset(rl_src2.s_reg_low);
-      LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
+      LIR *m = NewLIR3(kX86Imul32RM, rs_r1.GetReg(), rs_rX86_SP.GetReg(),
+                       displacement + LOWORD_OFFSET);
       AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                               true /* is_load */, true /* is_64bit */);
     }
 
     // ECX <- ECX + EAX  (2H * 1L) + (1H * 2L)
-    NewLIR2(kX86Add32RR, r1, r0);
+    NewLIR2(kX86Add32RR, rs_r1.GetReg(), rs_r0.GetReg());
   }
 
   // EAX <- 2L
   if (src2_in_reg) {
-    NewLIR2(kX86Mov32RR, r0, rl_src2.reg.GetLowReg());
+    NewLIR2(kX86Mov32RR, rs_r0.GetReg(), rl_src2.reg.GetLowReg());
   } else {
     LoadBaseDisp(rs_rX86_SP, SRegOffset(rl_src2.s_reg_low) + LOWORD_OFFSET, rs_r0,
                  k32, rl_src2.s_reg_low);
@@ -1169,16 +1167,16 @@
     NewLIR1(kX86Mul32DaR, rl_src1.reg.GetLowReg());
   } else {
     int displacement = SRegOffset(rl_src1.s_reg_low);
-    LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET);
+    LIR *m = NewLIR2(kX86Mul32DaM, rs_rX86_SP.GetReg(), displacement + LOWORD_OFFSET);
     AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
                             true /* is_load */, true /* is_64bit */);
   }
 
   // EDX <- EDX + ECX (add high words)
-  NewLIR2(kX86Add32RR, r2, r1);
+  NewLIR2(kX86Add32RR, rs_r2.GetReg(), rs_r1.GetReg());
 
   // Result is EDX:EAX
-  RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+  RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
                            RegStorage::MakeRegPair(rs_r0, rs_r2), INVALID_SREG, INVALID_SREG};
   StoreValueWide(rl_dest, rl_result);
 }
@@ -1295,12 +1293,12 @@
 
   // Get one of the source operands into temporary register.
   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
-  if (IsTemp(rl_src1.reg.GetLowReg()) && IsTemp(rl_src1.reg.GetHighReg())) {
+  if (IsTemp(rl_src1.reg.GetLow()) && IsTemp(rl_src1.reg.GetHigh())) {
     GenLongRegOrMemOp(rl_src1, rl_src2, op);
   } else if (is_commutative) {
     rl_src2 = LoadValueWide(rl_src2, kCoreReg);
     // We need at least one of them to be a temporary.
-    if (!(IsTemp(rl_src2.reg.GetLowReg()) && IsTemp(rl_src2.reg.GetHighReg()))) {
+    if (!(IsTemp(rl_src2.reg.GetLow()) && IsTemp(rl_src2.reg.GetHigh()))) {
       rl_src1 = ForceTempWide(rl_src1);
       GenLongRegOrMemOp(rl_src1, rl_src2, op);
     } else {
@@ -1358,7 +1356,7 @@
   StoreValueWide(rl_dest, rl_result);
 }
 
-void X86Mir2Lir::OpRegThreadMem(OpKind op, int r_dest, ThreadOffset<4> thread_offset) {
+void X86Mir2Lir::OpRegThreadMem(OpKind op, RegStorage r_dest, ThreadOffset<4> thread_offset) {
   X86OpCode opcode = kX86Bkpt;
   switch (op) {
   case kOpCmp: opcode = kX86Cmp32RT;  break;
@@ -1367,7 +1365,7 @@
     LOG(FATAL) << "Bad opcode: " << op;
     break;
   }
-  NewLIR2(opcode, r_dest, thread_offset.Int32Value());
+  NewLIR2(opcode, r_dest.GetReg(), thread_offset.Int32Value());
 }
 
 /*
@@ -1375,7 +1373,7 @@
  */
 void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_dest, int scale) {
-  RegisterClass reg_class = oat_reg_class_by_size(size);
+  RegisterClass reg_class = RegClassBySize(size);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   RegLocation rl_result;
   rl_array = LoadValue(rl_array, kCoreReg);
@@ -1410,13 +1408,11 @@
     }
   }
   rl_result = EvalLoc(rl_dest, reg_class, true);
+  LoadBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_result.reg, size,
+                      INVALID_SREG);
   if ((size == k64) || (size == kDouble)) {
-    LoadBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_result.reg.GetLow(),
-                        rl_result.reg.GetHigh(), size, INVALID_SREG);
     StoreValueWide(rl_dest, rl_result);
   } else {
-    LoadBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_result.reg,
-                        RegStorage::InvalidReg(), size, INVALID_SREG);
     StoreValue(rl_dest, rl_result);
   }
 }
@@ -1427,7 +1423,7 @@
  */
 void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
-  RegisterClass reg_class = oat_reg_class_by_size(size);
+  RegisterClass reg_class = RegClassBySize(size);
   int len_offset = mirror::Array::LengthOffset().Int32Value();
   int data_offset;
 
@@ -1466,24 +1462,19 @@
     rl_src = LoadValue(rl_src, reg_class);
   }
   // If the src reg can't be byte accessed, move it to a temp first.
-  if ((size == kSignedByte || size == kUnsignedByte) && rl_src.reg.GetReg() >= 4) {
+  if ((size == kSignedByte || size == kUnsignedByte) &&
+      rl_src.reg.GetRegNum() >= rs_rX86_SP.GetRegNum()) {
     RegStorage temp = AllocTemp();
     OpRegCopy(temp, rl_src.reg);
-    StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, temp,
-                         RegStorage::InvalidReg(), size, INVALID_SREG);
+    StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, temp, size, INVALID_SREG);
   } else {
-    if (rl_src.wide) {
-      StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_src.reg.GetLow(),
-                           rl_src.reg.GetHigh(), size, INVALID_SREG);
-    } else {
-      StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_src.reg,
-                           RegStorage::InvalidReg(), size, INVALID_SREG);
-    }
+    StoreBaseIndexedDisp(rl_array.reg, rl_index.reg, scale, data_offset, rl_src.reg, size,
+                         INVALID_SREG);
   }
   if (card_mark) {
     // Free rl_index if its a temp. Ensures there are 2 free regs for card mark.
     if (!constant_index) {
-      FreeTemp(rl_index.reg.GetReg());
+      FreeTemp(rl_index.reg);
     }
     MarkGCCard(rl_src.reg, rl_array.reg);
   }
@@ -1501,7 +1492,7 @@
         LoadConstant(rl_result.reg.GetLow(), 0);
       } else if (shift_amount > 31) {
         OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg.GetLow());
-        FreeTemp(rl_src.reg.GetHighReg());
+        FreeTemp(rl_src.reg.GetHigh());
         NewLIR2(kX86Sal32RI, rl_result.reg.GetHighReg(), shift_amount - 32);
         LoadConstant(rl_result.reg.GetLow(), 0);
       } else {
@@ -1679,7 +1670,7 @@
                                 int32_t value) {
   bool in_mem = loc.location != kLocPhysReg;
   bool byte_imm = IS_SIMM8(value);
-  DCHECK(in_mem || !IsFpReg(loc.reg));
+  DCHECK(in_mem || !loc.reg.IsFloat());
   switch (op) {
     case Instruction::ADD_LONG:
     case Instruction::ADD_LONG_2ADDR:
@@ -1763,7 +1754,7 @@
 
   RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
   DCHECK_EQ(rl_result.location, kLocPhysReg);
-  DCHECK(!IsFpReg(rl_result.reg));
+  DCHECK(!rl_result.reg.IsFloat());
 
   if (!IsNoOp(op, val_lo)) {
     X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo);
@@ -1788,8 +1779,7 @@
   // Can we do this directly into the destination registers?
   if (rl_dest.location == kLocPhysReg && rl_src1.location == kLocPhysReg &&
       rl_dest.reg.GetLowReg() == rl_src1.reg.GetLowReg() &&
-      rl_dest.reg.GetHighReg() == rl_src1.reg.GetHighReg() &&
-      !IsFpReg(rl_dest.reg)) {
+      rl_dest.reg.GetHighReg() == rl_src1.reg.GetHighReg() && !rl_dest.reg.IsFloat()) {
     if (!IsNoOp(op, val_lo)) {
       X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo);
       NewLIR2(x86op, rl_dest.reg.GetLowReg(), val_lo);
@@ -1829,9 +1819,9 @@
   RegStorage result_reg = rl_result.reg;
 
   // SETcc only works with EAX..EDX.
-  if (result_reg == object.reg || result_reg.GetReg() >= 4) {
+  if (result_reg == object.reg || result_reg.GetRegNum() >= rs_rX86_SP.GetRegNum()) {
     result_reg = AllocTypedTemp(false, kCoreReg);
-    DCHECK_LT(result_reg.GetReg(), 4);
+    DCHECK_LT(result_reg.GetRegNum(), rs_rX86_SP.GetRegNum());
   }
 
   // Assume that there is no match.
@@ -1930,7 +1920,7 @@
   RegLocation rl_result = GetReturn(false);
 
   // SETcc only works with EAX..EDX.
-  DCHECK_LT(rl_result.reg.GetReg(), 4);
+  DCHECK_LT(rl_result.reg.GetRegNum(), 4);
 
   // Is the class NULL?
   LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
@@ -2091,7 +2081,7 @@
           OpMemReg(op, rl_result, t_reg.GetReg());
           FreeTemp(t_reg);
           return;
-        } else if (!IsFpReg(rl_result.reg.GetReg())) {
+        } else if (!rl_result.reg.IsFloat()) {
           // Can do this directly into the result register
           OpRegReg(op, rl_result.reg, t_reg);
           FreeTemp(t_reg);
@@ -2118,7 +2108,7 @@
             OpRegMem(op, rl_result.reg, rl_rhs);
             StoreFinalValue(rl_dest, rl_result);
             return;
-          } else if (!IsFpReg(rl_rhs.reg)) {
+          } else if (!rl_rhs.reg.IsFloat()) {
             OpRegReg(op, rl_result.reg, rl_rhs.reg);
             StoreFinalValue(rl_dest, rl_result);
             return;
@@ -2129,7 +2119,7 @@
           // Okay, we can do this into memory.
           OpMemReg(op, rl_result, rl_rhs.reg.GetReg());
           return;
-        } else if (!IsFpReg(rl_result.reg)) {
+        } else if (!rl_result.reg.IsFloat()) {
           // Can do this directly into the result register.
           OpRegReg(op, rl_result.reg, rl_rhs.reg);
           StoreFinalValue(rl_dest, rl_result);
@@ -2195,10 +2185,10 @@
 
 bool X86Mir2Lir::IsOperationSafeWithoutTemps(RegLocation rl_lhs, RegLocation rl_rhs) {
   // If we have non-core registers, then we can't do good things.
-  if (rl_lhs.location == kLocPhysReg && IsFpReg(rl_lhs.reg.GetReg())) {
+  if (rl_lhs.location == kLocPhysReg && rl_lhs.reg.IsFloat()) {
     return false;
   }
-  if (rl_rhs.location == kLocPhysReg && IsFpReg(rl_rhs.reg.GetReg())) {
+  if (rl_rhs.location == kLocPhysReg && rl_rhs.reg.IsFloat()) {
     return false;
   }
 
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 3e3fa72..05bef52 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -26,27 +26,53 @@
 
 namespace art {
 
-// FIXME: restore "static" when usage uncovered
-/*static*/ int core_regs[] = {
-  rAX, rCX, rDX, rBX, rX86_SP, rBP, rSI, rDI
+static const RegStorage core_regs_arr[] = {
+    rs_rAX, rs_rCX, rs_rDX, rs_rBX, rs_rX86_SP, rs_rBP, rs_rSI, rs_rDI
 #ifdef TARGET_REX_SUPPORT
-  r8, r9, r10, r11, r12, r13, r14, 15
+    rs_r8, rs_r9, rs_r10, rs_r11, rs_r12, rs_r13, rs_r14, rs_r15
 #endif
 };
-/*static*/ int ReservedRegs[] = {rX86_SP};
-/*static*/ int core_temps[] = {rAX, rCX, rDX, rBX};
-/*static*/ int FpRegs[] = {
-  fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
+static const RegStorage sp_regs_arr[] = {
+    rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7,
 #ifdef TARGET_REX_SUPPORT
-  fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
+    rs_fr8, rs_fr9, rs_fr10, rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15
 #endif
 };
-/*static*/ int fp_temps[] = {
-  fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
+static const RegStorage dp_regs_arr[] = {
+    rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7,
 #ifdef TARGET_REX_SUPPORT
-  fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
+    rs_dr8, rs_dr9, rs_dr10, rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15
 #endif
 };
+static const RegStorage reserved_regs_arr[] = {rs_rX86_SP};
+static const RegStorage core_temps_arr[] = {rs_rAX, rs_rCX, rs_rDX, rs_rBX};
+static const RegStorage sp_temps_arr[] = {
+    rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7,
+#ifdef TARGET_REX_SUPPORT
+    rs_fr8, rs_fr9, rs_fr10, rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15
+#endif
+};
+static const RegStorage dp_temps_arr[] = {
+    rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7,
+#ifdef TARGET_REX_SUPPORT
+    rs_dr8, rs_dr9, rs_dr10, rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15
+#endif
+};
+
+static const std::vector<RegStorage> core_regs(core_regs_arr,
+    core_regs_arr + sizeof(core_regs_arr) / sizeof(core_regs_arr[0]));
+static const std::vector<RegStorage> sp_regs(sp_regs_arr,
+    sp_regs_arr + sizeof(sp_regs_arr) / sizeof(sp_regs_arr[0]));
+static const std::vector<RegStorage> dp_regs(dp_regs_arr,
+    dp_regs_arr + sizeof(dp_regs_arr) / sizeof(dp_regs_arr[0]));
+static const std::vector<RegStorage> reserved_regs(reserved_regs_arr,
+    reserved_regs_arr + sizeof(reserved_regs_arr) / sizeof(reserved_regs_arr[0]));
+static const std::vector<RegStorage> core_temps(core_temps_arr,
+    core_temps_arr + sizeof(core_temps_arr) / sizeof(core_temps_arr[0]));
+static const std::vector<RegStorage> sp_temps(sp_temps_arr,
+    sp_temps_arr + sizeof(sp_temps_arr) / sizeof(sp_temps_arr[0]));
+static const std::vector<RegStorage> dp_temps(dp_temps_arr,
+    dp_temps_arr + sizeof(dp_temps_arr) / sizeof(dp_temps_arr[0]));
 
 RegLocation X86Mir2Lir::LocCReturn() {
   return x86_loc_c_return;
@@ -66,29 +92,29 @@
 
 // Return a target-dependent special register.
 RegStorage X86Mir2Lir::TargetReg(SpecialTargetRegister reg) {
-  int res_reg = RegStorage::kInvalidRegVal;
+  RegStorage res_reg = RegStorage::InvalidReg();
   switch (reg) {
-    case kSelf: res_reg = rX86_SELF; break;
-    case kSuspend: res_reg =  rX86_SUSPEND; break;
-    case kLr: res_reg =  rX86_LR; break;
-    case kPc: res_reg =  rX86_PC; break;
-    case kSp: res_reg =  rX86_SP; break;
-    case kArg0: res_reg = rX86_ARG0; break;
-    case kArg1: res_reg = rX86_ARG1; break;
-    case kArg2: res_reg = rX86_ARG2; break;
-    case kArg3: res_reg = rX86_ARG3; break;
-    case kFArg0: res_reg = rX86_FARG0; break;
-    case kFArg1: res_reg = rX86_FARG1; break;
-    case kFArg2: res_reg = rX86_FARG2; break;
-    case kFArg3: res_reg = rX86_FARG3; break;
-    case kRet0: res_reg = rX86_RET0; break;
-    case kRet1: res_reg = rX86_RET1; break;
-    case kInvokeTgt: res_reg = rX86_INVOKE_TGT; break;
-    case kHiddenArg: res_reg = rAX; break;
-    case kHiddenFpArg: res_reg = fr0; break;
-    case kCount: res_reg = rX86_COUNT; break;
+    case kSelf: res_reg = RegStorage::InvalidReg(); break;
+    case kSuspend: res_reg =  RegStorage::InvalidReg(); break;
+    case kLr: res_reg =  RegStorage::InvalidReg(); break;
+    case kPc: res_reg =  RegStorage::InvalidReg(); break;
+    case kSp: res_reg =  rs_rX86_SP; break;
+    case kArg0: res_reg = rs_rX86_ARG0; break;
+    case kArg1: res_reg = rs_rX86_ARG1; break;
+    case kArg2: res_reg = rs_rX86_ARG2; break;
+    case kArg3: res_reg = rs_rX86_ARG3; break;
+    case kFArg0: res_reg = rs_rX86_FARG0; break;
+    case kFArg1: res_reg = rs_rX86_FARG1; break;
+    case kFArg2: res_reg = rs_rX86_FARG2; break;
+    case kFArg3: res_reg = rs_rX86_FARG3; break;
+    case kRet0: res_reg = rs_rX86_RET0; break;
+    case kRet1: res_reg = rs_rX86_RET1; break;
+    case kInvokeTgt: res_reg = rs_rX86_INVOKE_TGT; break;
+    case kHiddenArg: res_reg = rs_rAX; break;
+    case kHiddenFpArg: res_reg = rs_fr0; break;
+    case kCount: res_reg = rs_rX86_COUNT; break;
   }
-  return RegStorage::Solo32(res_reg);
+  return res_reg;
 }
 
 RegStorage X86Mir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
@@ -106,34 +132,19 @@
   }
 }
 
-// Create a double from a pair of singles.
-int X86Mir2Lir::S2d(int low_reg, int high_reg) {
-  return X86_S2D(low_reg, high_reg);
-}
-
-// Return mask to strip off fp reg flags and bias.
-uint32_t X86Mir2Lir::FpRegMask() {
-  return X86_FP_REG_MASK;
-}
-
-// True if both regs single, both core or both double.
-bool X86Mir2Lir::SameRegType(int reg1, int reg2) {
-  return (X86_REGTYPE(reg1) == X86_REGTYPE(reg2));
-}
-
 /*
  * Decode the register id.
  */
-uint64_t X86Mir2Lir::GetRegMaskCommon(int reg) {
+uint64_t X86Mir2Lir::GetRegMaskCommon(RegStorage reg) {
   uint64_t seed;
   int shift;
   int reg_id;
 
-  reg_id = reg & 0xf;
+  reg_id = reg.GetRegNum();
   /* Double registers in x86 are just a single FP register */
   seed = 1;
   /* FP register starts at bit position 16 */
-  shift = X86_FPREG(reg) ? kX86FPReg0 : 0;
+  shift = reg.IsFloat() ? kX86FPReg0 : 0;
   /* Expand the double register id into single offset */
   shift += reg_id;
   return (seed << shift);
@@ -162,34 +173,34 @@
   }
 
   if (flags & REG_DEFA) {
-    SetupRegMask(&lir->u.m.def_mask, rAX);
+    SetupRegMask(&lir->u.m.def_mask, rs_rAX.GetReg());
   }
 
   if (flags & REG_DEFD) {
-    SetupRegMask(&lir->u.m.def_mask, rDX);
+    SetupRegMask(&lir->u.m.def_mask, rs_rDX.GetReg());
   }
   if (flags & REG_USEA) {
-    SetupRegMask(&lir->u.m.use_mask, rAX);
+    SetupRegMask(&lir->u.m.use_mask, rs_rAX.GetReg());
   }
 
   if (flags & REG_USEC) {
-    SetupRegMask(&lir->u.m.use_mask, rCX);
+    SetupRegMask(&lir->u.m.use_mask, rs_rCX.GetReg());
   }
 
   if (flags & REG_USED) {
-    SetupRegMask(&lir->u.m.use_mask, rDX);
+    SetupRegMask(&lir->u.m.use_mask, rs_rDX.GetReg());
   }
 
   if (flags & REG_USEB) {
-    SetupRegMask(&lir->u.m.use_mask, rBX);
+    SetupRegMask(&lir->u.m.use_mask, rs_rBX.GetReg());
   }
 
   // Fixup hard to describe instruction: Uses rAX, rCX, rDI; sets rDI.
   if (lir->opcode == kX86RepneScasw) {
-    SetupRegMask(&lir->u.m.use_mask, rAX);
-    SetupRegMask(&lir->u.m.use_mask, rCX);
-    SetupRegMask(&lir->u.m.use_mask, rDI);
-    SetupRegMask(&lir->u.m.def_mask, rDI);
+    SetupRegMask(&lir->u.m.use_mask, rs_rAX.GetReg());
+    SetupRegMask(&lir->u.m.use_mask, rs_rCX.GetReg());
+    SetupRegMask(&lir->u.m.use_mask, rs_rDI.GetReg());
+    SetupRegMask(&lir->u.m.def_mask, rs_rDI.GetReg());
   }
 
   if (flags & USE_FP_STACK) {
@@ -261,12 +272,13 @@
             break;
           }
           case 'r':
-            if (X86_FPREG(operand) || X86_DOUBLEREG(operand)) {
-              int fp_reg = operand & X86_FP_REG_MASK;
+            if (RegStorage::IsFloat(operand)) {
+              int fp_reg = RegStorage::RegNum(operand);
               buf += StringPrintf("xmm%d", fp_reg);
             } else {
-              DCHECK_LT(static_cast<size_t>(operand), sizeof(x86RegName));
-              buf += x86RegName[operand];
+              int reg_num = RegStorage::RegNum(operand);
+              DCHECK_LT(static_cast<size_t>(reg_num), sizeof(x86RegName));
+              buf += x86RegName[reg_num];
             }
             break;
           case 't':
@@ -329,7 +341,7 @@
 
 void X86Mir2Lir::AdjustSpillMask() {
   // Adjustment for LR spilling, x86 has no LR so nothing to do here
-  core_spill_mask_ |= (1 << rRET);
+  core_spill_mask_ |= (1 << rs_rRET.GetRegNum());
   num_core_spills_++;
 }
 
@@ -339,97 +351,56 @@
  * include any holes in the mask.  Associate holes with
  * Dalvik register INVALID_VREG (0xFFFFU).
  */
-void X86Mir2Lir::MarkPreservedSingle(int v_reg, int reg) {
-  UNIMPLEMENTED(WARNING) << "MarkPreservedSingle";
-#if 0
-  LOG(FATAL) << "No support yet for promoted FP regs";
-#endif
+void X86Mir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
+  UNIMPLEMENTED(FATAL) << "MarkPreservedSingle";
 }
 
-void X86Mir2Lir::FlushRegWide(RegStorage reg) {
-  RegisterInfo* info1 = GetRegInfo(reg.GetLowReg());
-  RegisterInfo* info2 = GetRegInfo(reg.GetHighReg());
-  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->is_temp && info2->is_temp)) {
-      /* Should not happen.  If it does, there's a problem in eval_loc */
-      LOG(FATAL) << "Long half-temp, half-promoted";
-    }
-
-    info1->dirty = false;
-    info2->dirty = false;
-    if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
-      info1 = info2;
-    int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
-    StoreBaseDispWide(rs_rX86_SP, VRegOffset(v_reg),
-                      RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner));
-  }
-}
-
-void X86Mir2Lir::FlushReg(RegStorage reg) {
-  // FIXME: need to handle 32 bits in 64-bit register as well as wide values held in single reg.
-  DCHECK(!reg.IsPair());
-  RegisterInfo* info = GetRegInfo(reg.GetReg());
-  if (info->live && info->dirty) {
-    info->dirty = false;
-    int v_reg = mir_graph_->SRegToVReg(info->s_reg);
-    StoreBaseDisp(rs_rX86_SP, VRegOffset(v_reg), reg, k32);
-  }
-}
-
-/* Give access to the target-dependent FP register encoding to common code */
-bool X86Mir2Lir::IsFpReg(int reg) {
-  return X86_FPREG(reg);
-}
-
-bool X86Mir2Lir::IsFpReg(RegStorage reg) {
-  return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg());
+void X86Mir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
+  UNIMPLEMENTED(FATAL) << "MarkPreservedDouble";
 }
 
 /* Clobber all regs that might be used by an external C call */
 void X86Mir2Lir::ClobberCallerSave() {
-  Clobber(rAX);
-  Clobber(rCX);
-  Clobber(rDX);
-  Clobber(rBX);
+  Clobber(rs_rAX);
+  Clobber(rs_rCX);
+  Clobber(rs_rDX);
+  Clobber(rs_rBX);
 }
 
 RegLocation X86Mir2Lir::GetReturnWideAlt() {
   RegLocation res = LocCReturnWide();
-  CHECK(res.reg.GetLowReg() == rAX);
-  CHECK(res.reg.GetHighReg() == rDX);
-  Clobber(rAX);
-  Clobber(rDX);
-  MarkInUse(rAX);
-  MarkInUse(rDX);
-  MarkPair(res.reg.GetLowReg(), res.reg.GetHighReg());
+  DCHECK(res.reg.GetLowReg() == rs_rAX.GetReg());
+  DCHECK(res.reg.GetHighReg() == rs_rDX.GetReg());
+  Clobber(rs_rAX);
+  Clobber(rs_rDX);
+  MarkInUse(rs_rAX);
+  MarkInUse(rs_rDX);
+  MarkWide(res.reg);
   return res;
 }
 
 RegLocation X86Mir2Lir::GetReturnAlt() {
   RegLocation res = LocCReturn();
-  res.reg.SetReg(rDX);
-  Clobber(rDX);
-  MarkInUse(rDX);
+  res.reg.SetReg(rs_rDX.GetReg());
+  Clobber(rs_rDX);
+  MarkInUse(rs_rDX);
   return res;
 }
 
 /* To be used when explicitly managing register use */
 void X86Mir2Lir::LockCallTemps() {
-  LockTemp(rX86_ARG0);
-  LockTemp(rX86_ARG1);
-  LockTemp(rX86_ARG2);
-  LockTemp(rX86_ARG3);
+  LockTemp(rs_rX86_ARG0);
+  LockTemp(rs_rX86_ARG1);
+  LockTemp(rs_rX86_ARG2);
+  LockTemp(rs_rX86_ARG3);
 }
 
 /* To be used when explicitly managing register use */
 void X86Mir2Lir::FreeCallTemps() {
-  FreeTemp(rX86_ARG0);
-  FreeTemp(rX86_ARG1);
-  FreeTemp(rX86_ARG2);
-  FreeTemp(rX86_ARG3);
+  FreeTemp(rs_rX86_ARG0);
+  FreeTemp(rs_rX86_ARG1);
+  FreeTemp(rs_rX86_ARG2);
+  FreeTemp(rs_rX86_ARG3);
 }
 
 bool X86Mir2Lir::ProvidesFullMemoryBarrier(X86OpCode opcode) {
@@ -495,40 +466,35 @@
 
 RegStorage X86Mir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
   if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
-    return AllocTempFloat();
+    return AllocTempSingle();
   }
   return AllocTemp();
 }
 
 void X86Mir2Lir::CompilerInitializeRegAlloc() {
-  int num_regs = sizeof(core_regs)/sizeof(*core_regs);
-  int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
-  int num_temps = sizeof(core_temps)/sizeof(*core_temps);
-  int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
-  int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
-  reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
-                                                       kArenaAllocRegAlloc));
-  reg_pool_->num_core_regs = num_regs;
-  reg_pool_->core_regs =
-      static_cast<RegisterInfo*>(arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs),
-                                               kArenaAllocRegAlloc));
-  reg_pool_->num_fp_regs = num_fp_regs;
-  reg_pool_->FPRegs =
-      static_cast<RegisterInfo *>(arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs),
-                                                kArenaAllocRegAlloc));
-  CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
-  CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
-  // Keep special registers from being allocated
-  for (int i = 0; i < num_reserved; i++) {
-    MarkInUse(ReservedRegs[i]);
+  reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, sp_regs, dp_regs, reserved_regs,
+                                        core_temps, sp_temps, dp_temps);
+
+  // Target-specific adjustments.
+
+  // Alias single precision xmm to double xmms.
+  // TODO: as needed, add larger vector sizes - alias all to the largest.
+  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
+  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
+    int sp_reg_num = info->GetReg().GetRegNum();
+    RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | sp_reg_num);
+    RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
+    // 64-bit xmm vector register's master storage should refer to itself.
+    DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
+    // Redirect 32-bit vector's master storage to 64-bit vector.
+    info->SetMaster(dp_reg_info);
   }
-  // Mark temp regs - all others not in use can be used for promotion
-  for (int i = 0; i < num_temps; i++) {
-    MarkTemp(core_temps[i]);
-  }
-  for (int i = 0; i < num_fp_temps; i++) {
-    MarkTemp(fp_temps[i]);
-  }
+
+  // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
+  // TODO: adjust for x86/hard float calling convention.
+  reg_pool_->next_core_reg_ = 2;
+  reg_pool_->next_sp_reg_ = 2;
+  reg_pool_->next_dp_reg_ = 1;
 }
 
 void X86Mir2Lir::FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free) {
@@ -541,8 +507,7 @@
   if ((free_low != keep_low) && (free_low != keep_high) &&
       (free_high != keep_low) && (free_high != keep_high)) {
     // No overlap, free both
-    FreeTemp(free_low);
-    FreeTemp(free_high);
+    FreeTemp(rl_free.reg);
   }
 }
 
@@ -551,7 +516,7 @@
     return;
   }
   // Spill mask not including fake return address register
-  uint32_t mask = core_spill_mask_ & ~(1 << rRET);
+  uint32_t mask = core_spill_mask_ & ~(1 << rs_rRET.GetRegNum());
   int offset = frame_size_ - (4 * num_core_spills_);
   for (int reg = 0; mask; mask >>= 1, reg++) {
     if (mask & 0x1) {
@@ -566,7 +531,7 @@
     return;
   }
   // Spill mask not including fake return address register
-  uint32_t mask = core_spill_mask_ & ~(1 << rRET);
+  uint32_t mask = core_spill_mask_ & ~(1 << rs_rRET.GetRegNum());
   int offset = frame_size_ - (4 * num_core_spills_);
   for (int reg = 0; mask; mask >>= 1, reg++) {
     if (mask & 0x1) {
@@ -629,215 +594,6 @@
   return X86Mir2Lir::EncodingMap[opcode].fmt;
 }
 
-/*
- * Return an updated location record with current in-register status.
- * If the value lives in live temps, reflect that fact.  No code
- * is generated.  If the live value is part of an older pair,
- * clobber both low and high.
- */
-// TODO: Reunify with common code after 'pair mess' has been fixed
-RegLocation X86Mir2Lir::UpdateLocWide(RegLocation loc) {
-  DCHECK(loc.wide);
-  DCHECK(CheckCorePoolSanity());
-  if (loc.location != kLocPhysReg) {
-    DCHECK((loc.location == kLocDalvikFrame) ||
-         (loc.location == kLocCompilerTemp));
-    // Are the dalvik regs already live in physical registers?
-    RegisterInfo* info_lo = AllocLive(loc.s_reg_low, kAnyReg);
-
-    // Handle FP registers specially on x86.
-    if (info_lo && IsFpReg(info_lo->reg)) {
-      bool match = true;
-
-      // We can't match a FP register with a pair of Core registers.
-      match = match && (info_lo->pair == 0);
-
-      if (match) {
-        // We can reuse;update the register usage info.
-        loc.location = kLocPhysReg;
-        loc.vec_len = kVectorLength8;
-        // TODO: use k64BitVector
-        loc.reg = RegStorage(RegStorage::k64BitPair, info_lo->reg, info_lo->reg);
-        DCHECK(IsFpReg(loc.reg.GetLowReg()));
-        return loc;
-      }
-      // We can't easily reuse; clobber and free any overlaps.
-      if (info_lo) {
-        Clobber(info_lo->reg);
-        FreeTemp(info_lo->reg);
-        if (info_lo->pair)
-          Clobber(info_lo->partner);
-      }
-    } else {
-      RegisterInfo* info_hi = AllocLive(GetSRegHi(loc.s_reg_low), kAnyReg);
-      bool match = true;
-      match = match && (info_lo != NULL);
-      match = match && (info_hi != NULL);
-      // Are they both core or both FP?
-      match = match && (IsFpReg(info_lo->reg) == IsFpReg(info_hi->reg));
-      // If a pair of floating point singles, are they properly aligned?
-      if (match && IsFpReg(info_lo->reg)) {
-        match &= ((info_lo->reg & 0x1) == 0);
-        match &= ((info_hi->reg - info_lo->reg) == 1);
-      }
-      // If previously used as a pair, it is the same pair?
-      if (match && (info_lo->pair || info_hi->pair)) {
-        match = (info_lo->pair == info_hi->pair);
-        match &= ((info_lo->reg == info_hi->partner) &&
-              (info_hi->reg == info_lo->partner));
-      }
-      if (match) {
-        // Can reuse - update the register usage info
-        loc.reg = RegStorage(RegStorage::k64BitPair, info_lo->reg, info_hi->reg);
-        loc.location = kLocPhysReg;
-        MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
-        DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
-        return loc;
-      }
-      // Can't easily reuse - clobber and free any overlaps
-      if (info_lo) {
-        Clobber(info_lo->reg);
-        FreeTemp(info_lo->reg);
-        if (info_lo->pair)
-          Clobber(info_lo->partner);
-      }
-      if (info_hi) {
-        Clobber(info_hi->reg);
-        FreeTemp(info_hi->reg);
-        if (info_hi->pair)
-          Clobber(info_hi->partner);
-      }
-    }
-  }
-  return loc;
-}
-
-// TODO: Reunify with common code after 'pair mess' has been fixed
-RegLocation X86Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update) {
-  DCHECK(loc.wide);
-
-  loc = UpdateLocWide(loc);
-
-  /* If it is already in a register, we can assume proper form.  Is it the right reg class? */
-  if (loc.location == kLocPhysReg) {
-    DCHECK_EQ(IsFpReg(loc.reg.GetLowReg()), loc.IsVectorScalar());
-    if (!RegClassMatches(reg_class, loc.reg)) {
-      /* It is the wrong register class.  Reallocate and copy. */
-      if (!IsFpReg(loc.reg.GetLowReg())) {
-        // We want this in a FP reg, and it is in core registers.
-        DCHECK(reg_class != kCoreReg);
-        // Allocate this into any FP reg, and mark it with the right size.
-        int32_t low_reg = AllocTypedTemp(true, reg_class).GetReg();
-        OpVectorRegCopyWide(low_reg, loc.reg.GetLowReg(), loc.reg.GetHighReg());
-        CopyRegInfo(low_reg, loc.reg.GetLowReg());
-        Clobber(loc.reg);
-        loc.reg.SetReg(low_reg);
-        loc.reg.SetHighReg(low_reg);  // Play nice with existing code.
-        loc.vec_len = kVectorLength8;
-      } else {
-        // The value is in a FP register, and we want it in a pair of core registers.
-        DCHECK_EQ(reg_class, kCoreReg);
-        DCHECK_EQ(loc.reg.GetLowReg(), loc.reg.GetHighReg());
-        RegStorage new_regs = AllocTypedTempWide(false, kCoreReg);  // Force to core registers.
-        OpRegCopyWide(new_regs, loc.reg);
-        CopyRegInfo(new_regs.GetLowReg(), loc.reg.GetLowReg());
-        CopyRegInfo(new_regs.GetHighReg(), loc.reg.GetHighReg());
-        Clobber(loc.reg);
-        loc.reg = new_regs;
-        MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
-        DCHECK(!IsFpReg(loc.reg.GetLowReg()) || ((loc.reg.GetLowReg() & 0x1) == 0));
-      }
-    }
-    return loc;
-  }
-
-  DCHECK_NE(loc.s_reg_low, INVALID_SREG);
-  DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG);
-
-  loc.reg = AllocTypedTempWide(loc.fp, reg_class);
-
-  // FIXME: take advantage of RegStorage notation.
-  if (loc.reg.GetLowReg() == loc.reg.GetHighReg()) {
-    DCHECK(IsFpReg(loc.reg.GetLowReg()));
-    loc.vec_len = kVectorLength8;
-  } else {
-    MarkPair(loc.reg.GetLowReg(), loc.reg.GetHighReg());
-  }
-  if (update) {
-    loc.location = kLocPhysReg;
-    MarkLive(loc.reg.GetLow(), loc.s_reg_low);
-    if (loc.reg.GetLowReg() != loc.reg.GetHighReg()) {
-      MarkLive(loc.reg.GetHigh(), GetSRegHi(loc.s_reg_low));
-    }
-  }
-  return loc;
-}
-
-// TODO: Reunify with common code after 'pair mess' has been fixed
-RegLocation X86Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) {
-  if (loc.wide)
-    return EvalLocWide(loc, reg_class, update);
-
-  loc = UpdateLoc(loc);
-
-  if (loc.location == kLocPhysReg) {
-    if (!RegClassMatches(reg_class, loc.reg)) {
-      /* Wrong register class.  Realloc, copy and transfer ownership. */
-      RegStorage new_reg = AllocTypedTemp(loc.fp, reg_class);
-      OpRegCopy(new_reg, loc.reg);
-      CopyRegInfo(new_reg, loc.reg);
-      Clobber(loc.reg);
-      loc.reg = new_reg;
-      if (IsFpReg(loc.reg.GetReg()) && reg_class != kCoreReg)
-        loc.vec_len = kVectorLength4;
-    }
-    return loc;
-  }
-
-  DCHECK_NE(loc.s_reg_low, INVALID_SREG);
-
-  loc.reg = AllocTypedTemp(loc.fp, reg_class);
-  if (IsFpReg(loc.reg.GetReg()) && reg_class != kCoreReg)
-    loc.vec_len = kVectorLength4;
-
-  if (update) {
-    loc.location = kLocPhysReg;
-    MarkLive(loc.reg, loc.s_reg_low);
-  }
-  return loc;
-}
-
-RegStorage X86Mir2Lir::AllocTempDouble() {
-  // We really don't need a pair of registers.
-  // FIXME - update to double
-  int reg = AllocTempFloat().GetReg();
-  return RegStorage(RegStorage::k64BitPair, reg, reg);
-}
-
-// TODO: Reunify with common code after 'pair mess' has been fixed
-void X86Mir2Lir::ResetDefLocWide(RegLocation rl) {
-  DCHECK(rl.wide);
-  RegisterInfo* p_low = IsTemp(rl.reg.GetLowReg());
-  if (IsFpReg(rl.reg.GetLowReg())) {
-    // We are using only the low register.
-    if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) {
-      NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low);
-    }
-    ResetDef(rl.reg.GetLowReg());
-  } else {
-    RegisterInfo* p_high = IsTemp(rl.reg.GetHighReg());
-    if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) {
-      DCHECK(p_low->pair);
-      NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low);
-    }
-    if (p_high && !(cu_->disable_opt & (1 << kSuppressLoads))) {
-      DCHECK(p_high->pair);
-    }
-    ResetDef(rl.reg.GetLowReg());
-    ResetDef(rl.reg.GetHighReg());
-  }
-}
-
 void X86Mir2Lir::GenConstWide(RegLocation rl_dest, int64_t value) {
   // Can we do this directly to memory?
   rl_dest = UpdateLocWide(rl_dest);
@@ -872,7 +628,6 @@
              << (loc.ref ? " r" : "  ")
              << (loc.high_word ? " h" : "  ")
              << (loc.home ? " H" : "  ")
-             << " vec_len: " << loc.vec_len
              << ", low: " << static_cast<int>(loc.reg.GetLowReg())
              << ", high: " << static_cast<int>(loc.reg.GetHighReg())
              << ", s_reg: " << loc.s_reg_low
@@ -1059,7 +814,7 @@
 
   // We need to preserve EDI, but have no spare registers, so push it on the stack.
   // We have to remember that all stack addresses after this are offset by sizeof(EDI).
-  NewLIR1(kX86Push32R, rDI);
+  NewLIR1(kX86Push32R, rs_rDI.GetReg());
 
   // Compute the number of words to search in to rCX.
   Load32Disp(rs_rDX, count_offset, rs_rCX);
@@ -1096,7 +851,7 @@
         OpRegReg(kOpSub, rs_rCX, rl_start.reg);
         if (rl_start.reg == rs_rDI) {
           // The special case. We will use EDI further, so lets put start index to stack.
-          NewLIR1(kX86Push32R, rDI);
+          NewLIR1(kX86Push32R, rs_rDI.GetReg());
           is_index_on_stack = true;
         }
       } else {
@@ -1110,7 +865,7 @@
         length_compare = OpCmpBranch(kCondLe, rs_rCX, rs_rBX, nullptr);
         OpRegReg(kOpSub, rs_rCX, rs_rBX);
         // Put the start index to stack.
-        NewLIR1(kX86Push32R, rBX);
+        NewLIR1(kX86Push32R, rs_rBX.GetReg());
         is_index_on_stack = true;
       }
     }
@@ -1130,12 +885,12 @@
     if (start_value == 0) {
       OpRegCopy(rs_rDI, rs_rBX);
     } else {
-      NewLIR3(kX86Lea32RM, rDI, rBX, 2 * start_value);
+      NewLIR3(kX86Lea32RM, rs_rDI.GetReg(), rs_rBX.GetReg(), 2 * start_value);
     }
   } else {
     if (is_index_on_stack == true) {
       // Load the start index from stack.
-      NewLIR1(kX86Pop32R, rDX);
+      NewLIR1(kX86Pop32R, rs_rDX.GetReg());
       OpLea(rs_rDI, rs_rBX, rs_rDX, 1, 0);
     } else {
       OpLea(rs_rDI, rs_rBX, rl_start.reg, 1, 0);
@@ -1153,7 +908,7 @@
   // index = ((curr_ptr - orig_ptr) / 2) - 1.
   OpRegReg(kOpSub, rs_rDI, rs_rBX);
   OpRegImm(kOpAsr, rs_rDI, 1);
-  NewLIR3(kX86Lea32RM, rl_return.reg.GetReg(), rDI, -1);
+  NewLIR3(kX86Lea32RM, rl_return.reg.GetReg(), rs_rDI.GetReg(), -1);
   LIR *all_done = NewLIR1(kX86Jmp8, 0);
 
   // Failed to match; return -1.
@@ -1165,7 +920,7 @@
   // And join up at the end.
   all_done->target = NewLIR0(kPseudoTargetLabel);
   // Restore EDI from the stack.
-  NewLIR1(kX86Pop32R, rDI);
+  NewLIR1(kX86Pop32R, rs_rDI.GetReg());
 
   // Out of line code returns here.
   if (slowpath_branch != nullptr) {
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 4d45055..da6ded5 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -26,18 +26,19 @@
 LIR* X86Mir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
   int opcode;
   /* must be both DOUBLE or both not DOUBLE */
-  DCHECK_EQ(X86_DOUBLEREG(r_dest.GetReg()), X86_DOUBLEREG(r_src.GetReg()));
-  if (X86_DOUBLEREG(r_dest.GetReg())) {
+  DCHECK(r_dest.IsFloat() || r_src.IsFloat());
+  DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
+  if (r_dest.IsDouble()) {
     opcode = kX86MovsdRR;
   } else {
-    if (X86_SINGLEREG(r_dest.GetReg())) {
-      if (X86_SINGLEREG(r_src.GetReg())) {
+    if (r_dest.IsSingle()) {
+      if (r_src.IsSingle()) {
         opcode = kX86MovssRR;
       } else {  // Fpr <- Gpr
         opcode = kX86MovdxrRR;
       }
     } else {  // Gpr <- Fpr
-      DCHECK(X86_SINGLEREG(r_src.GetReg()));
+      DCHECK(r_src.IsSingle()) << "Raw: 0x" << std::hex << r_src.GetRawBits();
       opcode = kX86MovdrxRR;
     }
   }
@@ -76,11 +77,10 @@
  */
 LIR* X86Mir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
   RegStorage r_dest_save = r_dest;
-  if (X86_FPREG(r_dest.GetReg())) {
+  if (r_dest.IsFloat()) {
     if (value == 0) {
       return NewLIR2(kX86XorpsRR, r_dest.GetReg(), r_dest.GetReg());
     }
-    DCHECK(X86_SINGLEREG(r_dest.GetReg()));
     r_dest = AllocTemp();
   }
 
@@ -92,7 +92,7 @@
     res = NewLIR2(kX86Mov32RI, r_dest.GetReg(), value);
   }
 
-  if (X86_FPREG(r_dest_save.GetReg())) {
+  if (r_dest_save.IsFloat()) {
     NewLIR2(kX86MovdxrRR, r_dest_save.GetReg(), r_dest.GetReg());
     FreeTemp(r_dest);
   }
@@ -129,7 +129,7 @@
 LIR* X86Mir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
   X86OpCode opcode = kX86Bkpt;
   bool byte_imm = IS_SIMM8(value);
-  DCHECK(!X86_FPREG(r_dest_src1.GetReg()));
+  DCHECK(!r_dest_src1.IsFloat());
   switch (op) {
     case kOpLsl: opcode = kX86Sal32RI; break;
     case kOpLsr: opcode = kX86Shr32RI; break;
@@ -191,8 +191,10 @@
       case kOpOr:  opcode = kX86Or32RR; break;
       case kOpXor: opcode = kX86Xor32RR; break;
       case kOp2Byte:
+        // TODO: there are several instances of this check.  A utility function perhaps?
+        // TODO: Similar to Arm's reg < 8 check.  Perhaps add attribute checks to RegStorage?
         // Use shifts instead of a byte operand if the source can't be byte accessed.
-        if (r_src2.GetReg() >= 4) {
+        if (r_src2.GetRegNum() >= rs_rX86_SP.GetRegNum()) {
           NewLIR2(kX86Mov32RR, r_dest_src1.GetReg(), r_src2.GetReg());
           NewLIR2(kX86Sal32RI, r_dest_src1.GetReg(), 24);
           return NewLIR2(kX86Sar32RI, r_dest_src1.GetReg(), 24);
@@ -207,49 +209,49 @@
         LOG(FATAL) << "Bad case in OpRegReg " << op;
         break;
     }
-    CHECK(!src2_must_be_cx || r_src2.GetReg() == rCX);
+    CHECK(!src2_must_be_cx || r_src2.GetReg() == rs_rCX.GetReg());
     return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg());
 }
 
 LIR* X86Mir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset, MoveType move_type) {
-  DCHECK(!(X86_FPREG(r_base.GetReg())));
+  DCHECK(!r_base.IsFloat());
   X86OpCode opcode = kX86Nop;
   int dest = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg();
   switch (move_type) {
     case kMov8GP:
-      CHECK(!X86_FPREG(dest));
+      CHECK(!r_dest.IsFloat());
       opcode = kX86Mov8RM;
       break;
     case kMov16GP:
-      CHECK(!X86_FPREG(dest));
+      CHECK(!r_dest.IsFloat());
       opcode = kX86Mov16RM;
       break;
     case kMov32GP:
-      CHECK(!X86_FPREG(dest));
+      CHECK(!r_dest.IsFloat());
       opcode = kX86Mov32RM;
       break;
     case kMov32FP:
-      CHECK(X86_FPREG(dest));
+      CHECK(r_dest.IsFloat());
       opcode = kX86MovssRM;
       break;
     case kMov64FP:
-      CHECK(X86_FPREG(dest));
+      CHECK(r_dest.IsFloat());
       opcode = kX86MovsdRM;
       break;
     case kMovU128FP:
-      CHECK(X86_FPREG(dest));
+      CHECK(r_dest.IsFloat());
       opcode = kX86MovupsRM;
       break;
     case kMovA128FP:
-      CHECK(X86_FPREG(dest));
+      CHECK(r_dest.IsFloat());
       opcode = kX86MovapsRM;
       break;
     case kMovLo128FP:
-      CHECK(X86_FPREG(dest));
+      CHECK(r_dest.IsFloat());
       opcode = kX86MovlpsRM;
       break;
     case kMovHi128FP:
-      CHECK(X86_FPREG(dest));
+      CHECK(r_dest.IsFloat());
       opcode = kX86MovhpsRM;
       break;
     case kMov64GP:
@@ -264,45 +266,45 @@
 }
 
 LIR* X86Mir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
-  DCHECK(!(X86_FPREG(r_base.GetReg())));
+  DCHECK(!r_base.IsFloat());
   int src = r_src.IsPair() ? r_src.GetLowReg() : r_src.GetReg();
 
   X86OpCode opcode = kX86Nop;
   switch (move_type) {
     case kMov8GP:
-      CHECK(!X86_FPREG(src));
+      CHECK(!r_src.IsFloat());
       opcode = kX86Mov8MR;
       break;
     case kMov16GP:
-      CHECK(!X86_FPREG(src));
+      CHECK(!r_src.IsFloat());
       opcode = kX86Mov16MR;
       break;
     case kMov32GP:
-      CHECK(!X86_FPREG(src));
+      CHECK(!r_src.IsFloat());
       opcode = kX86Mov32MR;
       break;
     case kMov32FP:
-      CHECK(X86_FPREG(src));
+      CHECK(r_src.IsFloat());
       opcode = kX86MovssMR;
       break;
     case kMov64FP:
-      CHECK(X86_FPREG(src));
+      CHECK(r_src.IsFloat());
       opcode = kX86MovsdMR;
       break;
     case kMovU128FP:
-      CHECK(X86_FPREG(src));
+      CHECK(r_src.IsFloat());
       opcode = kX86MovupsMR;
       break;
     case kMovA128FP:
-      CHECK(X86_FPREG(src));
+      CHECK(r_src.IsFloat());
       opcode = kX86MovapsMR;
       break;
     case kMovLo128FP:
-      CHECK(X86_FPREG(src));
+      CHECK(r_src.IsFloat());
       opcode = kX86MovlpsMR;
       break;
     case kMovHi128FP:
-      CHECK(X86_FPREG(src));
+      CHECK(r_src.IsFloat());
       opcode = kX86MovhpsMR;
       break;
     case kMov64GP:
@@ -367,7 +369,7 @@
       LOG(FATAL) << "Bad case in OpMemReg " << op;
       break;
   }
-  LIR *l = NewLIR3(opcode, rX86_SP, displacement, r_value);
+  LIR *l = NewLIR3(opcode, rs_rX86_SP.GetReg(), displacement, r_value);
   AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, false /* is_64bit */);
   AnnotateDalvikRegAccess(l, displacement >> 2, false /* is_load */, false /* is_64bit */);
   return l;
@@ -390,7 +392,7 @@
       LOG(FATAL) << "Bad case in OpRegMem " << op;
       break;
   }
-  LIR *l = NewLIR3(opcode, r_dest.GetReg(), rX86_SP, displacement);
+  LIR *l = NewLIR3(opcode, r_dest.GetReg(), rs_rX86_SP.GetReg(), displacement);
   AnnotateDalvikRegAccess(l, displacement >> 2, true /* is_load */, false /* is_64bit */);
   return l;
 }
@@ -449,7 +451,7 @@
     X86OpCode opcode = IS_SIMM8(value) ? kX86Imul32RRI8 : kX86Imul32RRI;
     return NewLIR3(opcode, r_dest.GetReg(), r_src.GetReg(), value);
   } else if (op == kOpAnd) {
-    if (value == 0xFF && r_src.GetReg() < 4) {
+    if (value == 0xFF && r_src.Low4()) {
       return NewLIR2(kX86Movzx8RR, r_dest.GetReg(), r_src.GetReg());
     } else if (value == 0xFFFF) {
       return NewLIR2(kX86Movzx16RR, r_dest.GetReg(), r_src.GetReg());
@@ -497,7 +499,7 @@
     int32_t val_hi = High32Bits(value);
     int32_t low_reg_val = r_dest.IsPair() ? r_dest.GetLowReg() : r_dest.GetReg();
     LIR *res;
-    bool is_fp = X86_FPREG(low_reg_val);
+    bool is_fp = RegStorage::IsFloat(low_reg_val);
     // TODO: clean this up once we fully recognize 64-bit storage containers.
     if (is_fp) {
       if (value == 0) {
@@ -530,10 +532,9 @@
           res = LoadConstantNoClobber(RegStorage::Solo32(low_reg_val), val_lo);
         }
         if (val_hi != 0) {
-          // FIXME: clean up when AllocTempDouble no longer returns a pair.
           RegStorage r_dest_hi = AllocTempDouble();
-          LoadConstantNoClobber(RegStorage::Solo32(r_dest_hi.GetLowReg()), val_hi);
-          NewLIR2(kX86PunpckldqRR, low_reg_val, r_dest_hi.GetLowReg());
+          LoadConstantNoClobber(r_dest_hi, val_hi);
+          NewLIR2(kX86PunpckldqRR, low_reg_val, r_dest_hi.GetReg());
           FreeTemp(r_dest_hi);
         }
       }
@@ -544,25 +545,20 @@
     return res;
 }
 
-// FIXME: don't split r_dest into two storage units.
 LIR* X86Mir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
-                                     int displacement, RegStorage r_dest, RegStorage r_dest_hi,
-                                     OpSize size, int s_reg) {
+                                     int displacement, RegStorage r_dest, OpSize size, int s_reg) {
   LIR *load = NULL;
   LIR *load2 = NULL;
   bool is_array = r_index.Valid();
-  bool pair = false;
-  bool is64bit = false;
+  bool pair = r_dest.IsPair();
+  bool is64bit = ((size == k64) || (size == kDouble));
   X86OpCode opcode = kX86Nop;
   switch (size) {
     case k64:
     case kDouble:
-      // TODO: use regstorage attributes here.
-      is64bit = true;
-      if (X86_FPREG(r_dest.GetReg())) {
+      if (r_dest.IsFloat()) {
         opcode = is_array ? kX86MovsdRA : kX86MovsdRM;
       } else {
-        pair = true;
         opcode = is_array ? kX86Mov32RA  : kX86Mov32RM;
       }
       // TODO: double store is to unaligned address
@@ -572,9 +568,9 @@
     case kSingle:
     case kReference:  // TODO: update for reference decompression on 64-bit targets.
       opcode = is_array ? kX86Mov32RA : kX86Mov32RM;
-      if (X86_FPREG(r_dest.GetReg())) {
+      if (r_dest.IsFloat()) {
         opcode = is_array ? kX86MovssRA : kX86MovssRM;
-        DCHECK(X86_SINGLEREG(r_dest.GetReg()));
+        DCHECK(r_dest.IsFloat());
       }
       DCHECK_EQ((displacement & 0x3), 0);
       break;
@@ -600,13 +596,14 @@
     if (!pair) {
       load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
     } else {
-      if (r_base == r_dest) {
-        load2 = NewLIR3(opcode, r_dest_hi.GetReg(), r_base.GetReg(),
+      DCHECK(!r_dest.IsFloat());  // Make sure we're not still using a pair here.
+      if (r_base == r_dest.GetLow()) {
+        load2 = NewLIR3(opcode, r_dest.GetHighReg(), r_base.GetReg(),
                         displacement + HIWORD_OFFSET);
-        load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
+        load = NewLIR3(opcode, r_dest.GetLowReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
       } else {
-        load = NewLIR3(opcode, r_dest.GetReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
-        load2 = NewLIR3(opcode, r_dest_hi.GetReg(), r_base.GetReg(),
+        load = NewLIR3(opcode, r_dest.GetLowReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
+        load2 = NewLIR3(opcode, r_dest.GetHighReg(), r_base.GetReg(),
                         displacement + HIWORD_OFFSET);
       }
     }
@@ -623,36 +620,37 @@
       load = NewLIR5(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
                      displacement + LOWORD_OFFSET);
     } else {
-      if (r_base == r_dest) {
-        if (r_dest_hi == r_index) {
+      DCHECK(!r_dest.IsFloat());  // Make sure we're not still using a pair here.
+      if (r_base == r_dest.GetLow()) {
+        if (r_dest.GetHigh() == r_index) {
           // We can't use either register for the first load.
           RegStorage temp = AllocTemp();
           load2 = NewLIR5(opcode, temp.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
                           displacement + HIWORD_OFFSET);
-          load = NewLIR5(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+          load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
                          displacement + LOWORD_OFFSET);
-          OpRegCopy(r_dest_hi, temp);
+          OpRegCopy(r_dest.GetHigh(), temp);
           FreeTemp(temp);
         } else {
-          load2 = NewLIR5(opcode, r_dest_hi.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+          load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale,
                           displacement + HIWORD_OFFSET);
-          load = NewLIR5(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+          load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
                          displacement + LOWORD_OFFSET);
         }
       } else {
-        if (r_dest == r_index) {
+        if (r_dest.GetLow() == r_index) {
           // We can't use either register for the first load.
           RegStorage temp = AllocTemp();
           load = NewLIR5(opcode, temp.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
                          displacement + LOWORD_OFFSET);
-          load2 = NewLIR5(opcode, r_dest_hi.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+          load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale,
                           displacement + HIWORD_OFFSET);
-          OpRegCopy(r_dest, temp);
+          OpRegCopy(r_dest.GetLow(), temp);
           FreeTemp(temp);
         } else {
-          load = NewLIR5(opcode, r_dest.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+          load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
                          displacement + LOWORD_OFFSET);
-          load2 = NewLIR5(opcode, r_dest_hi.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+          load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale,
                           displacement + HIWORD_OFFSET);
         }
       }
@@ -665,44 +663,38 @@
 /* Load value from base + scaled index. */
 LIR* X86Mir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
                                  int scale, OpSize size) {
-  return LoadBaseIndexedDisp(r_base, r_index, scale, 0,
-                             r_dest, RegStorage::InvalidReg(), size, INVALID_SREG);
+  return LoadBaseIndexedDisp(r_base, r_index, scale, 0, r_dest, size, INVALID_SREG);
 }
 
-LIR* X86Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement,
-                  RegStorage r_dest, OpSize size, int s_reg) {
+LIR* X86Mir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
+                              OpSize size, int s_reg) {
   // TODO: base this on target.
   if (size == kWord) {
     size = k32;
   }
-  return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement,
-                             r_dest, RegStorage::InvalidReg(), size, s_reg);
+  return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_dest,
+                             size, s_reg);
 }
 
 LIR* X86Mir2Lir::LoadBaseDispWide(RegStorage r_base, int displacement, RegStorage r_dest,
                                   int s_reg) {
-  return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement,
-                             r_dest.GetLow(), r_dest.GetHigh(), k64, s_reg);
+  return LoadBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_dest, k64, s_reg);
 }
 
 LIR* X86Mir2Lir::StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale,
-                                      int displacement, RegStorage r_src, RegStorage r_src_hi,
-                                      OpSize size, int s_reg) {
+                                      int displacement, RegStorage r_src, OpSize size, int s_reg) {
   LIR *store = NULL;
   LIR *store2 = NULL;
   bool is_array = r_index.Valid();
-  // FIXME: use regstorage attributes in place of these.
-  bool pair = false;
-  bool is64bit = false;
+  bool pair = r_src.IsPair();
+  bool is64bit = (size == k64) || (size == kDouble);
   X86OpCode opcode = kX86Nop;
   switch (size) {
     case k64:
     case kDouble:
-      is64bit = true;
-      if (X86_FPREG(r_src.GetReg())) {
+      if (r_src.IsFloat()) {
         opcode = is_array ? kX86MovsdAR : kX86MovsdMR;
       } else {
-        pair = true;
         opcode = is_array ? kX86Mov32AR  : kX86Mov32MR;
       }
       // TODO: double store is to unaligned address
@@ -712,9 +704,9 @@
     case kSingle:
     case kReference:
       opcode = is_array ? kX86Mov32AR : kX86Mov32MR;
-      if (X86_FPREG(r_src.GetReg())) {
+      if (r_src.IsFloat()) {
         opcode = is_array ? kX86MovssAR : kX86MovssMR;
-        DCHECK(X86_SINGLEREG(r_src.GetReg()));
+        DCHECK(r_src.IsSingle());
       }
       DCHECK_EQ((displacement & 0x3), 0);
       break;
@@ -735,8 +727,9 @@
     if (!pair) {
       store = NewLIR3(opcode, r_base.GetReg(), displacement + LOWORD_OFFSET, r_src.GetReg());
     } else {
-      store = NewLIR3(opcode, r_base.GetReg(), displacement + LOWORD_OFFSET, r_src.GetReg());
-      store2 = NewLIR3(opcode, r_base.GetReg(), displacement + HIWORD_OFFSET, r_src_hi.GetReg());
+      DCHECK(!r_src.IsFloat());  // Make sure we're not still using a pair here.
+      store = NewLIR3(opcode, r_base.GetReg(), displacement + LOWORD_OFFSET, r_src.GetLowReg());
+      store2 = NewLIR3(opcode, r_base.GetReg(), displacement + HIWORD_OFFSET, r_src.GetHighReg());
     }
     if (r_base == rs_rX86_SP) {
       AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
@@ -751,21 +744,20 @@
       store = NewLIR5(opcode, r_base.GetReg(), r_index.GetReg(), scale,
                       displacement + LOWORD_OFFSET, r_src.GetReg());
     } else {
+      DCHECK(!r_src.IsFloat());  // Make sure we're not still using a pair here.
       store = NewLIR5(opcode, r_base.GetReg(), r_index.GetReg(), scale,
-                      displacement + LOWORD_OFFSET, r_src.GetReg());
+                      displacement + LOWORD_OFFSET, r_src.GetLowReg());
       store2 = NewLIR5(opcode, r_base.GetReg(), r_index.GetReg(), scale,
-                       displacement + HIWORD_OFFSET, r_src_hi.GetReg());
+                       displacement + HIWORD_OFFSET, r_src.GetHighReg());
     }
   }
-
   return store;
 }
 
 /* store value base base + scaled index. */
 LIR* X86Mir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
                       int scale, OpSize size) {
-  return StoreBaseIndexedDisp(r_base, r_index, scale, 0,
-                              r_src, RegStorage::InvalidReg(), size, INVALID_SREG);
+  return StoreBaseIndexedDisp(r_base, r_index, scale, 0, r_src, size, INVALID_SREG);
 }
 
 LIR* X86Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement,
@@ -774,25 +766,13 @@
   if (size == kWord) {
     size = k32;
   }
-  return StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_src,
-                              RegStorage::InvalidReg(), size, INVALID_SREG);
+  return StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_src, size,
+                              INVALID_SREG);
 }
 
 LIR* X86Mir2Lir::StoreBaseDispWide(RegStorage r_base, int displacement, RegStorage r_src) {
   return StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement,
-                              r_src.GetLow(), r_src.GetHigh(), k64, INVALID_SREG);
-}
-
-/*
- * Copy a long value in Core registers to an XMM register
- *
- */
-void X86Mir2Lir::OpVectorRegCopyWide(uint8_t fp_reg, uint8_t low_reg, uint8_t high_reg) {
-  NewLIR2(kX86MovdxrRR, fp_reg, low_reg);
-  int tmp_reg = AllocTempDouble().GetLowReg();
-  NewLIR2(kX86MovdxrRR, tmp_reg, high_reg);
-  NewLIR2(kX86PunpckldqRR, fp_reg, tmp_reg);
-  FreeTemp(tmp_reg);
+                              r_src, k64, INVALID_SREG);
 }
 
 LIR* X86Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
@@ -889,7 +869,7 @@
 
 void X86Mir2Lir::AnalyzeFPInstruction(int opcode, BasicBlock * bb, MIR *mir) {
   // Look at all the uses, and see if they are double constants.
-  uint64_t attrs = mir_graph_->oat_data_flow_attributes_[opcode];
+  uint64_t attrs = MIRGraph::GetDataFlowAttributes(static_cast<Instruction::Code>(opcode));
   int next_sreg = 0;
   if (attrs & DF_UA) {
     if (attrs & DF_A_WIDE) {
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 1759cbe..9bf49c3 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -102,27 +102,6 @@
  * +========================+
  */
 
-// Offset to distingish FP regs.
-#define X86_FP_REG_OFFSET 32
-// Offset to distinguish DP FP regs.
-#define X86_FP_DOUBLE (X86_FP_REG_OFFSET + 16)
-// Reg types.
-#define X86_REGTYPE(x) (x & (X86_FP_REG_OFFSET | X86_FP_DOUBLE))
-#define X86_FPREG(x) ((x & X86_FP_REG_OFFSET) == X86_FP_REG_OFFSET)
-#define X86_DOUBLEREG(x) ((x & X86_FP_DOUBLE) == X86_FP_DOUBLE)
-#define X86_SINGLEREG(x) (X86_FPREG(x) && !X86_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 X86_S2D(x, y) ((x) | X86_FP_DOUBLE)
-/* Mask to strip off fp flags */
-#define X86_FP_REG_MASK 0xF
-
 enum X86ResourceEncodingPos {
   kX86GPReg0   = 0,
   kX86RegSP    = 4,
@@ -135,72 +114,119 @@
 #define ENCODE_X86_REG_SP           (1ULL << kX86RegSP)
 #define ENCODE_X86_FP_STACK         (1ULL << kX86FPStack)
 
+// FIXME: for 64-bit, perhaps add an X86_64NativeRegisterPool enum?
 enum X86NativeRegisterPool {
-  r0     = 0,
-  rAX    = r0,
-  r1     = 1,
-  rCX    = r1,
-  r2     = 2,
-  rDX    = r2,
-  r3     = 3,
-  rBX    = r3,
-  r4sp   = 4,
-  rX86_SP    = r4sp,
+  r0             = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 0,
+  rAX            = r0,
+  r1             = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 1,
+  rCX            = r1,
+  r2             = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 2,
+  rDX            = r2,
+  r3             = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 3,
+  rBX            = r3,
+  r4sp           = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 4,
+  rX86_SP        = r4sp,
   r4sib_no_index = r4sp,
-  r5     = 5,
-  rBP    = r5,
-  r5sib_no_base = r5,
-  r6     = 6,
-  rSI    = r6,
-  r7     = 7,
-  rDI    = r7,
+  r5             = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 5,
+  rBP            = r5,
+  r5sib_no_base  = r5,
+  r6             = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 6,
+  rSI            = r6,
+  r7             = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 7,
+  rDI            = r7,
 #ifndef TARGET_REX_SUPPORT
-  rRET   = 8,  // fake return address register for core spill mask.
+  // fake return address register for core spill mask.
+  rRET           = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 8,
 #else
-  r8     = 8,
-  r9     = 9,
-  r10    = 10,
-  r11    = 11,
-  r12    = 12,
-  r13    = 13,
-  r14    = 14,
-  r15    = 15,
-  rRET   = 16,  // fake return address register for core spill mask.
+  r8             = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 8,
+  r9             = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 9,
+  r10            = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 10,
+  r11            = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 11,
+  r12            = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 12,
+  r13            = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 13,
+  r14            = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 14,
+  r15            = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 15,
+  // fake return address register for core spill mask.
+  rRET           = RegStorage::k32BitSolo | RegStorage::kCoreRegister | 16,
 #endif
-  fr0  =  0 + X86_FP_REG_OFFSET,
-  fr1  =  1 + X86_FP_REG_OFFSET,
-  fr2  =  2 + X86_FP_REG_OFFSET,
-  fr3  =  3 + X86_FP_REG_OFFSET,
-  fr4  =  4 + X86_FP_REG_OFFSET,
-  fr5  =  5 + X86_FP_REG_OFFSET,
-  fr6  =  6 + X86_FP_REG_OFFSET,
-  fr7  =  7 + X86_FP_REG_OFFSET,
-  fr8  =  8 + X86_FP_REG_OFFSET,
-  fr9  =  9 + X86_FP_REG_OFFSET,
-  fr10 = 10 + X86_FP_REG_OFFSET,
-  fr11 = 11 + X86_FP_REG_OFFSET,
-  fr12 = 12 + X86_FP_REG_OFFSET,
-  fr13 = 13 + X86_FP_REG_OFFSET,
-  fr14 = 14 + X86_FP_REG_OFFSET,
-  fr15 = 15 + X86_FP_REG_OFFSET,
+
+  // xmm registers, single precision view
+  fr0  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 0,
+  fr1  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 1,
+  fr2  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 2,
+  fr3  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 3,
+  fr4  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 4,
+  fr5  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 5,
+  fr6  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 6,
+  fr7  = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 7,
+
+  // xmm registers, double precision alises
+  dr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0,
+  dr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 1,
+  dr2  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2,
+  dr3  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 3,
+  dr4  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 4,
+  dr5  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 5,
+  dr6  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 6,
+  dr7  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 7,
+
+  // xmm registers, quad precision alises
+  qr0  = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 0,
+  qr1  = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 1,
+  qr2  = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 2,
+  qr3  = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 3,
+  qr4  = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 4,
+  qr5  = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 5,
+  qr6  = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 6,
+  qr7  = RegStorage::k128BitSolo | RegStorage::kFloatingPoint | 7,
+
+  // TODO: as needed, add 256, 512 and 1024-bit xmm views.
 };
 
-const RegStorage rs_r0(RegStorage::k32BitSolo, r0);
-const RegStorage rs_rAX = rs_r0;
-const RegStorage rs_r1(RegStorage::k32BitSolo, r1);
-const RegStorage rs_rCX = rs_r1;
-const RegStorage rs_r2(RegStorage::k32BitSolo, r2);
-const RegStorage rs_rDX = rs_r2;
-const RegStorage rs_r3(RegStorage::k32BitSolo, r3);
-const RegStorage rs_rBX = rs_r3;
-const RegStorage rs_r4sp(RegStorage::k32BitSolo, r4sp);
-const RegStorage rs_rX86_SP = rs_r4sp;
-const RegStorage rs_r5(RegStorage::k32BitSolo, r5);
-const RegStorage rs_rBP = rs_r5;
-const RegStorage rs_r6(RegStorage::k32BitSolo, r6);
-const RegStorage rs_rSI = rs_r6;
-const RegStorage rs_r7(RegStorage::k32BitSolo, r7);
-const RegStorage rs_rDI = rs_r7;
+constexpr RegStorage rs_r0(RegStorage::kValid | r0);
+constexpr RegStorage rs_rAX = rs_r0;
+constexpr RegStorage rs_r1(RegStorage::kValid | r1);
+constexpr RegStorage rs_rCX = rs_r1;
+constexpr RegStorage rs_r2(RegStorage::kValid | r2);
+constexpr RegStorage rs_rDX = rs_r2;
+constexpr RegStorage rs_r3(RegStorage::kValid | r3);
+constexpr RegStorage rs_rBX = rs_r3;
+constexpr RegStorage rs_r4sp(RegStorage::kValid | r4sp);
+constexpr RegStorage rs_rX86_SP = rs_r4sp;
+constexpr RegStorage rs_r5(RegStorage::kValid | r5);
+constexpr RegStorage rs_rBP = rs_r5;
+constexpr RegStorage rs_r6(RegStorage::kValid | r6);
+constexpr RegStorage rs_rSI = rs_r6;
+constexpr RegStorage rs_r7(RegStorage::kValid | r7);
+constexpr RegStorage rs_rDI = rs_r7;
+constexpr RegStorage rs_rRET(RegStorage::kValid | rRET);
+
+constexpr RegStorage rs_fr0(RegStorage::kValid | fr0);
+constexpr RegStorage rs_fr1(RegStorage::kValid | fr1);
+constexpr RegStorage rs_fr2(RegStorage::kValid | fr2);
+constexpr RegStorage rs_fr3(RegStorage::kValid | fr3);
+constexpr RegStorage rs_fr4(RegStorage::kValid | fr4);
+constexpr RegStorage rs_fr5(RegStorage::kValid | fr5);
+constexpr RegStorage rs_fr6(RegStorage::kValid | fr6);
+constexpr RegStorage rs_fr7(RegStorage::kValid | fr7);
+
+constexpr RegStorage rs_dr0(RegStorage::kValid | dr0);
+constexpr RegStorage rs_dr1(RegStorage::kValid | dr1);
+constexpr RegStorage rs_dr2(RegStorage::kValid | dr2);
+constexpr RegStorage rs_dr3(RegStorage::kValid | dr3);
+constexpr RegStorage rs_dr4(RegStorage::kValid | dr4);
+constexpr RegStorage rs_dr5(RegStorage::kValid | dr5);
+constexpr RegStorage rs_dr6(RegStorage::kValid | dr6);
+constexpr RegStorage rs_dr7(RegStorage::kValid | dr7);
+
+constexpr RegStorage rs_qr0(RegStorage::kValid | qr0);
+constexpr RegStorage rs_qr1(RegStorage::kValid | qr1);
+constexpr RegStorage rs_qr2(RegStorage::kValid | qr2);
+constexpr RegStorage rs_qr3(RegStorage::kValid | qr3);
+constexpr RegStorage rs_qr4(RegStorage::kValid | qr4);
+constexpr RegStorage rs_qr5(RegStorage::kValid | qr5);
+constexpr RegStorage rs_qr6(RegStorage::kValid | qr6);
+constexpr RegStorage rs_qr7(RegStorage::kValid | qr7);
 
 // TODO: elminate these #defines?
 #define rX86_ARG0 rAX
@@ -234,19 +260,17 @@
 
 // RegisterLocation templates return values (r_V0, or r_V0/r_V1).
 const RegLocation x86_loc_c_return
-    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1,
      RegStorage(RegStorage::k32BitSolo, rAX), INVALID_SREG, INVALID_SREG};
 const RegLocation x86_loc_c_return_wide
-    {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
+    {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
      RegStorage(RegStorage::k64BitPair, rAX, rDX), INVALID_SREG, INVALID_SREG};
-// TODO: update to use k32BitVector (must encode in 7 bits, including fp flag).
 const RegLocation x86_loc_c_return_float
-    {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1, kVectorLength4,
+    {kLocPhysReg, 0, 0, 0, 1, 0, 0, 0, 1,
      RegStorage(RegStorage::k32BitSolo, fr0), INVALID_SREG, INVALID_SREG};
-// TODO: update to use k64BitVector (must encode in 7 bits, including fp flag).
 const RegLocation x86_loc_c_return_double
-    {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1, kVectorLength8,
-     RegStorage(RegStorage::k64BitPair, fr0, fr0), INVALID_SREG, INVALID_SREG};
+    {kLocPhysReg, 1, 0, 0, 1, 0, 0, 0, 1,
+     RegStorage(RegStorage::k64BitSolo, dr0), INVALID_SREG, INVALID_SREG};
 
 /*
  * The following enum defines the list of supported X86 instructions by the
diff --git a/compiler/dex/reg_storage.h b/compiler/dex/reg_storage.h
index 11bec99..df5aa7b 100644
--- a/compiler/dex/reg_storage.h
+++ b/compiler/dex/reg_storage.h
@@ -21,77 +21,105 @@
 namespace art {
 
 /*
- * Representation of the physical register, register pair or vector holding a Dalvik value.
- * The basic configuration of the storage (i.e. solo reg, pair, vector) is common across all
- * targets, but the encoding of the actual storage element is target independent.
+ * 16-bit representation of the physical register container holding a Dalvik value.
+ * The encoding allows up to 32 physical elements per storage class, and supports eight
+ * register container shapes.
  *
- * The two most-significant bits describe the basic shape of the storage, while meaning of the
- * lower 14 bits depends on the shape:
+ * [V] [D] [HHHHH] [SSS] [F] [LLLLL]
  *
- *  [PW]
- *       P: 0 -> pair, 1 -> solo (or vector)
- *       W: 1 -> 64 bits, 0 -> 32 bits
+ * [LLLLL]
+ *  Physical register number for the low or solo register.
+ *    0..31
  *
- *  [00] [xxxxxxxxxxxxxx]     Invalid (typically all zeros)
- *  [01] [HHHHHHH] [LLLLLLL]  64-bit storage, composed of 2 32-bit registers
- *  [10] [0] [xxxxxx] [RRRRRRR]  32-bit solo register
- *  [11] [0] [xxxxxx] [RRRRRRR]  64-bit solo register
- *  [10] [1] [xxxxxx] [VVVVVVV]  32-bit vector storage
- *  [11] [1] [xxxxxx] [VVVVVVV]  64-bit vector storage
+ * [F]
+ *  Describes type of the [LLLLL] register.
+ *    0: Core
+ *    1: Floating point
  *
- * x - don't care
- * L - low register number of a pair
- * H - high register number of a pair
- * R - register number of a solo reg
- * V - vector description
+ * [SSS]
+ *  Shape of the register container.
+ *    000: Invalid
+ *    001: 32-bit solo register
+ *    010: 64-bit solo register
+ *    011: 64-bit pair consisting of two 32-bit solo registers
+ *    100: 128-bit solo register
+ *    101: 256-bit solo register
+ *    110: 512-bit solo register
+ *    111: 1024-bit solo register
  *
- * Note that in all non-invalid cases, the low 7 bits must be sufficient to describe
- * whether the storage element is floating point (see IsFloatReg()).
+ * [HHHHH]
+ *  Physical register number of the high register (valid only for register pair).
+ *    0..31
  *
+ * [D]
+ *  Describes type of the [HHHHH] register (valid only for register pair).
+ *    0: Core
+ *    1: Floating point
+ *
+ * [V]
+ *    0 -> Invalid
+ *    1 -> Valid
+ *
+ * Note that in all non-invalid cases, we can determine if the storage is floating point
+ * by testing bit 6.  Though a mismatch appears to be permitted by the format, the [F][D] values
+ * from each half of a pair must match (this allows the high and low regs of a pair to be more
+ * easily individually manipulated).
+ *
+ * On some target architectures, the same underlying physical register container can be given
+ * different views.  For example, Arm's 32-bit single-precision floating point registers
+ * s2 and s3 map to the low and high halves of double-precision d1.  Similarly, X86's xmm3
+ * vector register can be viewed as 32-bit, 64-bit, 128-bit, etc.  In these cases the use of
+ * one view will affect the other views.  The RegStorage class does not concern itself
+ * with potential aliasing.  That will be done using the associated RegisterInfo struct.
+ * Distinct RegStorage elements should be created for each view of a physical register
+ * container.  The management of the aliased physical elements will be handled via RegisterInfo
+ * records.
  */
 
 class RegStorage {
  public:
   enum RegStorageKind {
-    kInvalid     = 0x0000,
-    k64BitPair   = 0x4000,
-    k32BitSolo   = 0x8000,
-    k64BitSolo   = 0xc000,
-    k32BitVector = 0xa000,
-    k64BitVector = 0xe000,
-    kPairMask    = 0x8000,
-    kPair        = 0x0000,
-    kSizeMask    = 0x4000,
-    k64Bit       = 0x4000,
-    k32Bit       = 0x0000,
-    kVectorMask  = 0xa000,
-    kVector      = 0xa000,
-    kSolo        = 0x8000,
-    kShapeMask   = 0xc000,
-    kKindMask    = 0xe000
+    kValidMask     = 0x8000,
+    kValid         = 0x8000,
+    kInvalid       = 0x0000,
+    kShapeMask     = 0x01c0,
+    k32BitSolo     = 0x0040,
+    k64BitSolo     = 0x0080,
+    k64BitPair     = 0x00c0,
+    k128BitSolo    = 0x0100,
+    k256BitSolo    = 0x0140,
+    k512BitSolo    = 0x0180,
+    k1024BitSolo   = 0x01c0,
+    k64BitMask     = 0x0180,
+    k64Bits        = 0x0080,
+    kShapeTypeMask = 0x01e0,
+    kFloatingPoint = 0x0020,
+    kCoreRegister  = 0x0000,
   };
 
-  static const uint16_t kRegValMask = 0x007f;
-  static const uint16_t kInvalidRegVal = 0x007f;
-  static const uint16_t kHighRegShift = 7;
-  static const uint16_t kHighRegMask = kRegValMask << kHighRegShift;
+  static const uint16_t kRegValMask  = 0x01ff;  // Num, type and shape.
+  static const uint16_t kRegTypeMask = 0x003f;  // Num and type.
+  static const uint16_t kRegNumMask  = 0x001f;  // Num only.
+  static const uint16_t kMaxRegs     = kRegValMask + 1;
+  // TODO: deprecate use of kInvalidRegVal and speed up GetReg().
+  static const uint16_t kInvalidRegVal = 0x01ff;
+  static const uint16_t kHighRegShift = 9;
+  static const uint16_t kShapeMaskShift = 6;
+  static const uint16_t kHighRegMask = (kRegTypeMask << kHighRegShift);
 
+  // Reg is [F][LLLLL], will override any existing shape and use rs_kind.
   RegStorage(RegStorageKind rs_kind, int reg) {
-    DCHECK_NE(rs_kind & kShapeMask, kInvalid);
-    DCHECK_NE(rs_kind & kShapeMask, k64BitPair);
-    DCHECK_EQ(rs_kind & ~kKindMask, 0);
-    DCHECK_EQ(reg & ~kRegValMask, 0);
-    reg_ = rs_kind | reg;
+    DCHECK_NE(rs_kind, k64BitPair);
+    DCHECK_EQ(rs_kind & ~kShapeMask, 0);
+    reg_ = kValid | rs_kind | (reg & kRegTypeMask);
   }
   RegStorage(RegStorageKind rs_kind, int low_reg, int high_reg) {
     DCHECK_EQ(rs_kind, k64BitPair);
-    DCHECK_EQ(low_reg & ~kRegValMask, 0);
-    DCHECK_EQ(high_reg & ~kRegValMask, 0);
-    reg_ = rs_kind | (high_reg << kHighRegShift) | low_reg;
+    DCHECK_EQ(low_reg & kFloatingPoint, high_reg & kFloatingPoint);
+    reg_ = kValid | rs_kind | ((high_reg & kRegTypeMask) << kHighRegShift) | (low_reg & kRegTypeMask);
   }
-  explicit RegStorage(uint16_t val) : reg_(val) {}
+  constexpr explicit RegStorage(uint16_t val) : reg_(val) {}
   RegStorage() : reg_(kInvalid) {}
-  ~RegStorage() {}
 
   bool operator==(const RegStorage rhs) const {
     return (reg_ == rhs.GetRawBits());
@@ -102,73 +130,127 @@
   }
 
   bool Valid() const {
-    return ((reg_ & kShapeMask) != kInvalid);
+    return ((reg_ & kValidMask) == kValid);
   }
 
   bool Is32Bit() const {
-    return ((reg_ & kSizeMask) == k32Bit);
+    return ((reg_ & kShapeMask) == k32BitSolo);
   }
 
   bool Is64Bit() const {
-    return ((reg_ & kSizeMask) == k64Bit);
+    return ((reg_ & k64BitMask) == k64Bits);
   }
 
   bool IsPair() const {
-    return ((reg_ & kPairMask) == kPair);
+    return ((reg_ & kShapeMask) == k64BitPair);
   }
 
-  bool IsSolo() const {
-    return ((reg_ & kVectorMask) == kSolo);
+  bool IsFloat() const {
+    DCHECK(Valid());
+    return ((reg_ & kFloatingPoint) == kFloatingPoint);
   }
 
-  bool IsVector() const {
-    return ((reg_ & kVectorMask) == kVector);
+  bool IsDouble() const {
+    DCHECK(Valid());
+    return (reg_ & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
+  }
+
+  bool IsSingle() const {
+    DCHECK(Valid());
+    return (reg_ & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
+  }
+
+  static bool IsFloat(uint16_t reg) {
+    return ((reg & kFloatingPoint) == kFloatingPoint);
+  }
+
+  static bool IsDouble(uint16_t reg) {
+    return (reg & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
+  }
+
+  static bool IsSingle(uint16_t reg) {
+    return (reg & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
   }
 
   // Used to retrieve either the low register of a pair, or the only register.
   int GetReg() const {
-    DCHECK(!IsPair());
+    DCHECK(!IsPair()) << "reg_ = 0x" << std::hex << reg_;
     return Valid() ? (reg_ & kRegValMask) : kInvalidRegVal;
   }
 
+  // Sets shape, type and num of solo.
   void SetReg(int reg) {
     DCHECK(Valid());
+    DCHECK(!IsPair());
     reg_ = (reg_ & ~kRegValMask) | reg;
   }
 
+  // Set the reg number and type only, target remain 64-bit pair.
   void SetLowReg(int reg) {
     DCHECK(IsPair());
-    reg_ = (reg_ & ~kRegValMask) | reg;
+    reg_ = (reg_ & ~kRegTypeMask) | (reg & kRegTypeMask);
   }
 
-  // Retrieve the least significant register of a pair.
+  // Retrieve the least significant register of a pair and return as 32-bit solo.
   int GetLowReg() const {
     DCHECK(IsPair());
-    return (reg_ & kRegValMask);
+    return ((reg_ & kRegTypeMask) | k32BitSolo);
   }
 
   // Create a stand-alone RegStorage from the low reg of a pair.
   RegStorage GetLow() const {
     DCHECK(IsPair());
-    return RegStorage(k32BitSolo, reg_ & kRegValMask);
+    return RegStorage(k32BitSolo, reg_ & kRegTypeMask);
   }
 
   // Retrieve the most significant register of a pair.
   int GetHighReg() const {
     DCHECK(IsPair());
-    return (reg_ & kHighRegMask) >> kHighRegShift;
+    return k32BitSolo | ((reg_ & kHighRegMask) >> kHighRegShift);
   }
 
   // Create a stand-alone RegStorage from the high reg of a pair.
   RegStorage GetHigh() const {
     DCHECK(IsPair());
-    return RegStorage(k32BitSolo, (reg_ & kHighRegMask) >> kHighRegShift);
+    return RegStorage(kValid | GetHighReg());
   }
 
   void SetHighReg(int reg) {
     DCHECK(IsPair());
-    reg_ = (reg_ & ~kHighRegMask) | (reg << kHighRegShift);
-    DCHECK_EQ(GetHighReg(), reg);
+    reg_ = (reg_ & ~kHighRegMask) | ((reg & kRegTypeMask) << kHighRegShift);
+  }
+
+  // Return the register number of low or solo.
+  int GetRegNum() const {
+    return reg_ & kRegNumMask;
+  }
+
+  // Aliased double to low single.
+  RegStorage DoubleToLowSingle() const {
+    DCHECK(IsDouble());
+    return FloatSolo32(GetRegNum() << 1);
+  }
+
+  // Aliased double to high single.
+  RegStorage DoubleToHighSingle() const {
+    DCHECK(IsDouble());
+    return FloatSolo32((GetRegNum() << 1) + 1);
+  }
+
+  // Single to aliased double.
+  RegStorage SingleToDouble() const {
+    DCHECK(IsSingle());
+    return FloatSolo64(GetRegNum() >> 1);
+  }
+
+  // Is register number in 0..7?
+  bool Low8() const {
+    return GetRegNum() < 8;
+  }
+
+  // Is register number in 0..3?
+  bool Low4() const {
+    return GetRegNum() < 4;
   }
 
   // Combine 2 32-bit solo regs into a pair.
@@ -180,24 +262,61 @@
     return RegStorage(k64BitPair, low.GetReg(), high.GetReg());
   }
 
+  static bool SameRegType(RegStorage reg1, RegStorage reg2) {
+    return (reg1.IsDouble() == reg2.IsDouble()) && (reg1.IsSingle() == reg2.IsSingle());
+  }
+
+  static bool SameRegType(int reg1, int reg2) {
+    return (IsDouble(reg1) == IsDouble(reg2)) && (IsSingle(reg1) == IsSingle(reg2));
+  }
+
   // Create a 32-bit solo.
   static RegStorage Solo32(int reg_num) {
-    return RegStorage(k32BitSolo, reg_num);
+    return RegStorage(k32BitSolo, reg_num & kRegTypeMask);
+  }
+
+  // Create a floating point 32-bit solo.
+  static RegStorage FloatSolo32(int reg_num) {
+    return RegStorage(k32BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
   }
 
   // Create a 64-bit solo.
   static RegStorage Solo64(int reg_num) {
-    return RegStorage(k64BitSolo, reg_num);
+    return RegStorage(k64BitSolo, reg_num & kRegTypeMask);
+  }
+
+  // Create a floating point 64-bit solo.
+  static RegStorage FloatSolo64(int reg_num) {
+    return RegStorage(k64BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
   }
 
   static RegStorage InvalidReg() {
     return RegStorage(kInvalid);
   }
 
+  static uint16_t RegNum(int raw_reg_bits) {
+    return raw_reg_bits & kRegNumMask;
+  }
+
   int GetRawBits() const {
     return reg_;
   }
 
+  size_t StorageSize() {
+    switch (reg_ & kShapeMask) {
+      case kInvalid: return 0;
+      case k32BitSolo: return 4;
+      case k64BitSolo: return 8;
+      case k64BitPair: return 8;  // Is this useful?  Might want to disallow taking size of pair.
+      case k128BitSolo: return 16;
+      case k256BitSolo: return 32;
+      case k512BitSolo: return 64;
+      case k1024BitSolo: return 128;
+      default: LOG(FATAL) << "Unexpected shap";
+    }
+    return 0;
+  }
+
  private:
   uint16_t reg_;
 };
diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc
index 4be0f59..95b3d86 100644
--- a/compiler/dex/vreg_analysis.cc
+++ b/compiler/dex/vreg_analysis.cc
@@ -124,7 +124,7 @@
 bool MIRGraph::InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed) {
   SSARepresentation *ssa_rep = mir->ssa_rep;
   if (ssa_rep) {
-    uint64_t attrs = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
+    uint64_t attrs = GetDataFlowAttributes(mir);
     const int* uses = ssa_rep->uses;
     const int* defs = ssa_rep->defs;
 
@@ -403,7 +403,7 @@
 }
 
 // FIXME - will likely need to revisit all uses of this.
-static const RegLocation fresh_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0, kVectorNotUsed,
+static const RegLocation fresh_loc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, 0, 0,
                                       RegStorage(), INVALID_SREG, INVALID_SREG};
 
 void MIRGraph::InitRegLocations() {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 0ad30be..e5decc5 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -905,13 +905,14 @@
 
 bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx,
                                         bool* is_type_initialized, bool* use_direct_type_ptr,
-                                        uintptr_t* direct_type_ptr) {
+                                        uintptr_t* direct_type_ptr, bool* out_is_finalizable) {
   ScopedObjectAccess soa(Thread::Current());
   mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class == nullptr) {
     return false;
   }
+  *out_is_finalizable = resolved_class->IsFinalizable();
   const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
   if (compiling_boot) {
     // boot -> boot class pointers.
@@ -1699,44 +1700,34 @@
               !StringPiece(descriptor).ends_with("$NoPreloadHolder;");
           if (can_init_static_fields) {
             VLOG(compiler) << "Initializing: " << descriptor;
-            if (strcmp("Ljava/lang/Void;", descriptor) == 0) {
-              // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
-              ObjectLock<mirror::Class> lock(soa.Self(), &klass);
-              mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
-              CHECK_EQ(fields->GetLength(), 1);
-              fields->Get(0)->SetObj<false>(klass.get(),
-                                                     manager->GetClassLinker()->FindPrimitiveClass('V'));
-              klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self());
-            } else {
-              // TODO multithreading support. We should ensure the current compilation thread has
-              // exclusive access to the runtime and the transaction. To achieve this, we could use
-              // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
-              // checks in Thread::AssertThreadSuspensionIsAllowable.
-              Runtime* const runtime = Runtime::Current();
-              Transaction transaction;
+            // TODO multithreading support. We should ensure the current compilation thread has
+            // exclusive access to the runtime and the transaction. To achieve this, we could use
+            // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
+            // checks in Thread::AssertThreadSuspensionIsAllowable.
+            Runtime* const runtime = Runtime::Current();
+            Transaction transaction;
 
-              // Run the class initializer in transaction mode.
-              runtime->EnterTransactionMode(&transaction);
-              const mirror::Class::Status old_status = klass->GetStatus();
-              bool success = manager->GetClassLinker()->EnsureInitialized(klass, true, true);
-              // TODO we detach transaction from runtime to indicate we quit the transactional
-              // mode which prevents the GC from visiting objects modified during the transaction.
-              // Ensure GC is not run so don't access freed objects when aborting transaction.
-              const char* old_casue = soa.Self()->StartAssertNoThreadSuspension("Transaction end");
-              runtime->ExitTransactionMode();
+            // Run the class initializer in transaction mode.
+            runtime->EnterTransactionMode(&transaction);
+            const mirror::Class::Status old_status = klass->GetStatus();
+            bool success = manager->GetClassLinker()->EnsureInitialized(klass, true, true);
+            // TODO we detach transaction from runtime to indicate we quit the transactional
+            // mode which prevents the GC from visiting objects modified during the transaction.
+            // Ensure GC is not run so don't access freed objects when aborting transaction.
+            const char* old_casue = soa.Self()->StartAssertNoThreadSuspension("Transaction end");
+            runtime->ExitTransactionMode();
 
-              if (!success) {
-                CHECK(soa.Self()->IsExceptionPending());
-                ThrowLocation throw_location;
-                mirror::Throwable* exception = soa.Self()->GetException(&throw_location);
-                VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
-                               << exception->Dump();
-                soa.Self()->ClearException();
-                transaction.Abort();
-                CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
-              }
-              soa.Self()->EndAssertNoThreadSuspension(old_casue);
+            if (!success) {
+              CHECK(soa.Self()->IsExceptionPending());
+              ThrowLocation throw_location;
+              mirror::Throwable* exception = soa.Self()->GetException(&throw_location);
+              VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
+                  << exception->Dump();
+              soa.Self()->ClearException();
+              transaction.Abort();
+              CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
             }
+            soa.Self()->EndAssertNoThreadSuspension(old_casue);
           }
         }
         soa.Self()->AssertNoPendingException();
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index d7d40d5..6ac9cf7 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -210,7 +210,7 @@
 
   bool CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx,
                           bool* is_type_initialized, bool* use_direct_type_ptr,
-                          uintptr_t* direct_type_ptr);
+                          uintptr_t* direct_type_ptr, bool* out_is_finalizable);
 
   // Get the DexCache for the
   mirror::DexCache* GetDexCache(const DexCompilationUnit* mUnit)
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index e6d983f..62817e7 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -587,7 +587,7 @@
 
   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
-    Object* ref = obj->GetFieldObject<Object, kVerifyNone, false>(offset);
+    Object* ref = obj->GetFieldObject<Object, kVerifyNone>(offset);
     // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
     // image.
     copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 1efdd38..b0aa63b 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -409,7 +409,7 @@
       uint32_t method_idx = instruction.VRegB_35c();
       uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
       uint32_t args[5];
-      instruction.GetArgs(args);
+      instruction.GetVarArgs(args);
       if (!BuildInvoke(instruction, dex_offset, method_idx, number_of_vreg_arguments, false, args, -1)) {
         return false;
       }
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index ff316e5..8b85d71 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -132,6 +132,12 @@
     }
   }
 
+  // Make all registers available for the return value.
+  for (size_t i = 0, e = GetNumberOfRegisters(); i < e; ++i) {
+    blocked_registers_[i] = false;
+  }
+  SetupBlockedRegisters(blocked_registers_);
+
   Location result_location = locations->Out();
   if (result_location.IsUnallocated()) {
     switch (result_location.GetPolicy()) {
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index ce1c4de..1b050cf 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -19,7 +19,7 @@
 
 #include "assembler.h"
 
-#include "gtest/gtest.h"
+#include "common_runtime_test.h"  // For ScratchFile
 
 #include <cstdio>
 #include <cstdlib>
@@ -30,6 +30,10 @@
 
 namespace art {
 
+// Use a glocal static variable to keep the same name for all test data. Else we'll just spam the
+// temp directory.
+static std::string tmpnam_;
+
 template<typename Ass, typename Reg, typename Imm>
 class AssemblerTest : public testing::Test {
  public:
@@ -203,6 +207,10 @@
   void SetUp() OVERRIDE {
     assembler_.reset(new Ass());
 
+    // Fake a runtime test for ScratchFile
+    std::string android_data;
+    CommonRuntimeTest::SetEnvironmentVariables(android_data);
+
     SetUpHelpers();
   }
 
@@ -667,7 +675,8 @@
   // Use a consistent tmpnam, so store it.
   std::string GetTmpnam() {
     if (tmpnam_.length() == 0) {
-      tmpnam_ = std::string(tmpnam(nullptr));
+      ScratchFile tmp;
+      tmpnam_ = tmp.GetFilename() + "asm";
     }
     return tmpnam_;
   }
@@ -677,7 +686,6 @@
   std::string resolved_assembler_cmd_;
   std::string resolved_objdump_cmd_;
   std::string resolved_disassemble_cmd_;
-  std::string tmpnam_;
 
   static constexpr size_t OBJDUMP_SECTION_LINE_MIN_TOKENS = 6;
 };
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 85a2c9e..7b66613 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1435,4 +1435,118 @@
 UNIMPLEMENTED art_quick_shr_long
 UNIMPLEMENTED art_quick_ushr_long
 UNIMPLEMENTED art_quick_indexof
-UNIMPLEMENTED art_quick_string_compareto
+
+   /*
+     * String's compareTo.
+     *
+     * TODO: Not very optimized.
+     *
+     * On entry:
+     *    x0:   this object pointer
+     *    x1:   comp object pointer
+     *
+     */
+    .extern __memcmp16
+ENTRY art_quick_string_compareto
+    mov    x2, x0         // x0 is return, use x2 for first input.
+    sub    x0, x2, x1     // Same string object?
+    cbnz   x0,1f
+    ret
+1:                        // Different string objects.
+
+    ldr    w6, [x2, #STRING_OFFSET_OFFSET]
+    ldr    w5, [x1, #STRING_OFFSET_OFFSET]
+    ldr    w4, [x2, #STRING_COUNT_OFFSET]
+    ldr    w3, [x1, #STRING_COUNT_OFFSET]
+    ldr    w2, [x2, #STRING_VALUE_OFFSET]
+    ldr    w1, [x1, #STRING_VALUE_OFFSET]
+
+    /*
+     * Now:           CharArray*    Offset   Count
+     *    first arg      x2          w6        w4
+     *   second arg      x1          w5        w3
+     */
+
+    // x0 := str1.length(w4) - str2.length(w3). ldr zero-extended w3/w4 into x3/x4.
+    subs x0, x4, x3
+    // Min(count1, count2) into w3.
+    csel x3, x3, x4, ge
+
+    // Build pointer into string data.
+
+    // Add offset in array (substr etc.) (sign extend and << 1).
+    add x2, x2, w6, sxtw #1
+    add x1, x1, w5, sxtw #1
+
+    // Add offset in CharArray to array.
+    add x2, x2, #STRING_DATA_OFFSET
+    add x1, x1, #STRING_DATA_OFFSET
+
+    // Check for long string, do memcmp16 for them.
+    cmp w3, #28  // Constant from arm32.
+    bgt .Ldo_memcmp16
+
+    /*
+     * Now:
+     *   x2: *first string data
+     *   x1: *second string data
+     *   w3: iteration count
+     *   x0: return value if comparison equal
+     *   x4, x5, x6, x7: free
+     */
+
+    // Do a simple unrolled loop.
+.Lloop:
+    // At least two more elements?
+    subs w3, w3, #2
+    b.lt .Lremainder_or_done
+
+    ldrh w4, [x2], #2
+    ldrh w5, [x1], #2
+
+    ldrh w6, [x2], #2
+    ldrh w7, [x1], #2
+
+    subs w4, w4, w5
+    b.ne .Lw4_result
+
+    subs w6, w6, w7
+    b.ne .Lw6_result
+
+    b .Lloop
+
+.Lremainder_or_done:
+    adds w3, w3, #1
+    b.eq .Lremainder
+    ret
+
+.Lremainder:
+    ldrh w4, [x2], #2
+    ldrh w5, [x1], #2
+    subs w4, w4, w5
+    b.ne .Lw4_result
+    ret
+
+// Result is in w4
+.Lw4_result:
+    sxtw x0, w4
+    ret
+
+// Result is in w6
+.Lw6_result:
+    sxtw x0, w6
+    ret
+
+.Ldo_memcmp16:
+    str x0, [sp,#-16]!           // Save x0
+
+    mov x0, x2
+    uxtw x2, w3
+    bl __memcmp16
+
+    ldr x1, [sp], #16            // Restore old x0 = length diff
+
+    cmp x0, #0                   // Check the memcmp difference
+    csel x0, x0, x1, ne          // x0 := x0 != 0 ? x0 : x1
+    ret
+END art_quick_string_compareto
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 8fbca94..94a7598 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -15,6 +15,7 @@
  */
 
 #include "common_runtime_test.h"
+#include "mirror/string-inl.h"
 
 #include <cstdio>
 
@@ -182,13 +183,14 @@
 #endif
 }
 
-
 #if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
 extern "C" void art_quick_lock_object(void);
 #endif
 
 TEST_F(StubTest, LockObject) {
 #if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+  static constexpr size_t kThinLockLoops = 100;
+
   Thread* self = Thread::Current();
   // Create an object
   ScopedObjectAccess soa(self);
@@ -206,6 +208,72 @@
   LockWord lock_after = obj->GetLockWord(false);
   LockWord::LockState new_state = lock_after.GetState();
   EXPECT_EQ(LockWord::LockState::kThinLocked, new_state);
+  EXPECT_EQ(lock_after.ThinLockCount(), 0U);  // Thin lock starts count at zero
+
+  for (size_t i = 1; i < kThinLockLoops; ++i) {
+    Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+              reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+
+    // Check we're at lock count i
+
+    LockWord l_inc = obj->GetLockWord(false);
+    LockWord::LockState l_inc_state = l_inc.GetState();
+    EXPECT_EQ(LockWord::LockState::kThinLocked, l_inc_state);
+    EXPECT_EQ(l_inc.ThinLockCount(), i);
+  }
+
+  // TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
+
+#else
+  LOG(INFO) << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA;
+  // Force-print to std::cout so it's also outside the logcat.
+  std::cout << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
+#endif
+}
+
+class RandGen {
+ public:
+  explicit RandGen(uint32_t seed) : val_(seed) {}
+
+  uint32_t next() {
+    val_ = val_ * 48271 % 2147483647 + 13;
+    return val_;
+  }
+
+  uint32_t val_;
+};
+
+
+#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+extern "C" void art_quick_lock_object(void);
+extern "C" void art_quick_unlock_object(void);
+#endif
+
+TEST_F(StubTest, UnlockObject) {
+#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+  static constexpr size_t kThinLockLoops = 100;
+
+  Thread* self = Thread::Current();
+  // Create an object
+  ScopedObjectAccess soa(self);
+  // garbage is created during ClassLinker::Init
+
+  SirtRef<mirror::String> obj(soa.Self(),
+                              mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
+  LockWord lock = obj->GetLockWord(false);
+  LockWord::LockState old_state = lock.GetState();
+  EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
+
+  Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+          reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+
+  // This should be an illegal monitor state.
+  EXPECT_TRUE(self->IsExceptionPending());
+  self->ClearException();
+
+  LockWord lock_after = obj->GetLockWord(false);
+  LockWord::LockState new_state = lock_after.GetState();
+  EXPECT_EQ(LockWord::LockState::kUnlocked, new_state);
 
   Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
           reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
@@ -214,12 +282,94 @@
   LockWord::LockState new_state2 = lock_after2.GetState();
   EXPECT_EQ(LockWord::LockState::kThinLocked, new_state2);
 
+  Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+          reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+
+  LockWord lock_after3 = obj->GetLockWord(false);
+  LockWord::LockState new_state3 = lock_after3.GetState();
+  EXPECT_EQ(LockWord::LockState::kUnlocked, new_state3);
+
+  // Stress test:
+  // Keep a number of objects and their locks in flight. Randomly lock or unlock one of them in
+  // each step.
+
+  RandGen r(0x1234);
+
+  constexpr size_t kNumberOfLocks = 10;  // Number of objects = lock
+  constexpr size_t kIterations = 10000;  // Number of iterations
+
+  size_t counts[kNumberOfLocks];
+  SirtRef<mirror::String>* objects[kNumberOfLocks];
+
+  // Initialize = allocate.
+  for (size_t i = 0; i < kNumberOfLocks; ++i) {
+    counts[i] = 0;
+    objects[i] = new SirtRef<mirror::String>(soa.Self(),
+                                             mirror::String::AllocFromModifiedUtf8(soa.Self(), ""));
+  }
+
+  for (size_t i = 0; i < kIterations; ++i) {
+    // Select which lock to update.
+    size_t index = r.next() % kNumberOfLocks;
+
+    bool lock;  // Whether to lock or unlock in this step.
+    if (counts[index] == 0) {
+      lock = true;
+    } else if (counts[index] == kThinLockLoops) {
+      lock = false;
+    } else {
+      // Randomly.
+      lock = r.next() % 2 == 0;
+    }
+
+    if (lock) {
+      Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
+              reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+      counts[index]++;
+    } else {
+      Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
+              reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+      counts[index]--;
+    }
+
+    EXPECT_FALSE(self->IsExceptionPending());
+
+    // Check the new state.
+    LockWord lock_iter = objects[index]->get()->GetLockWord(false);
+    LockWord::LockState iter_state = lock_iter.GetState();
+    if (counts[index] > 0) {
+      EXPECT_EQ(LockWord::LockState::kThinLocked, iter_state);
+      EXPECT_EQ(counts[index] - 1, lock_iter.ThinLockCount());
+    } else {
+      EXPECT_EQ(LockWord::LockState::kUnlocked, iter_state);
+    }
+  }
+
+  // Unlock the remaining count times and then check it's unlocked. Then deallocate.
+  // Go reverse order to correctly handle SirtRefs.
+  for (size_t i = 0; i < kNumberOfLocks; ++i) {
+    size_t index = kNumberOfLocks - 1 - i;
+    size_t count = counts[index];
+    while (count > 0) {
+      Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
+              reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
+
+      count--;
+    }
+
+    LockWord lock_after4 = objects[index]->get()->GetLockWord(false);
+    LockWord::LockState new_state4 = lock_after4.GetState();
+    EXPECT_EQ(LockWord::LockState::kUnlocked, new_state4);
+
+    delete objects[index];
+  }
+
   // TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
 
 #else
-  LOG(INFO) << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA;
+  LOG(INFO) << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA;
   // Force-print to std::cout so it's also outside the logcat.
-  std::cout << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
+  std::cout << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
 #endif
 }
 
@@ -634,14 +784,14 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
 extern "C" void art_quick_string_compareto(void);
 #endif
 
 TEST_F(StubTest, StringCompareTo) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
-#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
   // TODO: Check the "Unresolved" allocation stubs
 
   Thread* self = Thread::Current();
@@ -650,30 +800,48 @@
 
   // Create some strings
   // Use array so we can index into it and use a matrix for expected results
-  constexpr size_t string_count = 7;
-  const char* c[string_count] = { "", "", "a", "aa", "ab", "aac", "aac" };
+  // Setup: The first half is standard. The second half uses a non-zero offset.
+  // TODO: Shared backing arrays.
+  constexpr size_t base_string_count = 7;
+  const char* c[base_string_count] = { "", "", "a", "aa", "ab", "aac", "aac" , };
+
+  constexpr size_t string_count = 2 * base_string_count;
 
   SirtRef<mirror::String>* s[string_count];
 
-  for (size_t i = 0; i < string_count; ++i) {
+  for (size_t i = 0; i < base_string_count; ++i) {
     s[i] = new SirtRef<mirror::String>(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(),
                                                                                          c[i]));
   }
 
+  RandGen r(0x1234);
+
+  for (size_t i = base_string_count; i < string_count; ++i) {
+    s[i] = new SirtRef<mirror::String>(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(),
+                                                                         c[i - base_string_count]));
+    int32_t length = s[i]->get()->GetLength();
+    if (length > 1) {
+      // Set a random offset and length.
+      int32_t new_offset = 1 + (r.next() % (length - 1));
+      int32_t rest = length - new_offset - 1;
+      int32_t new_length = 1 + (rest > 0 ? r.next() % rest : 0);
+
+      s[i]->get()->SetField32<false>(mirror::String::CountOffset(), new_length);
+      s[i]->get()->SetField32<false>(mirror::String::OffsetOffset(), new_offset);
+    }
+  }
+
   // TODO: wide characters
 
   // Matrix of expectations. First component is first parameter. Note we only check against the
-  // sign, not the value.
-  int32_t expected[string_count][string_count] = {
-      {  0,  0, -1, -1, -1, -1, -1 },  // ""
-      {  0,  0, -1, -1, -1, -1, -1 },  // ""
-      {  1,  1,  0, -1, -1, -1, -1 },  // "a"
-      {  1,  1,  1,  0, -1, -1, -1 },  // "aa"
-      {  1,  1,  1,  1,  0,  1,  1 },  // "ab"
-      {  1,  1,  1,  1, -1,  0,  0 },  // "aac"
-      {  1,  1,  1,  1, -1,  0,  0 }   // "aac"
-  //    ""  ""   a  aa  ab  aac aac
-  };
+  // sign, not the value. As we are testing random offsets, we need to compute this and need to
+  // rely on String::CompareTo being correct.
+  int32_t expected[string_count][string_count];
+  for (size_t x = 0; x < string_count; ++x) {
+    for (size_t y = 0; y < string_count; ++y) {
+      expected[x][y] = s[x]->get()->CompareTo(s[y]->get());
+    }
+  }
 
   // Play with it...
 
@@ -693,12 +861,17 @@
       } conv;
       conv.r = result;
       int32_t e = expected[x][y];
-      EXPECT_TRUE(e == 0 ? conv.i == 0 : true) << "x=" << c[x] << " y=" << c[y];
-      EXPECT_TRUE(e < 0 ? conv.i < 0 : true)   << "x=" << c[x] << " y="  << c[y];
-      EXPECT_TRUE(e > 0 ? conv.i > 0 : true)   << "x=" << c[x] << " y=" << c[y];
+      EXPECT_TRUE(e == 0 ? conv.i == 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" <<
+          conv.r;
+      EXPECT_TRUE(e < 0 ? conv.i < 0 : true)   << "x=" << c[x] << " y="  << c[y] << " res=" <<
+          conv.r;
+      EXPECT_TRUE(e > 0 ? conv.i > 0 : true)   << "x=" << c[x] << " y=" << c[y] << " res=" <<
+          conv.r;
     }
   }
 
+  // TODO: Deallocate things.
+
   // Tests done.
 #else
   LOG(INFO) << "Skipping string_compareto as I don't know how to do that on " << kRuntimeISA;
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 9ccf6c9..7b56718 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -870,18 +870,138 @@
 UNIMPLEMENTED art_quick_lshl
 UNIMPLEMENTED art_quick_lshr
 UNIMPLEMENTED art_quick_lushr
-UNIMPLEMENTED art_quick_set32_instance
-UNIMPLEMENTED art_quick_set64_instance
-UNIMPLEMENTED art_quick_set_obj_instance
-UNIMPLEMENTED art_quick_get32_instance
-UNIMPLEMENTED art_quick_get64_instance
-UNIMPLEMENTED art_quick_get_obj_instance
-UNIMPLEMENTED art_quick_set32_static
-UNIMPLEMENTED art_quick_set64_static
-UNIMPLEMENTED art_quick_set_obj_static
-UNIMPLEMENTED art_quick_get32_static
-UNIMPLEMENTED art_quick_get64_static
-UNIMPLEMENTED art_quick_get_obj_static
+
+DEFINE_FUNCTION art_quick_set32_instance
+    movq 8(%rsp), %rcx                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx, Object* and new_val are in rdi/rsi/rdx
+    movq %gs:THREAD_SELF_OFFSET, %r8   // pass Thread::Current()
+    movq %rsp, %r9                     // pass SP
+    call PLT_SYMBOL(artSet32InstanceFromCode)  // (field_idx, Object*, new_val, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_IF_EAX_ZERO                 // return or deliver exception
+END_FUNCTION art_quick_set32_instance
+
+DEFINE_FUNCTION art_quick_set64_instance
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx, Object* and new_val are in rdi/rsi/rdx
+    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
+    movq %rsp, %r8                     // pass SP
+    call PLT_SYMBOL(artSet64InstanceFromCode)  // (field_idx, Object*, new_val, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_IF_EAX_ZERO                 // return or deliver exception
+END_FUNCTION art_quick_set64_instance
+
+DEFINE_FUNCTION art_quick_set_obj_instance
+    movq 8(%rsp), %rcx                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx, Object* and new_val are in rdi/rsi/rdx
+    movq %gs:THREAD_SELF_OFFSET, %r8   // pass Thread::Current()
+    movq %rsp, %r9                     // pass SP
+    call PLT_SYMBOL(artSetObjInstanceFromCode)  // (field_idx, Object*, new_val, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_IF_EAX_ZERO                 // return or deliver exception
+END_FUNCTION art_quick_set_obj_instance
+
+DEFINE_FUNCTION art_quick_get32_instance
+    movq 8(%rsp), %rdx                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx and Object* are in rdi/rsi
+    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
+    movq %rsp, %r8                     // pass SP
+    call PLT_SYMBOL(artGet32InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_OR_DELIVER_PENDING_EXCEPTION  // return or deliver exception
+END_FUNCTION art_quick_get32_instance
+
+DEFINE_FUNCTION art_quick_get64_instance
+    movq 8(%rsp), %rdx                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx and Object* are in rdi/rsi
+    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
+    movq %rsp, %r8                     // pass SP
+    call PLT_SYMBOL(artGet64InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_OR_DELIVER_PENDING_EXCEPTION  // return or deliver exception
+END_FUNCTION art_quick_get64_instance
+
+DEFINE_FUNCTION art_quick_get_obj_instance
+    movq 8(%rsp), %rdx                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx and Object* are in rdi/rsi
+    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
+    movq %rsp, %r8                     // pass SP
+    call PLT_SYMBOL(artGetObjInstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_OR_DELIVER_PENDING_EXCEPTION  // return or deliver exception
+END_FUNCTION art_quick_get_obj_instance
+
+DEFINE_FUNCTION art_quick_set32_static
+    movq 8(%rsp), %rdx                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx and new_val are in rdi/rsi
+    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
+    movq %rsp, %r8                     // pass SP
+    call PLT_SYMBOL(artSet32StaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_IF_EAX_ZERO                 // return or deliver exception
+END_FUNCTION art_quick_set32_static
+
+DEFINE_FUNCTION art_quick_set64_static
+    movq %rsi, %rdx                    // pass new_val
+    movq 8(%rsp), %rsi                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx is in rdi
+    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
+    movq %rsp, %r8                     // pass SP
+    call PLT_SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_IF_EAX_ZERO                 // return or deliver exception
+END_FUNCTION art_quick_set64_static
+
+DEFINE_FUNCTION art_quick_set_obj_static
+    movq 8(%rsp), %rdx                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx and new_val are in rdi/rsi
+    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
+    movq %rsp, %r8                     // pass SP
+    call PLT_SYMBOL(artSetObjStaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_OR_DELIVER_PENDING_EXCEPTION
+END_FUNCTION art_quick_set_obj_static
+
+DEFINE_FUNCTION art_quick_get32_static
+    movq 8(%rsp), %rsi                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx is in rdi
+    movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
+    movq %rsp, %rcx                    // pass SP
+    call PLT_SYMBOL(artGet32StaticFromCode)  // (field_idx, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_OR_DELIVER_PENDING_EXCEPTION
+END_FUNCTION art_quick_get32_static
+
+DEFINE_FUNCTION art_quick_get64_static
+    movq 8(%rsp), %rsi                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx is in rdi
+    movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
+    movq %rsp, %rcx                    // pass SP
+    call PLT_SYMBOL(artGet64StaticFromCode)  // (field_idx, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_OR_DELIVER_PENDING_EXCEPTION
+END_FUNCTION art_quick_get64_static
+
+DEFINE_FUNCTION art_quick_get_obj_static
+    movq 8(%rsp), %rsi                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // field_idx is in rdi
+    movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
+    movq %rsp, %rcx                    // pass SP
+    call PLT_SYMBOL(artGetObjStaticFromCode)  // (field_idx, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    RETURN_OR_DELIVER_PENDING_EXCEPTION
+END_FUNCTION art_quick_get_obj_static
 
 DEFINE_FUNCTION art_quick_proxy_invoke_handler
     // Save callee and GPR args, mixed together to agree with core spills bitmap of ref. and args
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 6c53563..df88794 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -66,6 +66,9 @@
     SirtRef<mirror::DexCache> dex_cache(Thread::Current(), declaring_class->GetDexCache());
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_string = ResolveString(dex_file, string_idx, dex_cache);
+    if (resolved_string != nullptr) {
+      DCHECK_EQ(dex_cache->GetResolvedString(string_idx), resolved_string);
+    }
   }
   return resolved_string;
 }
@@ -80,6 +83,9 @@
     SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
+    if (resolved_type != nullptr) {
+      DCHECK_EQ(dex_cache->GetResolvedType(type_idx), resolved_type);
+    }
   }
   return resolved_type;
 }
@@ -94,6 +100,9 @@
     SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
+    if (resolved_type != nullptr) {
+      DCHECK_EQ(dex_cache->GetResolvedType(type_idx), resolved_type);
+    }
   }
   return resolved_type;
 }
@@ -110,6 +119,9 @@
     SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_method = ResolveMethod(dex_file, method_idx, dex_cache, class_loader, referrer, type);
+    if (resolved_method != nullptr) {
+      DCHECK_EQ(dex_cache->GetResolvedMethod(method_idx), resolved_method);
+    }
   }
   return resolved_method;
 }
@@ -126,6 +138,9 @@
     SirtRef<mirror::ClassLoader> class_loader(self, declaring_class->GetClassLoader());
     const DexFile& dex_file = *dex_cache->GetDexFile();
     resolved_field = ResolveField(dex_file, field_idx, dex_cache, class_loader, is_static);
+    if (resolved_field != nullptr) {
+      DCHECK_EQ(dex_cache->GetResolvedField(field_idx), resolved_field);
+    }
   }
   return resolved_field;
 }
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 703229c..dbea0d8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -803,13 +803,29 @@
 bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file,
                                          const char* dex_location,
                                          uint32_t dex_location_checksum,
+                                         const InstructionSet instruction_set,
                                          std::string* error_msg) {
   Runtime* runtime = Runtime::Current();
-  const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
-  uint32_t image_oat_checksum = image_header.GetOatChecksum();
-  uintptr_t image_oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
-  bool image_check = ((oat_file->GetOatHeader().GetImageFileLocationOatChecksum() == image_oat_checksum)
-                      && (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin() == image_oat_data_begin));
+  const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+
+  // If the requested instruction set is the same as the current runtime,
+  // we can use the checksums directly. If it isn't, we'll have to read the
+  // image header from the image for the right instruction set.
+  uint32_t image_oat_checksum = 0;
+  uintptr_t image_oat_data_begin = 0;
+  if (instruction_set == kRuntimeISA) {
+    const ImageHeader& image_header = image_space->GetImageHeader();
+    image_oat_checksum = image_header.GetOatChecksum();
+    image_oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
+  } else {
+    UniquePtr<ImageHeader> image_header(gc::space::ImageSpace::ReadImageHeaderOrDie(
+        image_space->GetImageLocation().c_str(), instruction_set));
+    image_oat_checksum = image_header->GetOatChecksum();
+    image_oat_data_begin = reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin());
+  }
+  const OatHeader& oat_header = oat_file->GetOatHeader();
+  bool image_check = ((oat_header.GetImageFileLocationOatChecksum() == image_oat_checksum)
+                      && (oat_header.GetImageFileLocationOatDataBegin() == image_oat_data_begin));
 
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, &dex_location_checksum);
   if (oat_dex_file == NULL) {
@@ -873,7 +889,7 @@
     dex_file = oat_dex_file->OpenDexFile(error_msg);
   } else {
     bool verified = VerifyOatFileChecksums(oat_file.get(), dex_location, dex_location_checksum,
-                                           error_msg);
+                                           kRuntimeISA, error_msg);
     if (!verified) {
       return nullptr;
     }
@@ -3215,12 +3231,8 @@
   mirror::ArtMethod* clinit = klass->FindClassInitializer();
   if (clinit != NULL) {
     CHECK(can_init_statics);
-    if (LIKELY(Runtime::Current()->IsStarted())) {
-      JValue result;
-      clinit->Invoke(self, NULL, 0, &result, "V");
-    } else {
-      art::interpreter::EnterInterpreterFromInvoke(self, clinit, NULL, NULL, NULL);
-    }
+    JValue result;
+    clinit->Invoke(self, NULL, 0, &result, "V");
   }
 
   uint64_t t1 = NanoTime();
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index a23add0..2c6873e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -288,6 +288,7 @@
   static bool VerifyOatFileChecksums(const OatFile* oat_file,
                                      const char* dex_location,
                                      uint32_t dex_location_checksum,
+                                     const InstructionSet instruction_set,
                                      std::string* error_msg);
 
   // TODO: replace this with multiple methods that allocate the correct managed type.
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 723e32c..79d3690 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -57,6 +57,9 @@
 class ScratchFile {
  public:
   ScratchFile() {
+    // ANDROID_DATA needs to be set
+    CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
+        "Are you subclassing RuntimeTest?";
     filename_ = getenv("ANDROID_DATA");
     filename_ += "/TmpFile-XXXXXX";
     int fd = mkstemp(&filename_[0]);
diff --git a/runtime/dex_instruction-inl.h b/runtime/dex_instruction-inl.h
index 207b0b6..ad9491f 100644
--- a/runtime/dex_instruction-inl.h
+++ b/runtime/dex_instruction-inl.h
@@ -24,6 +24,68 @@
 //------------------------------------------------------------------------------
 // VRegA
 //------------------------------------------------------------------------------
+inline bool Instruction::HasVRegA() const {
+  switch (FormatOf(Opcode())) {
+    case k10t: return true;
+    case k10x: return true;
+    case k11n: return true;
+    case k11x: return true;
+    case k12x: return true;
+    case k20t: return true;
+    case k21c: return true;
+    case k21h: return true;
+    case k21s: return true;
+    case k21t: return true;
+    case k22b: return true;
+    case k22c: return true;
+    case k22s: return true;
+    case k22t: return true;
+    case k22x: return true;
+    case k23x: return true;
+    case k30t: return true;
+    case k31c: return true;
+    case k31i: return true;
+    case k31t: return true;
+    case k32x: return true;
+    case k35c: return true;
+    case k3rc: return true;
+    case k51l: return true;
+    default: return false;
+  }
+}
+
+inline int32_t Instruction::VRegA() const {
+  switch (FormatOf(Opcode())) {
+    case k10t: return VRegA_10t();
+    case k10x: return VRegA_10x();
+    case k11n: return VRegA_11n();
+    case k11x: return VRegA_11x();
+    case k12x: return VRegA_12x();
+    case k20t: return VRegA_20t();
+    case k21c: return VRegA_21c();
+    case k21h: return VRegA_21h();
+    case k21s: return VRegA_21s();
+    case k21t: return VRegA_21t();
+    case k22b: return VRegA_22b();
+    case k22c: return VRegA_22c();
+    case k22s: return VRegA_22s();
+    case k22t: return VRegA_22t();
+    case k22x: return VRegA_22x();
+    case k23x: return VRegA_23x();
+    case k30t: return VRegA_30t();
+    case k31c: return VRegA_31c();
+    case k31i: return VRegA_31i();
+    case k31t: return VRegA_31t();
+    case k32x: return VRegA_32x();
+    case k35c: return VRegA_35c();
+    case k3rc: return VRegA_3rc();
+    case k51l: return VRegA_51l();
+    default:
+      LOG(FATAL) << "Tried to access vA of instruction " << Name() << " which has no A operand.";
+      exit(EXIT_FAILURE);
+  }
+}
+
 inline int8_t Instruction::VRegA_10t(uint16_t inst_data) const {
   DCHECK_EQ(FormatOf(Opcode()), k10t);
   return static_cast<int8_t>(InstAA(inst_data));
@@ -147,6 +209,66 @@
 //------------------------------------------------------------------------------
 // VRegB
 //------------------------------------------------------------------------------
+inline bool Instruction::HasVRegB() const {
+  switch (FormatOf(Opcode())) {
+    case k11n: return true;
+    case k12x: return true;
+    case k21c: return true;
+    case k21h: return true;
+    case k21s: return true;
+    case k21t: return true;
+    case k22b: return true;
+    case k22c: return true;
+    case k22s: return true;
+    case k22t: return true;
+    case k22x: return true;
+    case k23x: return true;
+    case k31c: return true;
+    case k31i: return true;
+    case k31t: return true;
+    case k32x: return true;
+    case k35c: return true;
+    case k3rc: return true;
+    case k51l: return true;
+    default: return false;
+  }
+}
+
+inline bool Instruction::HasWideVRegB() const {
+  return FormatOf(Opcode()) == k51l;
+}
+
+inline int32_t Instruction::VRegB() const {
+  switch (FormatOf(Opcode())) {
+    case k11n: return VRegB_11n();
+    case k12x: return VRegB_12x();
+    case k21c: return VRegB_21c();
+    case k21h: return VRegB_21h();
+    case k21s: return VRegB_21s();
+    case k21t: return VRegB_21t();
+    case k22b: return VRegB_22b();
+    case k22c: return VRegB_22c();
+    case k22s: return VRegB_22s();
+    case k22t: return VRegB_22t();
+    case k22x: return VRegB_22x();
+    case k23x: return VRegB_23x();
+    case k31c: return VRegB_31c();
+    case k31i: return VRegB_31i();
+    case k31t: return VRegB_31t();
+    case k32x: return VRegB_32x();
+    case k35c: return VRegB_35c();
+    case k3rc: return VRegB_3rc();
+    case k51l: return VRegB_51l();
+    default:
+      LOG(FATAL) << "Tried to access vB of instruction " << Name() << " which has no B operand.";
+      exit(EXIT_FAILURE);
+  }
+}
+
+inline uint64_t Instruction::WideVRegB() const {
+  return VRegB_51l();
+}
+
 inline int4_t Instruction::VRegB_11n(uint16_t inst_data) const {
   DCHECK_EQ(FormatOf(Opcode()), k11n);
   return static_cast<int4_t>((InstB(inst_data) << 28) >> 28);
@@ -246,6 +368,34 @@
 //------------------------------------------------------------------------------
 // VRegC
 //------------------------------------------------------------------------------
+inline bool Instruction::HasVRegC() const {
+  switch (FormatOf(Opcode())) {
+    case k22b: return true;
+    case k22c: return true;
+    case k22s: return true;
+    case k22t: return true;
+    case k23x: return true;
+    case k35c: return true;
+    case k3rc: return true;
+    default: return false;
+  }
+}
+
+inline int32_t Instruction::VRegC() const {
+  switch (FormatOf(Opcode())) {
+    case k22b: return VRegC_22b();
+    case k22c: return VRegC_22c();
+    case k22s: return VRegC_22s();
+    case k22t: return VRegC_22t();
+    case k23x: return VRegC_23x();
+    case k35c: return VRegC_35c();
+    case k3rc: return VRegC_3rc();
+    default:
+      LOG(FATAL) << "Tried to access vC of instruction " << Name() << " which has no C operand.";
+      exit(EXIT_FAILURE);
+  }
+}
+
 inline int8_t Instruction::VRegC_22b() const {
   DCHECK_EQ(FormatOf(Opcode()), k22b);
   return static_cast<int8_t>(Fetch16(1) >> 8);
@@ -281,7 +431,11 @@
   return Fetch16(2);
 }
 
-inline void Instruction::GetArgs(uint32_t arg[5], uint16_t inst_data) const {
+inline bool Instruction::HasVarArgs() const {
+  return FormatOf(Opcode()) == k35c;
+}
+
+inline void Instruction::GetVarArgs(uint32_t arg[5], uint16_t inst_data) const {
   DCHECK_EQ(FormatOf(Opcode()), k35c);
 
   /*
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index 7546245..0494f22 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -70,121 +70,6 @@
 #undef INSTRUCTION_SIZE
 };
 
-/*
- * Handy macros for helping decode instructions.
- */
-#define FETCH(_offset)      (insns[(_offset)])
-#define FETCH_uint32(_offset)   (fetch_uint32_impl((_offset), insns))
-#define INST_A(_insn)       (((uint16_t)(_insn) >> 8) & 0x0f)
-#define INST_B(_insn)       ((uint16_t)(_insn) >> 12)
-#define INST_AA(_insn)      ((_insn) >> 8)
-
-/* Helper for FETCH_uint32, above. */
-static inline uint32_t fetch_uint32_impl(uint32_t offset, const uint16_t* insns) {
-  return insns[offset] | ((uint32_t) insns[offset+1] << 16);
-}
-
-
-bool Instruction::HasVRegC() const {
-  switch (FormatOf(Opcode())) {
-    case k23x: return true;
-    case k35c: return true;
-    case k3rc: return true;
-    default: return false;
-  }
-}
-
-bool Instruction::HasVRegB() const {
-  switch (FormatOf(Opcode())) {
-    case k12x: return true;
-    case k22b: return true;
-    case k22c: return true;
-    case k22s: return true;
-    case k22t: return true;
-    case k22x: return true;
-    case k23x: return true;
-    case k32x: return true;
-    default: return false;
-  }
-}
-
-bool Instruction::HasVRegA() const {
-  switch (FormatOf(Opcode())) {
-    case k11n: return true;
-    case k11x: return true;
-    case k12x: return true;
-    case k21c: return true;
-    case k21h: return true;
-    case k21s: return true;
-    case k21t: return true;
-    case k22b: return true;
-    case k22c: return true;
-    case k22s: return true;
-    case k22t: return true;
-    case k22x: return true;
-    case k23x: return true;
-    case k31c: return true;
-    case k31i: return true;
-    case k31t: return true;
-    case k32x: return true;
-    case k51l: return true;
-    default: return false;
-  }
-}
-
-int32_t Instruction::VRegC() const {
-  switch (FormatOf(Opcode())) {
-    case k23x: return VRegC_23x();
-    case k35c: return VRegC_35c();
-    case k3rc: return VRegC_3rc();
-    default: LOG(FATAL) << "Tried to access vC of instruction " << Name() <<
-        " which has no C operand.";
-  }
-  return -1;
-}
-
-int32_t Instruction::VRegB() const {
-  switch (FormatOf(Opcode())) {
-    case k12x: return VRegB_12x();
-    case k22b: return VRegB_22b();
-    case k22c: return VRegB_22c();
-    case k22s: return VRegB_22s();
-    case k22t: return VRegB_22t();
-    case k22x: return VRegB_22x();
-    case k23x: return VRegB_23x();
-    case k32x: return VRegB_32x();
-    default: LOG(FATAL) << "Tried to access vB of instruction " << Name() <<
-        " which has no B operand.";
-  }
-  return -1;
-}
-
-int32_t Instruction::VRegA() const {
-  switch (FormatOf(Opcode())) {
-    case k11n: return VRegA_11n();
-    case k11x: return VRegA_11x();
-    case k12x: return VRegA_12x();
-    case k21c: return VRegA_21c();
-    case k21h: return VRegA_21h();
-    case k21s: return VRegA_21s();
-    case k21t: return VRegA_21t();
-    case k22b: return VRegA_22b();
-    case k22c: return VRegA_22c();
-    case k22s: return VRegA_22s();
-    case k22t: return VRegA_22t();
-    case k22x: return VRegA_22x();
-    case k23x: return VRegA_23x();
-    case k31c: return VRegA_31c();
-    case k31i: return VRegA_31i();
-    case k31t: return VRegA_31t();
-    case k32x: return VRegA_32x();
-    case k51l: return VRegA_51l();
-    default: LOG(FATAL) << "Tried to access vA of instruction " << Name() <<
-        " which has no A operand.";
-  }
-  return -1;
-}
-
 int32_t Instruction::GetTargetOffset() const {
   switch (FormatOf(Opcode())) {
     // Cases for conditional branches follow.
@@ -207,145 +92,6 @@
   return  FlagsOf(opcode) & Instruction::kContinue;
 }
 
-void Instruction::Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const {
-  const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
-  uint16_t insn = *insns;
-  Code opcode = static_cast<Code>(insn & 0xFF);
-
-  switch (FormatOf(opcode)) {
-    case k10x:       // op
-      /* nothing to do; copy the AA bits out for the verifier */
-      vA = INST_AA(insn);
-      break;
-    case k12x:       // op vA, vB
-      vA = INST_A(insn);
-      vB = INST_B(insn);
-      break;
-    case k11n:       // op vA, #+B
-      vA = INST_A(insn);
-      vB = (int32_t) (INST_B(insn) << 28) >> 28;  // sign extend 4-bit value
-      break;
-    case k11x:       // op vAA
-      vA = INST_AA(insn);
-      break;
-    case k10t:       // op +AA
-      vA = (int8_t) INST_AA(insn);              // sign-extend 8-bit value
-      break;
-    case k20t:       // op +AAAA
-      vA = (int16_t) FETCH(1);                   // sign-extend 16-bit value
-      break;
-    case k21c:       // op vAA, thing@BBBB
-    case k22x:       // op vAA, vBBBB
-      vA = INST_AA(insn);
-      vB = FETCH(1);
-      break;
-    case k21s:       // op vAA, #+BBBB
-    case k21t:       // op vAA, +BBBB
-      vA = INST_AA(insn);
-      vB = (int16_t) FETCH(1);                   // sign-extend 16-bit value
-      break;
-    case k21h:       // op vAA, #+BBBB0000[00000000]
-      vA = INST_AA(insn);
-      /*
-       * The value should be treated as right-zero-extended, but we don't
-       * actually do that here. Among other things, we don't know if it's
-       * the top bits of a 32- or 64-bit value.
-       */
-      vB = FETCH(1);
-      break;
-    case k23x:       // op vAA, vBB, vCC
-      vA = INST_AA(insn);
-      vB = FETCH(1) & 0xff;
-      vC = FETCH(1) >> 8;
-      break;
-    case k22b:       // op vAA, vBB, #+CC
-      vA = INST_AA(insn);
-      vB = FETCH(1) & 0xff;
-      vC = (int8_t) (FETCH(1) >> 8);            // sign-extend 8-bit value
-      break;
-    case k22s:       // op vA, vB, #+CCCC
-    case k22t:       // op vA, vB, +CCCC
-      vA = INST_A(insn);
-      vB = INST_B(insn);
-      vC = (int16_t) FETCH(1);                   // sign-extend 16-bit value
-      break;
-    case k22c:       // op vA, vB, thing@CCCC
-      vA = INST_A(insn);
-      vB = INST_B(insn);
-      vC = FETCH(1);
-      break;
-    case k30t:       // op +AAAAAAAA
-      vA = FETCH_uint32(1);                     // signed 32-bit value
-      break;
-    case k31t:       // op vAA, +BBBBBBBB
-    case k31c:       // op vAA, string@BBBBBBBB
-      vA = INST_AA(insn);
-      vB = FETCH_uint32(1);                     // 32-bit value
-      break;
-    case k32x:       // op vAAAA, vBBBB
-      vA = FETCH(1);
-      vB = FETCH(2);
-      break;
-    case k31i:       // op vAA, #+BBBBBBBB
-      vA = INST_AA(insn);
-      vB = FETCH_uint32(1);                     // signed 32-bit value
-      break;
-    case k35c:       // op {vC, vD, vE, vF, vG}, thing@BBBB
-      {
-        /*
-         * Note that the fields mentioned in the spec don't appear in
-         * their "usual" positions here compared to most formats. This
-         * was done so that the field names for the argument count and
-         * reference index match between this format and the corresponding
-         * range formats (3rc and friends).
-         *
-         * Bottom line: The argument count is always in vA, and the
-         * method constant (or equivalent) is always in vB.
-         */
-        uint16_t regList;
-        int count;
-
-        vA = INST_B(insn);  // This is labeled A in the spec.
-        vB = FETCH(1);
-        regList = FETCH(2);
-
-        count = vA;
-
-        /*
-         * Copy the argument registers into the arg[] array, and
-         * also copy the first argument (if any) into vC. (The
-         * DecodedInstruction structure doesn't have separate
-         * fields for {vD, vE, vF, vG}, so there's no need to make
-         * copies of those.) Note that cases 5..2 fall through.
-         */
-        switch (count) {
-        case 5: arg[4] = INST_A(insn);
-        case 4: arg[3] = (regList >> 12) & 0x0f;
-        case 3: arg[2] = (regList >> 8) & 0x0f;
-        case 2: arg[1] = (regList >> 4) & 0x0f;
-        case 1: vC = arg[0] = regList & 0x0f; break;
-        case 0: break;  // Valid, but no need to do anything.
-        default:
-          LOG(ERROR) << "Invalid arg count in 35c (" << count << ")";
-          return;
-        }
-      }
-      break;
-    case k3rc:       // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
-      vA = INST_AA(insn);
-      vB = FETCH(1);
-      vC = FETCH(2);
-        break;
-    case k51l:       // op vAA, #+BBBBBBBBBBBBBBBB
-      vA = INST_AA(insn);
-      vB_wide = FETCH_uint32(1) | ((uint64_t) FETCH_uint32(3) << 32);
-      break;
-    default:
-      LOG(ERROR) << "Can't decode unexpected format " << FormatOf(opcode) << " (op=" << opcode << ")";
-      return;
-  }
-}
-
 size_t Instruction::SizeInCodeUnitsComplexOpcode() const {
   const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
   // Handle special NOP encoded variable length sequences.
@@ -549,7 +295,7 @@
       break;
     case k35c: {
       uint32_t arg[5];
-      GetArgs(arg);
+      GetVarArgs(arg);
       switch (Opcode()) {
         case FILLED_NEW_ARRAY:
         {
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 4352c4a..560e5ff 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -151,8 +151,7 @@
     kVerifyError           = 0x80000,
   };
 
-  // Decodes this instruction, populating its arguments.
-  void Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const;
+  static constexpr uint32_t kMaxVarArgRegs = 5;
 
   // Returns the size (in 2 byte code units) of this instruction.
   size_t SizeInCodeUnits() const {
@@ -313,6 +312,9 @@
   bool HasVRegB() const;
   int32_t VRegB() const;
 
+  bool HasWideVRegB() const;
+  uint64_t WideVRegB() const;
+
   int4_t VRegB_11n() const {
     return VRegB_11n(Fetch16(0));
   }
@@ -365,9 +367,10 @@
   uint16_t VRegC_3rc() const;
 
   // Fills the given array with the 'arg' array of the instruction.
-  void GetArgs(uint32_t args[5], uint16_t inst_data) const;
-  void GetArgs(uint32_t args[5]) const {
-    return GetArgs(args, Fetch16(0));
+  bool HasVarArgs() const;
+  void GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const;
+  void GetVarArgs(uint32_t args[kMaxVarArgRegs]) const {
+    return GetVarArgs(args, Fetch16(0));
   }
 
   // Returns the opcode field of the instruction. The given "inst_data" parameter must be the first
@@ -549,23 +552,6 @@
 std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags);
 std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags);
 
-/*
- * Holds the contents of a decoded instruction.
- */
-struct DecodedInstruction {
-  uint32_t vA;
-  uint32_t vB;
-  uint64_t vB_wide;        /* for k51l */
-  uint32_t vC;
-  uint32_t arg[5];         /* vC/D/E/F/G in invoke or filled-new-array */
-  Instruction::Code opcode;
-
-  explicit DecodedInstruction(const Instruction* inst) {
-    inst->Decode(vA, vB, vB_wide, vC, arg);
-    opcode = inst->Opcode();
-  }
-};
-
 }  // namespace art
 
 #endif  // ART_RUNTIME_DEX_INSTRUCTION_H_
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 05912bf..e52a8fb 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -132,8 +132,7 @@
     if (klass == nullptr) {
       return nullptr;
     }
-    gc::Heap* heap = Runtime::Current()->GetHeap();
-    return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator());
+    return klass->Alloc<kInstrumented>(self, Runtime::Current()->GetHeap()->GetCurrentAllocator());
   }
   DCHECK(klass != nullptr);
   return klass->Alloc<kInstrumented>(self, allocator_type);
@@ -155,9 +154,11 @@
       return nullptr;
     }
     gc::Heap* heap = Runtime::Current()->GetHeap();
-    return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator());
+    // Pass in false since the object can not be finalizable.
+    return klass->Alloc<kInstrumented, false>(self, heap->GetCurrentAllocator());
   }
-  return klass->Alloc<kInstrumented>(self, allocator_type);
+  // Pass in false since the object can not be finalizable.
+  return klass->Alloc<kInstrumented, false>(self, allocator_type);
 }
 
 // Given the context of a calling Method and an initialized class, create an instance.
@@ -169,7 +170,8 @@
                                                                            gc::AllocatorType allocator_type)
     NO_THREAD_SAFETY_ANALYSIS {
   DCHECK(klass != nullptr);
-  return klass->Alloc<kInstrumented>(self, allocator_type);
+  // Pass in false since the object can not be finalizable.
+  return klass->Alloc<kInstrumented, false>(self, allocator_type);
 }
 
 
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 680ffbe..5d2603f 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -767,11 +767,18 @@
     if (virtual_or_interface) {
       // Refine called method based on receiver.
       CHECK(receiver != nullptr) << invoke_type;
+
+      mirror::ArtMethod* orig_called = called;
       if (invoke_type == kVirtual) {
         called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
       } else {
         called = receiver->GetClass()->FindVirtualMethodForInterface(called);
       }
+
+      CHECK(called != nullptr) << PrettyMethod(orig_called) << " "
+                               << PrettyTypeOf(receiver) << " "
+                               << invoke_type << " " << orig_called->GetVtableIndex();
+
       // We came here because of sharpening. Ensure the dex cache is up-to-date on the method index
       // of the sharpened method.
       if (called->GetDexCacheResolvedMethods() == caller->GetDexCacheResolvedMethods()) {
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index f113030..a693659 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -584,7 +584,7 @@
   return AllocRun(self, idx);
 }
 
-void* RosAlloc::AllocFromCurrentRunUnlocked(Thread* self, size_t idx) {
+inline void* RosAlloc::AllocFromCurrentRunUnlocked(Thread* self, size_t idx) {
   Run* current_run = current_runs_[idx];
   DCHECK(current_run != nullptr);
   void* slot_addr = current_run->AllocSlot();
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index f9a6abe..16add0b 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -128,6 +128,18 @@
   return (static_cast<uint64_t>(freed_bytes_) * 1000) / (NsToMs(GetDurationNs()) + 1);
 }
 
+void GarbageCollector::RecordFree(uint64_t freed_objects, int64_t freed_bytes) {
+  freed_objects_ += freed_objects;
+  freed_bytes_ += freed_bytes;
+  GetHeap()->RecordFree(freed_objects, freed_bytes);
+}
+
+void GarbageCollector::RecordFreeLargeObjects(uint64_t freed_objects, int64_t freed_bytes) {
+  freed_large_objects_ += freed_objects;
+  freed_large_object_bytes_ += freed_bytes;
+  GetHeap()->RecordFree(freed_objects, freed_bytes);
+}
+
 void GarbageCollector::ResetMeasurements() {
   cumulative_timings_.Reset();
   pause_histogram_.Reset();
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index ca4a1d5..d05f45b 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -88,19 +88,19 @@
   // this is the allocation space, for full GC then we swap the zygote bitmaps too.
   void SwapBitmaps() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  size_t GetFreedBytes() const {
+  int64_t GetFreedBytes() const {
     return freed_bytes_;
   }
 
-  size_t GetFreedLargeObjectBytes() const {
+  int64_t GetFreedLargeObjectBytes() const {
     return freed_large_object_bytes_;
   }
 
-  size_t GetFreedObjects() const {
+  uint64_t GetFreedObjects() const {
     return freed_objects_;
   }
 
-  size_t GetFreedLargeObjects() const {
+  uint64_t GetFreedLargeObjects() const {
     return freed_large_objects_;
   }
 
@@ -108,7 +108,7 @@
     return pause_histogram_.Sum();
   }
 
-  uint64_t GetTotalFreedBytes() const {
+  int64_t GetTotalFreedBytes() const {
     return total_freed_bytes_;
   }
 
@@ -141,6 +141,11 @@
   // Revoke all the thread-local buffers.
   virtual void RevokeAllThreadLocalBuffers() = 0;
 
+  // Record that you have freed some objects or large objects, calls Heap::RecordFree.
+  // TODO: These are not thread safe, add a lock if we get have parallel sweeping.
+  void RecordFree(uint64_t freed_objects, int64_t freed_bytes);
+  void RecordFreeLargeObjects(uint64_t freed_objects, int64_t freed_bytes);
+
   static constexpr size_t kPauseBucketSize = 500;
   static constexpr size_t kPauseBucketCount = 32;
 
@@ -158,13 +163,14 @@
   Histogram<uint64_t> pause_histogram_;
   uint64_t total_time_ns_;
   uint64_t total_freed_objects_;
-  uint64_t total_freed_bytes_;
+  int64_t total_freed_bytes_;
 
-  // Single GC statitstics.
-  AtomicInteger freed_bytes_;
-  AtomicInteger freed_large_object_bytes_;
-  AtomicInteger freed_objects_;
-  AtomicInteger freed_large_objects_;
+  // Single GC statitstics, freed bytes are signed since the GC can free negative bytes if it
+  // promotes objects to a space which has a larger allocation size.
+  int64_t freed_bytes_;
+  int64_t freed_large_object_bytes_;
+  uint64_t freed_objects_;
+  uint64_t freed_large_objects_;
 
   CumulativeLogger cumulative_timings_;
 
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index e225d5a..b8051c9 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -1116,13 +1116,10 @@
   timings_.EndSplit();
 
   timings_.StartSplit("RecordFree");
-  VLOG(heap) << "Freed " << freed_objects << "/" << count
-             << " objects with size " << PrettySize(freed_bytes);
-  heap_->RecordFree(freed_objects + freed_large_objects, freed_bytes + freed_large_object_bytes);
-  freed_objects_.FetchAndAdd(freed_objects);
-  freed_large_objects_.FetchAndAdd(freed_large_objects);
-  freed_bytes_.FetchAndAdd(freed_bytes);
-  freed_large_object_bytes_.FetchAndAdd(freed_large_object_bytes);
+  VLOG(heap) << "Freed " << freed_objects << "/" << count << " objects with size "
+             << PrettySize(freed_bytes);
+  RecordFree(freed_objects, freed_bytes);
+  RecordFreeLargeObjects(freed_large_objects, freed_large_object_bytes);
   timings_.EndSplit();
 
   timings_.StartSplit("ResetStack");
@@ -1150,9 +1147,7 @@
       size_t freed_objects = 0;
       size_t freed_bytes = 0;
       alloc_space->Sweep(swap_bitmaps, &freed_objects, &freed_bytes);
-      heap_->RecordFree(freed_objects, freed_bytes);
-      freed_objects_.FetchAndAdd(freed_objects);
-      freed_bytes_.FetchAndAdd(freed_bytes);
+      RecordFree(freed_objects, freed_bytes);
     }
   }
   SweepLargeObjects(swap_bitmaps);
@@ -1163,9 +1158,7 @@
   size_t freed_objects = 0;
   size_t freed_bytes = 0;
   heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps, &freed_objects, &freed_bytes);
-  freed_large_objects_.FetchAndAdd(freed_objects);
-  freed_large_object_bytes_.FetchAndAdd(freed_bytes);
-  heap_->RecordFree(freed_objects, freed_bytes);
+  RecordFreeLargeObjects(freed_objects, freed_bytes);
 }
 
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index b53ee10..f5d6299 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -262,27 +262,18 @@
   // before they are properly counted.
   RevokeAllThreadLocalBuffers();
   // Record freed memory.
-  uint64_t from_bytes = from_space_->GetBytesAllocated();
-  uint64_t to_bytes = bytes_moved_;
-  uint64_t from_objects = from_space_->GetObjectsAllocated();
-  uint64_t to_objects = objects_moved_;
+  const int64_t from_bytes = from_space_->GetBytesAllocated();
+  const int64_t to_bytes = bytes_moved_;
+  const uint64_t from_objects = from_space_->GetObjectsAllocated();
+  const uint64_t to_objects = objects_moved_;
   CHECK_LE(to_objects, from_objects);
-  int64_t freed_bytes = from_bytes - to_bytes;
-  int64_t freed_objects = from_objects - to_objects;
-  freed_bytes_.FetchAndAdd(freed_bytes);
-  freed_objects_.FetchAndAdd(freed_objects);
   // Note: Freed bytes can be negative if we copy form a compacted space to a free-list backed
   // space.
-  heap_->RecordFree(freed_objects, freed_bytes);
-
+  RecordFree(from_objects - to_objects, from_bytes - to_bytes);
   // Clear and protect the from space.
   from_space_->Clear();
-  VLOG(heap) << "Protecting space " << *from_space_;
-  if (kProtectFromSpace) {
-    from_space_->GetMemMap()->Protect(PROT_NONE);
-  } else {
-    from_space_->GetMemMap()->Protect(PROT_READ);
-  }
+  VLOG(heap) << "Protecting from_space_: " << *from_space_;
+  from_space_->GetMemMap()->Protect(kProtectFromSpace ? PROT_NONE : PROT_READ);
   if (swap_semi_spaces_) {
     heap_->SwapSemiSpaces();
   }
@@ -687,9 +678,7 @@
       size_t freed_objects = 0;
       size_t freed_bytes = 0;
       alloc_space->Sweep(swap_bitmaps, &freed_objects, &freed_bytes);
-      heap_->RecordFree(freed_objects, freed_bytes);
-      freed_objects_.FetchAndAdd(freed_objects);
-      freed_bytes_.FetchAndAdd(freed_bytes);
+      RecordFree(freed_objects, freed_bytes);
     }
   }
   if (!is_large_object_space_immune_) {
@@ -703,9 +692,7 @@
   size_t freed_objects = 0;
   size_t freed_bytes = 0;
   heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps, &freed_objects, &freed_bytes);
-  freed_large_objects_.FetchAndAdd(freed_objects);
-  freed_large_object_bytes_.FetchAndAdd(freed_bytes);
-  heap_->RecordFree(freed_objects, freed_bytes);
+  RecordFreeLargeObjects(freed_objects, freed_bytes);
 }
 
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc
index b25f7ff..9e73f14 100644
--- a/runtime/gc/gc_cause.cc
+++ b/runtime/gc/gc_cause.cc
@@ -29,7 +29,9 @@
     case kGcCauseBackground: return "Background";
     case kGcCauseExplicit: return "Explicit";
     case kGcCauseForNativeAlloc: return "NativeAlloc";
-    case kGcCauseCollectorTransition: return" CollectorTransition";
+    case kGcCauseCollectorTransition: return "CollectorTransition";
+    case kGcCauseDisableMovingGc: return "DisableMovingGc";
+    case kGcCauseTrim: return "HeapTrim";
     default:
       LOG(FATAL) << "Unreachable";
   }
diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h
index 7499b9e..10e6667 100644
--- a/runtime/gc/gc_cause.h
+++ b/runtime/gc/gc_cause.h
@@ -35,6 +35,10 @@
   kGcCauseForNativeAlloc,
   // GC triggered for a collector transition.
   kGcCauseCollectorTransition,
+  // Not a real GC cause, used when we disable moving GC (currently for GetPrimitiveArrayCritical).
+  kGcCauseDisableMovingGc,
+  // Not a real GC cause, used when we trim the heap.
+  kGcCauseTrim,
 };
 
 const char* PrettyCause(GcCause cause);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5d517bb..4484494 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -498,7 +498,7 @@
   MutexLock mu(self, *gc_complete_lock_);
   ++disable_moving_gc_count_;
   if (IsMovingGc(collector_type_running_)) {
-    WaitForGcToCompleteLocked(self);
+    WaitForGcToCompleteLocked(kGcCauseDisableMovingGc, self);
   }
 }
 
@@ -962,7 +962,7 @@
     // trimming.
     MutexLock mu(self, *gc_complete_lock_);
     // Ensure there is only one GC at a time.
-    WaitForGcToCompleteLocked(self);
+    WaitForGcToCompleteLocked(kGcCauseTrim, self);
     collector_type_running_ = kCollectorTypeHeapTrim;
   }
   uint64_t start_ns = NanoTime();
@@ -1143,13 +1143,13 @@
   GetLiveBitmap()->Walk(Heap::VerificationCallback, this);
 }
 
-void Heap::RecordFree(ssize_t freed_objects, ssize_t freed_bytes) {
+void Heap::RecordFree(uint64_t freed_objects, int64_t freed_bytes) {
   // Use signed comparison since freed bytes can be negative when background compaction foreground
   // transitions occurs. This is caused by the moving objects from a bump pointer space to a
   // free list backed space typically increasing memory footprint due to padding and binning.
-  DCHECK_LE(freed_bytes, static_cast<ssize_t>(num_bytes_allocated_.Load()));
-  DCHECK_GE(freed_objects, 0);
-  num_bytes_allocated_.FetchAndSub(freed_bytes);
+  DCHECK_LE(freed_bytes, static_cast<int64_t>(num_bytes_allocated_.Load()));
+  // Note: This relies on 2s complement for handling negative freed_bytes.
+  num_bytes_allocated_.FetchAndSub(static_cast<ssize_t>(freed_bytes));
   if (Runtime::Current()->HasStatsEnabled()) {
     RuntimeStats* thread_stats = Thread::Current()->GetStats();
     thread_stats->freed_objects += freed_objects;
@@ -1171,7 +1171,7 @@
   SirtRef<mirror::Class> sirt_klass(self, *klass);
   // The allocation failed. If the GC is running, block until it completes, and then retry the
   // allocation.
-  collector::GcType last_gc = WaitForGcToComplete(self);
+  collector::GcType last_gc = WaitForGcToComplete(kGcCauseForAlloc, self);
   if (last_gc != collector::kGcTypeNone) {
     // If we were the default allocator but the allocator changed while we were suspended,
     // abort the allocation.
@@ -1418,7 +1418,7 @@
       ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
       MutexLock mu(self, *gc_complete_lock_);
       // Ensure there is only one GC at a time.
-      WaitForGcToCompleteLocked(self);
+      WaitForGcToCompleteLocked(kGcCauseCollectorTransition, self);
       // If someone else beat us to it and changed the collector before we could, exit.
       // This is safe to do before the suspend all since we set the collector_type_running_ before
       // we exit the loop. If another thread attempts to do the heap transition before we exit,
@@ -1819,7 +1819,7 @@
     ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
     MutexLock mu(self, *gc_complete_lock_);
     // Ensure there is only one GC at a time.
-    WaitForGcToCompleteLocked(self);
+    WaitForGcToCompleteLocked(gc_cause, self);
     compacting_gc = IsMovingGc(collector_type_);
     // GC can be disabled if someone has a used GetPrimitiveArrayCritical.
     if (compacting_gc && disable_moving_gc_count_ != 0) {
@@ -2448,13 +2448,13 @@
   }
 }
 
-collector::GcType Heap::WaitForGcToComplete(Thread* self) {
+collector::GcType Heap::WaitForGcToComplete(GcCause cause, Thread* self) {
   ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
   MutexLock mu(self, *gc_complete_lock_);
-  return WaitForGcToCompleteLocked(self);
+  return WaitForGcToCompleteLocked(cause, self);
 }
 
-collector::GcType Heap::WaitForGcToCompleteLocked(Thread* self) {
+collector::GcType Heap::WaitForGcToCompleteLocked(GcCause cause, Thread* self) {
   collector::GcType last_gc_type = collector::kGcTypeNone;
   uint64_t wait_start = NanoTime();
   while (collector_type_running_ != kCollectorTypeNone) {
@@ -2467,7 +2467,8 @@
   uint64_t wait_time = NanoTime() - wait_start;
   total_wait_time_ += wait_time;
   if (wait_time > long_pause_log_threshold_) {
-    LOG(INFO) << "WaitForGcToComplete blocked for " << PrettyDuration(wait_time);
+    LOG(INFO) << "WaitForGcToComplete blocked for " << PrettyDuration(wait_time)
+        << " for cause " << cause;
   }
   return last_gc_type;
 }
@@ -2611,12 +2612,14 @@
   non_moving_space_->ClearGrowthLimit();
 }
 
-void Heap::AddFinalizerReference(Thread* self, mirror::Object* object) {
+void Heap::AddFinalizerReference(Thread* self, mirror::Object** object) {
   ScopedObjectAccess soa(self);
-  ScopedLocalRef<jobject> arg(self->GetJniEnv(), soa.AddLocalReference<jobject>(object));
+  ScopedLocalRef<jobject> arg(self->GetJniEnv(), soa.AddLocalReference<jobject>(*object));
   jvalue args[1];
   args[0].l = arg.get();
   InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_FinalizerReference_add, args);
+  // Restore object in case it gets moved.
+  *object = soa.Decode<mirror::Object*>(arg.get());
 }
 
 void Heap::EnqueueClearedReferences() {
@@ -2659,7 +2662,7 @@
     return;
   }
   // Wait for any GCs currently running to finish.
-  if (WaitForGcToComplete(self) == collector::kGcTypeNone) {
+  if (WaitForGcToComplete(kGcCauseBackground, self) == collector::kGcTypeNone) {
     // If the we can't run the GC type we wanted to run, find the next appropriate one and try that
     // instead. E.g. can't do partial, so do full instead.
     if (CollectGarbageInternal(next_gc_type_, kGcCauseBackground, false) ==
@@ -2792,7 +2795,7 @@
     // The second watermark is higher than the gc watermark. If you hit this it means you are
     // allocating native objects faster than the GC can keep up with.
     if (static_cast<size_t>(native_bytes_allocated_) > native_footprint_limit_) {
-      if (WaitForGcToComplete(self) != collector::kGcTypeNone) {
+      if (WaitForGcToComplete(kGcCauseForNativeAlloc, self) != collector::kGcTypeNone) {
         // Just finished a GC, attempt to run finalizers.
         RunFinalization(env);
         CHECK(!env->ExceptionCheck());
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index d3b5cdc..7a9ef1e 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -300,7 +300,8 @@
 
   // Blocks the caller until the garbage collector becomes idle and returns the type of GC we
   // waited for.
-  collector::GcType WaitForGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
+  collector::GcType WaitForGcToComplete(GcCause cause, Thread* self)
+      LOCKS_EXCLUDED(gc_complete_lock_);
 
   // Update the heap's process state to a new value, may cause compaction to occur.
   void UpdateProcessState(ProcessState process_state);
@@ -357,7 +358,7 @@
 
   // Freed bytes can be negative in cases where we copy objects from a compacted space to a
   // free-list backed space.
-  void RecordFree(ssize_t freed_objects, ssize_t freed_bytes);
+  void RecordFree(uint64_t freed_objects, int64_t freed_bytes);
 
   // Must be called if a field of an Object in the heap changes, and before any GC safe-point.
   // The call is not needed if NULL is stored in the field.
@@ -380,7 +381,7 @@
     return card_table_.get();
   }
 
-  void AddFinalizerReference(Thread* self, mirror::Object* object);
+  void AddFinalizerReference(Thread* self, mirror::Object** object);
 
   // Returns the number of bytes currently allocated.
   size_t GetBytesAllocated() const {
@@ -641,7 +642,7 @@
 
   // Blocks the caller until the garbage collector becomes idle and returns the type of GC we
   // waited for.
-  collector::GcType WaitForGcToCompleteLocked(Thread* self)
+  collector::GcType WaitForGcToCompleteLocked(GcCause cause, Thread* self)
       EXCLUSIVE_LOCKS_REQUIRED(gc_complete_lock_);
 
   void RequestCollectorTransition(CollectorType desired_collector_type, uint64_t delta_time)
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 3de1ba4..858582e 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -33,15 +33,16 @@
 
 Atomic<uint32_t> ImageSpace::bitmap_index_(0);
 
-ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map,
-                       accounting::ContinuousSpaceBitmap* live_bitmap)
-    : MemMapSpace(name, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(),
-                  kGcRetentionPolicyNeverCollect) {
+ImageSpace::ImageSpace(const std::string& image_filename, const char* image_location,
+                       MemMap* mem_map, accounting::ContinuousSpaceBitmap* live_bitmap)
+    : MemMapSpace(image_filename, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(),
+                  kGcRetentionPolicyNeverCollect),
+      image_location_(image_location) {
   DCHECK(live_bitmap != nullptr);
   live_bitmap_.reset(live_bitmap);
 }
 
-static bool GenerateImage(const std::string& image_file_name, std::string* error_msg) {
+static bool GenerateImage(const std::string& image_filename, std::string* error_msg) {
   const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
   std::vector<std::string> boot_class_path;
   Split(boot_class_path_string, ':', boot_class_path);
@@ -57,7 +58,7 @@
   arg_vector.push_back(dex2oat);
 
   std::string image_option_string("--image=");
-  image_option_string += image_file_name;
+  image_option_string += image_filename;
   arg_vector.push_back(image_option_string);
 
   arg_vector.push_back("--runtime-arg");
@@ -72,7 +73,7 @@
   }
 
   std::string oat_file_option_string("--oat-file=");
-  oat_file_option_string += image_file_name;
+  oat_file_option_string += image_filename;
   oat_file_option_string.erase(oat_file_option_string.size() - 3);
   oat_file_option_string += "oat";
   arg_vector.push_back(oat_file_option_string);
@@ -98,37 +99,72 @@
   return Exec(arg_vector, error_msg);
 }
 
-ImageSpace* ImageSpace::Create(const char* original_image_file_name,
-                               const InstructionSet image_isa) {
-  if (OS::FileExists(original_image_file_name)) {
-    // If the /system file exists, it should be up-to-date, don't try to generate
-    std::string error_msg;
-    ImageSpace* space = ImageSpace::Init(original_image_file_name, false, &error_msg);
-    if (space == nullptr) {
-      LOG(FATAL) << "Failed to load image '" << original_image_file_name << "': " << error_msg;
-    }
-    return space;
+bool ImageSpace::FindImageFilename(const char* image_location,
+                                   const InstructionSet image_isa,
+                                   std::string* image_filename,
+                                   bool *is_system) {
+  if (OS::FileExists(image_location)) {
+    *image_filename = image_location;
+    *is_system = true;
+    return true;
   }
-  // If the /system file didn't exist, we need to use one from the dalvik-cache.
-  // If the cache file exists, try to open, but if it fails, regenerate.
-  // If it does not exist, generate.
+
   const std::string dalvik_cache = GetDalvikCacheOrDie(GetInstructionSetString(image_isa));
-  std::string image_file_name(GetDalvikCacheFilenameOrDie(original_image_file_name,
-                                                          dalvik_cache.c_str()));
+
+  // Always set output location even if it does not exist,
+  // so that the caller knows where to create the image.
+  *image_filename = GetDalvikCacheFilenameOrDie(image_location, dalvik_cache.c_str());
+  *is_system = false;
+  return OS::FileExists(image_filename->c_str());
+}
+
+ImageHeader* ImageSpace::ReadImageHeaderOrDie(const char* image_location,
+                                              const InstructionSet image_isa) {
+  std::string image_filename;
+  bool is_system = false;
+  if (FindImageFilename(image_location, image_isa, &image_filename, &is_system)) {
+    UniquePtr<File> image_file(OS::OpenFileForReading(image_filename.c_str()));
+    UniquePtr<ImageHeader> image_header(new ImageHeader);
+    const bool success = image_file->ReadFully(image_header.get(), sizeof(ImageHeader));
+    if (!success || !image_header->IsValid()) {
+      LOG(FATAL) << "Invalid Image header for: " << image_filename;
+      return nullptr;
+    }
+
+    return image_header.release();
+  }
+
+  LOG(FATAL) << "Unable to find image file for: " << image_location;
+  return nullptr;
+}
+
+ImageSpace* ImageSpace::Create(const char* image_location,
+                               const InstructionSet image_isa) {
+  std::string image_filename;
   std::string error_msg;
-  if (OS::FileExists(image_file_name.c_str())) {
-    space::ImageSpace* image_space = ImageSpace::Init(image_file_name.c_str(), true, &error_msg);
-    if (image_space != nullptr) {
-      return image_space;
+  bool is_system = false;
+  if (FindImageFilename(image_location, image_isa, &image_filename, &is_system)) {
+    ImageSpace* space = ImageSpace::Init(image_filename.c_str(), image_location,
+                                         !is_system, &error_msg);
+    if (space != nullptr) {
+      return space;
+    }
+
+    // If the /system file exists, it should be up-to-date, don't try to generate it.
+    // If it's not the /system file, log a warning and fall through to GenerateImage.
+    if (is_system) {
+      LOG(FATAL) << "Failed to load image '" << image_filename << "': " << error_msg;
+      return nullptr;
     } else {
       LOG(WARNING) << error_msg;
     }
   }
-  CHECK(GenerateImage(image_file_name, &error_msg))
-      << "Failed to generate image '" << image_file_name << "': " << error_msg;
-  ImageSpace* space = ImageSpace::Init(image_file_name.c_str(), true, &error_msg);
+
+  CHECK(GenerateImage(image_filename, &error_msg))
+      << "Failed to generate image '" << image_filename << "': " << error_msg;
+  ImageSpace* space = ImageSpace::Init(image_filename.c_str(), image_location, true, &error_msg);
   if (space == nullptr) {
-    LOG(FATAL) << "Failed to load image '" << original_image_file_name << "': " << error_msg;
+    LOG(FATAL) << "Failed to load image '" << image_filename << "': " << error_msg;
   }
   return space;
 }
@@ -147,25 +183,26 @@
   }
 }
 
-ImageSpace* ImageSpace::Init(const char* image_file_name, bool validate_oat_file,
-                             std::string* error_msg) {
-  CHECK(image_file_name != nullptr);
+ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_location,
+                             bool validate_oat_file, std::string* error_msg) {
+  CHECK(image_filename != nullptr);
+  CHECK(image_location != nullptr);
 
   uint64_t start_time = 0;
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     start_time = NanoTime();
-    LOG(INFO) << "ImageSpace::Init entering image_file_name=" << image_file_name;
+    LOG(INFO) << "ImageSpace::Init entering image_filename=" << image_filename;
   }
 
-  UniquePtr<File> file(OS::OpenFileForReading(image_file_name));
+  UniquePtr<File> file(OS::OpenFileForReading(image_filename));
   if (file.get() == NULL) {
-    *error_msg = StringPrintf("Failed to open '%s'", image_file_name);
+    *error_msg = StringPrintf("Failed to open '%s'", image_filename);
     return nullptr;
   }
   ImageHeader image_header;
   bool success = file->ReadFully(&image_header, sizeof(image_header));
   if (!success || !image_header.IsValid()) {
-    *error_msg = StringPrintf("Invalid image header in '%s'", image_file_name);
+    *error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
     return nullptr;
   }
 
@@ -177,7 +214,7 @@
                                                  file->Fd(),
                                                  0,
                                                  false,
-                                                 image_file_name,
+                                                 image_filename,
                                                  error_msg));
   if (map.get() == NULL) {
     DCHECK(!error_msg->empty());
@@ -190,14 +227,14 @@
                                                        PROT_READ, MAP_PRIVATE,
                                                        file->Fd(), image_header.GetBitmapOffset(),
                                                        false,
-                                                       image_file_name,
+                                                       image_filename,
                                                        error_msg));
   if (image_map.get() == nullptr) {
     *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str());
     return nullptr;
   }
   uint32_t bitmap_index = bitmap_index_.FetchAndAdd(1);
-  std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_file_name,
+  std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_filename,
                                        bitmap_index));
   UniquePtr<accounting::ContinuousSpaceBitmap> bitmap(
       accounting::ContinuousSpaceBitmap::CreateFromMemMap(bitmap_name, image_map.release(),
@@ -223,12 +260,13 @@
   callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
   runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
 
-  UniquePtr<ImageSpace> space(new ImageSpace(image_file_name, map.release(), bitmap.release()));
+  UniquePtr<ImageSpace> space(new ImageSpace(image_filename, image_location,
+                                             map.release(), bitmap.release()));
   if (kIsDebugBuild) {
     space->VerifyImageAllocations();
   }
 
-  space->oat_file_.reset(space->OpenOatFile(image_file_name, error_msg));
+  space->oat_file_.reset(space->OpenOatFile(image_filename, error_msg));
   if (space->oat_file_.get() == nullptr) {
     DCHECK(!error_msg->empty());
     return nullptr;
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 1652ec9..622371f 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -46,6 +46,11 @@
   static ImageSpace* Create(const char* image, const InstructionSet image_isa)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Reads the image header from the specified image location for the
+  // instruction set image_isa.
+  static ImageHeader* ReadImageHeaderOrDie(const char* image_location,
+                                           const InstructionSet image_isa);
+
   // Releases the OatFile from the ImageSpace so it can be transfer to
   // the caller, presumably the ClassLinker.
   OatFile* ReleaseOatFile()
@@ -58,10 +63,18 @@
     return *reinterpret_cast<ImageHeader*>(Begin());
   }
 
+  // Actual filename where image was loaded from.
+  // For example: /data/dalvik-cache/arm/system@framework@boot.art
   const std::string GetImageFilename() const {
     return GetName();
   }
 
+  // Symbolic location for image.
+  // For example: /system/framework/boot.art
+  const std::string GetImageLocation() const {
+    return image_location_;
+  }
+
   accounting::ContinuousSpaceBitmap* GetLiveBitmap() const OVERRIDE {
     return live_bitmap_.get();
   }
@@ -90,9 +103,21 @@
   // image's OatFile is up-to-date relative to its DexFile
   // inputs. Otherwise (for /data), validate the inputs and generate
   // the OatFile in /data/dalvik-cache if necessary.
-  static ImageSpace* Init(const char* image, bool validate_oat_file, std::string* error_msg)
+  static ImageSpace* Init(const char* image_filename, const char* image_location,
+                          bool validate_oat_file, std::string* error_msg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Returns the filename of the image corresponding to
+  // requested image_location, or the filename where a new image
+  // should be written if one doesn't exist. Looks for a generated
+  // image in the specified location and then in the dalvik-cache.
+  //
+  // Returns true if an image was found, false otherwise.
+  static bool FindImageFilename(const char* image_location,
+                                const InstructionSet image_isa,
+                                std::string* location,
+                                bool* is_system);
+
   OatFile* OpenOatFile(const char* image, std::string* error_msg) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -105,14 +130,16 @@
 
   UniquePtr<accounting::ContinuousSpaceBitmap> live_bitmap_;
 
-  ImageSpace(const std::string& name, MemMap* mem_map,
-             accounting::ContinuousSpaceBitmap* live_bitmap);
+  ImageSpace(const std::string& name, const char* image_location,
+             MemMap* mem_map, accounting::ContinuousSpaceBitmap* live_bitmap);
 
   // The OatFile associated with the image during early startup to
   // reserve space contiguous to the image. It is later released to
   // the ClassLinker during it's initialization.
   UniquePtr<OatFile> oat_file_;
 
+  const std::string image_location_;
+
   DISALLOW_COPY_AND_ASSIGN(ImageSpace);
 };
 
diff --git a/runtime/globals.h b/runtime/globals.h
index e3c54b8..eb52a46 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -20,6 +20,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include "read_barrier_c.h"
+#include "read_barrier_option.h"
 
 namespace art {
 
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 1e1a8c1..7232e54 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -27,10 +27,6 @@
 static void UnstartedRuntimeJni(Thread* self, ArtMethod* method,
                                 Object* receiver, uint32_t* args, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(Runtime::Current()->IsActiveTransaction()) << "Calling native method "
-                                                    << PrettyMethod(method)
-                                                    << " in unstarted runtime should only happen"
-                                                    << " in a transaction";
   std::string name(PrettyMethod(method));
   if (name == "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()") {
     result->SetL(NULL);
@@ -71,7 +67,11 @@
     result->SetL(Array::CreateMultiArray(self, sirt_class, sirt_dimensions));
   } else if (name == "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()") {
     ScopedObjectAccessUnchecked soa(self);
-    result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace<true>(soa)));
+    if (Runtime::Current()->IsActiveTransaction()) {
+      result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace<true>(soa)));
+    } else {
+      result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace<false>(soa)));
+    }
   } else if (name == "int java.lang.System.identityHashCode(java.lang.Object)") {
     mirror::Object* obj = reinterpret_cast<Object*>(args[0]);
     result->SetI((obj != nullptr) ? obj->IdentityHashCode() : 0);
@@ -82,13 +82,22 @@
     jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
     jint expectedValue = args[3];
     jint newValue = args[4];
-    bool success = obj->CasField32<true>(MemberOffset(offset), expectedValue, newValue);
+    bool success;
+    if (Runtime::Current()->IsActiveTransaction()) {
+      success = obj->CasField32<true>(MemberOffset(offset), expectedValue, newValue);
+    } else {
+      success = obj->CasField32<false>(MemberOffset(offset), expectedValue, newValue);
+    }
     result->SetZ(success ? JNI_TRUE : JNI_FALSE);
   } else if (name == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
     Object* obj = reinterpret_cast<Object*>(args[0]);
     jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
     Object* newValue = reinterpret_cast<Object*>(args[3]);
-    obj->SetFieldObject<true>(MemberOffset(offset), newValue);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      obj->SetFieldObject<true>(MemberOffset(offset), newValue);
+    } else {
+      obj->SetFieldObject<false>(MemberOffset(offset), newValue);
+    }
   } else if (name == "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)") {
     mirror::Class* component = reinterpret_cast<Object*>(args[0])->AsClass();
     Primitive::Type primitive_type = component->GetPrimitiveType();
@@ -97,9 +106,13 @@
     mirror::Class* component = reinterpret_cast<Object*>(args[0])->AsClass();
     Primitive::Type primitive_type = component->GetPrimitiveType();
     result->SetI(Primitive::ComponentSize(primitive_type));
-  } else {
+  } else if (Runtime::Current()->IsActiveTransaction()) {
     AbortTransaction(self, "Attempt to invoke native method in non-started runtime: %s",
                      name.c_str());
+
+  } else {
+    LOG(FATAL) << "Calling native method " << PrettyMethod(method) << " in an unstarted "
+        "non-transactional runtime";
   }
 }
 
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 5660508..ee6a869 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -85,7 +85,7 @@
     if (is_range) {
       vregC = inst->VRegC_3rc();
     } else {
-      inst->GetArgs(arg, inst_data);
+      inst->GetVarArgs(arg, inst_data);
     }
 
     // Handle receiver apart since it's not part of the shorty.
@@ -224,7 +224,7 @@
   if (is_range) {
     vregC = inst->VRegC_3rc();
   } else {
-    inst->GetArgs(arg);
+    inst->GetVarArgs(arg);
   }
   const bool is_primitive_int_component = componentClass->IsPrimitiveInt();
   for (int32_t i = 0; i < length; ++i) {
@@ -302,6 +302,8 @@
     CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: "
         << PrettyDescriptor(descriptor);
     result->SetL(found);
+  } else if (name == "java.lang.Class java.lang.Void.lookupType()") {
+    result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V'));
   } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
     SirtRef<ClassLoader> class_loader(self, down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset)));
     std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str()));
@@ -355,6 +357,12 @@
     args[0] = StackReference<mirror::Object>::FromMirrorPtr(found).AsVRegValue();
     EnterInterpreterFromInvoke(self, c, field.get(), args, NULL);
     result->SetL(field.get());
+  } else if (name == "int java.lang.Object.hashCode()") {
+    Object* obj = shadow_frame->GetVRegReference(arg_offset);
+    result->SetI(obj->IdentityHashCode());
+  } else if (name == "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)") {
+    ArtMethod* method = shadow_frame->GetVRegReference(arg_offset)->AsArtMethod();
+    result->SetL(MethodHelper(method).GetNameAsString());
   } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" ||
              name == "void java.lang.System.arraycopy(char[], int, char[], int, int)") {
     // Special case array copying without initializing System.
@@ -381,7 +389,18 @@
         dst->Set(dstPos + i, src->Get(srcPos + i));
       }
     } else {
-      UNIMPLEMENTED(FATAL) << "System.arraycopy of unexpected type: " << PrettyDescriptor(ctype);
+      self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;",
+                               "Unimplemented System.arraycopy for type '%s'",
+                               PrettyDescriptor(ctype).c_str());
+    }
+  } else  if (name == "java.lang.Object java.lang.ThreadLocal.get()") {
+    std::string caller(PrettyMethod(shadow_frame->GetLink()->GetMethod()));
+    if (caller == "java.lang.String java.lang.IntegralToString.convertInt(java.lang.AbstractStringBuilder, int)") {
+      // Allocate non-threadlocal buffer.
+      result->SetL(mirror::CharArray::Alloc(self, 11));
+    } else {
+      self->ThrowNewException(self->GetCurrentLocationForThrow(), "Ljava/lang/InternalError;",
+                              "Unimplemented ThreadLocal.get");
     }
   } else {
     // Not special, continue with regular interpreter execution.
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 071b658..14fc25c 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -322,11 +322,7 @@
   ASSERT_TRUE(mid2 != NULL);
   // Make sure we can actually use it.
   jstring s = env_->NewStringUTF("poop");
-  // TODO: this should return 4, but the runtime skips the method
-  // invoke because the runtime isn't started. In the future it would
-  // be nice to use interpretter for things like this. This still does
-  // validate that we have a sane jmethodID value.
-  ASSERT_EQ(0, env_->CallIntMethod(s, mid2));
+  ASSERT_EQ(4, env_->CallIntMethod(s, mid2));
 }
 
 void BogusMethod() {
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index bc8d348..65799cd 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -27,11 +27,11 @@
 namespace art {
 namespace mirror {
 
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline size_t Array::SizeOf() {
   // This is safe from overflow because the array was already allocated, so we know it's sane.
   size_t component_size =
-      GetClass<kVerifyFlags, kDoReadBarrier>()->template GetComponentSize<kDoReadBarrier>();
+      GetClass<kVerifyFlags, kReadBarrierOption>()->template GetComponentSize<kReadBarrierOption>();
   // Don't need to check this since we already check this in GetClass.
   int32_t component_count =
       GetLength<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>();
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 92f0e67..eead4eb 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -42,7 +42,8 @@
                                  const SirtRef<IntArray>& dimensions)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   size_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   int32_t GetLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 7453d4d..4275f25 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -287,9 +287,11 @@
   Runtime* runtime = Runtime::Current();
   // Call the invoke stub, passing everything as arguments.
   if (UNLIKELY(!runtime->IsStarted())) {
-    LOG(INFO) << "Not invoking " << PrettyMethod(this) << " for a runtime that isn't started";
-    if (result != NULL) {
-      result->SetJ(0);
+    if (IsStatic()) {
+      art::interpreter::EnterInterpreterFromInvoke(self, this, nullptr, args, result);
+    } else {
+      Object* receiver = reinterpret_cast<StackReference<Object>*>(&args[0])->AsMirrorPtr();
+      art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1, result);
     }
   } else {
     const bool kLogInvocationStartAndReturn = false;
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index f61a01d..71f0210 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -411,7 +411,7 @@
 
   static void SetClass(Class* java_lang_reflect_ArtMethod);
 
-  template <bool kDoReadBarrier = true>
+  template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   static Class* GetJavaLangReflectArtMethod() {
     // This does not need a RB because it is a root.
     return java_lang_reflect_ArtMethod_;
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 8a1f383..a556a1c 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -470,12 +470,21 @@
   DCHECK_GE(this->object_size_, sizeof(Object));
 }
 
-template <bool kIsInstrumented>
+template<bool kIsInstrumented, bool kCheckAddFinalizer>
 inline Object* Class::Alloc(Thread* self, gc::AllocatorType allocator_type) {
   CheckObjectAlloc();
   gc::Heap* heap = Runtime::Current()->GetHeap();
-  return heap->AllocObjectWithAllocator<kIsInstrumented, false>(self, this, this->object_size_,
-                                                                allocator_type, VoidFunctor());
+  const bool add_finalizer = kCheckAddFinalizer && IsFinalizable();
+  if (!kCheckAddFinalizer) {
+    DCHECK(!IsFinalizable());
+  }
+  mirror::Object* obj =
+      heap->AllocObjectWithAllocator<kIsInstrumented, false>(self, this, this->object_size_,
+                                                             allocator_type, VoidFunctor());
+  if (add_finalizer && LIKELY(obj != nullptr)) {
+    heap->AddFinalizerReference(self, &obj);
+  }
+  return obj;
 }
 
 inline Object* Class::AllocObject(Thread* self) {
@@ -492,17 +501,17 @@
   VisitStaticFieldsReferences<kVisitClass>(this, visitor);
 }
 
-template<bool kDoReadBarrier>
+template<ReadBarrierOption kReadBarrierOption>
 bool Class::IsArtFieldClass() {
-  Class* java_lang_Class = GetClass<kVerifyNone, kDoReadBarrier>();
+  Class* java_lang_Class = GetClass<kVerifyNone, kReadBarrierOption>();
   Class* java_lang_reflect_ArtField =
-      java_lang_Class->GetInstanceField(0)->GetClass<kVerifyNone, kDoReadBarrier>();
+      java_lang_Class->GetInstanceField(0)->GetClass<kVerifyNone, kReadBarrierOption>();
   return this == java_lang_reflect_ArtField;
 }
 
-template<bool kDoReadBarrier>
+template<ReadBarrierOption kReadBarrierOption>
 bool Class::IsArtMethodClass() {
-  return this == ArtMethod::GetJavaLangReflectArtMethod<kDoReadBarrier>();
+  return this == ArtMethod::GetJavaLangReflectArtMethod<kReadBarrierOption>();
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 23211c2..00ecead 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -360,9 +360,10 @@
     return depth;
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetComponentType<kVerifyFlags, kDoReadBarrier>() != NULL;
+    return GetComponentType<kVerifyFlags, kReadBarrierOption>() != NULL;
   }
 
   bool IsClassClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -371,19 +372,20 @@
 
   bool IsThrowableClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<bool kDoReadBarrier = true>
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArtFieldClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<bool kDoReadBarrier = true>
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArtMethodClass();
 
   static MemberOffset ComponentTypeOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Class, component_type_);
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   Class* GetComponentType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldObject<Class, kVerifyFlags, kDoReadBarrier>(ComponentTypeOffset());
+    return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(ComponentTypeOffset());
   }
 
   void SetComponentType(Class* new_component_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -393,10 +395,10 @@
     SetFieldObject<false, false>(ComponentTypeOffset(), new_component_type);
   }
 
-  template<bool kDoReadBarrier = true>
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   size_t GetComponentSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return Primitive::ComponentSize(
-        GetComponentType<kDefaultVerifyFlags, kDoReadBarrier>()->GetPrimitiveType());
+        GetComponentType<kDefaultVerifyFlags, kReadBarrierOption>()->GetPrimitiveType());
   }
 
   bool IsObjectClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -412,7 +414,7 @@
   }
 
   // Creates a raw object instance but does not invoke the default constructor.
-  template <bool kIsInstrumented>
+  template<bool kIsInstrumented, bool kCheckAddFinalizer = true>
   ALWAYS_INLINE Object* Alloc(Thread* self, gc::AllocatorType allocator_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -427,7 +429,8 @@
     return IsClassClass() || IsArrayClass();
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   uint32_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, class_size_));
   }
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index c70a08d..064fe30 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -34,9 +34,9 @@
 namespace art {
 namespace mirror {
 
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline Class* Object::GetClass() {
-  return GetFieldObject<Class, kVerifyFlags, kDoReadBarrier>(
+  return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(
       OFFSET_OF_OBJECT_MEMBER(Object, klass_));
 }
 
@@ -105,7 +105,8 @@
 inline Object* Object::GetReadBarrierPointer() {
 #ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
   DCHECK(kUseBakerOrBrooksReadBarrier);
-  return GetFieldObject<Object, kVerifyNone, false>(OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), false);
+  return GetFieldObject<Object, kVerifyNone, kWithoutReadBarrier>(
+      OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_));
 #else
   LOG(FATAL) << "Unreachable";
   return nullptr;
@@ -118,7 +119,7 @@
   // We don't mark the card as this occurs as part of object allocation. Not all objects have
   // backing cards, such as large objects.
   SetFieldObjectWithoutWriteBarrier<false, false, kVerifyNone>(
-      OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), rb_ptr, false);
+      OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), rb_ptr);
 #else
   LOG(FATAL) << "Unreachable";
 #endif
@@ -181,17 +182,17 @@
   return klass->IsAssignableFrom(GetClass<kVerifyFlags>());
 }
 
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline bool Object::IsClass() {
-  Class* java_lang_Class =
-      GetClass<kVerifyFlags, kDoReadBarrier>()->template GetClass<kVerifyFlags, kDoReadBarrier>();
-  return GetClass<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis), kDoReadBarrier>() ==
-      java_lang_Class;
+  Class* java_lang_Class = GetClass<kVerifyFlags, kReadBarrierOption>()->
+      template GetClass<kVerifyFlags, kReadBarrierOption>();
+  return GetClass<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis),
+      kReadBarrierOption>() == java_lang_Class;
 }
 
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline Class* Object::AsClass() {
-  DCHECK((IsClass<kVerifyFlags, kDoReadBarrier>()));
+  DCHECK((IsClass<kVerifyFlags, kReadBarrierOption>()));
   return down_cast<Class*>(this);
 }
 
@@ -208,15 +209,16 @@
   return down_cast<ObjectArray<T>*>(this);
 }
 
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline bool Object::IsArrayInstance() {
-  return GetClass<kVerifyFlags, kDoReadBarrier>()->
-      template IsArrayClass<kVerifyFlags, kDoReadBarrier>();
+  return GetClass<kVerifyFlags, kReadBarrierOption>()->
+      template IsArrayClass<kVerifyFlags, kReadBarrierOption>();
 }
 
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline bool Object::IsArtField() {
-  return GetClass<kVerifyFlags, kDoReadBarrier>()->template IsArtFieldClass<kDoReadBarrier>();
+  return GetClass<kVerifyFlags, kReadBarrierOption>()->
+      template IsArtFieldClass<kReadBarrierOption>();
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -225,9 +227,10 @@
   return down_cast<ArtField*>(this);
 }
 
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline bool Object::IsArtMethod() {
-  return GetClass<kVerifyFlags, kDoReadBarrier>()->template IsArtMethodClass<kDoReadBarrier>();
+  return GetClass<kVerifyFlags, kReadBarrierOption>()->
+      template IsArtMethodClass<kReadBarrierOption>();
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -247,9 +250,9 @@
   return down_cast<Reference*>(this);
 }
 
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline Array* Object::AsArray() {
-  DCHECK((IsArrayInstance<kVerifyFlags, kDoReadBarrier>()));
+  DCHECK((IsArrayInstance<kVerifyFlags, kReadBarrierOption>()));
   return down_cast<Array*>(this);
 }
 
@@ -375,21 +378,23 @@
   return GetClass<kVerifyFlags>()->IsPhantomReferenceClass();
 }
 
-template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline size_t Object::SizeOf() {
   size_t result;
   constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis);
-  if (IsArrayInstance<kVerifyFlags, kDoReadBarrier>()) {
-    result = AsArray<kNewFlags, kDoReadBarrier>()->template SizeOf<kNewFlags, kDoReadBarrier>();
-  } else if (IsClass<kNewFlags, kDoReadBarrier>()) {
-    result = AsClass<kNewFlags, kDoReadBarrier>()->template SizeOf<kNewFlags, kDoReadBarrier>();
+  if (IsArrayInstance<kVerifyFlags, kReadBarrierOption>()) {
+    result = AsArray<kNewFlags, kReadBarrierOption>()->
+        template SizeOf<kNewFlags, kReadBarrierOption>();
+  } else if (IsClass<kNewFlags, kReadBarrierOption>()) {
+    result = AsClass<kNewFlags, kReadBarrierOption>()->
+        template SizeOf<kNewFlags, kReadBarrierOption>();
   } else {
-    result = GetClass<kNewFlags, kDoReadBarrier>()->GetObjectSize();
+    result = GetClass<kNewFlags, kReadBarrierOption>()->GetObjectSize();
   }
   DCHECK_GE(result, sizeof(Object))
-      << " class=" << PrettyTypeOf(GetClass<kNewFlags, kDoReadBarrier>());
-  DCHECK(!(IsArtField<kNewFlags, kDoReadBarrier>())  || result == sizeof(ArtField));
-  DCHECK(!(IsArtMethod<kNewFlags, kDoReadBarrier>()) || result == sizeof(ArtMethod));
+      << " class=" << PrettyTypeOf(GetClass<kNewFlags, kReadBarrierOption>());
+  DCHECK(!(IsArtField<kNewFlags, kReadBarrierOption>())  || result == sizeof(ArtField));
+  DCHECK(!(IsArtMethod<kNewFlags, kReadBarrierOption>()) || result == sizeof(ArtMethod));
   return result;
 }
 
@@ -532,14 +537,15 @@
   return QuasiAtomic::Cas64(old_value, new_value, addr);
 }
 
-template<class T, VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier, bool kIsVolatile>
+template<class T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption,
+         bool kIsVolatile>
 inline T* Object::GetFieldObject(MemberOffset field_offset) {
   if (kVerifyFlags & kVerifyThis) {
     VerifyObject(this);
   }
   byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
   HeapReference<T>* objref_addr = reinterpret_cast<HeapReference<T>*>(raw_addr);
-  T* result = ReadBarrier::Barrier<T, kDoReadBarrier>(this, field_offset, objref_addr);
+  T* result = ReadBarrier::Barrier<T, kReadBarrierOption>(this, field_offset, objref_addr);
   if (kIsVolatile) {
     QuasiAtomic::MembarLoadLoad();  // Ensure loads don't re-order.
   }
@@ -549,9 +555,9 @@
   return result;
 }
 
-template<class T, VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
+template<class T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline T* Object::GetFieldObjectVolatile(MemberOffset field_offset) {
-  return GetFieldObject<T, kVerifyFlags, kDoReadBarrier, true>(field_offset);
+  return GetFieldObject<T, kVerifyFlags, kReadBarrierOption, true>(field_offset);
 }
 
 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags,
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 2cd71a0..2f775bc 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -92,9 +92,7 @@
     heap->WriteBarrierEveryFieldOf(dest);
   }
   if (c->IsFinalizable()) {
-    SirtRef<Object> sirt_dest(self, dest);
-    heap->AddFinalizerReference(self, dest);
-    return sirt_dest.get();
+    heap->AddFinalizerReference(self, &dest);
   }
   return dest;
 }
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index cf28b18..442909d 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -67,7 +67,8 @@
     return OFFSET_OF_OBJECT_MEMBER(Object, klass_);
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   Class* GetClass() ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -86,7 +87,8 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool InstanceOf(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   size_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Object* Clone(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -113,9 +115,11 @@
   void Wait(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void Wait(Thread* self, int64_t timeout, int32_t nanos) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   Class* AsClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -123,9 +127,11 @@
   template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ObjectArray<T>* AsObjectArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArrayInstance() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   Array* AsArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -158,12 +164,14 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   Throwable* AsThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ArtMethod* AsArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ArtField* AsArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -185,12 +193,12 @@
 
   // Accessor for Java type fields.
   template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
-      bool kDoReadBarrier = true, bool kIsVolatile = false>
+      ReadBarrierOption kReadBarrierOption = kWithReadBarrier, bool kIsVolatile = false>
   T* GetFieldObject(MemberOffset field_offset) ALWAYS_INLINE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
-      bool kDoReadBarrier = true>
+      ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   T* GetFieldObjectVolatile(MemberOffset field_offset) ALWAYS_INLINE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 1acbbb0..c324d96 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -57,6 +57,10 @@
   static void ResetClass();
   static void VisitRoots(RootCallback* callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static Class* GetStackTraceElement() {
+    DCHECK(java_lang_StackTraceElement_ != NULL);
+    return java_lang_StackTraceElement_;
+  }
 
  private:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
@@ -70,11 +74,6 @@
             SirtRef<String>& file_name, int32_t line_number)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static Class* GetStackTraceElement() {
-    DCHECK(java_lang_StackTraceElement_ != NULL);
-    return java_lang_StackTraceElement_;
-  }
-
   static Class* java_lang_StackTraceElement_;
 
   friend struct art::StackTraceElementOffsets;  // for verifying offset information
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index d393a13..6874fe5 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -24,6 +24,7 @@
 #include "object_array.h"
 #include "object_array-inl.h"
 #include "object_utils.h"
+#include "stack_trace_element.h"
 #include "utils.h"
 #include "well_known_classes.h"
 
@@ -53,6 +54,15 @@
   }
 }
 
+void Throwable::SetStackState(Object* state) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  CHECK(state != nullptr);
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetFieldObjectVolatile<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state);
+  } else {
+    SetFieldObjectVolatile<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state);
+  }
+}
+
 bool Throwable::IsCheckedException() {
   if (InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_Error))) {
     return false;
@@ -70,24 +80,49 @@
   result += "\n";
   Object* stack_state = GetStackState();
   // check stack state isn't missing or corrupt
-  if (stack_state != NULL && stack_state->IsObjectArray()) {
+  if (stack_state != nullptr && stack_state->IsObjectArray()) {
     // Decode the internal stack trace into the depth and method trace
     ObjectArray<Object>* method_trace = down_cast<ObjectArray<Object>*>(stack_state);
     int32_t depth = method_trace->GetLength() - 1;
     IntArray* pc_trace = down_cast<IntArray*>(method_trace->Get(depth));
     MethodHelper mh;
-    for (int32_t i = 0; i < depth; ++i) {
-      ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i));
-      mh.ChangeMethod(method);
-      uint32_t dex_pc = pc_trace->Get(i);
-      int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
-      const char* source_file = mh.GetDeclaringClassSourceFile();
-      result += StringPrintf("  at %s (%s:%d)\n", PrettyMethod(method, true).c_str(),
-                             source_file, line_number);
+    if (depth == 0) {
+      result += "(Throwable with empty stack trace)";
+    } else {
+      for (int32_t i = 0; i < depth; ++i) {
+        ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i));
+        mh.ChangeMethod(method);
+        uint32_t dex_pc = pc_trace->Get(i);
+        int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
+        const char* source_file = mh.GetDeclaringClassSourceFile();
+        result += StringPrintf("  at %s (%s:%d)\n", PrettyMethod(method, true).c_str(),
+                               source_file, line_number);
+      }
+    }
+  } else {
+    Object* stack_trace = GetStackTrace();
+    if (stack_trace != nullptr && stack_trace->IsObjectArray()) {
+      CHECK_EQ(stack_trace->GetClass()->GetComponentType(),
+               StackTraceElement::GetStackTraceElement());
+      ObjectArray<StackTraceElement>* ste_array =
+          down_cast<ObjectArray<StackTraceElement>*>(stack_trace);
+      if (ste_array->GetLength() == 0) {
+        result += "(Throwable with empty stack trace)";
+      } else {
+        for (int32_t i = 0; i < ste_array->GetLength(); ++i) {
+          StackTraceElement* ste = ste_array->Get(i);
+          result += StringPrintf("  at %s (%s:%d)\n",
+                                 ste->GetMethodName()->ToModifiedUtf8().c_str(),
+                                 ste->GetFileName()->ToModifiedUtf8().c_str(),
+                                 ste->GetLineNumber());
+        }
+      }
+    } else {
+      result += "(Throwable with no stack trace)";
     }
   }
   Throwable* cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_));
-  if (cause != NULL && cause != this) {  // Constructor makes cause == this by default.
+  if (cause != nullptr && cause != this) {  // Constructor makes cause == this by default.
     result += "Caused by: ";
     result += cause->Dump();
   }
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index 950b5e7..c4127e0 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -42,6 +42,7 @@
   // overridden. Also it asserts rather than throwing exceptions. Currently this is only used
   // in cases like the verifier where the checks cannot fail and initCause isn't overridden.
   void SetCause(Throwable* cause) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void SetStackState(Object* state) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsCheckedException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static Class* GetJavaLangThrowable() {
@@ -58,6 +59,9 @@
   Object* GetStackState() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_));
   }
+  Object* GetStackTrace() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_trace_));
+  }
 
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   HeapReference<Throwable> cause_;
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index d9c1309..ed1ee7a 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -377,6 +377,8 @@
     }
   }
 
+  const InstructionSet target_instruction_set = GetInstructionSetFromString(instruction_set);
+
   // Check if we have an odex file next to the dex file.
   std::string odex_filename(OatFile::DexFilenameToOdexFilename(filename));
   std::string error_msg;
@@ -403,6 +405,7 @@
         return JNI_FALSE;
       }
       if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename, location_checksum,
+                                              target_instruction_set,
                                               &error_msg)) {
         if (kVerboseLogging) {
           LOG(INFO) << "DexFile_isDexOptNeeded precompiled file " << odex_filename
@@ -433,33 +436,6 @@
     return JNI_TRUE;
   }
 
-  for (const auto& space : runtime->GetHeap()->GetContinuousSpaces()) {
-    if (space->IsImageSpace()) {
-      // TODO: Ensure this works with multiple image spaces.
-      const ImageHeader& image_header = space->AsImageSpace()->GetImageHeader();
-      if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() !=
-          image_header.GetOatChecksum()) {
-        if (kReasonLogging) {
-          ScopedObjectAccess soa(env);
-          LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
-              << " has out-of-date oat checksum compared to "
-              << oat_file->GetLocation();
-        }
-        return JNI_TRUE;
-      }
-      if (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin()
-          != reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin())) {
-        if (kReasonLogging) {
-          ScopedObjectAccess soa(env);
-          LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
-              << " has out-of-date oat begin compared to "
-              << oat_file->GetLocation();
-        }
-        return JNI_TRUE;
-      }
-    }
-  }
-
   uint32_t location_checksum;
   if (!DexFile::GetChecksum(filename, &location_checksum, &error_msg)) {
     if (kReasonLogging) {
@@ -470,7 +446,7 @@
   }
 
   if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename, location_checksum,
-                                           &error_msg)) {
+                                           target_instruction_set, &error_msg)) {
     if (kReasonLogging) {
       LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
           << " has out-of-date checksum compared to " << filename
diff --git a/runtime/oat.cc b/runtime/oat.cc
index c1a48e9..4b4b3d0 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '2', '2', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '2', '3', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
diff --git a/runtime/quick/inline_method_analyser.cc b/runtime/quick/inline_method_analyser.cc
index 8bd8dba..d8fc277 100644
--- a/runtime/quick/inline_method_analyser.cc
+++ b/runtime/quick/inline_method_analyser.cc
@@ -174,26 +174,24 @@
     return false;
   }
 
-  uint32_t return_reg = return_instruction->VRegA_11x();
+  int32_t return_reg = return_instruction->VRegA_11x();
   DCHECK_LT(return_reg, code_item->registers_size_);
 
-  uint32_t vA, vB, dummy;
-  uint64_t dummy_wide;
-  instruction->Decode(vA, vB, dummy_wide, dummy, nullptr);
+  int32_t const_value = instruction->VRegB();
   if (instruction->Opcode() == Instruction::CONST_HIGH16) {
-    vB <<= 16;
+    const_value <<= 16;
   }
-  DCHECK_LT(vA, code_item->registers_size_);
-  if (vA != return_reg) {
+  DCHECK_LT(instruction->VRegA(), code_item->registers_size_);
+  if (instruction->VRegA() != return_reg) {
     return false;  // Not returning the value set by const?
   }
-  if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
+  if (return_opcode == Instruction::RETURN_OBJECT && const_value != 0) {
     return false;  // Returning non-null reference constant?
   }
   if (result != nullptr) {
     result->opcode = kInlineOpNonWideConst;
     result->flags = kInlineSpecial;
-    result->d.data = static_cast<uint64_t>(vB);
+    result->d.data = static_cast<uint64_t>(const_value);
   }
   return true;
 }
diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h
index ea2f830..88e2f8f 100644
--- a/runtime/read_barrier-inl.h
+++ b/runtime/read_barrier-inl.h
@@ -23,17 +23,18 @@
 
 namespace art {
 
-template <typename MirrorType, bool kDoReadBarrier>
+template <typename MirrorType, ReadBarrierOption kReadBarrierOption>
 inline MirrorType* ReadBarrier::Barrier(
     mirror::Object* obj, MemberOffset offset, mirror::HeapReference<MirrorType>* ref_addr) {
   // Unused for now.
   UNUSED(obj);
   UNUSED(offset);
   UNUSED(ref_addr);
-  if (kDoReadBarrier && kUseBakerReadBarrier) {
+  const bool with_read_barrier = kReadBarrierOption == kWithReadBarrier;
+  if (with_read_barrier && kUseBakerReadBarrier) {
     // To be implemented.
     return ref_addr->AsMirrorPtr();
-  } else if (kDoReadBarrier && kUseBrooksReadBarrier) {
+  } else if (with_read_barrier && kUseBrooksReadBarrier) {
     // To be implemented.
     return ref_addr->AsMirrorPtr();
   } else {
diff --git a/runtime/read_barrier.h b/runtime/read_barrier.h
index 6f59004..73c3d43 100644
--- a/runtime/read_barrier.h
+++ b/runtime/read_barrier.h
@@ -33,7 +33,7 @@
 
 class ReadBarrier {
  public:
-  template <typename MirrorType, bool kDoReadBarrier = true>
+  template <typename MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   ALWAYS_INLINE static MirrorType* Barrier(
       mirror::Object* obj, MemberOffset offset, mirror::HeapReference<MirrorType>* ref_addr)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/read_barrier_option.h b/runtime/read_barrier_option.h
new file mode 100644
index 0000000..7de8b8a
--- /dev/null
+++ b/runtime/read_barrier_option.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 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_RUNTIME_READ_BARRIER_OPTION_H_
+#define ART_RUNTIME_READ_BARRIER_OPTION_H_
+namespace art {
+
+// Options for performing a read barrier or not.
+enum ReadBarrierOption {
+  kWithReadBarrier,     // Perform a read barrier.
+  kWithoutReadBarrier,  // Don't perform a read barrier.
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_READ_BARRIER_OPTION_H_
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index fbc0460..027feee 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -160,7 +160,7 @@
   Trace::Shutdown();
 
   // Make sure to let the GC complete if it is running.
-  heap_->WaitForGcToComplete(self);
+  heap_->WaitForGcToComplete(gc::kGcCauseBackground, self);
   heap_->DeleteThreadPool();
 
   // Make sure our internal threads are dead before we start tearing down things they're using.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index e67a64f..23a6779 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1639,6 +1639,13 @@
     if (cause.get() != nullptr) {
       exception->SetCause(down_cast<mirror::Throwable*>(DecodeJObject(cause.get())));
     }
+    ScopedLocalRef<jobject> trace(GetJniEnv(),
+                                  Runtime::Current()->IsActiveTransaction()
+                                      ? CreateInternalStackTrace<true>(soa)
+                                      : CreateInternalStackTrace<false>(soa));
+    if (trace.get() != nullptr) {
+      exception->SetStackState(down_cast<mirror::Throwable*>(DecodeJObject(trace.get())));
+    }
     ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
                                          throw_location.GetDexPc());
     SetException(gc_safe_throw_location, exception.get());
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 91170f0..03ceed3 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -649,54 +649,53 @@
 }
 
 bool MethodVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_offset) {
-  DecodedInstruction dec_insn(inst);
   bool result = true;
   switch (inst->GetVerifyTypeArgumentA()) {
     case Instruction::kVerifyRegA:
-      result = result && CheckRegisterIndex(dec_insn.vA);
+      result = result && CheckRegisterIndex(inst->VRegA());
       break;
     case Instruction::kVerifyRegAWide:
-      result = result && CheckWideRegisterIndex(dec_insn.vA);
+      result = result && CheckWideRegisterIndex(inst->VRegA());
       break;
   }
   switch (inst->GetVerifyTypeArgumentB()) {
     case Instruction::kVerifyRegB:
-      result = result && CheckRegisterIndex(dec_insn.vB);
+      result = result && CheckRegisterIndex(inst->VRegB());
       break;
     case Instruction::kVerifyRegBField:
-      result = result && CheckFieldIndex(dec_insn.vB);
+      result = result && CheckFieldIndex(inst->VRegB());
       break;
     case Instruction::kVerifyRegBMethod:
-      result = result && CheckMethodIndex(dec_insn.vB);
+      result = result && CheckMethodIndex(inst->VRegB());
       break;
     case Instruction::kVerifyRegBNewInstance:
-      result = result && CheckNewInstance(dec_insn.vB);
+      result = result && CheckNewInstance(inst->VRegB());
       break;
     case Instruction::kVerifyRegBString:
-      result = result && CheckStringIndex(dec_insn.vB);
+      result = result && CheckStringIndex(inst->VRegB());
       break;
     case Instruction::kVerifyRegBType:
-      result = result && CheckTypeIndex(dec_insn.vB);
+      result = result && CheckTypeIndex(inst->VRegB());
       break;
     case Instruction::kVerifyRegBWide:
-      result = result && CheckWideRegisterIndex(dec_insn.vB);
+      result = result && CheckWideRegisterIndex(inst->VRegB());
       break;
   }
   switch (inst->GetVerifyTypeArgumentC()) {
     case Instruction::kVerifyRegC:
-      result = result && CheckRegisterIndex(dec_insn.vC);
+      result = result && CheckRegisterIndex(inst->VRegC());
       break;
     case Instruction::kVerifyRegCField:
-      result = result && CheckFieldIndex(dec_insn.vC);
+      result = result && CheckFieldIndex(inst->VRegC());
       break;
     case Instruction::kVerifyRegCNewArray:
-      result = result && CheckNewArray(dec_insn.vC);
+      result = result && CheckNewArray(inst->VRegC());
       break;
     case Instruction::kVerifyRegCType:
-      result = result && CheckTypeIndex(dec_insn.vC);
+      result = result && CheckTypeIndex(inst->VRegC());
       break;
     case Instruction::kVerifyRegCWide:
-      result = result && CheckWideRegisterIndex(dec_insn.vC);
+      result = result && CheckWideRegisterIndex(inst->VRegC());
       break;
   }
   switch (inst->GetVerifyExtraFlags()) {
@@ -709,11 +708,14 @@
     case Instruction::kVerifySwitchTargets:
       result = result && CheckSwitchTargets(code_offset);
       break;
-    case Instruction::kVerifyVarArg:
-      result = result && CheckVarArgRegs(dec_insn.vA, dec_insn.arg);
+    case Instruction::kVerifyVarArg: {
+      uint32_t args[Instruction::kMaxVarArgRegs];
+      inst->GetVarArgs(args);
+      result = result && CheckVarArgRegs(inst->VRegA(), args);
       break;
+    }
     case Instruction::kVerifyVarArgRange:
-      result = result && CheckVarArgRangeRegs(dec_insn.vA, dec_insn.vC);
+      result = result && CheckVarArgRangeRegs(inst->VRegA(), inst->VRegC());
       break;
     case Instruction::kVerifyError:
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected opcode " << inst->Name();
@@ -1009,7 +1011,7 @@
 }
 
 bool MethodVerifier::CheckVarArgRegs(uint32_t vA, uint32_t arg[]) {
-  if (vA > 5) {
+  if (vA > Instruction::kMaxVarArgRegs) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid arg count (" << vA << ") in non-range invoke)";
     return false;
   }
@@ -3075,7 +3077,7 @@
   size_t params_size = params == NULL ? 0 : params->Size();
   uint32_t arg[5];
   if (!is_range) {
-    inst->GetArgs(arg);
+    inst->GetVarArgs(arg);
   }
   for (size_t param_index = 0; param_index < params_size; param_index++) {
     if (actual_args >= expected_args) {
@@ -3189,7 +3191,7 @@
   size_t params_size = params == NULL ? 0 : params->Size();
   uint32_t arg[5];
   if (!is_range) {
-    inst->GetArgs(arg);
+    inst->GetVarArgs(arg);
   }
   size_t actual_args = 1;
   for (size_t param_index = 0; param_index < params_size; param_index++) {
@@ -3255,7 +3257,7 @@
       uint32_t arg_count = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
       uint32_t arg[5];
       if (!is_range) {
-        inst->GetArgs(arg);
+        inst->GetVarArgs(arg);
       }
       for (size_t ui = 0; ui < arg_count; ui++) {
         uint32_t get_reg = is_range ? inst->VRegC_3rc() + ui : arg[ui];
diff --git a/test/run-all-tests b/test/run-all-tests
index a6675df..3a991e9 100755
--- a/test/run-all-tests
+++ b/test/run-all-tests
@@ -35,6 +35,7 @@
 
 run_args=""
 usage="no"
+sequental="no"
 
 while true; do
     if [ "x$1" = "x--host" ]; then
@@ -70,6 +71,12 @@
     elif [ "x$1" = "x--help" ]; then
         usage="yes"
         shift
+    elif [ "x$1" = "x--seq" ]; then
+        sequental="yes"
+        shift
+    elif [ "x$1" = "x-O" ]; then
+        run_args="${run_args} -O"
+        shift
     elif expr "x$1" : "x--" >/dev/null 2>&1; then
         echo "unknown $0 option: $1" 1>&2
         usage="yes"
@@ -89,34 +96,55 @@
              "further documentation:"
         echo "    --debug --dev --host --interpreter --jvm --no-optimize"
         echo "    --no-verify -O --update --valgrind --zygote"
+        echo "  Specific Runtime Options:"
+        echo "    --seq                Run tests one-by-one, avoiding failures caused by busy CPU"
     ) 1>&2
     exit 1
 fi
 
-# start all the tests
-i=0
-for test_name in *; do
-  if [ -d "$test_name" -a -r "$test_name" -a -r "$test_name/info.txt" ]; then
-    ./run-test ${run_args} "$test_name" &
-    test_pids[i]=$!
-    test_names[test_pids[i]]="$test_name"
-    let i+=1
-  fi
-done
+if [ "$sequental" == "yes" ]; then
+  i=0
+  for test_name in *; do
+    if [ -d "$test_name" -a -r "$test_name" -a -r "$test_name/info.txt" ]; then
+      ./run-test ${run_args} "$test_name"
+      RES=$?
+      test_pids[i]=i
+      test_names[test_pids[i]]="$test_name"
+      if [ "$RES" != "0" ]; then
+        let failure_count+=1
+        failed_test_names="$failed_test_names ${test_names[i]}"
+      else
+        let succeeded_count+=1
+      fi
+      let i+=1
+    fi
+  done
+else
+  # start all the tests
+  i=0
+  for test_name in *; do
+    if [ -d "$test_name" -a -r "$test_name" -a -r "$test_name/info.txt" ]; then
+      ./run-test ${run_args} "$test_name" &
+      test_pids[i]=$!
+      test_names[test_pids[i]]="$test_name"
+      let i+=1
+    fi
+  done
 
-# wait for all the tests, collecting the failures
-failure_count=0
-succeeded_count=0
-failed_test_names=""
-for pid in ${test_pids[@]}; do
-  wait $pid
-  if [ "$?" != "0" ]; then
-    let failure_count+=1
-    failed_test_names="$failed_test_names ${test_names[$pid]}[pid=$pid]"
-  else
-    let succeeded_count+=1
-  fi
-done
+  # wait for all the tests, collecting the failures
+  failure_count=0
+  succeeded_count=0
+  failed_test_names=""
+  for pid in ${test_pids[@]}; do
+    wait $pid
+    if [ "$?" != "0" ]; then
+      let failure_count+=1
+      failed_test_names="$failed_test_names ${test_names[$pid]}[pid=$pid]"
+    else
+      let succeeded_count+=1
+    fi
+  done
+fi
 
 echo "succeeded tests: $succeeded_count"
 echo "failed tests: $failure_count"
diff --git a/test/run-test b/test/run-test
index 6e59641..1c5904f 100755
--- a/test/run-test
+++ b/test/run-test
@@ -33,7 +33,7 @@
 progdir=`pwd`
 prog="${progdir}"/`basename "${prog}"`
 test_dir="test-$$"
-tmp_dir="/tmp/${test_dir}"
+tmp_dir="/tmp/$USER/${test_dir}"
 
 export JAVA="java"
 export JAVAC="javac -g"
@@ -165,6 +165,7 @@
         break
     fi
 done
+mkdir -p $tmp_dir
 
 if [ ! "$runtime" = "jvm" ]; then
   run_args="${run_args} --lib $lib"
@@ -356,7 +357,7 @@
     cd "$oldwd"
     rm -rf "$tmp_dir"
     if [ "$target_mode" = "yes" -a "$build_exit" = "0" ]; then
-        adb shell rm -r $DEX_LOCATION
+        adb shell rm -rf $DEX_LOCATION
     fi
     exit 0
 fi