Instruction set features for ARM64, MIPS and X86.

Also, refactor how feature strings are handled so they are additive or
subtractive.
Make MIPS have features for FPU 32-bit and MIPS v2. Use in the quick compiler
rather than #ifdefs that wouldn't have worked in cross-compilation.
Add SIMD features for x86/x86-64 proposed in:
  https://android-review.googlesource.com/#/c/112370/

Bug: 18056890

Change-Id: Ic88ff84a714926bd277beb74a430c5c7d5ed7666
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index a8041c5..991aaca 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -70,8 +70,15 @@
 
 RUNTIME_GTEST_COMMON_SRC_FILES := \
   runtime/arch/arch_test.cc \
+  runtime/arch/instruction_set_test.cc \
+  runtime/arch/instruction_set_features_test.cc \
   runtime/arch/memcmp16_test.cc \
   runtime/arch/stub_test.cc \
+  runtime/arch/arm/instruction_set_features_arm_test.cc \
+  runtime/arch/arm64/instruction_set_features_arm64_test.cc \
+  runtime/arch/mips/instruction_set_features_mips_test.cc \
+  runtime/arch/x86/instruction_set_features_x86_test.cc \
+  runtime/arch/x86_64/instruction_set_features_x86_64_test.cc \
   runtime/barrier_test.cc \
   runtime/base/bit_field_test.cc \
   runtime/base/bit_vector_test.cc \
@@ -109,7 +116,6 @@
   runtime/handle_scope_test.cc \
   runtime/indenter_test.cc \
   runtime/indirect_reference_table_test.cc \
-  runtime/instruction_set_test.cc \
   runtime/intern_table_test.cc \
   runtime/interpreter/safe_math_test.cc \
   runtime/java_vm_ext_test.cc \
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 9fe3807..e8b363b 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -23,6 +23,13 @@
 
 include art/build/Android.common_build.mk
 
+ifeq ($(DEX2OAT_HOST_INSTRUCTION_SET_FEATURES),)
+  DEX2OAT_HOST_INSTRUCTION_SET_FEATURES := default
+endif
+ifeq ($($(HOST_2ND_ARCH_VAR_PREFIX)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES),)
+  $(HOST_2ND_ARCH_VAR_PREFIX)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES := default
+endif
+
 # Use dex2oat debug version for better error reporting
 # $(1): compiler - default, optimizing or interpreter.
 # $(2): pic/no-pic
@@ -91,7 +98,7 @@
 	  $$(addprefix --dex-location=,$$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
 	  --oat-location=$$(PRIVATE_CORE_OAT_NAME) --image=$$(PRIVATE_CORE_IMG_NAME) \
 	  --base=$$(LIBART_IMG_HOST_BASE_ADDRESS) --instruction-set=$$($(3)ART_HOST_ARCH) \
-	  --instruction-set-features=$$($(3)HOST_INSTRUCTION_SET_FEATURES) \
+	  --instruction-set-features=$$($(3)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES) \
 	  --host --android-root=$$(HOST_OUT) --include-patch-information \
 	  $$(PRIVATE_CORE_COMPILE_OPTIONS)
 
@@ -194,7 +201,7 @@
 	  $$(addprefix --dex-location=,$$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
 	  --oat-location=$$(PRIVATE_CORE_OAT_NAME) --image=$$(PRIVATE_CORE_IMG_NAME) \
 	  --base=$$(LIBART_IMG_TARGET_BASE_ADDRESS) --instruction-set=$$($(3)TARGET_ARCH) \
-	  --instruction-set-features=$$($(3)TARGET_INSTRUCTION_SET_FEATURES) \
+	  --instruction-set-features=$$($(3)DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) \
 	  --android-root=$$(PRODUCT_OUT)/system --include-patch-information \
 	  $$(PRIVATE_CORE_COMPILE_OPTIONS) || (rm $$(PRIVATE_CORE_OAT_NAME); exit 1)
 
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 085d169..97387a1 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -16,6 +16,7 @@
 
 #include "common_compiler_test.h"
 
+#include "arch/instruction_set_features.h"
 #include "class_linker.h"
 #include "compiled_method.h"
 #include "dex/quick_compiler_callbacks.h"
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 0361cd1..7f76eef 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -21,7 +21,7 @@
 #include <string>
 #include <vector>
 
-#include "instruction_set.h"
+#include "arch/instruction_set.h"
 #include "method_reference.h"
 #include "utils.h"
 #include "utils/array_ref.h"
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 0d5aa90..0c7812b 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-#include "arm_lir.h"
 #include "codegen_arm.h"
+
+#include "arch/arm/instruction_set_features_arm.h"
+#include "arm_lir.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
 
@@ -974,7 +976,7 @@
   LIR* load;
   if (is_volatile == kVolatile && (size == k64 || size == kDouble) &&
       !cu_->compiler_driver->GetInstructionSetFeatures()->
-          AsArmInstructionSetFeatures()->HasLpae()) {
+          AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()) {
     // Only 64-bit load needs special handling.
     // If the cpu supports LPAE, aligned LDRD is atomic - fall through to LoadBaseDisp().
     DCHECK(!r_dest.IsFloat());  // See RegClassForFieldLoadSave().
@@ -1104,7 +1106,7 @@
   LIR* store;
   if (is_volatile == kVolatile && (size == k64 || size == kDouble) &&
       !cu_->compiler_driver->GetInstructionSetFeatures()->
-          AsArmInstructionSetFeatures()->HasLpae()) {
+          AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()) {
     // Only 64-bit store needs special handling.
     // If the cpu supports LPAE, aligned STRD is atomic - fall through to StoreBaseDisp().
     // Use STREXD for the atomic store. (Expect displacement > 0, don't optimize for == 0.)
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 7674e46..98ddc36 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "arch/arm/instruction_set_features_arm.h"
 #include "dex/compiler_ir.h"
 #include "dex/compiler_internals.h"
 #include "dex/quick/arm/arm_lir.h"
diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc
index ca71c30..0d1d9bf 100644
--- a/compiler/dex/quick/mips/assemble_mips.cc
+++ b/compiler/dex/quick/mips/assemble_mips.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_mips.h"
+
 #include "dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index 01784e2..ed73ef0 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -17,6 +17,7 @@
 /* This file contains codegen for the Mips ISA */
 
 #include "codegen_mips.h"
+
 #include "dex/quick/mir_to_lir-inl.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
diff --git a/compiler/dex/quick/mips/fp_mips.cc b/compiler/dex/quick/mips/fp_mips.cc
index 0a7aa99..495d85e 100644
--- a/compiler/dex/quick/mips/fp_mips.cc
+++ b/compiler/dex/quick/mips/fp_mips.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_mips.h"
+
 #include "dex/quick/mir_to_lir-inl.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "mips_lir.h"
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index d58ddb0..fb47238 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -17,6 +17,7 @@
 /* This file contains codegen for the Mips ISA */
 
 #include "codegen_mips.h"
+
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
 #include "entrypoints/quick/quick_entrypoints.h"
diff --git a/compiler/dex/quick/mips/mips_lir.h b/compiler/dex/quick/mips/mips_lir.h
index 3615916..3df8f2e 100644
--- a/compiler/dex/quick/mips/mips_lir.h
+++ b/compiler/dex/quick/mips/mips_lir.h
@@ -214,44 +214,43 @@
   rF30 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 30,
   rF31 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 31,
 #endif
-#if (FR_BIT == 0)
-  rD0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
-  rD1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
-  rD2  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
-  rD3  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
-  rD4  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
-  rD5  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
-  rD6  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
-  rD7  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+  // Double precision registers where the FPU is in 32-bit mode.
+  rD0_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
+  rD1_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
+  rD2_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
+  rD3_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
+  rD4_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
+  rD5_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+  rD6_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+  rD7_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
 #if 0  // TODO: expand resource mask to enable use of all MIPS fp registers.
-  rD8  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
-  rD9  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
-  rD10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
-  rD11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
-  rD12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
-  rD13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
-  rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
-  rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
+  rD8_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
+  rD9_fr0  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
+  rD10_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
+  rD11_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
+  rD12_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
+  rD13_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
+  rD14_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
+  rD15_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
 #endif
-#else
-  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,
+  // Double precision registers where the FPU is in 64-bit mode.
+  rD0_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  0,
+  rD1_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  1,
+  rD2_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  2,
+  rD3_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  3,
+  rD4_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  4,
+  rD5_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  5,
+  rD6_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  6,
+  rD7_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  7,
 #if 0  // TODO: expand resource mask to enable use of all MIPS fp registers.
-  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
+  rD8_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  8,
+  rD9_fr1  = RegStorage::k64BitSolo | RegStorage::kFloatingPoint |  9,
+  rD10_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+  rD11_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
+  rD12_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+  rD13_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
+  rD14_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+  rD15_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
 #endif
 };
 
@@ -309,14 +308,23 @@
 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);
+constexpr RegStorage rs_rD0_fr0(RegStorage::kValid | rD0_fr0);
+constexpr RegStorage rs_rD1_fr0(RegStorage::kValid | rD1_fr0);
+constexpr RegStorage rs_rD2_fr0(RegStorage::kValid | rD2_fr0);
+constexpr RegStorage rs_rD3_fr0(RegStorage::kValid | rD3_fr0);
+constexpr RegStorage rs_rD4_fr0(RegStorage::kValid | rD4_fr0);
+constexpr RegStorage rs_rD5_fr0(RegStorage::kValid | rD5_fr0);
+constexpr RegStorage rs_rD6_fr0(RegStorage::kValid | rD6_fr0);
+constexpr RegStorage rs_rD7_fr0(RegStorage::kValid | rD7_fr0);
+
+constexpr RegStorage rs_rD0_fr1(RegStorage::kValid | rD0_fr1);
+constexpr RegStorage rs_rD1_fr1(RegStorage::kValid | rD1_fr1);
+constexpr RegStorage rs_rD2_fr1(RegStorage::kValid | rD2_fr1);
+constexpr RegStorage rs_rD3_fr1(RegStorage::kValid | rD3_fr1);
+constexpr RegStorage rs_rD4_fr1(RegStorage::kValid | rD4_fr1);
+constexpr RegStorage rs_rD5_fr1(RegStorage::kValid | rD5_fr1);
+constexpr RegStorage rs_rD6_fr1(RegStorage::kValid | rD6_fr1);
+constexpr RegStorage rs_rD7_fr1(RegStorage::kValid | rD7_fr1);
 
 // TODO: reduce/eliminate use of these.
 #define rMIPS_SUSPEND rS0
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 4a340ec..185112d 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -20,6 +20,7 @@
 
 #include <string>
 
+#include "arch/mips/instruction_set_features_mips.h"
 #include "backend_mips.h"
 #include "dex/compiler_internals.h"
 #include "dex/quick/mir_to_lir-inl.h"
@@ -34,8 +35,12 @@
 static constexpr 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 constexpr RegStorage dp_regs_arr[] =
-    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+static constexpr RegStorage dp_fr0_regs_arr[] =
+    {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
+     rs_rD7_fr0};
+static constexpr RegStorage dp_fr1_regs_arr[] =
+    {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
+     rs_rD7_fr1};
 static constexpr RegStorage reserved_regs_arr[] =
     {rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
 static constexpr RegStorage core_temps_arr[] =
@@ -44,17 +49,23 @@
 static constexpr 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 constexpr RegStorage dp_temps_arr[] =
-    {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+static constexpr RegStorage dp_fr0_temps_arr[] =
+    {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
+     rs_rD7_fr0};
+static constexpr RegStorage dp_fr1_temps_arr[] =
+    {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
+     rs_rD7_fr1};
 
 static constexpr ArrayRef<const RegStorage> empty_pool;
 static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
 static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
-static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr0_regs(dp_fr0_regs_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr1_regs(dp_fr1_regs_arr);
 static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
 static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
 static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
-static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr0_temps(dp_fr0_temps_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr1_temps(dp_fr1_temps_arr);
 
 RegLocation MipsMir2Lir::LocCReturn() {
   return mips_loc_c_return;
@@ -129,14 +140,17 @@
  * Decode the register id.
  */
 ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
-  return reg.IsDouble()
-      /* Each double register is equal to a pair of single-precision FP registers */
-#if (FR_BIT == 0)
-      ? ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0)
-#else
-      ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0)
-#endif
-      : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kMipsFPReg0 : reg.GetRegNum());
+  if (reg.IsDouble()) {
+    if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
+      return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
+    } else {
+      return ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0);
+    }
+  } else if (reg.IsSingle()) {
+    return ResourceMask::Bit(reg.GetRegNum() + kMipsFPReg0);
+  } else {
+    return ResourceMask::Bit(reg.GetRegNum());
+  }
 }
 
 ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
@@ -382,14 +396,25 @@
   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);
+  if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
+    Clobber(rs_rD0_fr0);
+    Clobber(rs_rD1_fr0);
+    Clobber(rs_rD2_fr0);
+    Clobber(rs_rD3_fr0);
+    Clobber(rs_rD4_fr0);
+    Clobber(rs_rD5_fr0);
+    Clobber(rs_rD6_fr0);
+    Clobber(rs_rD7_fr0);
+  } else {
+    Clobber(rs_rD0_fr1);
+    Clobber(rs_rD1_fr1);
+    Clobber(rs_rD2_fr1);
+    Clobber(rs_rD3_fr1);
+    Clobber(rs_rD4_fr1);
+    Clobber(rs_rD5_fr1);
+    Clobber(rs_rD6_fr1);
+    Clobber(rs_rD7_fr1);
+  }
 }
 
 RegLocation MipsMir2Lir::GetReturnWideAlt() {
@@ -420,33 +445,37 @@
   FreeTemp(rs_rMIPS_ARG3);
 }
 
-bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
-  UNUSED(barrier_kind);
-#if ANDROID_SMP != 0
-  NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
-  return true;
-#else
-  return false;
-#endif
+bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind ATTRIBUTE_UNUSED) {
+  if (cu_->GetInstructionSetFeatures()->IsSmp()) {
+    NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
+    return true;
+  } else {
+    return false;
+  }
 }
 
 void MipsMir2Lir::CompilerInitializeRegAlloc() {
+  const bool fpu_is_32bit =
+      cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint();
   reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
-                                            sp_regs, dp_regs,
+                                            sp_regs,
+                                            fpu_is_32bit ? dp_fr0_regs : dp_fr1_regs,
                                             reserved_regs, empty_pool /* reserved64 */,
                                             core_temps, empty_pool /* core64_temps */,
-                                            sp_temps, dp_temps));
+                                            sp_temps,
+                                            fpu_is_32bit ? dp_fr0_temps : dp_fr1_temps));
 
   // Target-specific adjustments.
 
   // Alias single precision floats to appropriate half of overlapping double.
   for (RegisterInfo* info : reg_pool_->sp_regs_) {
     int sp_reg_num = info->GetReg().GetRegNum();
-#if (FR_BIT == 0)
-    int dp_reg_num = sp_reg_num & ~1;
-#else
-    int dp_reg_num = sp_reg_num >> 1;
-#endif
+    int dp_reg_num;
+    if (fpu_is_32bit) {
+      dp_reg_num = sp_reg_num & ~1;
+    } else {
+      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.
@@ -465,11 +494,11 @@
   // TODO: adjust when we roll to hard float calling convention.
   reg_pool_->next_core_reg_ = 2;
   reg_pool_->next_sp_reg_ = 2;
-#if (FR_BIT == 0)
-  reg_pool_->next_dp_reg_ = 2;
-#else
-  reg_pool_->next_dp_reg_ = 1;
-#endif
+  if (fpu_is_32bit) {
+    reg_pool_->next_dp_reg_ = 2;
+  } else {
+    reg_pool_->next_dp_reg_ = 1;
+  }
 }
 
 /*
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index a7dc84f..18f1cde 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -15,6 +15,8 @@
  */
 
 #include "codegen_mips.h"
+
+#include "arch/mips/instruction_set_features_mips.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
 #include "mips_lir.h"
@@ -304,20 +306,22 @@
     case kOpXor:
       return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
     case kOp2Byte:
-#if __mips_isa_rev >= 2
-      res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
-#else
-      res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
-      OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
-#endif
+      if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
+          ->IsMipsIsaRevGreaterThanEqual2()) {
+        res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
+      } else {
+        res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
+        OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
+      }
       return res;
     case kOp2Short:
-#if __mips_isa_rev >= 2
-      res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
-#else
-      res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
-      OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
-#endif
+      if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
+          ->IsMipsIsaRevGreaterThanEqual2()) {
+        res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
+      } else {
+        res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
+        OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
+      }
       return res;
     case kOp2Char:
        return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index bacc6d2..13ebc1e 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -17,7 +17,7 @@
 #ifndef ART_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
 #define ART_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
 
-#include "invoke_type.h"
+#include "arch/instruction_set.h"
 #include "compiled_method.h"
 #include "dex/compiler_enums.h"
 #include "dex/compiler_ir.h"
@@ -26,9 +26,9 @@
 #include "dex/backend.h"
 #include "dex/quick/resource_mask.h"
 #include "driver/compiler_driver.h"
-#include "instruction_set.h"
-#include "leb128.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "invoke_type.h"
+#include "leb128.h"
 #include "safe_map.h"
 #include "utils/array_ref.h"
 #include "utils/arena_allocator.h"
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ddb2342..437a1a9 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/mutex.h"
 #include "base/timing_logger.h"
 #include "class_reference.h"
@@ -28,7 +29,6 @@
 #include "compiler.h"
 #include "dex_file.h"
 #include "driver/compiler_options.h"
-#include "instruction_set.h"
 #include "invoke_type.h"
 #include "method_reference.h"
 #include "mirror/class.h"  // For mirror::Class::Status.
@@ -51,6 +51,7 @@
 class DexCompilationUnit;
 class DexFileToMethodInlinerMap;
 struct InlineIGetIPutData;
+class InstructionSetFeatures;
 class OatWriter;
 class ParallelCompilationManager;
 class ScopedObjectAccess;
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 7f30565..273b62d 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -17,12 +17,12 @@
 #ifndef ART_COMPILER_ELF_BUILDER_H_
 #define ART_COMPILER_ELF_BUILDER_H_
 
+#include "arch/instruction_set.h"
 #include "base/stl_util.h"
 #include "base/value_object.h"
 #include "buffered_output_stream.h"
 #include "elf_utils.h"
 #include "file_output_stream.h"
-#include "instruction_set.h"
 
 namespace art {
 
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index c384c57..ce4ed6d 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "arch/instruction_set_features.h"
 #include "class_linker.h"
 #include "common_compiler_test.h"
 #include "compiler.h"
@@ -97,7 +98,7 @@
 
   std::string error_msg;
   std::unique_ptr<const InstructionSetFeatures> insn_features(
-      InstructionSetFeatures::FromFeatureString(insn_set, "default", &error_msg));
+      InstructionSetFeatures::FromVariant(insn_set, "default", &error_msg));
   ASSERT_TRUE(insn_features.get() != nullptr) << error_msg;
   compiler_options_.reset(new CompilerOptions);
   verification_results_.reset(new VerificationResults(compiler_options_.get()));
@@ -198,7 +199,7 @@
     InstructionSet insn_set = kX86;
     std::string error_msg;
     std::unique_ptr<const InstructionSetFeatures> insn_features(
-        InstructionSetFeatures::FromFeatureString(insn_set, "default", &error_msg));
+        InstructionSetFeatures::FromVariant(insn_set, "default", &error_msg));
     ASSERT_TRUE(insn_features.get() != nullptr) << error_msg;
     std::vector<const DexFile*> dex_files;
     uint32_t image_file_location_oat_checksum = 0;
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index ac4fc67..63bf96c 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -17,9 +17,9 @@
 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
 
+#include "arch/instruction_set.h"
 #include "base/bit_field.h"
 #include "globals.h"
-#include "instruction_set.h"
 #include "locations.h"
 #include "memory_region.h"
 #include "nodes.h"
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 9752b1d..fee3ea6 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -16,6 +16,7 @@
 
 #include <functional>
 
+#include "arch/instruction_set.h"
 #include "base/macros.h"
 #include "builder.h"
 #include "code_generator_arm.h"
@@ -25,7 +26,6 @@
 #include "common_compiler_test.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
-#include "instruction_set.h"
 #include "nodes.h"
 #include "optimizing_unit_test.h"
 #include "prepare_for_register_allocation.h"
@@ -39,7 +39,7 @@
 
 class InternalCodeAllocator : public CodeAllocator {
  public:
-  InternalCodeAllocator() { }
+  InternalCodeAllocator() : size_(0) { }
 
   virtual uint8_t* Allocate(size_t size) {
     size_ = size;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index ad7e98d..67711e3 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -19,16 +19,16 @@
 
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "arm/constants_arm.h"
-#include "mips/constants_mips.h"
-#include "x86/constants_x86.h"
-#include "x86_64/constants_x86_64.h"
-#include "instruction_set.h"
 #include "managed_register.h"
 #include "memory_region.h"
+#include "mips/constants_mips.h"
 #include "offsets.h"
+#include "x86/constants_x86.h"
+#include "x86_64/constants_x86_64.h"
 
 namespace art {
 
diff --git a/compiler/utils/stack_checks.h b/compiler/utils/stack_checks.h
index e762f7d..c348f2c 100644
--- a/compiler/utils/stack_checks.h
+++ b/compiler/utils/stack_checks.h
@@ -17,7 +17,7 @@
 #ifndef ART_COMPILER_UTILS_STACK_CHECKS_H_
 #define ART_COMPILER_UTILS_STACK_CHECKS_H_
 
-#include "instruction_set.h"
+#include "arch/instruction_set.h"
 
 namespace art {
 
@@ -34,8 +34,7 @@
 // stack overflow check on method entry.
 //
 // A frame is considered large when it's above kLargeFrameSize.
-static inline bool FrameNeedsStackCheck(size_t size, InstructionSet isa) {
-  UNUSED(isa);
+static inline bool FrameNeedsStackCheck(size_t size, InstructionSet isa ATTRIBUTE_UNUSED) {
   return size >= kLargeFrameSize;
 }
 
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 47b492a..2d2a82e 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -31,8 +31,9 @@
 #endif
 
 #define ATRACE_TAG ATRACE_TAG_DALVIK
-#include "cutils/trace.h"
+#include <cutils/trace.h>
 
+#include "arch/instruction_set_features.h"
 #include "base/dumpable.h"
 #include "base/stl_util.h"
 #include "base/stringpiece.h"
@@ -577,11 +578,18 @@
         }
       } else if (option.starts_with("--instruction-set-features=")) {
         StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
-        instruction_set_features_.reset(
-            InstructionSetFeatures::FromFeatureString(instruction_set_, str.as_string(),
-                                                      &error_msg));
         if (instruction_set_features_.get() == nullptr) {
-          Usage("%s", error_msg.c_str());
+          instruction_set_features_.reset(
+              InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg));
+          if (instruction_set_features_.get() == nullptr) {
+            Usage("Problem initializing default instruction set features variant: %s",
+                  error_msg.c_str());
+          }
+        }
+        instruction_set_features_.reset(
+            instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg));
+        if (instruction_set_features_.get() == nullptr) {
+          Usage("Error parsing '%s': %s", option.data(), error_msg.c_str());
         }
       } else if (option.starts_with("--compiler-backend=")) {
         StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
@@ -802,7 +810,11 @@
     // instruction set.
     if (instruction_set_features_.get() == nullptr) {
       instruction_set_features_.reset(
-          InstructionSetFeatures::FromFeatureString(instruction_set_, "default", &error_msg));
+          InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg));
+      if (instruction_set_features_.get() == nullptr) {
+        Usage("Problem initializing default instruction set features variant: %s",
+              error_msg.c_str());
+      }
     }
 
     if (instruction_set_ == kRuntimeISA) {
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 487f433..9cd631c 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -21,8 +21,8 @@
 
 #include <iosfwd>
 
+#include "arch/instruction_set.h"
 #include "base/macros.h"
-#include "instruction_set.h"
 
 namespace art {
 
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index f1f1a56..d6309f7 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -23,6 +23,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include "arch/instruction_set_features.h"
 #include "base/stringpiece.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 75160ca..6b6d11e 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -34,12 +34,8 @@
 #include "elf_file_impl.h"
 #include "gc/space/image_space.h"
 #include "image.h"
-#include "instruction_set.h"
-#include "mirror/art_field.h"
 #include "mirror/art_field-inl.h"
-#include "mirror/art_method.h"
 #include "mirror/art_method-inl.h"
-#include "mirror/object.h"
 #include "mirror/object-inl.h"
 #include "mirror/reference.h"
 #include "noop_compiler_callbacks.h"
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index 0ceef64..5a3545b 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -17,14 +17,14 @@
 #ifndef ART_PATCHOAT_PATCHOAT_H_
 #define ART_PATCHOAT_PATCHOAT_H_
 
+#include "arch/instruction_set.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "instruction_set.h"
-#include "os.h"
 #include "elf_file.h"
 #include "elf_utils.h"
 #include "gc/accounting/space_bitmap.h"
 #include "gc/heap.h"
+#include "os.h"
 #include "utils.h"
 
 namespace art {
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 082e8dd..8ced4d9 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -73,7 +73,6 @@
   hprof/hprof.cc \
   image.cc \
   indirect_reference_table.cc \
-  instruction_set.cc \
   instrumentation.cc \
   intern_table.cc \
   interpreter/interpreter.cc \
@@ -165,11 +164,18 @@
 
 LIBART_COMMON_SRC_FILES += \
   arch/context.cc \
+  arch/instruction_set.cc \
+  arch/instruction_set_features.cc \
   arch/memcmp16.cc \
+  arch/arm/instruction_set_features_arm.cc \
   arch/arm/registers_arm.cc \
+  arch/arm64/instruction_set_features_arm64.cc \
   arch/arm64/registers_arm64.cc \
-  arch/x86/registers_x86.cc \
+  arch/mips/instruction_set_features_mips.cc \
   arch/mips/registers_mips.cc \
+  arch/x86/instruction_set_features_x86.cc \
+  arch/x86/registers_x86.cc \
+  arch/x86_64/registers_x86_64.cc \
   entrypoints/entrypoint_utils.cc \
   entrypoints/interpreter/interpreter_entrypoints.cc \
   entrypoints/jni/jni_entrypoints.cc \
@@ -216,7 +222,7 @@
 LIBART_TARGET_SRC_FILES_arm := \
   arch/arm/context_arm.cc.arm \
   arch/arm/entrypoints_init_arm.cc \
-  arch/arm/instruction_set_features_arm.S \
+  arch/arm/instruction_set_features_assembly_tests.S \
   arch/arm/jni_entrypoints_arm.S \
   arch/arm/memcmp16_arm.S \
   arch/arm/portable_entrypoints_arm.S \
@@ -292,7 +298,7 @@
   $(LIBART_SRC_FILES_x86_64)
 
 LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \
-  arch/x86_64/registers_x86_64.h \
+  arch/instruction_set.h \
   base/allocator.h \
   base/mutex.h \
   debugger.h \
@@ -306,7 +312,6 @@
   gc/heap.h \
   instrumentation.h \
   indirect_reference_table.h \
-  instruction_set.h \
   invoke_type.h \
   jdwp/jdwp.h \
   jdwp/jdwp_constants.h \
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index 480190a..325b283 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -23,7 +23,6 @@
 #include "globals.h"
 #include "base/logging.h"
 #include "base/hex_dump.h"
-#include "instruction_set.h"
 #include "mirror/art_method.h"
 #include "mirror/art_method-inl.h"
 #include "thread.h"
diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc
new file mode 100644
index 0000000..f49c037
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm.cc
@@ -0,0 +1,297 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features_arm.h"
+
+#if defined(HAVE_ANDROID_OS) && defined(__arm__)
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#endif
+
+#include "signal.h"
+#include <fstream>
+
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+#if defined(__arm__)
+extern "C" bool artCheckForArmSdivInstruction();
+#endif
+
+namespace art {
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromVariant(
+    const std::string& variant, std::string* error_msg) {
+  // Assume all ARM processors are SMP.
+  // TODO: set the SMP support based on variant.
+  const bool smp = true;
+
+  // Look for variants that have divide support.
+  static const char* arm_variants_with_div[] = {
+          "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", "cortex-a53", "cortex-a57",
+          "cortex-m3", "cortex-m4", "cortex-r4", "cortex-r5",
+          "cyclone", "denver", "krait", "swift"};
+
+  bool has_div = FindVariantInArray(arm_variants_with_div, arraysize(arm_variants_with_div),
+                                    variant);
+
+  // Look for variants that have LPAE support.
+  static const char* arm_variants_with_lpae[] = {
+      "cortex-a7", "cortex-a15", "krait", "denver"
+  };
+  bool has_lpae = FindVariantInArray(arm_variants_with_lpae, arraysize(arm_variants_with_lpae),
+                                     variant);
+
+  if (has_div == false && has_lpae == false) {
+    // Avoid unsupported variants.
+    static const char* unsupported_arm_variants[] = {
+        // ARM processors that aren't ARMv7 compatible aren't supported.
+        "arm2", "arm250", "arm3", "arm6", "arm60", "arm600", "arm610", "arm620",
+        "cortex-m0", "cortex-m0plus", "cortex-m1",
+        "fa526", "fa626", "fa606te", "fa626te", "fmp626", "fa726te",
+        "iwmmxt", "iwmmxt2",
+        "strongarm", "strongarm110", "strongarm1100", "strongarm1110",
+        "xscale"
+    };
+    if (FindVariantInArray(unsupported_arm_variants, arraysize(unsupported_arm_variants),
+                           variant)) {
+      *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", variant.c_str());
+      return nullptr;
+    }
+    // Warn if the variant is unknown.
+    // TODO: some of the variants below may have feature support, but that support is currently
+    //       unknown so we'll choose conservative (sub-optimal) defaults without warning.
+    // TODO: some of the architectures may not support all features required by ART and should be
+    //       moved to unsupported_arm_variants[] above.
+    static const char* arm_variants_without_known_features[] = {
+        "default",
+        "arm7", "arm7m", "arm7d", "arm7dm", "arm7di", "arm7dmi", "arm70", "arm700", "arm700i",
+        "arm710", "arm710c", "arm7100", "arm720", "arm7500", "arm7500fe", "arm7tdmi", "arm7tdmi-s",
+        "arm710t", "arm720t", "arm740t",
+        "arm8", "arm810",
+        "arm9", "arm9e", "arm920", "arm920t", "arm922t", "arm946e-s", "arm966e-s", "arm968e-s",
+        "arm926ej-s", "arm940t", "arm9tdmi",
+        "arm10tdmi", "arm1020t", "arm1026ej-s", "arm10e", "arm1020e", "arm1022e",
+        "arm1136j-s", "arm1136jf-s",
+        "arm1156t2-s", "arm1156t2f-s", "arm1176jz-s", "arm1176jzf-s",
+        "cortex-a5", "cortex-a8", "cortex-a9", "cortex-a9-mp", "cortex-r4f",
+        "marvell-pj4", "mpcore", "mpcorenovfp"
+    };
+    if (!FindVariantInArray(arm_variants_without_known_features,
+                            arraysize(arm_variants_without_known_features),
+                            variant)) {
+      LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant
+          << ") using conservative defaults";
+    }
+  }
+  return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  bool has_div = (bitmap & kDivBitfield) != 0;
+  bool has_atomic_ldrd_strd = (bitmap & kAtomicLdrdStrdBitfield) != 0;
+  return new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCppDefines() {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+  const bool smp = false;
+#else
+  const bool smp = true;
+#endif
+
+#if defined(__ARM_ARCH_EXT_IDIV__)
+  const bool has_div = true;
+#else
+  const bool has_div = false;
+#endif
+#if defined(__ARM_FEATURE_LPAE)
+  const bool has_lpae = true;
+#else
+  const bool has_lpae = false;
+#endif
+  return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCpuInfo() {
+  // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
+  // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
+  bool smp = false;
+  bool has_lpae = false;
+  bool has_div = false;
+
+  std::ifstream in("/proc/cpuinfo");
+  if (!in.fail()) {
+    while (!in.eof()) {
+      std::string line;
+      std::getline(in, line);
+      if (!in.eof()) {
+        LOG(INFO) << "cpuinfo line: " << line;
+        if (line.find("Features") != std::string::npos) {
+          LOG(INFO) << "found features";
+          if (line.find("idivt") != std::string::npos) {
+            // We always expect both ARM and Thumb divide instructions to be available or not
+            // available.
+            CHECK_NE(line.find("idiva"), std::string::npos);
+            has_div = true;
+          }
+          if (line.find("lpae") != std::string::npos) {
+            has_lpae = true;
+          }
+        } else if (line.find("processor") != std::string::npos &&
+            line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromHwcap() {
+  bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1;
+
+  bool has_div = false;
+  bool has_lpae = false;
+
+#if defined(HAVE_ANDROID_OS) && defined(__arm__)
+  uint64_t hwcaps = getauxval(AT_HWCAP);
+  LOG(INFO) << "hwcaps=" << hwcaps;
+  if ((hwcaps & HWCAP_IDIVT) != 0) {
+    // We always expect both ARM and Thumb divide instructions to be available or not
+    // available.
+    CHECK_NE(hwcaps & HWCAP_IDIVA, 0U);
+    has_div = true;
+  }
+  if ((hwcaps & HWCAP_LPAE) != 0) {
+    has_lpae = true;
+  }
+#endif
+
+  return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+// A signal handler called by a fault for an illegal instruction.  We record the fact in r0
+// and then increment the PC in the signal context to return to the next instruction.  We know the
+// instruction is an sdiv (4 bytes long).
+static void bad_divide_inst_handle(int signo ATTRIBUTE_UNUSED, siginfo_t* si ATTRIBUTE_UNUSED,
+                                   void* data) {
+#if defined(__arm__)
+  struct ucontext *uc = (struct ucontext *)data;
+  struct sigcontext *sc = &uc->uc_mcontext;
+  sc->arm_r0 = 0;     // Set R0 to #0 to signal error.
+  sc->arm_pc += 4;    // Skip offending instruction.
+#else
+  UNUSED(data);
+#endif
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromAssembly() {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+  const bool smp = false;
+#else
+  const bool smp = true;
+#endif
+  // See if have a sdiv instruction.  Register a signal handler and try to execute an sdiv
+  // instruction.  If we get a SIGILL then it's not supported.
+  struct sigaction sa, osa;
+  sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
+  sa.sa_sigaction = bad_divide_inst_handle;
+  sigaction(SIGILL, &sa, &osa);
+
+  bool has_div = false;
+#if defined(__arm__)
+  if (artCheckForArmSdivInstruction()) {
+    has_div = true;
+  }
+#endif
+
+  // Restore the signal handler.
+  sigaction(SIGILL, &osa, nullptr);
+
+  // Use compile time features to "detect" LPAE support.
+  // TODO: write an assembly LPAE support test.
+#if defined(__ARM_FEATURE_LPAE)
+  const bool has_lpae = true;
+#else
+  const bool has_lpae = false;
+#endif
+  return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (kArm != other->GetInstructionSet()) {
+    return false;
+  }
+  const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
+  return IsSmp() == other_as_arm->IsSmp() &&
+      has_div_ == other_as_arm->has_div_ &&
+      has_atomic_ldrd_strd_ == other_as_arm->has_atomic_ldrd_strd_;
+}
+
+uint32_t ArmInstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0) |
+      (has_div_ ? kDivBitfield : 0) |
+      (has_atomic_ldrd_strd_ ? kAtomicLdrdStrdBitfield : 0);
+}
+
+std::string ArmInstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  if (has_div_) {
+    result += ",div";
+  } else {
+    result += ",-div";
+  }
+  if (has_atomic_ldrd_strd_) {
+    result += ",atomic_ldrd_strd";
+  } else {
+    result += ",-atomic_ldrd_strd";
+  }
+  return result;
+}
+
+const InstructionSetFeatures* ArmInstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+  bool has_atomic_ldrd_strd = has_atomic_ldrd_strd_;
+  bool has_div = has_div_;
+  for (auto i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "div") {
+      has_div = true;
+    } else if (feature == "-div") {
+      has_div = false;
+    } else if (feature == "atomic_ldrd_strd") {
+      has_atomic_ldrd_strd = true;
+    } else if (feature == "-atomic_ldrd_strd") {
+      has_atomic_ldrd_strd = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
+  }
+  return new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd);
+}
+
+}  // namespace art
diff --git a/runtime/arch/arm/instruction_set_features_arm.h b/runtime/arch/arm/instruction_set_features_arm.h
new file mode 100644
index 0000000..221bf1f
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm.h
@@ -0,0 +1,99 @@
+/*
+ * 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_ARCH_ARM_INSTRUCTION_SET_FEATURES_ARM_H_
+#define ART_RUNTIME_ARCH_ARM_INSTRUCTION_SET_FEATURES_ARM_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the ARM architecture.
+class ArmInstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "krait" or "cortex-a15" and create InstructionSetFeatures.
+  static const ArmInstructionSetFeatures* FromVariant(const std::string& variant,
+                                                      std::string* error_msg);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const ArmInstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const ArmInstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const ArmInstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const ArmInstructionSetFeatures* FromHwcap();
+
+  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+  static const ArmInstructionSetFeatures* FromAssembly();
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kArm;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  // Return a string of the form "div,lpae" or "none".
+  std::string GetFeatureString() const OVERRIDE;
+
+  // Is the divide instruction feature enabled?
+  bool HasDivideInstruction() const {
+      return has_div_;
+  }
+
+  // Are the ldrd and strd instructions atomic? This is commonly true when the Large Physical
+  // Address Extension (LPAE) is present.
+  bool HasAtomicLdrdAndStrd() const {
+    return has_atomic_ldrd_strd_;
+  }
+
+  virtual ~ArmInstructionSetFeatures() {}
+
+ protected:
+  // Parse a vector of the form "div", "lpae" adding these to a new ArmInstructionSetFeatures.
+  const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE;
+
+ private:
+  ArmInstructionSetFeatures(bool smp, bool has_div, bool has_atomic_ldrd_strd)
+      : InstructionSetFeatures(smp),
+        has_div_(has_div), has_atomic_ldrd_strd_(has_atomic_ldrd_strd) {
+  }
+
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+    kDivBitfield = 2,
+    kAtomicLdrdStrdBitfield = 4,
+  };
+
+  const bool has_div_;
+  const bool has_atomic_ldrd_strd_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArmInstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_ARM_INSTRUCTION_SET_FEATURES_ARM_H_
diff --git a/runtime/arch/arm/instruction_set_features_arm_test.cc b/runtime/arch/arm/instruction_set_features_arm_test.cc
new file mode 100644
index 0000000..44b1640
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm_test.cc
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features_arm.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+TEST(ArmInstructionSetFeaturesTest, ArmFeaturesFromVariant) {
+  // Build features for a 32-bit ARM krait processor.
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> krait_features(
+      InstructionSetFeatures::FromVariant(kArm, "krait", &error_msg));
+  ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
+
+  ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
+  EXPECT_TRUE(krait_features->Equals(krait_features.get()));
+  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str());
+  EXPECT_EQ(krait_features->AsBitmap(), 7U);
+
+  // Build features for a 32-bit ARM denver processor.
+  std::unique_ptr<const InstructionSetFeatures> denver_features(
+      InstructionSetFeatures::FromVariant(kArm, "denver", &error_msg));
+  ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
+
+  EXPECT_TRUE(denver_features->Equals(denver_features.get()));
+  EXPECT_TRUE(denver_features->Equals(krait_features.get()));
+  EXPECT_TRUE(krait_features->Equals(denver_features.get()));
+  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str());
+  EXPECT_EQ(denver_features->AsBitmap(), 7U);
+
+  // Build features for a 32-bit ARMv7 processor.
+  std::unique_ptr<const InstructionSetFeatures> arm7_features(
+      InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
+  ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
+
+  EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
+  EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
+  EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
+  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,-div,-atomic_ldrd_strd", arm7_features->GetFeatureString().c_str());
+  EXPECT_EQ(arm7_features->AsBitmap(), 1U);
+
+  // ARM6 is not a supported architecture variant.
+  std::unique_ptr<const InstructionSetFeatures> arm6_features(
+      InstructionSetFeatures::FromVariant(kArm, "arm6", &error_msg));
+  EXPECT_TRUE(arm6_features.get() == nullptr);
+  EXPECT_NE(error_msg.size(), 0U);
+}
+
+TEST(ArmInstructionSetFeaturesTest, ArmAddFeaturesFromString) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> base_features(
+      InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
+  ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
+
+  // Build features for a 32-bit ARM with LPAE and div processor.
+  std::unique_ptr<const InstructionSetFeatures> krait_features(
+      base_features->AddFeaturesFromString("atomic_ldrd_strd,div", &error_msg));
+  ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
+
+  ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
+  EXPECT_TRUE(krait_features->Equals(krait_features.get()));
+  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str());
+  EXPECT_EQ(krait_features->AsBitmap(), 7U);
+
+  // Build features for a 32-bit ARM processor with LPAE and div flipped.
+  std::unique_ptr<const InstructionSetFeatures> denver_features(
+      base_features->AddFeaturesFromString("div,atomic_ldrd_strd", &error_msg));
+  ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
+
+  EXPECT_TRUE(denver_features->Equals(denver_features.get()));
+  EXPECT_TRUE(denver_features->Equals(krait_features.get()));
+  EXPECT_TRUE(krait_features->Equals(denver_features.get()));
+  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str());
+  EXPECT_EQ(denver_features->AsBitmap(), 7U);
+
+  // Build features for a 32-bit default ARM processor.
+  std::unique_ptr<const InstructionSetFeatures> arm7_features(
+      base_features->AddFeaturesFromString("default", &error_msg));
+  ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
+
+  EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
+  EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
+  EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
+  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+  EXPECT_STREQ("smp,-div,-atomic_ldrd_strd", arm7_features->GetFeatureString().c_str());
+  EXPECT_EQ(arm7_features->AsBitmap(), 1U);
+}
+
+}  // namespace art
diff --git a/runtime/arch/arm/instruction_set_features_arm.S b/runtime/arch/arm/instruction_set_features_assembly_tests.S
similarity index 94%
rename from runtime/arch/arm/instruction_set_features_arm.S
rename to runtime/arch/arm/instruction_set_features_assembly_tests.S
index c26f2cd..c1086df 100644
--- a/runtime/arch/arm/instruction_set_features_arm.S
+++ b/runtime/arch/arm/instruction_set_features_assembly_tests.S
@@ -23,7 +23,7 @@
 // caller must arrange for the signal handler to set the r0
 // register to 0 and move the pc forward by 4 bytes (to skip
 // the invalid instruction).
-ENTRY artCheckForARMSDIVInstruction
+ENTRY artCheckForArmSdivInstruction
   mov r1,#1
   // depending on the architecture, the assembler will not allow an
   // sdiv instruction, so we will have to output the bytes directly.
@@ -35,4 +35,4 @@
   // It will have 0 otherwise (set by the signal handler)
   // the value is just returned from this function.
   bx lr
-END artCheckForARMSDIVInstruction
+END artCheckForArmSdivInstruction
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc
new file mode 100644
index 0000000..18536ed
--- /dev/null
+++ b/runtime/arch/arm64/instruction_set_features_arm64.cc
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features_arm64.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+namespace art {
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromVariant(
+    const std::string& variant ATTRIBUTE_UNUSED, std::string* error_msg ATTRIBUTE_UNUSED) {
+  if (variant != "default") {
+    std::ostringstream os;
+    os << "Unexpected CPU variant for Arm64: " << variant;
+    *error_msg = os.str();
+    return nullptr;
+  }
+  const bool smp = true;  // Conservative default.
+  const bool is_a53 = true;  // Pessimistically assume all ARM64s are A53s.
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  bool is_a53 = (bitmap & kA53Bitfield) != 0;
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromCppDefines() {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+  const bool smp = false;
+#else
+  const bool smp = true;
+#endif
+
+  const bool is_a53 = true;  // Pessimistically assume all ARM64s are A53s.
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromCpuInfo() {
+  // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
+  // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
+  bool smp = false;
+  const bool is_a53 = true;  // Conservative default.
+
+  std::ifstream in("/proc/cpuinfo");
+  if (!in.fail()) {
+    while (!in.eof()) {
+      std::string line;
+      std::getline(in, line);
+      if (!in.eof()) {
+        LOG(INFO) << "cpuinfo line: " << line;
+        if (line.find("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromHwcap() {
+  bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1;
+  const bool is_a53 = true;  // Pessimistically assume all ARM64s are A53s.
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromAssembly() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+bool Arm64InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (kArm64 != other->GetInstructionSet()) {
+    return false;
+  }
+  const Arm64InstructionSetFeatures* other_as_arm = other->AsArm64InstructionSetFeatures();
+  return fix_cortex_a53_835769_ == other_as_arm->fix_cortex_a53_835769_;
+}
+
+uint32_t Arm64InstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0) | (fix_cortex_a53_835769_ ? kA53Bitfield : 0);
+}
+
+std::string Arm64InstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  if (fix_cortex_a53_835769_) {
+    result += ",a53";
+  } else {
+    result += ",-a53";
+  }
+  return result;
+}
+
+const InstructionSetFeatures* Arm64InstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+  bool is_a53 = fix_cortex_a53_835769_;
+  for (auto i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "a53") {
+      is_a53 = true;
+    } else if (feature == "-a53") {
+      is_a53 = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
+  }
+  return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+}  // namespace art
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.h b/runtime/arch/arm64/instruction_set_features_arm64.h
new file mode 100644
index 0000000..ee41536
--- /dev/null
+++ b/runtime/arch/arm64/instruction_set_features_arm64.h
@@ -0,0 +1,90 @@
+/*
+ * 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_ARCH_ARM64_INSTRUCTION_SET_FEATURES_ARM64_H_
+#define ART_RUNTIME_ARCH_ARM64_INSTRUCTION_SET_FEATURES_ARM64_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the ARM64 architecture.
+class Arm64InstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "krait" or "cortex-a15" and create InstructionSetFeatures.
+  static const Arm64InstructionSetFeatures* FromVariant(const std::string& variant,
+                                                        std::string* error_msg);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const Arm64InstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const Arm64InstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const Arm64InstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const Arm64InstructionSetFeatures* FromHwcap();
+
+  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+  static const Arm64InstructionSetFeatures* FromAssembly();
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kArm64;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  // Return a string of the form "a53" or "none".
+  std::string GetFeatureString() const OVERRIDE;
+
+  // Generate code addressing Cortex-A53 erratum 835769?
+  bool NeedFixCortexA53_835769() const {
+      return fix_cortex_a53_835769_;
+  }
+
+  virtual ~Arm64InstructionSetFeatures() {}
+
+ protected:
+  // Parse a vector of the form "a53" adding these to a new ArmInstructionSetFeatures.
+  const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE;
+
+ private:
+  explicit Arm64InstructionSetFeatures(bool smp, bool is_a53)
+      : InstructionSetFeatures(smp), fix_cortex_a53_835769_(is_a53) {
+  }
+
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+    kA53Bitfield = 2,
+  };
+
+  const bool fix_cortex_a53_835769_;
+
+  DISALLOW_COPY_AND_ASSIGN(Arm64InstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_ARM64_INSTRUCTION_SET_FEATURES_ARM64_H_
diff --git a/runtime/arch/arm64/instruction_set_features_arm64_test.cc b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
new file mode 100644
index 0000000..027e59c
--- /dev/null
+++ b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features_arm64.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(Arm64InstructionSetFeaturesTest, Arm64Features) {
+  // Build features for an ARM64 processor.
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> arm64_features(
+      InstructionSetFeatures::FromVariant(kArm64, "default", &error_msg));
+  ASSERT_TRUE(arm64_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(arm64_features->GetInstructionSet(), kArm64);
+  EXPECT_TRUE(arm64_features->Equals(arm64_features.get()));
+  EXPECT_STREQ("smp,a53", arm64_features->GetFeatureString().c_str());
+  EXPECT_EQ(arm64_features->AsBitmap(), 3U);
+}
+
+}  // namespace art
diff --git a/runtime/arch/instruction_set.cc b/runtime/arch/instruction_set.cc
new file mode 100644
index 0000000..92fa727
--- /dev/null
+++ b/runtime/arch/instruction_set.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set.h"
+
+#include "globals.h"
+
+namespace art {
+
+const char* GetInstructionSetString(const InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      return "arm";
+    case kArm64:
+      return "arm64";
+    case kX86:
+      return "x86";
+    case kX86_64:
+      return "x86_64";
+    case kMips:
+      return "mips";
+    case kMips64:
+      return "mips64";
+    case kNone:
+      return "none";
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+InstructionSet GetInstructionSetFromString(const char* isa_str) {
+  CHECK(isa_str != nullptr);
+
+  if (strcmp("arm", isa_str) == 0) {
+    return kArm;
+  } else if (strcmp("arm64", isa_str) == 0) {
+    return kArm64;
+  } else if (strcmp("x86", isa_str) == 0) {
+    return kX86;
+  } else if (strcmp("x86_64", isa_str) == 0) {
+    return kX86_64;
+  } else if (strcmp("mips", isa_str) == 0) {
+    return kMips;
+  } else if (strcmp("mips64", isa_str) == 0) {
+    return kMips;
+  }
+
+  return kNone;
+}
+
+size_t GetInstructionSetAlignment(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+      // Fall-through.
+    case kThumb2:
+      return kArmAlignment;
+    case kArm64:
+      return kArm64Alignment;
+    case kX86:
+      // Fall-through.
+    case kX86_64:
+      return kX86Alignment;
+    case kMips:
+      return kMipsAlignment;
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have alignment.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+static constexpr size_t kDefaultStackOverflowReservedBytes = 16 * KB;
+static constexpr size_t kMipsStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
+
+static constexpr size_t kArmStackOverflowReservedBytes =    8 * KB;
+static constexpr size_t kArm64StackOverflowReservedBytes =  8 * KB;
+static constexpr size_t kX86StackOverflowReservedBytes =    8 * KB;
+static constexpr size_t kX86_64StackOverflowReservedBytes = 8 * KB;
+
+size_t GetStackOverflowReservedBytes(InstructionSet isa) {
+  switch (isa) {
+    case kArm:      // Intentional fall-through.
+    case kThumb2:
+      return kArmStackOverflowReservedBytes;
+
+    case kArm64:
+      return kArm64StackOverflowReservedBytes;
+
+    case kMips:
+      return kMipsStackOverflowReservedBytes;
+
+    case kX86:
+      return kX86StackOverflowReservedBytes;
+
+    case kX86_64:
+      return kX86_64StackOverflowReservedBytes;
+
+    case kNone:
+      LOG(FATAL) << "kNone has no stack overflow size";
+      UNREACHABLE();
+
+    default:
+      LOG(FATAL) << "Unknown instruction set" << isa;
+      UNREACHABLE();
+  }
+}
+
+}  // namespace art
diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h
new file mode 100644
index 0000000..46622eb
--- /dev/null
+++ b/runtime/arch/instruction_set.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
+#define ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/logging.h"  // Logging is required for FATAL in the helper functions.
+
+namespace art {
+
+enum InstructionSet {
+  kNone,
+  kArm,
+  kArm64,
+  kThumb2,
+  kX86,
+  kX86_64,
+  kMips,
+  kMips64
+};
+std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
+
+#if defined(__arm__)
+static constexpr InstructionSet kRuntimeISA = kArm;
+#elif defined(__aarch64__)
+static constexpr InstructionSet kRuntimeISA = kArm64;
+#elif defined(__mips__)
+static constexpr InstructionSet kRuntimeISA = kMips;
+#elif defined(__i386__)
+static constexpr InstructionSet kRuntimeISA = kX86;
+#elif defined(__x86_64__)
+static constexpr InstructionSet kRuntimeISA = kX86_64;
+#else
+static constexpr InstructionSet kRuntimeISA = kNone;
+#endif
+
+// Architecture-specific pointer sizes
+static constexpr size_t kArmPointerSize = 4;
+static constexpr size_t kArm64PointerSize = 8;
+static constexpr size_t kMipsPointerSize = 4;
+static constexpr size_t kMips64PointerSize = 8;
+static constexpr size_t kX86PointerSize = 4;
+static constexpr size_t kX86_64PointerSize = 8;
+
+// ARM instruction alignment. ARM processors require code to be 4-byte aligned,
+// but ARM ELF requires 8..
+static constexpr size_t kArmAlignment = 8;
+
+// ARM64 instruction alignment. This is the recommended alignment for maximum performance.
+static constexpr size_t kArm64Alignment = 16;
+
+// MIPS instruction alignment.  MIPS processors require code to be 4-byte aligned.
+// TODO: Can this be 4?
+static constexpr size_t kMipsAlignment = 8;
+
+// X86 instruction alignment. This is the recommended alignment for maximum performance.
+static constexpr size_t kX86Alignment = 16;
+
+
+const char* GetInstructionSetString(InstructionSet isa);
+
+// Note: Returns kNone when the string cannot be parsed to a known value.
+InstructionSet GetInstructionSetFromString(const char* instruction_set);
+
+static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+      // Fall-through.
+    case kThumb2:
+      return kArmPointerSize;
+    case kArm64:
+      return kArm64PointerSize;
+    case kX86:
+      return kX86PointerSize;
+    case kX86_64:
+      return kX86_64PointerSize;
+    case kMips:
+      return kMipsPointerSize;
+    case kMips64:
+      return kMips64PointerSize;
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have pointer size.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+size_t GetInstructionSetAlignment(InstructionSet isa);
+
+static inline bool Is64BitInstructionSet(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+    case kX86:
+    case kMips:
+      return false;
+
+    case kArm64:
+    case kX86_64:
+    case kMips64:
+      return true;
+
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have bit width.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+      // Fall-through.
+    case kThumb2:
+      return 4;
+    case kArm64:
+      return 8;
+    case kX86:
+      return 4;
+    case kX86_64:
+      return 8;
+    case kMips:
+      return 4;
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have spills.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+      // Fall-through.
+    case kThumb2:
+      return 4;
+    case kArm64:
+      return 8;
+    case kX86:
+      return 8;
+    case kX86_64:
+      return 8;
+    case kMips:
+      return 4;
+    case kNone:
+      LOG(FATAL) << "ISA kNone does not have spills.";
+      UNREACHABLE();
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+size_t GetStackOverflowReservedBytes(InstructionSet isa);
+
+// The following definitions create return types for two word-sized entities that will be passed
+// in registers so that memory operations for the interface trampolines can be avoided. The entities
+// are the resolved method and the pointer to the code to be invoked.
+//
+// On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
+// uint64_t or long long int.
+//
+// On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two
+// size_t-sized values.
+//
+// We need two operations:
+//
+// 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
+//    GetTwoWordFailureValue() will return a value that has lower part == 0.
+//
+// 2) A value that combines two word-sized values.
+//    GetTwoWordSuccessValue() constructs this.
+//
+// IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
+//            that the object does not move or the value is updated. Simple use of this is NOT SAFE
+//            when the garbage collector can move objects concurrently. Ensure that required locks
+//            are held when using!
+
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+typedef uint64_t TwoWordReturn;
+
+// Encodes method_ptr==nullptr and code_ptr==nullptr
+static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
+  return 0;
+}
+
+// Use the lower 32b for the method pointer and the upper 32b for the code pointer.
+static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
+  static_assert(sizeof(uint32_t) == sizeof(uintptr_t), "Unexpected size difference");
+  uint32_t lo32 = lo;
+  uint64_t hi64 = static_cast<uint64_t>(hi);
+  return ((hi64 << 32) | lo32);
+}
+
+#elif defined(__x86_64__) || defined(__aarch64__)
+struct TwoWordReturn {
+  uintptr_t lo;
+  uintptr_t hi;
+};
+
+// Encodes method_ptr==nullptr. Leaves random value in code pointer.
+static inline TwoWordReturn GetTwoWordFailureValue() {
+  TwoWordReturn ret;
+  ret.lo = 0;
+  return ret;
+}
+
+// Write values into their respective members.
+static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
+  TwoWordReturn ret;
+  ret.lo = lo;
+  ret.hi = hi;
+  return ret;
+}
+#else
+#error "Unsupported architecture"
+#endif
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
diff --git a/runtime/arch/instruction_set_features.cc b/runtime/arch/instruction_set_features.cc
new file mode 100644
index 0000000..1072562
--- /dev/null
+++ b/runtime/arch/instruction_set_features.cc
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features.h"
+
+#include "base/casts.h"
+#include "utils.h"
+
+
+#include "arm/instruction_set_features_arm.h"
+#include "arm64/instruction_set_features_arm64.h"
+#include "mips/instruction_set_features_mips.h"
+#include "x86/instruction_set_features_x86.h"
+#include "x86_64/instruction_set_features_x86_64.h"
+
+namespace art {
+
+const InstructionSetFeatures* InstructionSetFeatures::FromVariant(InstructionSet isa,
+                                                                  const std::string& variant,
+                                                                  std::string* error_msg) {
+  const InstructionSetFeatures* result;
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << isa;
+      UNREACHABLE();
+  }
+  CHECK_EQ(result == nullptr, error_msg->size() != 0);
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromBitmap(InstructionSet isa,
+                                                                 uint32_t bitmap) {
+  const InstructionSetFeatures* result;
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromBitmap(bitmap);
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << isa;
+      UNREACHABLE();
+  }
+  CHECK_EQ(bitmap, result->AsBitmap());
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCppDefines() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromCppDefines();
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromCppDefines();
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromCppDefines();
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromCppDefines();
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromCppDefines();
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << kRuntimeISA;
+      UNREACHABLE();
+  }
+  return result;
+}
+
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCpuInfo() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromCpuInfo();
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromCpuInfo();
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromCpuInfo();
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromCpuInfo();
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromCpuInfo();
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << kRuntimeISA;
+      UNREACHABLE();
+  }
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromHwcap() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromHwcap();
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromHwcap();
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromHwcap();
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromHwcap();
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromHwcap();
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << kRuntimeISA;
+      UNREACHABLE();
+  }
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromAssembly() {
+  const InstructionSetFeatures* result;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      result = ArmInstructionSetFeatures::FromAssembly();
+      break;
+    case kArm64:
+      result = Arm64InstructionSetFeatures::FromAssembly();
+      break;
+    case kMips:
+      result = MipsInstructionSetFeatures::FromAssembly();
+      break;
+    case kX86:
+      result = X86InstructionSetFeatures::FromAssembly();
+      break;
+    case kX86_64:
+      result = X86_64InstructionSetFeatures::FromAssembly();
+      break;
+    default:
+      UNIMPLEMENTED(FATAL) << kRuntimeISA;
+      UNREACHABLE();
+  }
+  return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::AddFeaturesFromString(
+    const std::string& feature_list, std::string* error_msg) const {
+  if (feature_list.empty()) {
+    *error_msg = "No instruction set features specified";
+    return nullptr;
+  }
+  std::vector<std::string> features;
+  Split(feature_list, ',', &features);
+  bool smp = smp_;
+  bool use_default = false;  // Have we seen the 'default' feature?
+  bool first = false;  // Is this first feature?
+  for (auto it = features.begin(); it != features.end();) {
+    if (use_default) {
+      *error_msg = "Unexpected instruction set features after 'default'";
+      return nullptr;
+    }
+    std::string feature = Trim(*it);
+    bool erase = false;
+    if (feature == "default") {
+      if (!first) {
+        use_default = true;
+        erase = true;
+      } else {
+        *error_msg = "Unexpected instruction set features before 'default'";
+        return nullptr;
+      }
+    } else if (feature == "smp") {
+      smp = true;
+      erase = true;
+    } else if (feature == "-smp") {
+      smp = false;
+      erase = true;
+    }
+    // Erase the smp feature once processed.
+    if (!erase) {
+      ++it;
+    } else {
+      it = features.erase(it);
+    }
+    first = true;
+  }
+  DCHECK_EQ(use_default, features.empty());
+  return AddFeaturesFromSplitString(smp, features, error_msg);
+}
+
+const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
+  DCHECK_EQ(kArm, GetInstructionSet());
+  return down_cast<const ArmInstructionSetFeatures*>(this);
+}
+
+const Arm64InstructionSetFeatures* InstructionSetFeatures::AsArm64InstructionSetFeatures() const {
+  DCHECK_EQ(kArm64, GetInstructionSet());
+  return down_cast<const Arm64InstructionSetFeatures*>(this);
+}
+
+const MipsInstructionSetFeatures* InstructionSetFeatures::AsMipsInstructionSetFeatures() const {
+  DCHECK_EQ(kMips, GetInstructionSet());
+  return down_cast<const MipsInstructionSetFeatures*>(this);
+}
+
+const X86InstructionSetFeatures* InstructionSetFeatures::AsX86InstructionSetFeatures() const {
+  DCHECK(kX86 == GetInstructionSet() || kX86_64 == GetInstructionSet());
+  return down_cast<const X86InstructionSetFeatures*>(this);
+}
+
+const X86_64InstructionSetFeatures* InstructionSetFeatures::AsX86_64InstructionSetFeatures() const {
+  DCHECK_EQ(kX86_64, GetInstructionSet());
+  return down_cast<const X86_64InstructionSetFeatures*>(this);
+}
+
+bool InstructionSetFeatures::FindVariantInArray(const char* variants[], size_t num_variants,
+                                                const std::string& variant) {
+  const char** begin = variants;
+  const char** end = begin + num_variants;
+  return std::find(begin, end, variant) != end;
+}
+
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs) {
+  os << "ISA: " << rhs.GetInstructionSet() << " Feature string: " << rhs.GetFeatureString();
+  return os;
+}
+
+}  // namespace art
diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h
new file mode 100644
index 0000000..2c6e699
--- /dev/null
+++ b/runtime/arch/instruction_set_features.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
+#define ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
+
+#include <ostream>
+#include <vector>
+
+#include "base/macros.h"
+#include "instruction_set.h"
+
+namespace art {
+
+class ArmInstructionSetFeatures;
+class Arm64InstructionSetFeatures;
+class MipsInstructionSetFeatures;
+class X86InstructionSetFeatures;
+class X86_64InstructionSetFeatures;
+
+// Abstraction used to describe features of a different instruction sets.
+class InstructionSetFeatures {
+ public:
+  // Process a CPU variant string for the given ISA and create an InstructionSetFeatures.
+  static const InstructionSetFeatures* FromVariant(InstructionSet isa,
+                                                   const std::string& variant,
+                                                   std::string* error_msg);
+
+  // Parse a bitmap for the given isa and create an InstructionSetFeatures.
+  static const InstructionSetFeatures* FromBitmap(InstructionSet isa, uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features for kRuntimeISA.
+  static const InstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const InstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const InstructionSetFeatures* FromHwcap();
+
+  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+  static const InstructionSetFeatures* FromAssembly();
+
+  // Parse a string of the form "div,-atomic_ldrd_strd" adding and removing these features to
+  // create a new InstructionSetFeatures.
+  const InstructionSetFeatures* AddFeaturesFromString(const std::string& feature_list,
+                                                      std::string* error_msg) const WARN_UNUSED;
+
+  // Are these features the same as the other given features?
+  virtual bool Equals(const InstructionSetFeatures* other) const = 0;
+
+  // Return the ISA these features relate to.
+  virtual InstructionSet GetInstructionSet() const = 0;
+
+  // Return a bitmap that represents the features. ISA specific.
+  virtual uint32_t AsBitmap() const = 0;
+
+  // Return a string of the form "div,lpae" or "none".
+  virtual std::string GetFeatureString() const = 0;
+
+  // Does the instruction set variant require instructions for correctness with SMP?
+  bool IsSmp() const {
+    return smp_;
+  }
+
+  // Down cast this ArmInstructionFeatures.
+  const ArmInstructionSetFeatures* AsArmInstructionSetFeatures() const;
+
+  // Down cast this Arm64InstructionFeatures.
+  const Arm64InstructionSetFeatures* AsArm64InstructionSetFeatures() const;
+
+  // Down cast this MipsInstructionFeatures.
+  const MipsInstructionSetFeatures* AsMipsInstructionSetFeatures() const;
+
+  // Down cast this X86InstructionFeatures.
+  const X86InstructionSetFeatures* AsX86InstructionSetFeatures() const;
+
+  // Down cast this X86_64InstructionFeatures.
+  const X86_64InstructionSetFeatures* AsX86_64InstructionSetFeatures() const;
+
+  virtual ~InstructionSetFeatures() {}
+
+ protected:
+  explicit InstructionSetFeatures(bool smp) : smp_(smp) {}
+
+  // Returns true if variant appears in the array variants.
+  static bool FindVariantInArray(const char* variants[], size_t num_variants,
+                                 const std::string& variant);
+
+  // Add architecture specific features in sub-classes.
+  virtual const InstructionSetFeatures*
+      AddFeaturesFromSplitString(bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const = 0;
+
+ private:
+  const bool smp_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstructionSetFeatures);
+};
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc
new file mode 100644
index 0000000..83571cf
--- /dev/null
+++ b/runtime/arch/instruction_set_features_test.cc
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features.h"
+
+#include <gtest/gtest.h>
+
+#ifdef HAVE_ANDROID_OS
+#include "cutils/properties.h"
+#endif
+
+#include "base/stringprintf.h"
+
+namespace art {
+
+#ifdef HAVE_ANDROID_OS
+TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyVariant) {
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Read the features property.
+  std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
+  char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
+  if (property_get(key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
+    // Use features from property to build InstructionSetFeatures and check against build's
+    // features.
+    std::string error_msg;
+    std::unique_ptr<const InstructionSetFeatures> property_features(
+        InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
+    ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
+
+    EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
+      << "System property features: " << *property_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+  }
+}
+
+TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyString) {
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Read the features property.
+  std::string key = StringPrintf("dalvik.vm.isa.%s.features", GetInstructionSetString(kRuntimeISA));
+  char dex2oat_isa_features[PROPERTY_VALUE_MAX];
+  if (property_get(key.c_str(), dex2oat_isa_features, nullptr) > 0) {
+    // Use features from property to build InstructionSetFeatures and check against build's
+    // features.
+    std::string error_msg;
+    std::unique_ptr<const InstructionSetFeatures> base_features(
+        InstructionSetFeatures::FromVariant(kRuntimeISA, "default", &error_msg));
+    ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
+
+    std::unique_ptr<const InstructionSetFeatures> property_features(
+        base_features->AddFeaturesFromString(dex2oat_isa_features, &error_msg));
+    ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
+
+    EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
+      << "System property features: " << *property_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+  }
+}
+
+#if defined(__arm__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromCpuInfo) {
+  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST(InstructionSetFeaturesTest, FeaturesFromCpuInfo) {
+#endif
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Check we get the same instruction set features using /proc/cpuinfo.
+  std::unique_ptr<const InstructionSetFeatures> cpuinfo_features(
+      InstructionSetFeatures::FromCpuInfo());
+  EXPECT_TRUE(cpuinfo_features->Equals(instruction_set_features.get()))
+      << "CPU Info features: " << *cpuinfo_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+}
+#endif
+
+#ifndef HAVE_ANDROID_OS
+TEST(InstructionSetFeaturesTest, HostFeaturesFromCppDefines) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> default_features(
+      InstructionSetFeatures::FromVariant(kRuntimeISA, "default", &error_msg));
+  ASSERT_TRUE(error_msg.empty());
+
+  std::unique_ptr<const InstructionSetFeatures> cpp_features(
+      InstructionSetFeatures::FromCppDefines());
+  EXPECT_TRUE(default_features->Equals(cpp_features.get()))
+      << "Default variant features: " << *default_features.get()
+      << "\nFeatures from build: " << *cpp_features.get();
+}
+#endif
+
+#if defined(__arm__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromHwcap) {
+  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST(InstructionSetFeaturesTest, FeaturesFromHwcap) {
+#endif
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Check we get the same instruction set features using AT_HWCAP.
+  std::unique_ptr<const InstructionSetFeatures> hwcap_features(
+      InstructionSetFeatures::FromHwcap());
+  EXPECT_TRUE(hwcap_features->Equals(instruction_set_features.get()))
+      << "Hwcap features: " << *hwcap_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
+
+#if defined(__arm__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromAssembly) {
+  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST(InstructionSetFeaturesTest, FeaturesFromAssembly) {
+#endif
+  // Take the default set of instruction features from the build.
+  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+      InstructionSetFeatures::FromCppDefines());
+
+  // Check we get the same instruction set features using assembly tests.
+  std::unique_ptr<const InstructionSetFeatures> assembly_features(
+      InstructionSetFeatures::FromAssembly());
+  EXPECT_TRUE(assembly_features->Equals(instruction_set_features.get()))
+      << "Assembly features: " << *assembly_features.get()
+      << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
+}  // namespace art
diff --git a/runtime/arch/instruction_set_test.cc b/runtime/arch/instruction_set_test.cc
new file mode 100644
index 0000000..932ef32
--- /dev/null
+++ b/runtime/arch/instruction_set_test.cc
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set.h"
+
+#include <gtest/gtest.h>
+
+#include "base/stringprintf.h"
+
+namespace art {
+
+TEST(InstructionSetTest, GetInstructionSetFromString) {
+  EXPECT_EQ(kArm, GetInstructionSetFromString("arm"));
+  EXPECT_EQ(kArm64, GetInstructionSetFromString("arm64"));
+  EXPECT_EQ(kX86, GetInstructionSetFromString("x86"));
+  EXPECT_EQ(kX86_64, GetInstructionSetFromString("x86_64"));
+  EXPECT_EQ(kMips, GetInstructionSetFromString("mips"));
+  EXPECT_EQ(kNone, GetInstructionSetFromString("none"));
+  EXPECT_EQ(kNone, GetInstructionSetFromString("random-string"));
+}
+
+TEST(InstructionSetTest, GetInstructionSetString) {
+  EXPECT_STREQ("arm", GetInstructionSetString(kArm));
+  EXPECT_STREQ("arm", GetInstructionSetString(kThumb2));
+  EXPECT_STREQ("arm64", GetInstructionSetString(kArm64));
+  EXPECT_STREQ("x86", GetInstructionSetString(kX86));
+  EXPECT_STREQ("x86_64", GetInstructionSetString(kX86_64));
+  EXPECT_STREQ("mips", GetInstructionSetString(kMips));
+  EXPECT_STREQ("none", GetInstructionSetString(kNone));
+}
+
+TEST(InstructionSetTest, TestRoundTrip) {
+  EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA)));
+}
+
+TEST(InstructionSetTest, PointerSize) {
+  EXPECT_EQ(sizeof(void*), GetInstructionSetPointerSize(kRuntimeISA));
+}
+
+}  // namespace art
diff --git a/runtime/arch/mips/instruction_set_features_mips.cc b/runtime/arch/mips/instruction_set_features_mips.cc
new file mode 100644
index 0000000..efec993
--- /dev/null
+++ b/runtime/arch/mips/instruction_set_features_mips.cc
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features_mips.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+namespace art {
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromVariant(
+    const std::string& variant ATTRIBUTE_UNUSED, std::string* error_msg ATTRIBUTE_UNUSED) {
+  if (variant != "default") {
+    std::ostringstream os;
+    LOG(WARNING) << "Unexpected CPU variant for Mips using defaults: " << variant;
+  }
+  bool smp = true;  // Conservative default.
+  bool fpu_32bit = true;
+  bool mips_isa_gte2 = true;
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  bool fpu_32bit = (bitmap & kFpu32Bitfield) != 0;
+  bool mips_isa_gte2 = (bitmap & kIsaRevGte2Bitfield) != 0;
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromCppDefines() {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+  const bool smp = false;
+#else
+  const bool smp = true;
+#endif
+
+  // TODO: here we assume the FPU is always 32-bit.
+  const bool fpu_32bit = true;
+
+#if __mips_isa_rev >= 2
+  const bool mips_isa_gte2 = true;
+#else
+  const bool mips_isa_gte2 = false;
+#endif
+
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromCpuInfo() {
+  // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
+  // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
+  bool smp = false;
+
+  // TODO: here we assume the FPU is always 32-bit.
+  const bool fpu_32bit = true;
+
+  // TODO: here we assume all MIPS processors are >= v2.
+#if __mips_isa_rev >= 2
+  const bool mips_isa_gte2 = true;
+#else
+  const bool mips_isa_gte2 = false;
+#endif
+
+  std::ifstream in("/proc/cpuinfo");
+  if (!in.fail()) {
+    while (!in.eof()) {
+      std::string line;
+      std::getline(in, line);
+      if (!in.eof()) {
+        LOG(INFO) << "cpuinfo line: " << line;
+        if (line.find("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromHwcap() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromAssembly() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+bool MipsInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (kMips != other->GetInstructionSet()) {
+    return false;
+  }
+  const MipsInstructionSetFeatures* other_as_mips = other->AsMipsInstructionSetFeatures();
+  return (IsSmp() == other->IsSmp()) &&
+      (fpu_32bit_ == other_as_mips->fpu_32bit_) &&
+      (mips_isa_gte2_ == other_as_mips->mips_isa_gte2_);
+}
+
+uint32_t MipsInstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0) |
+      (fpu_32bit_ ? kFpu32Bitfield : 0) |
+      (mips_isa_gte2_ ? kIsaRevGte2Bitfield : 0);
+}
+
+std::string MipsInstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  if (fpu_32bit_) {
+    result += ",fpu32";
+  } else {
+    result += ",-fpu32";
+  }
+  if (mips_isa_gte2_) {
+    result += ",mips2";
+  } else {
+    result += ",-mips2";
+  }
+  return result;
+}
+
+const InstructionSetFeatures* MipsInstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+  bool fpu_32bit = fpu_32bit_;
+  bool mips_isa_gte2 = mips_isa_gte2_;
+  for (auto i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "fpu32") {
+      fpu_32bit = true;
+    } else if (feature == "-fpu32") {
+      fpu_32bit = false;
+    } else if (feature == "mips2") {
+      mips_isa_gte2 = true;
+    } else if (feature == "-mips2") {
+      mips_isa_gte2 = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
+  }
+  return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+}  // namespace art
diff --git a/runtime/arch/mips/instruction_set_features_mips.h b/runtime/arch/mips/instruction_set_features_mips.h
new file mode 100644
index 0000000..f7c64fe
--- /dev/null
+++ b/runtime/arch/mips/instruction_set_features_mips.h
@@ -0,0 +1,98 @@
+/*
+ * 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_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
+#define ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the MIPS architecture.
+class MipsInstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "r4000" and create InstructionSetFeatures.
+  static const MipsInstructionSetFeatures* FromVariant(const std::string& variant,
+                                                        std::string* error_msg);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const MipsInstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const MipsInstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const MipsInstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const MipsInstructionSetFeatures* FromHwcap();
+
+  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+  static const MipsInstructionSetFeatures* FromAssembly();
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kMips;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  std::string GetFeatureString() const OVERRIDE;
+
+  // Is this an ISA revision greater than 2 opening up new opcodes.
+  bool IsMipsIsaRevGreaterThanEqual2() const {
+    return mips_isa_gte2_;
+  }
+
+  // Floating point double registers are encoded differently based on whether the Status.FR bit is
+  // set. When the FR bit is 0 then the FPU is 32-bit, 1 its 64-bit. Return true if the code should
+  // be generated assuming Status.FR is 0.
+  bool Is32BitFloatingPoint() const {
+    return fpu_32bit_;
+  }
+
+  virtual ~MipsInstructionSetFeatures() {}
+
+ protected:
+  // Parse a vector of the form "fpu32", "mips2" adding these to a new MipsInstructionSetFeatures.
+  virtual const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE;
+
+ private:
+  MipsInstructionSetFeatures(bool smp, bool fpu_32bit, bool mips_isa_gte2)
+      : InstructionSetFeatures(smp), fpu_32bit_(fpu_32bit),  mips_isa_gte2_(mips_isa_gte2) {
+  }
+
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+    kFpu32Bitfield = 2,
+    kIsaRevGte2Bitfield = 4,
+  };
+
+  const bool fpu_32bit_;
+  const bool mips_isa_gte2_;
+
+  DISALLOW_COPY_AND_ASSIGN(MipsInstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
diff --git a/runtime/arch/mips/instruction_set_features_mips_test.cc b/runtime/arch/mips/instruction_set_features_mips_test.cc
new file mode 100644
index 0000000..9b81ce2
--- /dev/null
+++ b/runtime/arch/mips/instruction_set_features_mips_test.cc
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features_mips.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(MipsInstructionSetFeaturesTest, MipsFeatures) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> mips_features(
+      InstructionSetFeatures::FromVariant(kMips, "default", &error_msg));
+  ASSERT_TRUE(mips_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(mips_features->GetInstructionSet(), kMips);
+  EXPECT_TRUE(mips_features->Equals(mips_features.get()));
+  EXPECT_STREQ("smp,fpu32,mips2", mips_features->GetFeatureString().c_str());
+  EXPECT_EQ(mips_features->AsBitmap(), 7U);
+}
+
+}  // namespace art
diff --git a/runtime/arch/x86/instruction_set_features_x86.cc b/runtime/arch/x86/instruction_set_features_x86.cc
new file mode 100644
index 0000000..32cf909
--- /dev/null
+++ b/runtime/arch/x86/instruction_set_features_x86.cc
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features_x86.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "arch/x86_64/instruction_set_features_x86_64.h"
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+namespace art {
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromVariant(
+    const std::string& variant ATTRIBUTE_UNUSED, std::string* error_msg ATTRIBUTE_UNUSED,
+    bool x86_64) {
+  bool known_variant = false;
+  bool smp = true;  // Conservative default.
+  static const char* x86_variants_with_ssse3[] = {
+      "atom"
+  };
+  bool has_SSSE3 = FindVariantInArray(x86_variants_with_ssse3, arraysize(x86_variants_with_ssse3),
+                                      variant);
+  bool has_SSE4_1 = false;
+  bool has_SSE4_2 = false;
+  bool has_AVX = false;
+  bool has_AVX2 = false;
+  if (!known_variant && variant != "default") {
+    std::ostringstream os;
+    LOG(WARNING) << "Unexpected CPU variant for X86 using defaults: " << variant;
+  }
+
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromBitmap(uint32_t bitmap,
+                                                                       bool x86_64) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  bool has_SSSE3 = (bitmap & kSsse3Bitfield) != 0;
+  bool has_SSE4_1 = (bitmap & kSse4_1Bitfield) != 0;
+  bool has_SSE4_2 = (bitmap & kSse4_2Bitfield) != 0;
+  bool has_AVX = (bitmap & kAvxBitfield) != 0;
+  bool has_AVX2 = (bitmap & kAvxBitfield) != 0;
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromCppDefines(bool x86_64) {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+  const bool smp = false;
+#else
+  const bool smp = true;
+#endif
+
+#ifndef __SSSE3__
+  const bool has_SSSE3 = false;
+#else
+  const bool has_SSSE3 = true;
+#endif
+
+#ifndef __SSE4_1__
+  const bool has_SSE4_1 = false;
+#else
+  const bool has_SSE4_1 = true;
+#endif
+
+#ifndef __SSE4_2__
+  const bool has_SSE4_2 = false;
+#else
+  const bool has_SSE4_2 = true;
+#endif
+
+#ifndef __AVX__
+  const bool has_AVX = false;
+#else
+  const bool has_AVX = true;
+#endif
+
+#ifndef __AVX2__
+  const bool has_AVX2 = false;
+#else
+  const bool has_AVX2 = true;
+#endif
+
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromCpuInfo(bool x86_64) {
+  // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
+  // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
+  bool smp = false;
+  bool has_SSSE3 = false;
+  bool has_SSE4_1 = false;
+  bool has_SSE4_2 = false;
+  bool has_AVX = false;
+  bool has_AVX2 = false;
+
+  std::ifstream in("/proc/cpuinfo");
+  if (!in.fail()) {
+    while (!in.eof()) {
+      std::string line;
+      std::getline(in, line);
+      if (!in.eof()) {
+        LOG(INFO) << "cpuinfo line: " << line;
+        if (line.find("flags") != std::string::npos) {
+          LOG(INFO) << "found flags";
+          if (line.find("ssse3") != std::string::npos) {
+            has_SSSE3 = true;
+          }
+          if (line.find("sse4_1") != std::string::npos) {
+            has_SSE4_1 = true;
+          }
+          if (line.find("sse4_2") != std::string::npos) {
+            has_SSE4_2 = true;
+          }
+          if (line.find("avx") != std::string::npos) {
+            has_AVX = true;
+          }
+          if (line.find("avx2") != std::string::npos) {
+            has_AVX2 = true;
+          }
+        } else if (line.find("processor") != std::string::npos &&
+            line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromHwcap(bool x86_64) {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines(x86_64);
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromAssembly(bool x86_64) {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines(x86_64);
+}
+
+bool X86InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (GetInstructionSet() != other->GetInstructionSet()) {
+    return false;
+  }
+  const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures();
+  return (IsSmp() == other->IsSmp()) &&
+      (has_SSSE3_ == other_as_x86->has_SSSE3_) &&
+      (has_SSE4_1_ == other_as_x86->has_SSE4_1_) &&
+      (has_SSE4_2_ == other_as_x86->has_SSE4_2_) &&
+      (has_AVX_ == other_as_x86->has_AVX_) &&
+      (has_AVX2_ == other_as_x86->has_AVX2_);
+}
+
+uint32_t X86InstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0) |
+      (has_SSSE3_ ? kSsse3Bitfield : 0) |
+      (has_SSE4_1_ ? kSse4_1Bitfield : 0) |
+      (has_SSE4_2_ ? kSse4_2Bitfield : 0) |
+      (has_AVX_ ? kAvxBitfield : 0) |
+      (has_AVX2_ ? kAvx2Bitfield : 0);
+}
+
+std::string X86InstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  if (has_SSSE3_) {
+    result += ",ssse3";
+  } else {
+    result += ",-ssse3";
+  }
+  if (has_SSE4_1_) {
+    result += ",sse4.1";
+  } else {
+    result += ",-sse4.1";
+  }
+  if (has_SSE4_2_) {
+    result += ",sse4.2";
+  } else {
+    result += ",-sse4.2";
+  }
+  if (has_AVX_) {
+    result += ",avx";
+  } else {
+    result += ",-avx";
+  }
+  if (has_AVX2_) {
+    result += ",avx2";
+  } else {
+    result += ",-avx2";
+  }
+  return result;
+}
+
+const InstructionSetFeatures* X86InstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, bool x86_64,
+    std::string* error_msg) const {
+  bool has_SSSE3 = has_SSSE3_;
+  bool has_SSE4_1 = has_SSE4_1_;
+  bool has_SSE4_2 = has_SSE4_2_;
+  bool has_AVX = has_AVX_;
+  bool has_AVX2 = has_AVX2_;
+  for (auto i = features.begin(); i != features.end(); i++) {
+    std::string feature = Trim(*i);
+    if (feature == "ssse3") {
+      has_SSSE3 = true;
+    } else if (feature == "-ssse3") {
+      has_SSSE3 = false;
+    } else if (feature == "sse4.1") {
+      has_SSE4_1 = true;
+    } else if (feature == "-sse4.1") {
+      has_SSE4_1 = false;
+    } else if (feature == "sse4.2") {
+      has_SSE4_2 = true;
+    } else if (feature == "-sse4.2") {
+      has_SSE4_2 = false;
+    } else if (feature == "avx") {
+      has_AVX = true;
+    } else if (feature == "-avx") {
+      has_AVX = false;
+    } else if (feature == "avx2") {
+      has_AVX2 = true;
+    } else if (feature == "-avx2") {
+      has_AVX2 = false;
+    } else {
+      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+      return nullptr;
+    }
+  }
+  if (x86_64) {
+    return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  } else {
+    return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+                                            has_AVX2);
+  }
+}
+
+}  // namespace art
diff --git a/runtime/arch/x86/instruction_set_features_x86.h b/runtime/arch/x86/instruction_set_features_x86.h
new file mode 100644
index 0000000..926fabb
--- /dev/null
+++ b/runtime/arch/x86/instruction_set_features_x86.h
@@ -0,0 +1,101 @@
+/*
+ * 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_ARCH_X86_INSTRUCTION_SET_FEATURES_X86_H_
+#define ART_RUNTIME_ARCH_X86_INSTRUCTION_SET_FEATURES_X86_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the X86 architecture.
+class X86InstructionSetFeatures : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "atom" or "nehalem" and create InstructionSetFeatures.
+  static const X86InstructionSetFeatures* FromVariant(const std::string& variant,
+                                                        std::string* error_msg,
+                                                        bool x86_64 = false);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const X86InstructionSetFeatures* FromBitmap(uint32_t bitmap, bool x86_64 = false);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const X86InstructionSetFeatures* FromCppDefines(bool x86_64 = false);
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const X86InstructionSetFeatures* FromCpuInfo(bool x86_64 = false);
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const X86InstructionSetFeatures* FromHwcap(bool x86_64 = false);
+
+  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+  static const X86InstructionSetFeatures* FromAssembly(bool x86_64 = false);
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  virtual InstructionSet GetInstructionSet() const OVERRIDE {
+    return kX86;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  std::string GetFeatureString() const OVERRIDE;
+
+  virtual ~X86InstructionSetFeatures() {}
+
+ protected:
+  // Parse a string of the form "ssse3" adding these to a new InstructionSetFeatures.
+  virtual const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE {
+    return AddFeaturesFromSplitString(smp, features, false, error_msg);
+  }
+
+  const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 bool x86_64, std::string* error_msg) const;
+
+  X86InstructionSetFeatures(bool smp, bool has_SSSE3, bool has_SSE4_1, bool has_SSE4_2,
+                            bool has_AVX, bool has_AVX2)
+      : InstructionSetFeatures(smp), has_SSSE3_(has_SSSE3), has_SSE4_1_(has_SSE4_1),
+        has_SSE4_2_(has_SSE4_2), has_AVX_(has_AVX), has_AVX2_(has_AVX2) {
+  }
+
+ private:
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+    kSsse3Bitfield = 2,
+    kSse4_1Bitfield = 4,
+    kSse4_2Bitfield = 8,
+    kAvxBitfield = 16,
+    kAvx2Bitfield = 32,
+  };
+
+  const bool has_SSSE3_;   // x86 128bit SIMD - Supplemental SSE.
+  const bool has_SSE4_1_;  // x86 128bit SIMD SSE4.1.
+  const bool has_SSE4_2_;  // x86 128bit SIMD SSE4.2.
+  const bool has_AVX_;     // x86 256bit SIMD AVX.
+  const bool has_AVX2_;    // x86 256bit SIMD AVX 2.0.
+
+  DISALLOW_COPY_AND_ASSIGN(X86InstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_X86_INSTRUCTION_SET_FEATURES_X86_H_
diff --git a/runtime/arch/x86/instruction_set_features_x86_test.cc b/runtime/arch/x86/instruction_set_features_x86_test.cc
new file mode 100644
index 0000000..d231beb
--- /dev/null
+++ b/runtime/arch/x86/instruction_set_features_x86_test.cc
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features_x86.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(X86InstructionSetFeaturesTest, X86FeaturesFromDefaultVariant) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> x86_features(
+      InstructionSetFeatures::FromVariant(kX86, "default", &error_msg));
+  ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
+  EXPECT_TRUE(x86_features->Equals(x86_features.get()));
+  EXPECT_STREQ("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2", x86_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_features->AsBitmap(), 1U);
+}
+
+TEST(X86InstructionSetFeaturesTest, X86FeaturesFromAtomVariant) {
+  // Build features for a 32-bit x86 atom processor.
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> x86_features(
+      InstructionSetFeatures::FromVariant(kX86, "atom", &error_msg));
+  ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
+  EXPECT_TRUE(x86_features->Equals(x86_features.get()));
+  EXPECT_STREQ("smp,ssse3,-sse4.1,-sse4.2,-avx,-avx2", x86_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_features->AsBitmap(), 3U);
+
+  // Build features for a 32-bit x86 default processor.
+  std::unique_ptr<const InstructionSetFeatures> x86_default_features(
+      InstructionSetFeatures::FromVariant(kX86, "default", &error_msg));
+  ASSERT_TRUE(x86_default_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(x86_default_features->GetInstructionSet(), kX86);
+  EXPECT_TRUE(x86_default_features->Equals(x86_default_features.get()));
+  EXPECT_STREQ("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2",
+               x86_default_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_default_features->AsBitmap(), 1U);
+
+  // Build features for a 64-bit x86-64 atom processor.
+  std::unique_ptr<const InstructionSetFeatures> x86_64_features(
+      InstructionSetFeatures::FromVariant(kX86_64, "atom", &error_msg));
+  ASSERT_TRUE(x86_64_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(x86_64_features->GetInstructionSet(), kX86_64);
+  EXPECT_TRUE(x86_64_features->Equals(x86_64_features.get()));
+  EXPECT_STREQ("smp,ssse3,-sse4.1,-sse4.2,-avx,-avx2",
+               x86_64_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_64_features->AsBitmap(), 3U);
+
+  EXPECT_FALSE(x86_64_features->Equals(x86_features.get()));
+  EXPECT_FALSE(x86_64_features->Equals(x86_default_features.get()));
+  EXPECT_FALSE(x86_features->Equals(x86_default_features.get()));
+}
+
+}  // namespace art
diff --git a/runtime/arch/x86_64/instruction_set_features_x86_64.h b/runtime/arch/x86_64/instruction_set_features_x86_64.h
new file mode 100644
index 0000000..3280177
--- /dev/null
+++ b/runtime/arch/x86_64/instruction_set_features_x86_64.h
@@ -0,0 +1,88 @@
+/*
+ * 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_ARCH_X86_64_INSTRUCTION_SET_FEATURES_X86_64_H_
+#define ART_RUNTIME_ARCH_X86_64_INSTRUCTION_SET_FEATURES_X86_64_H_
+
+#include "arch/x86/instruction_set_features_x86.h"
+
+namespace art {
+
+// Instruction set features relevant to the X86_64 architecture.
+class X86_64InstructionSetFeatures FINAL : public X86InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "atom" or "nehalem" and create InstructionSetFeatures.
+  static const X86_64InstructionSetFeatures* FromVariant(const std::string& variant,
+                                                         std::string* error_msg) {
+    return X86InstructionSetFeatures::FromVariant(variant, error_msg, true)
+        ->AsX86_64InstructionSetFeatures();
+  }
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const X86_64InstructionSetFeatures* FromBitmap(uint32_t bitmap) {
+    return X86InstructionSetFeatures::FromBitmap(bitmap, true)->AsX86_64InstructionSetFeatures();
+  }
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const X86_64InstructionSetFeatures* FromCppDefines() {
+    return X86InstructionSetFeatures::FromCppDefines(true)->AsX86_64InstructionSetFeatures();
+  }
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const X86_64InstructionSetFeatures* FromCpuInfo() {
+    return X86InstructionSetFeatures::FromCpuInfo(true)->AsX86_64InstructionSetFeatures();
+  }
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const X86_64InstructionSetFeatures* FromHwcap() {
+    return X86InstructionSetFeatures::FromHwcap(true)->AsX86_64InstructionSetFeatures();
+  }
+
+  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+  static const X86_64InstructionSetFeatures* FromAssembly() {
+    return X86InstructionSetFeatures::FromAssembly(true)->AsX86_64InstructionSetFeatures();
+  }
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kX86_64;
+  }
+
+  virtual ~X86_64InstructionSetFeatures() {}
+
+ protected:
+  // Parse a string of the form "ssse3" adding these to a new InstructionSetFeatures.
+  const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE {
+    return X86InstructionSetFeatures::AddFeaturesFromSplitString(smp, features, true, error_msg);
+  }
+
+ private:
+  X86_64InstructionSetFeatures(bool smp, bool has_SSSE3, bool has_SSE4_1, bool has_SSE4_2,
+                               bool has_AVX, bool has_AVX2)
+      : X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2) {
+  }
+
+  friend class X86InstructionSetFeatures;
+
+  DISALLOW_COPY_AND_ASSIGN(X86_64InstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_X86_64_INSTRUCTION_SET_FEATURES_X86_64_H_
diff --git a/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc b/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc
new file mode 100644
index 0000000..5171080
--- /dev/null
+++ b/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include "instruction_set_features_x86_64.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(X86_64InstructionSetFeaturesTest, X86Features) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> x86_64_features(
+      InstructionSetFeatures::FromVariant(kX86_64, "default", &error_msg));
+  ASSERT_TRUE(x86_64_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(x86_64_features->GetInstructionSet(), kX86_64);
+  EXPECT_TRUE(x86_64_features->Equals(x86_64_features.get()));
+  EXPECT_STREQ("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2",
+               x86_64_features->GetFeatureString().c_str());
+  EXPECT_EQ(x86_64_features->AsBitmap(), 1U);
+}
+
+}  // namespace art
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index b6cf921..37c5f9c 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "arch/instruction_set.h"
 #include "base/logging.h"
 #include "base/stringprintf.h"
 #include "base/stl_util.h"
@@ -29,7 +30,6 @@
 #include "elf_utils.h"
 #include "leb128.h"
 #include "utils.h"
-#include "instruction_set.h"
 
 namespace art {
 
diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h
index 49357ad..9ffd199 100644
--- a/runtime/entrypoints/quick/callee_save_frame.h
+++ b/runtime/entrypoints/quick/callee_save_frame.h
@@ -17,8 +17,8 @@
 #ifndef ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_
 #define ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_
 
+#include "arch/instruction_set.h"
 #include "base/mutex.h"
-#include "instruction_set.h"
 #include "runtime.h"
 #include "thread-inl.h"
 
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index f78273f..00f5cd5 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -16,7 +16,6 @@
 
 #include "callee_save_frame.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
-#include "instruction_set.h"
 #include "instrumentation.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 4f61707..c4bc969 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -21,7 +21,6 @@
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/card_table-inl.h"
-#include "instruction_set.h"
 #include "interpreter/interpreter.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index cf7352e..69a573e 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "allocator_type.h"
+#include "arch/instruction_set.h"
 #include "atomic.h"
 #include "base/timing_logger.h"
 #include "gc/accounting/atomic_stack.h"
@@ -32,7 +33,6 @@
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 #include "globals.h"
-#include "instruction_set.h"
 #include "jni.h"
 #include "object_callbacks.h"
 #include "offsets.h"
diff --git a/runtime/instruction_set.cc b/runtime/instruction_set.cc
deleted file mode 100644
index e165a75..0000000
--- a/runtime/instruction_set.cc
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "instruction_set.h"
-
-#include <signal.h>
-#include <fstream>
-
-#include "base/casts.h"
-#include "base/stringprintf.h"
-#include "utils.h"
-
-namespace art {
-
-const char* GetInstructionSetString(const InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-    case kThumb2:
-      return "arm";
-    case kArm64:
-      return "arm64";
-    case kX86:
-      return "x86";
-    case kX86_64:
-      return "x86_64";
-    case kMips:
-      return "mips";
-    case kNone:
-      return "none";
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      UNREACHABLE();
-  }
-}
-
-InstructionSet GetInstructionSetFromString(const char* isa_str) {
-  CHECK(isa_str != nullptr);
-
-  if (strcmp("arm", isa_str) == 0) {
-    return kArm;
-  } else if (strcmp("arm64", isa_str) == 0) {
-    return kArm64;
-  } else if (strcmp("x86", isa_str) == 0) {
-    return kX86;
-  } else if (strcmp("x86_64", isa_str) == 0) {
-    return kX86_64;
-  } else if (strcmp("mips", isa_str) == 0) {
-    return kMips;
-  }
-
-  return kNone;
-}
-
-size_t GetInstructionSetAlignment(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-      // Fall-through.
-    case kThumb2:
-      return kArmAlignment;
-    case kArm64:
-      return kArm64Alignment;
-    case kX86:
-      // Fall-through.
-    case kX86_64:
-      return kX86Alignment;
-    case kMips:
-      return kMipsAlignment;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have alignment.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-
-static constexpr size_t kDefaultStackOverflowReservedBytes = 16 * KB;
-static constexpr size_t kMipsStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
-
-static constexpr size_t kArmStackOverflowReservedBytes =    8 * KB;
-static constexpr size_t kArm64StackOverflowReservedBytes =  8 * KB;
-static constexpr size_t kX86StackOverflowReservedBytes =    8 * KB;
-static constexpr size_t kX86_64StackOverflowReservedBytes = 8 * KB;
-
-size_t GetStackOverflowReservedBytes(InstructionSet isa) {
-  switch (isa) {
-    case kArm:      // Intentional fall-through.
-    case kThumb2:
-      return kArmStackOverflowReservedBytes;
-
-    case kArm64:
-      return kArm64StackOverflowReservedBytes;
-
-    case kMips:
-      return kMipsStackOverflowReservedBytes;
-
-    case kX86:
-      return kX86StackOverflowReservedBytes;
-
-    case kX86_64:
-      return kX86_64StackOverflowReservedBytes;
-
-    case kNone:
-      LOG(FATAL) << "kNone has no stack overflow size";
-      return 0;
-
-    default:
-      LOG(FATAL) << "Unknown instruction set" << isa;
-      return 0;
-  }
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromVariant(InstructionSet isa,
-                                                                  const std::string& variant,
-                                                                  std::string* error_msg) {
-  const InstructionSetFeatures* result;
-  switch (isa) {
-    case kArm:
-    case kThumb2:
-      result = ArmInstructionSetFeatures::FromVariant(variant, error_msg);
-      break;
-    default:
-      result = UnknownInstructionSetFeatures::Unknown(isa);
-      break;
-  }
-  CHECK_EQ(result == nullptr, error_msg->size() != 0);
-  return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromFeatureString(InstructionSet isa,
-                                                                        const std::string& feature_list,
-                                                                        std::string* error_msg) {
-  const InstructionSetFeatures* result;
-  switch (isa) {
-    case kArm:
-    case kThumb2:
-      result = ArmInstructionSetFeatures::FromFeatureString(feature_list, error_msg);
-      break;
-    default:
-      result = UnknownInstructionSetFeatures::Unknown(isa);
-      break;
-  }
-  // TODO: warn if feature_list doesn't agree with result's GetFeatureList().
-  CHECK_EQ(result == nullptr, error_msg->size() != 0);
-  return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromBitmap(InstructionSet isa,
-                                                                 uint32_t bitmap) {
-  const InstructionSetFeatures* result;
-  switch (isa) {
-    case kArm:
-    case kThumb2:
-      result = ArmInstructionSetFeatures::FromBitmap(bitmap);
-      break;
-    default:
-      result = UnknownInstructionSetFeatures::Unknown(isa);
-      break;
-  }
-  CHECK_EQ(bitmap, result->AsBitmap());
-  return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromCppDefines() {
-  const InstructionSetFeatures* result;
-  switch (kRuntimeISA) {
-    case kArm:
-    case kThumb2:
-      result = ArmInstructionSetFeatures::FromCppDefines();
-      break;
-    default:
-      result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
-      break;
-  }
-  return result;
-}
-
-
-const InstructionSetFeatures* InstructionSetFeatures::FromCpuInfo() {
-  const InstructionSetFeatures* result;
-  switch (kRuntimeISA) {
-    case kArm:
-    case kThumb2:
-      result = ArmInstructionSetFeatures::FromCpuInfo();
-      break;
-    default:
-      result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
-      break;
-  }
-  return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromHwcap() {
-  const InstructionSetFeatures* result;
-  switch (kRuntimeISA) {
-    case kArm:
-    case kThumb2:
-      result = ArmInstructionSetFeatures::FromHwcap();
-      break;
-    default:
-      result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
-      break;
-  }
-  return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromAssembly() {
-  const InstructionSetFeatures* result;
-  switch (kRuntimeISA) {
-    case kArm:
-    case kThumb2:
-      result = ArmInstructionSetFeatures::FromAssembly();
-      break;
-    default:
-      result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
-      break;
-  }
-  return result;
-}
-
-const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
-  DCHECK_EQ(kArm, GetInstructionSet());
-  return down_cast<const ArmInstructionSetFeatures*>(this);
-}
-
-std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs) {
-  os << "ISA: " << rhs.GetInstructionSet() << " Feature string: " << rhs.GetFeatureString();
-  return os;
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromFeatureString(
-    const std::string& feature_list, std::string* error_msg) {
-  std::vector<std::string> features;
-  Split(feature_list, ',', &features);
-  bool has_lpae = false;
-  bool has_div = false;
-  for (auto i = features.begin(); i != features.end(); i++) {
-    std::string feature = Trim(*i);
-    if (feature == "default" || feature == "none") {
-      // Nothing to do.
-    } else if (feature == "div") {
-      has_div = true;
-    } else if (feature == "nodiv") {
-      has_div = false;
-    } else if (feature == "lpae") {
-      has_lpae = true;
-    } else if (feature == "nolpae") {
-      has_lpae = false;
-    } else {
-      *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
-      return nullptr;
-    }
-  }
-  return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromVariant(
-    const std::string& variant, std::string* error_msg) {
-  // Look for variants that have divide support.
-  bool has_div = false;
-  {
-    static const char* arm_variants_with_div[] = {
-        "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", "cortex-a53", "cortex-a57",
-        "cortex-m3", "cortex-m4", "cortex-r4", "cortex-r5",
-        "cyclone", "denver", "krait", "swift"
-    };
-    for (const char* div_variant : arm_variants_with_div) {
-      if (variant == div_variant) {
-        has_div = true;
-        break;
-      }
-    }
-  }
-  // Look for variants that have LPAE support.
-  bool has_lpae = false;
-  {
-    static const char* arm_variants_with_lpae[] = {
-        "cortex-a7", "cortex-a15", "krait", "denver"
-    };
-    for (const char* lpae_variant : arm_variants_with_lpae) {
-      if (variant == lpae_variant) {
-        has_lpae = true;
-        break;
-      }
-    }
-  }
-  if (has_div == false && has_lpae == false) {
-    // Avoid unsupported variants.
-    static const char* unsupported_arm_variants[] = {
-        // ARM processors that aren't ARMv7 compatible aren't supported.
-        "arm2", "arm250", "arm3", "arm6", "arm60", "arm600", "arm610", "arm620",
-        "cortex-m0", "cortex-m0plus", "cortex-m1",
-        "fa526", "fa626", "fa606te", "fa626te", "fmp626", "fa726te",
-        "iwmmxt", "iwmmxt2",
-        "strongarm", "strongarm110", "strongarm1100", "strongarm1110",
-        "xscale"
-    };
-    for (const char* us_variant : unsupported_arm_variants) {
-      if (variant == us_variant) {
-        *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", us_variant);
-        return nullptr;
-      }
-    }
-    // Warn if the variant is unknown.
-    // TODO: some of the variants below may have feature support, but that support is currently
-    //       unknown so we'll choose conservative (sub-optimal) defaults without warning.
-    // TODO: some of the architectures may not support all features required by ART and should be
-    //       moved to unsupported_arm_variants[] above.
-    static const char* arm_variants_without_known_features[] = {
-        "arm7", "arm7m", "arm7d", "arm7dm", "arm7di", "arm7dmi", "arm70", "arm700", "arm700i",
-        "arm710", "arm710c", "arm7100", "arm720", "arm7500", "arm7500fe", "arm7tdmi", "arm7tdmi-s",
-        "arm710t", "arm720t", "arm740t",
-        "arm8", "arm810",
-        "arm9", "arm9e", "arm920", "arm920t", "arm922t", "arm946e-s", "arm966e-s", "arm968e-s",
-        "arm926ej-s", "arm940t", "arm9tdmi",
-        "arm10tdmi", "arm1020t", "arm1026ej-s", "arm10e", "arm1020e", "arm1022e",
-        "arm1136j-s", "arm1136jf-s",
-        "arm1156t2-s", "arm1156t2f-s", "arm1176jz-s", "arm1176jzf-s",
-        "cortex-a5", "cortex-a8", "cortex-a9", "cortex-a9-mp", "cortex-r4f",
-        "marvell-pj4", "mpcore", "mpcorenovfp"
-    };
-    bool found = false;
-    for (const char* ff_variant : arm_variants_without_known_features) {
-      if (variant == ff_variant) {
-        found = true;
-        break;
-      }
-    }
-    if (!found) {
-      LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant
-          << ") using conservative defaults";
-    }
-  }
-  return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
-  bool has_lpae = (bitmap & kLpaeBitfield) != 0;
-  bool has_div = (bitmap & kDivBitfield) != 0;
-  return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCppDefines() {
-#if defined(__ARM_ARCH_EXT_IDIV__)
-  bool has_div = true;
-#else
-  bool has_div = false;
-#endif
-#if defined(__ARM_FEATURE_LPAE)
-  bool has_lpae = true;
-#else
-  bool has_lpae = false;
-#endif
-  return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCpuInfo() {
-  // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
-  // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
-  bool has_lpae = false;
-  bool has_div = false;
-
-  std::ifstream in("/proc/cpuinfo");
-  if (!in.fail()) {
-    while (!in.eof()) {
-      std::string line;
-      std::getline(in, line);
-      if (!in.eof()) {
-        LOG(INFO) << "cpuinfo line: " << line;
-        if (line.find("Features") != std::string::npos) {
-          LOG(INFO) << "found features";
-          if (line.find("idivt") != std::string::npos) {
-            // We always expect both ARM and Thumb divide instructions to be available or not
-            // available.
-            CHECK_NE(line.find("idiva"), std::string::npos);
-            has_div = true;
-          }
-          if (line.find("lpae") != std::string::npos) {
-            has_lpae = true;
-          }
-        }
-      }
-    }
-    in.close();
-  } else {
-    LOG(INFO) << "Failed to open /proc/cpuinfo";
-  }
-  return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-#if defined(HAVE_ANDROID_OS) && defined(__arm__)
-#include <sys/auxv.h>
-#include <asm/hwcap.h>
-#endif
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromHwcap() {
-  bool has_lpae = false;
-  bool has_div = false;
-
-#if defined(HAVE_ANDROID_OS) && defined(__arm__)
-  uint64_t hwcaps = getauxval(AT_HWCAP);
-  LOG(INFO) << "hwcaps=" << hwcaps;
-  if ((hwcaps & HWCAP_IDIVT) != 0) {
-    // We always expect both ARM and Thumb divide instructions to be available or not
-    // available.
-    CHECK_NE(hwcaps & HWCAP_IDIVA, 0U);
-    has_div = true;
-  }
-  if ((hwcaps & HWCAP_LPAE) != 0) {
-    has_lpae = true;
-  }
-#endif
-
-  return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-// A signal handler called by a fault for an illegal instruction.  We record the fact in r0
-// and then increment the PC in the signal context to return to the next instruction.  We know the
-// instruction is an sdiv (4 bytes long).
-static void bad_divide_inst_handle(int signo ATTRIBUTE_UNUSED, siginfo_t* si ATTRIBUTE_UNUSED,
-                                   void* data) {
-#if defined(__arm__)
-  struct ucontext *uc = (struct ucontext *)data;
-  struct sigcontext *sc = &uc->uc_mcontext;
-  sc->arm_r0 = 0;     // Set R0 to #0 to signal error.
-  sc->arm_pc += 4;    // Skip offending instruction.
-#else
-  UNUSED(data);
-#endif
-}
-
-#if defined(__arm__)
-extern "C" bool artCheckForARMSDIVInstruction();
-#endif
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromAssembly() {
-  // See if have a sdiv instruction.  Register a signal handler and try to execute an sdiv
-  // instruction.  If we get a SIGILL then it's not supported.
-  struct sigaction sa, osa;
-  sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
-  sa.sa_sigaction = bad_divide_inst_handle;
-  sigaction(SIGILL, &sa, &osa);
-
-  bool has_div = false;
-#if defined(__arm__)
-  if (artCheckForARMSDIVInstruction()) {
-    has_div = true;
-  }
-#endif
-
-  // Restore the signal handler.
-  sigaction(SIGILL, &osa, nullptr);
-
-  // Use compile time features to "detect" LPAE support.
-  // TODO: write an assembly LPAE support test.
-#if defined(__ARM_FEATURE_LPAE)
-  bool has_lpae = true;
-#else
-  bool has_lpae = false;
-#endif
-  return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-
-bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
-  if (kArm != other->GetInstructionSet()) {
-    return false;
-  }
-  const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
-  return has_lpae_ == other_as_arm->has_lpae_ && has_div_ == other_as_arm->has_div_;
-}
-
-uint32_t ArmInstructionSetFeatures::AsBitmap() const {
-  return (has_lpae_ ? kLpaeBitfield : 0) | (has_div_ ? kDivBitfield : 0);
-}
-
-std::string ArmInstructionSetFeatures::GetFeatureString() const {
-  std::string result;
-  if (has_div_) {
-    result += ",div";
-  }
-  if (has_lpae_) {
-    result += ",lpae";
-  }
-  if (result.size() == 0) {
-    return "none";
-  } else {
-    // Strip leading comma.
-    return result.substr(1, result.size());
-  }
-}
-
-}  // namespace art
diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h
deleted file mode 100644
index 84a3e80..0000000
--- a/runtime/instruction_set.h
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_INSTRUCTION_SET_H_
-#define ART_RUNTIME_INSTRUCTION_SET_H_
-
-#include <iosfwd>
-#include <string>
-
-#include "base/logging.h"  // Logging is required for FATAL in the helper functions.
-#include "base/macros.h"
-#include "base/value_object.h"
-#include "globals.h"       // For KB.
-
-namespace art {
-
-enum InstructionSet {
-  kNone,
-  kArm,
-  kArm64,
-  kThumb2,
-  kX86,
-  kX86_64,
-  kMips,
-  kMips64
-};
-std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
-
-#if defined(__arm__)
-static constexpr InstructionSet kRuntimeISA = kArm;
-#elif defined(__aarch64__)
-static constexpr InstructionSet kRuntimeISA = kArm64;
-#elif defined(__mips__)
-static constexpr InstructionSet kRuntimeISA = kMips;
-#elif defined(__i386__)
-static constexpr InstructionSet kRuntimeISA = kX86;
-#elif defined(__x86_64__)
-static constexpr InstructionSet kRuntimeISA = kX86_64;
-#else
-static constexpr InstructionSet kRuntimeISA = kNone;
-#endif
-
-// Architecture-specific pointer sizes
-static constexpr size_t kArmPointerSize = 4;
-static constexpr size_t kArm64PointerSize = 8;
-static constexpr size_t kMipsPointerSize = 4;
-static constexpr size_t kMips64PointerSize = 8;
-static constexpr size_t kX86PointerSize = 4;
-static constexpr size_t kX86_64PointerSize = 8;
-
-// ARM instruction alignment. ARM processors require code to be 4-byte aligned,
-// but ARM ELF requires 8..
-static constexpr size_t kArmAlignment = 8;
-
-// ARM64 instruction alignment. This is the recommended alignment for maximum performance.
-static constexpr size_t kArm64Alignment = 16;
-
-// MIPS instruction alignment.  MIPS processors require code to be 4-byte aligned.
-// TODO: Can this be 4?
-static constexpr size_t kMipsAlignment = 8;
-
-// X86 instruction alignment. This is the recommended alignment for maximum performance.
-static constexpr size_t kX86Alignment = 16;
-
-
-const char* GetInstructionSetString(InstructionSet isa);
-
-// Note: Returns kNone when the string cannot be parsed to a known value.
-InstructionSet GetInstructionSetFromString(const char* instruction_set);
-
-static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-      // Fall-through.
-    case kThumb2:
-      return kArmPointerSize;
-    case kArm64:
-      return kArm64PointerSize;
-    case kX86:
-      return kX86PointerSize;
-    case kX86_64:
-      return kX86_64PointerSize;
-    case kMips:
-      return kMipsPointerSize;
-    case kMips64:
-      return kMips64PointerSize;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have pointer size.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-size_t GetInstructionSetAlignment(InstructionSet isa);
-
-static inline bool Is64BitInstructionSet(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-    case kThumb2:
-    case kX86:
-    case kMips:
-      return false;
-
-    case kArm64:
-    case kX86_64:
-    case kMips64:
-      return true;
-
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have bit width.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-      // Fall-through.
-    case kThumb2:
-      return 4;
-    case kArm64:
-      return 8;
-    case kX86:
-      return 4;
-    case kX86_64:
-      return 8;
-    case kMips:
-      return 4;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have spills.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
-  switch (isa) {
-    case kArm:
-      // Fall-through.
-    case kThumb2:
-      return 4;
-    case kArm64:
-      return 8;
-    case kX86:
-      return 8;
-    case kX86_64:
-      return 8;
-    case kMips:
-      return 4;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have spills.";
-      return 0;
-    default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      return 0;
-  }
-}
-
-size_t GetStackOverflowReservedBytes(InstructionSet isa);
-
-class ArmInstructionSetFeatures;
-
-// Abstraction used to describe features of a different instruction sets.
-class InstructionSetFeatures {
- public:
-  // Process a CPU variant string for the given ISA and create an InstructionSetFeatures.
-  static const InstructionSetFeatures* FromVariant(InstructionSet isa,
-                                                   const std::string& variant,
-                                                   std::string* error_msg);
-
-  // Parse a string of the form "div,lpae" and create an InstructionSetFeatures.
-  static const InstructionSetFeatures* FromFeatureString(InstructionSet isa,
-                                                         const std::string& feature_list,
-                                                         std::string* error_msg);
-
-  // Parse a bitmap for the given isa and create an InstructionSetFeatures.
-  static const InstructionSetFeatures* FromBitmap(InstructionSet isa, uint32_t bitmap);
-
-  // Turn C pre-processor #defines into the equivalent instruction set features for kRuntimeISA.
-  static const InstructionSetFeatures* FromCppDefines();
-
-  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
-  static const InstructionSetFeatures* FromCpuInfo();
-
-  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
-  // InstructionSetFeatures.
-  static const InstructionSetFeatures* FromHwcap();
-
-  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
-  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
-  static const InstructionSetFeatures* FromAssembly();
-
-  // Are these features the same as the other given features?
-  virtual bool Equals(const InstructionSetFeatures* other) const = 0;
-
-  // Return the ISA these features relate to.
-  virtual InstructionSet GetInstructionSet() const = 0;
-
-  // Return a bitmap that represents the features. ISA specific.
-  virtual uint32_t AsBitmap() const = 0;
-
-  // Return a string of the form "div,lpae" or "none".
-  virtual std::string GetFeatureString() const = 0;
-
-  // Down cast this ArmInstructionFeatures.
-  const ArmInstructionSetFeatures* AsArmInstructionSetFeatures() const;
-
-  virtual ~InstructionSetFeatures() {}
-
- protected:
-  InstructionSetFeatures() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(InstructionSetFeatures);
-};
-std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs);
-
-// Instruction set features relevant to the ARM architecture.
-class ArmInstructionSetFeatures FINAL : public InstructionSetFeatures {
- public:
-  // Process a CPU variant string like "krait" or "cortex-a15" and create InstructionSetFeatures.
-  static const ArmInstructionSetFeatures* FromVariant(const std::string& variant,
-                                                      std::string* error_msg);
-
-  // Parse a string of the form "div,lpae" and create an InstructionSetFeatures.
-  static const ArmInstructionSetFeatures* FromFeatureString(const std::string& feature_list,
-                                                            std::string* error_msg);
-
-  // Parse a bitmap and create an InstructionSetFeatures.
-  static const ArmInstructionSetFeatures* FromBitmap(uint32_t bitmap);
-
-  // Turn C pre-processor #defines into the equivalent instruction set features.
-  static const ArmInstructionSetFeatures* FromCppDefines();
-
-  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
-  static const ArmInstructionSetFeatures* FromCpuInfo();
-
-  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
-  // InstructionSetFeatures.
-  static const ArmInstructionSetFeatures* FromHwcap();
-
-  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
-  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
-  static const ArmInstructionSetFeatures* FromAssembly();
-
-  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
-
-  InstructionSet GetInstructionSet() const OVERRIDE {
-    return kArm;
-  }
-
-  uint32_t AsBitmap() const OVERRIDE;
-
-  // Return a string of the form "div,lpae" or "none".
-  std::string GetFeatureString() const OVERRIDE;
-
-  // Is the divide instruction feature enabled?
-  bool HasDivideInstruction() const {
-      return has_div_;
-  }
-
-  // Is the Large Physical Address Extension (LPAE) instruction feature enabled? When true code can
-  // be used that assumes double register loads and stores (ldrd, strd) don't tear.
-  bool HasLpae() const {
-    return has_lpae_;
-  }
-
-  virtual ~ArmInstructionSetFeatures() {}
-
- private:
-  ArmInstructionSetFeatures(bool has_lpae, bool has_div)
-      : has_lpae_(has_lpae), has_div_(has_div) {
-  }
-
-  // Bitmap positions for encoding features as a bitmap.
-  enum {
-    kDivBitfield = 1,
-    kLpaeBitfield = 2,
-  };
-
-  const bool has_lpae_;
-  const bool has_div_;
-
-  DISALLOW_COPY_AND_ASSIGN(ArmInstructionSetFeatures);
-};
-
-// A class used for instruction set features on ISAs that don't yet have any features defined.
-class UnknownInstructionSetFeatures FINAL : public InstructionSetFeatures {
- public:
-  static const UnknownInstructionSetFeatures* Unknown(InstructionSet isa) {
-    return new UnknownInstructionSetFeatures(isa);
-  }
-
-  bool Equals(const InstructionSetFeatures* other) const OVERRIDE {
-    return isa_ == other->GetInstructionSet();
-  }
-
-  InstructionSet GetInstructionSet() const OVERRIDE {
-    return isa_;
-  }
-
-  uint32_t AsBitmap() const OVERRIDE {
-    return 0;
-  }
-
-  std::string GetFeatureString() const OVERRIDE {
-    return "none";
-  }
-
-  virtual ~UnknownInstructionSetFeatures() {}
-
- private:
-  explicit UnknownInstructionSetFeatures(InstructionSet isa) : isa_(isa) {}
-
-  const InstructionSet isa_;
-
-  DISALLOW_COPY_AND_ASSIGN(UnknownInstructionSetFeatures);
-};
-
-// The following definitions create return types for two word-sized entities that will be passed
-// in registers so that memory operations for the interface trampolines can be avoided. The entities
-// are the resolved method and the pointer to the code to be invoked.
-//
-// On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
-// uint64_t or long long int.
-//
-// On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two
-// size_t-sized values.
-//
-// We need two operations:
-//
-// 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
-//    GetTwoWordFailureValue() will return a value that has lower part == 0.
-//
-// 2) A value that combines two word-sized values.
-//    GetTwoWordSuccessValue() constructs this.
-//
-// IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
-//            that the object does not move or the value is updated. Simple use of this is NOT SAFE
-//            when the garbage collector can move objects concurrently. Ensure that required locks
-//            are held when using!
-
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
-typedef uint64_t TwoWordReturn;
-
-// Encodes method_ptr==nullptr and code_ptr==nullptr
-static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
-  return 0;
-}
-
-// Use the lower 32b for the method pointer and the upper 32b for the code pointer.
-static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
-  static_assert(sizeof(uint32_t) == sizeof(uintptr_t), "Unexpected size difference");
-  uint32_t lo32 = lo;
-  uint64_t hi64 = static_cast<uint64_t>(hi);
-  return ((hi64 << 32) | lo32);
-}
-
-#elif defined(__x86_64__) || defined(__aarch64__)
-struct TwoWordReturn {
-  uintptr_t lo;
-  uintptr_t hi;
-};
-
-// Encodes method_ptr==nullptr. Leaves random value in code pointer.
-static inline TwoWordReturn GetTwoWordFailureValue() {
-  TwoWordReturn ret;
-  ret.lo = 0;
-  return ret;
-}
-
-// Write values into their respective members.
-static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
-  TwoWordReturn ret;
-  ret.lo = lo;
-  ret.hi = hi;
-  return ret;
-}
-#else
-#error "Unsupported architecture"
-#endif
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_INSTRUCTION_SET_H_
diff --git a/runtime/instruction_set_test.cc b/runtime/instruction_set_test.cc
deleted file mode 100644
index 3f2d16b..0000000
--- a/runtime/instruction_set_test.cc
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * 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.
- */
-
-#include "instruction_set.h"
-
-#include "base/stringprintf.h"
-#include "common_runtime_test.h"
-
-namespace art {
-
-class InstructionSetTest : public CommonRuntimeTest {};
-
-TEST_F(InstructionSetTest, GetInstructionSetFromString) {
-  EXPECT_EQ(kArm, GetInstructionSetFromString("arm"));
-  EXPECT_EQ(kArm64, GetInstructionSetFromString("arm64"));
-  EXPECT_EQ(kX86, GetInstructionSetFromString("x86"));
-  EXPECT_EQ(kX86_64, GetInstructionSetFromString("x86_64"));
-  EXPECT_EQ(kMips, GetInstructionSetFromString("mips"));
-  EXPECT_EQ(kNone, GetInstructionSetFromString("none"));
-  EXPECT_EQ(kNone, GetInstructionSetFromString("random-string"));
-}
-
-TEST_F(InstructionSetTest, GetInstructionSetString) {
-  EXPECT_STREQ("arm", GetInstructionSetString(kArm));
-  EXPECT_STREQ("arm", GetInstructionSetString(kThumb2));
-  EXPECT_STREQ("arm64", GetInstructionSetString(kArm64));
-  EXPECT_STREQ("x86", GetInstructionSetString(kX86));
-  EXPECT_STREQ("x86_64", GetInstructionSetString(kX86_64));
-  EXPECT_STREQ("mips", GetInstructionSetString(kMips));
-  EXPECT_STREQ("none", GetInstructionSetString(kNone));
-}
-
-TEST_F(InstructionSetTest, TestRoundTrip) {
-  EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA)));
-}
-
-TEST_F(InstructionSetTest, PointerSize) {
-  EXPECT_EQ(sizeof(void*), GetInstructionSetPointerSize(kRuntimeISA));
-}
-
-TEST_F(InstructionSetTest, X86Features) {
-  // Build features for a 32-bit x86 atom processor.
-  std::string error_msg;
-  std::unique_ptr<const InstructionSetFeatures> x86_features(
-      InstructionSetFeatures::FromVariant(kX86, "atom", &error_msg));
-  ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
-  EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
-  EXPECT_TRUE(x86_features->Equals(x86_features.get()));
-  EXPECT_STREQ("none", x86_features->GetFeatureString().c_str());
-  EXPECT_EQ(x86_features->AsBitmap(), 0U);
-
-  // Build features for a 32-bit x86 default processor.
-  std::unique_ptr<const InstructionSetFeatures> x86_default_features(
-      InstructionSetFeatures::FromFeatureString(kX86, "default", &error_msg));
-  ASSERT_TRUE(x86_default_features.get() != nullptr) << error_msg;
-  EXPECT_EQ(x86_default_features->GetInstructionSet(), kX86);
-  EXPECT_TRUE(x86_default_features->Equals(x86_default_features.get()));
-  EXPECT_STREQ("none", x86_default_features->GetFeatureString().c_str());
-  EXPECT_EQ(x86_default_features->AsBitmap(), 0U);
-
-  // Build features for a 64-bit x86-64 atom processor.
-  std::unique_ptr<const InstructionSetFeatures> x86_64_features(
-      InstructionSetFeatures::FromVariant(kX86_64, "atom", &error_msg));
-  ASSERT_TRUE(x86_64_features.get() != nullptr) << error_msg;
-  EXPECT_EQ(x86_64_features->GetInstructionSet(), kX86_64);
-  EXPECT_TRUE(x86_64_features->Equals(x86_64_features.get()));
-  EXPECT_STREQ("none", x86_64_features->GetFeatureString().c_str());
-  EXPECT_EQ(x86_64_features->AsBitmap(), 0U);
-
-  EXPECT_FALSE(x86_64_features->Equals(x86_features.get()));
-  EXPECT_FALSE(x86_64_features->Equals(x86_default_features.get()));
-  EXPECT_TRUE(x86_features->Equals(x86_default_features.get()));
-}
-
-TEST_F(InstructionSetTest, ArmFeaturesFromVariant) {
-  // Build features for a 32-bit ARM krait processor.
-  std::string error_msg;
-  std::unique_ptr<const InstructionSetFeatures> krait_features(
-      InstructionSetFeatures::FromVariant(kArm, "krait", &error_msg));
-  ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
-
-  ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
-  EXPECT_TRUE(krait_features->Equals(krait_features.get()));
-  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
-  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasLpae());
-  EXPECT_STREQ("div,lpae", krait_features->GetFeatureString().c_str());
-  EXPECT_EQ(krait_features->AsBitmap(), 3U);
-
-  // Build features for a 32-bit ARM denver processor.
-  std::unique_ptr<const InstructionSetFeatures> denver_features(
-      InstructionSetFeatures::FromVariant(kArm, "denver", &error_msg));
-  ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
-
-  EXPECT_TRUE(denver_features->Equals(denver_features.get()));
-  EXPECT_TRUE(denver_features->Equals(krait_features.get()));
-  EXPECT_TRUE(krait_features->Equals(denver_features.get()));
-  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
-  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasLpae());
-  EXPECT_STREQ("div,lpae", denver_features->GetFeatureString().c_str());
-  EXPECT_EQ(denver_features->AsBitmap(), 3U);
-
-  // Build features for a 32-bit ARMv7 processor.
-  std::unique_ptr<const InstructionSetFeatures> arm7_features(
-      InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
-  ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
-
-  EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
-  EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
-  EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
-  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
-  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasLpae());
-  EXPECT_STREQ("none", arm7_features->GetFeatureString().c_str());
-  EXPECT_EQ(arm7_features->AsBitmap(), 0U);
-
-  // ARM6 is not a supported architecture variant.
-  std::unique_ptr<const InstructionSetFeatures> arm6_features(
-      InstructionSetFeatures::FromVariant(kArm, "arm6", &error_msg));
-  EXPECT_TRUE(arm6_features.get() == nullptr);
-  EXPECT_NE(error_msg.size(), 0U);
-}
-
-TEST_F(InstructionSetTest, ArmFeaturesFromString) {
-  // Build features for a 32-bit ARM with LPAE and div processor.
-  std::string error_msg;
-  std::unique_ptr<const InstructionSetFeatures> krait_features(
-      InstructionSetFeatures::FromFeatureString(kArm, "lpae,div", &error_msg));
-  ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
-
-  ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
-  EXPECT_TRUE(krait_features->Equals(krait_features.get()));
-  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
-  EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasLpae());
-  EXPECT_STREQ("div,lpae", krait_features->GetFeatureString().c_str());
-  EXPECT_EQ(krait_features->AsBitmap(), 3U);
-
-  // Build features for a 32-bit ARM processor with LPAE and div flipped.
-  std::unique_ptr<const InstructionSetFeatures> denver_features(
-      InstructionSetFeatures::FromFeatureString(kArm, "div,lpae", &error_msg));
-  ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
-
-  EXPECT_TRUE(denver_features->Equals(denver_features.get()));
-  EXPECT_TRUE(denver_features->Equals(krait_features.get()));
-  EXPECT_TRUE(krait_features->Equals(denver_features.get()));
-  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
-  EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasLpae());
-  EXPECT_STREQ("div,lpae", denver_features->GetFeatureString().c_str());
-  EXPECT_EQ(denver_features->AsBitmap(), 3U);
-
-  // Build features for a 32-bit default ARM processor.
-  std::unique_ptr<const InstructionSetFeatures> arm7_features(
-      InstructionSetFeatures::FromFeatureString(kArm, "default", &error_msg));
-  ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
-
-  EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
-  EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
-  EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
-  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
-  EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasLpae());
-  EXPECT_STREQ("none", arm7_features->GetFeatureString().c_str());
-  EXPECT_EQ(arm7_features->AsBitmap(), 0U);
-}
-
-#ifdef HAVE_ANDROID_OS
-#include "cutils/properties.h"
-
-TEST_F(InstructionSetTest, FeaturesFromSystemPropertyVariant) {
-  // Take the default set of instruction features from the build.
-  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
-      InstructionSetFeatures::FromCppDefines());
-
-  // Read the features property.
-  std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
-  char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
-  if (property_get(key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
-    // Use features from property to build InstructionSetFeatures and check against build's
-    // features.
-    std::string error_msg;
-    std::unique_ptr<const InstructionSetFeatures> property_features(
-        InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
-    ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
-
-    EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
-      << "System property features: " << *property_features.get()
-      << "\nFeatures from build: " << *instruction_set_features.get();
-  }
-}
-
-TEST_F(InstructionSetTest, FeaturesFromSystemPropertyString) {
-  // Take the default set of instruction features from the build.
-  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
-      InstructionSetFeatures::FromCppDefines());
-
-  // Read the features property.
-  std::string key = StringPrintf("dalvik.vm.isa.%s.features", GetInstructionSetString(kRuntimeISA));
-  char dex2oat_isa_features[PROPERTY_VALUE_MAX];
-  if (property_get(key.c_str(), dex2oat_isa_features, nullptr) > 0) {
-    // Use features from property to build InstructionSetFeatures and check against build's
-    // features.
-    std::string error_msg;
-    std::unique_ptr<const InstructionSetFeatures> property_features(
-        InstructionSetFeatures::FromFeatureString(kRuntimeISA, dex2oat_isa_features, &error_msg));
-    ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
-
-    EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
-      << "System property features: " << *property_features.get()
-      << "\nFeatures from build: " << *instruction_set_features.get();
-  }
-}
-#endif
-
-#if defined(__arm__)
-TEST_F(InstructionSetTest, DISABLED_FeaturesFromCpuInfo) {
-  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
-#else
-TEST_F(InstructionSetTest, FeaturesFromCpuInfo) {
-#endif
-  // Take the default set of instruction features from the build.
-  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
-      InstructionSetFeatures::FromCppDefines());
-
-  // Check we get the same instruction set features using /proc/cpuinfo.
-  std::unique_ptr<const InstructionSetFeatures> cpuinfo_features(
-      InstructionSetFeatures::FromCpuInfo());
-  EXPECT_TRUE(cpuinfo_features->Equals(instruction_set_features.get()))
-      << "CPU Info features: " << *cpuinfo_features.get()
-      << "\nFeatures from build: " << *instruction_set_features.get();
-}
-
-#if defined(__arm__)
-TEST_F(InstructionSetTest, DISABLED_FeaturesFromHwcap) {
-  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
-#else
-TEST_F(InstructionSetTest, FeaturesFromHwcap) {
-#endif
-  // Take the default set of instruction features from the build.
-  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
-      InstructionSetFeatures::FromCppDefines());
-
-  // Check we get the same instruction set features using AT_HWCAP.
-  std::unique_ptr<const InstructionSetFeatures> hwcap_features(
-      InstructionSetFeatures::FromHwcap());
-  EXPECT_TRUE(hwcap_features->Equals(instruction_set_features.get()))
-      << "Hwcap features: " << *hwcap_features.get()
-      << "\nFeatures from build: " << *instruction_set_features.get();
-}
-
-
-#if defined(__arm__)
-TEST_F(InstructionSetTest, DISABLED_FeaturesFromAssembly) {
-  LOG(WARNING) << "Test disabled due to buggy ARM kernels";
-#else
-TEST_F(InstructionSetTest, FeaturesFromAssembly) {
-#endif
-  // Take the default set of instruction features from the build.
-  std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
-      InstructionSetFeatures::FromCppDefines());
-
-  // Check we get the same instruction set features using assembly tests.
-  std::unique_ptr<const InstructionSetFeatures> assembly_features(
-      InstructionSetFeatures::FromAssembly());
-  EXPECT_TRUE(assembly_features->Equals(instruction_set_features.get()))
-      << "Assembly features: " << *assembly_features.get()
-      << "\nFeatures from build: " << *instruction_set_features.get();
-}
-
-}  // namespace art
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 646c7ae..369039d 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -21,8 +21,8 @@
 #include <list>
 #include <map>
 
+#include "arch/instruction_set.h"
 #include "atomic.h"
-#include "instruction_set.h"
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "gc_root.h"
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index f6e2b21..d40d64b 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -17,8 +17,14 @@
 #include "dalvik_system_VMRuntime.h"
 
 #include <limits.h>
+#include <ScopedUtfChars.h>
 
-#include "ScopedUtfChars.h"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include "toStringArray.h"
+#pragma GCC diagnostic pop
+
+#include "arch/instruction_set.h"
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "debugger.h"
@@ -28,7 +34,6 @@
 #include "gc/heap.h"
 #include "gc/space/dlmalloc_space.h"
 #include "gc/space/image_space.h"
-#include "instruction_set.h"
 #include "intern_table.h"
 #include "jni_internal.h"
 #include "mirror/art_method-inl.h"
@@ -41,11 +46,6 @@
 #include "thread.h"
 #include "thread_list.h"
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshadow"
-#include "toStringArray.h"
-#pragma GCC diagnostic pop
-
 namespace art {
 
 static jfloat VMRuntime_getTargetHeapUtilization(JNIEnv*, jobject) {
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 0966954..f1a04cb 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -18,8 +18,8 @@
 
 #include <stdlib.h>
 
+#include "arch/instruction_set.h"
 #include "debugger.h"
-#include "instruction_set.h"
 #include "java_vm_ext.h"
 #include "jni_internal.h"
 #include "JNIHelp.h"
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 0749c06..02c60ab 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -15,11 +15,13 @@
  */
 
 #include "oat.h"
-#include "utils.h"
 
 #include <string.h>
 #include <zlib.h>
 
+#include "arch/instruction_set_features.h"
+#include "utils.h"
+
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
diff --git a/runtime/oat.h b/runtime/oat.h
index f577b07..8fb02b8 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -19,14 +19,16 @@
 
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/macros.h"
 #include "dex_file.h"
-#include "instruction_set.h"
 #include "quick/quick_method_frame_info.h"
 #include "safe_map.h"
 
 namespace art {
 
+class InstructionSetFeatures;
+
 class PACKED(4) OatHeader {
  public:
   static const uint8_t kOatMagic[4];
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 26a2f31..9294868 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -25,7 +25,7 @@
 #include "globals.h"
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
-#include "instruction_set.h"
+#include "arch/instruction_set.h"
 #include "profiler_options.h"
 
 namespace art {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d338ad7..78c6542 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -37,6 +37,7 @@
 #include "arch/arm/registers_arm.h"
 #include "arch/arm64/quick_method_frame_info_arm64.h"
 #include "arch/arm64/registers_arm64.h"
+#include "arch/instruction_set_features.h"
 #include "arch/mips/quick_method_frame_info_mips.h"
 #include "arch/mips/registers_mips.h"
 #include "arch/x86/quick_method_frame_info_x86.h"
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 3cbe1e5..39fd910 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -26,11 +26,11 @@
 #include <utility>
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/allocator.h"
 #include "compiler_callbacks.h"
 #include "gc_root.h"
 #include "instrumentation.h"
-#include "instruction_set.h"
 #include "jobject_comparator.h"
 #include "object_callbacks.h"
 #include "offsets.h"
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index d4ec803..d448460 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -27,10 +27,10 @@
 
 #include <sstream>
 
+#include "arch/instruction_set.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "gc/heap.h"
-#include "instruction_set.h"
 #include "os.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
diff --git a/runtime/stack.h b/runtime/stack.h
index 66c840d..1d772e6 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -20,8 +20,8 @@
 #include <stdint.h>
 #include <string>
 
+#include "arch/instruction_set.h"
 #include "dex_file.h"
-#include "instruction_set.h"
 #include "mirror/object_reference.h"
 #include "throw_location.h"
 #include "utils.h"
diff --git a/runtime/thread.h b/runtime/thread.h
index 7e567fb..b69d2f4 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -25,6 +25,7 @@
 #include <setjmp.h>
 #include <string>
 
+#include "arch/instruction_set.h"
 #include "atomic.h"
 #include "base/macros.h"
 #include "base/mutex.h"
@@ -34,7 +35,6 @@
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "globals.h"
 #include "handle_scope.h"
-#include "instruction_set.h"
 #include "jvalue.h"
 #include "object_callbacks.h"
 #include "offsets.h"
diff --git a/runtime/utils.h b/runtime/utils.h
index 669fe6c..891b47b 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -24,10 +24,10 @@
 #include <string>
 #include <vector>
 
+#include "arch/instruction_set.h"
 #include "base/logging.h"
 #include "base/mutex.h"
 #include "globals.h"
-#include "instruction_set.h"
 #include "primitive.h"
 
 namespace art {