Merge "Don't pre-initialize Class.name fields in boot images"
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index 34a6469..0000000
--- a/Android.bp
+++ /dev/null
@@ -1,56 +0,0 @@
-// TODO: These should be handled with transitive static library dependencies
-art_static_dependencies = [
-    // Note: the order is important because of static linking resolution.
-    "libziparchive",
-    "libnativehelper",
-    "libnativebridge",
-    "libnativeloader",
-    "libsigchain_dummy",
-    "liblog",
-    "libz",
-    "libbacktrace",
-    "libcutils",
-    "libunwindstack",
-    "libutils",
-    "libbase",
-    "liblz4",
-    "liblzma",
-    "libmetricslogger_static",
-]
-
-subdirs = [
-    "adbconnection",
-    "benchmark",
-    "build",
-    "cmdline",
-    "compiler",
-    "dalvikvm",
-    "dex2oat",
-    "dexdump",
-    "dexlayout",
-    "dexlist",
-    "dexoptanalyzer",
-    "disassembler",
-    "dt_fd_forward",
-    "dt_fd_forward/export",
-    "imgdiag",
-    "libartbase",
-    "libdexfile",
-    "libprofile",
-    "oatdump",
-    "openjdkjvm",
-    "openjdkjvmti",
-    "patchoat",
-    "profman",
-    "runtime",
-    "sigchainlib",
-    "simulator",
-    "test",
-    "tools",
-    "tools/breakpoint-logger",
-    "tools/cpp-define-generator",
-    "tools/dmtracedump",
-    "tools/hiddenapi",
-    "tools/titrace",
-    "tools/wrapagentproperties",
-]
diff --git a/build/art.go b/build/art.go
index 61b1a4e..6c08486 100644
--- a/build/art.go
+++ b/build/art.go
@@ -283,6 +283,7 @@
 	android.RegisterModuleType("art_cc_test_library", artTestLibrary)
 	android.RegisterModuleType("art_cc_defaults", artDefaultsFactory)
 	android.RegisterModuleType("libart_cc_defaults", libartDefaultsFactory)
+	android.RegisterModuleType("libart_static_cc_defaults", libartStaticDefaultsFactory)
 	android.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
 	android.RegisterModuleType("art_debug_defaults", artDebugDefaultsFactory)
 }
@@ -336,6 +337,33 @@
 	return module
 }
 
+func libartStaticDefaultsFactory() android.Module {
+	c := &codegenProperties{}
+	module := cc.DefaultsFactory(c)
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		codegen(ctx, c, true)
+
+		type props struct {
+			Target struct {
+				Android struct {
+					Static_libs []string
+				}
+			}
+		}
+
+		p := &props{}
+		// TODO: express this in .bp instead b/79671158
+		if !envTrue(ctx, "ART_TARGET_LINUX") {
+			p.Target.Android.Static_libs = []string{
+				"libmetricslogger_static",
+			}
+		}
+		ctx.AppendProperties(p)
+	})
+
+	return module
+}
+
 func artLibrary() android.Module {
 	m, _ := cc.NewLibrary(android.HostAndDeviceSupported)
 	module := m.Init()
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 42c6a5f..97daafa 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -131,7 +131,7 @@
     art::InitLogging(nullptr, art::Runtime::Abort);  // argv = null
   }
 
-  virtual void SetUp() {
+  void SetUp() override {
     parser_ = ParsedOptions::MakeParser(false);  // do not ignore unrecognized options
   }
 
diff --git a/compiler/Android.bp b/compiler/Android.bp
index c365537..c2f8e3c 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -191,6 +191,15 @@
     export_include_dirs: ["."],
 }
 
+cc_defaults {
+    name: "libart-compiler_static_base_defaults",
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "liblzma",
+    ],
+}
+
 gensrcs {
     name: "art_compiler_operator_srcs",
     cmd: "$(location generate_operator_out) art/compiler $(in) > $(out)",
@@ -260,6 +269,18 @@
     },
 }
 
+cc_defaults {
+    name: "libart-compiler_static_defaults",
+    defaults: [
+        "libart-compiler_static_base_defaults",
+        "libart_static_defaults",
+        "libartbase_static_defaults",
+        "libdexfile_static_defaults",
+        "libprofile_static_defaults",
+    ],
+    static_libs: ["libart-compiler"],
+}
+
 art_cc_library {
     name: "libartd-compiler",
     defaults: [
@@ -302,6 +323,18 @@
     ],
 }
 
+cc_defaults {
+    name: "libartd-compiler_static_defaults",
+    defaults: [
+        "libart-compiler_static_base_defaults",
+        "libartd_static_defaults",
+        "libartbased_static_defaults",
+        "libdexfiled_static_defaults",
+        "libprofiled_static_defaults",
+    ],
+    static_libs: ["libartd-compiler"],
+}
+
 art_cc_library {
     name: "libart-compiler-gtest",
     defaults: ["libart-gtest-defaults"],
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index d603d96..586891a 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -108,7 +108,7 @@
   int result = mprotect(reinterpret_cast<void*>(base), len, PROT_READ | PROT_WRITE | PROT_EXEC);
   CHECK_EQ(result, 0);
 
-  FlushInstructionCache(reinterpret_cast<char*>(base), reinterpret_cast<char*>(base + len));
+  FlushInstructionCache(reinterpret_cast<void*>(base), reinterpret_cast<void*>(base + len));
 }
 
 void CommonCompilerTest::MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader,
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f6afe2c..95d08b3 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2564,8 +2564,8 @@
                                      thread_pool);
 
   auto compile = [&context, &compile_fn](size_t class_def_index) {
-    ScopedTrace trace(__FUNCTION__);
     const DexFile& dex_file = *context.GetDexFile();
+    SCOPED_TRACE << "compile " << dex_file.GetLocation() << "@" << class_def_index;
     ClassLinker* class_linker = context.GetClassLinker();
     jobject jclass_loader = context.GetClassLoader();
     ClassReference ref(&dex_file, class_def_index);
diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc
index fd17364..80c0a68 100644
--- a/compiler/exception_test.cc
+++ b/compiler/exception_test.cc
@@ -50,7 +50,7 @@
   // which always points to the first source statement.
   static constexpr const uint32_t kDexPc = 0;
 
-  virtual void SetUp() {
+  void SetUp() override {
     CommonRuntimeTest::SetUp();
 
     ScopedObjectAccess soa(Thread::Current());
diff --git a/compiler/optimizing/code_generator_vector_arm64.cc b/compiler/optimizing/code_generator_vector_arm64.cc
index 6d135a9..43169ba 100644
--- a/compiler/optimizing/code_generator_vector_arm64.cc
+++ b/compiler/optimizing/code_generator_vector_arm64.cc
@@ -1354,6 +1354,7 @@
   Register scratch;
 
   switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt16:  // (short) s.charAt(.) can yield HVecLoad/Int16/StringCharAt.
     case DataType::Type::kUint16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       // Special handling of compressed/uncompressed string load.
@@ -1385,7 +1386,6 @@
     case DataType::Type::kBool:
     case DataType::Type::kUint8:
     case DataType::Type::kInt8:
-    case DataType::Type::kInt16:
     case DataType::Type::kInt32:
     case DataType::Type::kFloat32:
     case DataType::Type::kInt64:
diff --git a/compiler/optimizing/code_generator_vector_x86.cc b/compiler/optimizing/code_generator_vector_x86.cc
index 086ae07..2502275 100644
--- a/compiler/optimizing/code_generator_vector_x86.cc
+++ b/compiler/optimizing/code_generator_vector_x86.cc
@@ -1205,6 +1205,7 @@
   XmmRegister reg = locations->Out().AsFpuRegister<XmmRegister>();
   bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
   switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt16:  // (short) s.charAt(.) can yield HVecLoad/Int16/StringCharAt.
     case DataType::Type::kUint16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       // Special handling of compressed/uncompressed string load.
@@ -1232,7 +1233,6 @@
     case DataType::Type::kBool:
     case DataType::Type::kUint8:
     case DataType::Type::kInt8:
-    case DataType::Type::kInt16:
     case DataType::Type::kInt32:
     case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
diff --git a/compiler/optimizing/code_generator_vector_x86_64.cc b/compiler/optimizing/code_generator_vector_x86_64.cc
index 4d31ab6..4a67daf 100644
--- a/compiler/optimizing/code_generator_vector_x86_64.cc
+++ b/compiler/optimizing/code_generator_vector_x86_64.cc
@@ -1178,6 +1178,7 @@
   XmmRegister reg = locations->Out().AsFpuRegister<XmmRegister>();
   bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
   switch (instruction->GetPackedType()) {
+    case DataType::Type::kInt16:  // (short) s.charAt(.) can yield HVecLoad/Int16/StringCharAt.
     case DataType::Type::kUint16:
       DCHECK_EQ(8u, instruction->GetVectorLength());
       // Special handling of compressed/uncompressed string load.
@@ -1205,7 +1206,6 @@
     case DataType::Type::kBool:
     case DataType::Type::kUint8:
     case DataType::Type::kInt8:
-    case DataType::Type::kInt16:
     case DataType::Type::kInt32:
     case DataType::Type::kInt64:
       DCHECK_LE(2u, instruction->GetVectorLength());
diff --git a/compiler/optimizing/constructor_fence_redundancy_elimination.cc b/compiler/optimizing/constructor_fence_redundancy_elimination.cc
index 3cb8bf2..3a1a9e0 100644
--- a/compiler/optimizing/constructor_fence_redundancy_elimination.cc
+++ b/compiler/optimizing/constructor_fence_redundancy_elimination.cc
@@ -78,7 +78,7 @@
     VisitSetLocation(instruction, value);
   }
 
-  void VisitDeoptimize(HDeoptimize* instruction ATTRIBUTE_UNUSED) {
+  void VisitDeoptimize(HDeoptimize* instruction ATTRIBUTE_UNUSED) override {
     // Pessimize: Merge all fences.
     MergeCandidateFences();
   }
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2757f7b..bb96c21 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -2146,22 +2146,6 @@
     ReferenceTypeInfo argument_rti = argument->GetReferenceTypeInfo();
     if (argument_rti.IsValid() && argument_rti.IsStringClass()) {
       optimizations.SetArgumentIsString();
-    } else if (kUseReadBarrier) {
-      DCHECK(instruction->GetResolvedMethod() != nullptr);
-      DCHECK(instruction->GetResolvedMethod()->GetDeclaringClass()->IsStringClass() ||
-             // Object.equals() can be devirtualized to String.equals().
-             instruction->GetResolvedMethod()->GetDeclaringClass()->IsObjectClass());
-      Runtime* runtime = Runtime::Current();
-      // For AOT, we always assume that the boot image shall contain the String.class and
-      // we do not need a read barrier for boot image classes as they are non-moveable.
-      // For JIT, check if we actually have a boot image; if we do, the String.class
-      // should also be non-moveable.
-      if (runtime->IsAotCompiler() || runtime->GetHeap()->HasBootImageSpace()) {
-        DCHECK(runtime->IsAotCompiler() ||
-               !runtime->GetHeap()->IsMovableObject(
-                   instruction->GetResolvedMethod()->GetDeclaringClass()));
-        optimizations.SetNoReadBarrierForStringClass();
-      }
     }
   }
 }
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 06e2fbb..2d93f23 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -219,7 +219,6 @@
 
   INTRINSIC_OPTIMIZATION(ArgumentNotNull, 0);
   INTRINSIC_OPTIMIZATION(ArgumentIsString, 1);
-  INTRINSIC_OPTIMIZATION(NoReadBarrierForStringClass, 2);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(StringEqualsOptimizations);
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 1abfcb0..7684dc7 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -1398,13 +1398,6 @@
 }
 
 void IntrinsicLocationsBuilderARM64::VisitStringEquals(HInvoke* invoke) {
-  if (kEmitCompilerReadBarrier &&
-      !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
-      !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
-    // No support for this odd case (String class is moveable, not in the boot image).
-    return;
-  }
-
   LocationSummary* locations =
       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   locations->SetInAt(0, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 1127fb8..bc59fcf 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -1458,13 +1458,6 @@
 }
 
 void IntrinsicLocationsBuilderARMVIXL::VisitStringEquals(HInvoke* invoke) {
-  if (kEmitCompilerReadBarrier &&
-      !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
-      !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
-    // No support for this odd case (String class is moveable, not in the boot image).
-    return;
-  }
-
   LocationSummary* locations =
       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   InvokeRuntimeCallingConventionARMVIXL calling_convention;
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 771714b..6f7f5e4 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -1516,13 +1516,6 @@
 
 // boolean java.lang.String.equals(Object anObject)
 void IntrinsicLocationsBuilderMIPS::VisitStringEquals(HInvoke* invoke) {
-  if (kEmitCompilerReadBarrier &&
-      !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
-      !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
-    // No support for this odd case (String class is moveable, not in the boot image).
-    return;
-  }
-
   LocationSummary* locations =
       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   locations->SetInAt(0, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 4a1bd5b..2eb2529 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1369,13 +1369,6 @@
 
 // boolean java.lang.String.equals(Object anObject)
 void IntrinsicLocationsBuilderMIPS64::VisitStringEquals(HInvoke* invoke) {
-  if (kEmitCompilerReadBarrier &&
-      !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
-      !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
-    // No support for this odd case (String class is moveable, not in the boot image).
-    return;
-  }
-
   LocationSummary* locations =
       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   locations->SetInAt(0, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index d33c0c3..3504d7a 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -922,13 +922,6 @@
 }
 
 void IntrinsicLocationsBuilderX86::VisitStringEquals(HInvoke* invoke) {
-  if (kEmitCompilerReadBarrier &&
-      !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
-      !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
-    // No support for this odd case (String class is moveable, not in the boot image).
-    return;
-  }
-
   LocationSummary* locations =
       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   locations->SetInAt(0, Location::RequiresRegister());
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index ae88974..96f6eaa 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -1230,13 +1230,6 @@
 }
 
 void IntrinsicLocationsBuilderX86_64::VisitStringEquals(HInvoke* invoke) {
-  if (kEmitCompilerReadBarrier &&
-      !StringEqualsOptimizations(invoke).GetArgumentIsString() &&
-      !StringEqualsOptimizations(invoke).GetNoReadBarrierForStringClass()) {
-    // No support for this odd case (String class is moveable, not in the boot image).
-    return;
-  }
-
   LocationSummary* locations =
       new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified);
   locations->SetInAt(0, Location::RequiresRegister());
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 7f71745..b33d0f4 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -692,7 +692,7 @@
     VisitSetLocation(instruction, idx, instruction->InputAt(2));
   }
 
-  void VisitDeoptimize(HDeoptimize* instruction) {
+  void VisitDeoptimize(HDeoptimize* instruction) override {
     const ScopedArenaVector<HInstruction*>& heap_values =
         heap_values_for_[instruction->GetBlock()->GetBlockId()];
     for (HInstruction* heap_value : heap_values) {
diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc
index be1f7ea..a52031c 100644
--- a/compiler/optimizing/optimizing_cfi_test.cc
+++ b/compiler/optimizing/optimizing_cfi_test.cc
@@ -128,7 +128,7 @@
    public:
     InternalCodeAllocator() {}
 
-    virtual uint8_t* Allocate(size_t size) {
+    uint8_t* Allocate(size_t size) override {
       memory_.resize(size);
       return memory_.data();
     }
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 0a74705..ff1207a 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -79,7 +79,7 @@
   explicit CodeVectorAllocator(ArenaAllocator* allocator)
       : memory_(allocator->Adapter(kArenaAllocCodeBuffer)) {}
 
-  virtual uint8_t* Allocate(size_t size) {
+  uint8_t* Allocate(size_t size) override {
     memory_.resize(size);
     return &memory_[0];
   }
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index a9d5902..9079658 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -114,9 +114,9 @@
   void VisitCheckCast(HCheckCast* instr) override;
   void VisitBoundType(HBoundType* instr) override;
   void VisitNullCheck(HNullCheck* instr) override;
-  void VisitPhi(HPhi* phi);
+  void VisitPhi(HPhi* phi) override;
 
-  void VisitBasicBlock(HBasicBlock* block);
+  void VisitBasicBlock(HBasicBlock* block) override;
   void ProcessWorklist();
 
  private:
diff --git a/compiler/utils/mips/assembler_mips32r5_test.cc b/compiler/utils/mips/assembler_mips32r5_test.cc
index f9919f5..bd73c12 100644
--- a/compiler/utils/mips/assembler_mips32r5_test.cc
+++ b/compiler/utils/mips/assembler_mips32r5_test.cc
@@ -229,7 +229,7 @@
     STLDeleteElements(&vec_registers_);
   }
 
-  std::vector<mips::MipsLabel> GetAddresses() {
+  std::vector<mips::MipsLabel> GetAddresses() override {
     UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
     UNREACHABLE();
   }
diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc
index 1ec7a6a..9637c25 100644
--- a/compiler/utils/mips/assembler_mips32r6_test.cc
+++ b/compiler/utils/mips/assembler_mips32r6_test.cc
@@ -242,7 +242,7 @@
     STLDeleteElements(&vec_registers_);
   }
 
-  std::vector<mips::MipsLabel> GetAddresses() {
+  std::vector<mips::MipsLabel> GetAddresses() override {
     UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
     UNREACHABLE();
   }
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index 9527fa6..f137c60 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -176,7 +176,7 @@
     STLDeleteElements(&fp_registers_);
   }
 
-  std::vector<mips::MipsLabel> GetAddresses() {
+  std::vector<mips::MipsLabel> GetAddresses() override {
     UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
     UNREACHABLE();
   }
diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc
index 4ceb356..3218ae3 100644
--- a/compiler/utils/mips64/assembler_mips64_test.cc
+++ b/compiler/utils/mips64/assembler_mips64_test.cc
@@ -240,7 +240,7 @@
     STLDeleteElements(&vec_registers_);
   }
 
-  std::vector<mips64::Mips64Label> GetAddresses() {
+  std::vector<mips64::Mips64Label> GetAddresses() override {
     UNIMPLEMENTED(FATAL) << "Feature not implemented yet";
     UNREACHABLE();
   }
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index e1de1f1..65711e0 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -297,7 +297,7 @@
     STLDeleteElements(&fp_registers_);
   }
 
-  std::vector<x86_64::Address> GetAddresses() {
+  std::vector<x86_64::Address> GetAddresses() override {
     return addresses_;
   }
 
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 81932a9..523c90b 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -52,7 +52,7 @@
   bool IsRelocationPossible() override { return false; }
 
   verifier::VerifierDeps* GetVerifierDeps() const override { return deps_; }
-  void SetVerifierDeps(verifier::VerifierDeps* deps) { deps_ = deps; }
+  void SetVerifierDeps(verifier::VerifierDeps* deps) override { deps_ = deps; }
 
  private:
   verifier::VerifierDeps* deps_;
@@ -60,7 +60,7 @@
 
 class VerifierDepsTest : public CommonCompilerTest {
  public:
-  void SetUpRuntimeOptions(RuntimeOptions* options) {
+  void SetUpRuntimeOptions(RuntimeOptions* options) override {
     CommonCompilerTest::SetUpRuntimeOptions(options);
     callbacks_.reset(new VerifierDepsCompilerCallbacks());
   }
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 88e69cd..666db42 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -89,6 +89,20 @@
     },
 }
 
+cc_defaults {
+    name: "libart-dex2oat_static_base_defaults",
+    target: {
+        android: {
+            static_libs: ["libcutils"],
+        },
+    },
+    static_libs: [
+        "libbase",
+        "liblz4",
+        "liblzma",
+    ],
+}
+
 gensrcs {
     name: "art_dex2oat_operator_srcs",
     cmd: "$(location generate_operator_out) art/dex2oat $(in) > $(out)",
@@ -110,6 +124,20 @@
     ],
 }
 
+cc_defaults {
+    name: "libart-dex2oat_static_defaults",
+    defaults: [
+        "libart-dex2oat_static_base_defaults",
+        "libart_static_defaults",
+        "libprofile_static_defaults",
+    ],
+    static_libs: [
+        "libart-compiler",
+        "libart-dexlayout",
+        "libart-dex2oat",
+    ],
+}
+
 art_cc_static_library {
     name: "libartd-dex2oat",
     defaults: [
@@ -124,6 +152,20 @@
     ],
 }
 
+cc_defaults {
+    name: "libartd-dex2oat_static_defaults",
+    defaults: [
+        "libart-dex2oat_static_base_defaults",
+        "libartd_static_defaults",
+        "libprofiled_static_defaults",
+    ],
+    static_libs: [
+        "libartd-compiler",
+        "libartd-dexlayout",
+        "libartd-dex2oat",
+    ],
+}
+
 cc_library_headers {
     name: "dex2oat_headers",
     host_supported: true,
@@ -255,7 +297,9 @@
     name: "dex2oats-defaults",
     device_supported: false,
     static_executable: true,
-    defaults: ["dex2oat-defaults"],
+    defaults: [
+        "dex2oat-defaults",
+    ],
     target: {
         darwin: {
             enabled: false,
@@ -269,22 +313,24 @@
         // Try to get rid of it.
         "-z muldefs",
     ],
-    static_libs: art_static_dependencies,
+    static_libs: [
+        "libbase",
+        "liblz4",
+        "libsigchain_dummy",
+    ],
 }
 
 art_cc_binary {
     name: "dex2oats",
-    defaults: ["dex2oats-defaults"],
-    static_libs: [
-        "libart-dex2oat",
-        "libart-compiler",
-        "libart-dexlayout",
-        "libart",
-        "libartbase",
-        "libdexfile",
-        "libprofile",
-        "libvixl-arm",
-        "libvixl-arm64",
+    defaults: [
+        "dex2oats-defaults",
+        "libart_static_defaults",
+        "libart-compiler_static_defaults",
+        "libart-dexlayout_static_defaults",
+        "libartbase_static_defaults",
+        "libdexfile_static_defaults",
+        "libprofile_static_defaults",
+        "libart-dex2oat_static_defaults",
     ],
 }
 
@@ -293,6 +339,13 @@
     defaults: [
         "art_debug_defaults",
         "dex2oats-defaults",
+        "libartd_static_defaults",
+        "libartd-compiler_static_defaults",
+        "libartd-dexlayout_static_defaults",
+        "libartbased_static_defaults",
+        "libdexfiled_static_defaults",
+        "libprofiled_static_defaults",
+        "libartd-dex2oat_static_defaults",
     ],
     target: {
         linux_glibc_x86_64: {
@@ -301,17 +354,6 @@
     },
     // b/79417743, oatdump 32-bit tests failed with clang lld
     use_clang_lld: false,
-    static_libs: [
-        "libartd-dex2oat",
-        "libartd-compiler",
-        "libartd-dexlayout",
-        "libartd",
-        "libartbased",
-        "libprofiled",
-        "libdexfiled",
-        "libvixld-arm",
-        "libvixld-arm64",
-    ],
 }
 
 art_cc_test {
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index 852293b..9a7f93d 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -68,7 +68,7 @@
         debug_info_(debug_info) {
   }
 
-  void Run(Thread*) {
+  void Run(Thread*) override {
     result_ = debug::MakeMiniDebugInfo(isa_,
                                        instruction_set_features_,
                                        text_section_address_,
diff --git a/dex2oat/linker/elf_writer_test.cc b/dex2oat/linker/elf_writer_test.cc
index 40495f3..ef85fd1 100644
--- a/dex2oat/linker/elf_writer_test.cc
+++ b/dex2oat/linker/elf_writer_test.cc
@@ -34,7 +34,7 @@
 
 class ElfWriterTest : public CommonCompilerTest {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     ReserveImageSpace();
     CommonCompilerTest::SetUp();
   }
diff --git a/dex2oat/linker/multi_oat_relative_patcher_test.cc b/dex2oat/linker/multi_oat_relative_patcher_test.cc
index a5831b6..2610561 100644
--- a/dex2oat/linker/multi_oat_relative_patcher_test.cc
+++ b/dex2oat/linker/multi_oat_relative_patcher_test.cc
@@ -96,12 +96,12 @@
 
     void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
                                      const LinkerPatch& patch ATTRIBUTE_UNUSED,
-                                     uint32_t patch_offset ATTRIBUTE_UNUSED) {
+                                     uint32_t patch_offset ATTRIBUTE_UNUSED) override {
       LOG(FATAL) << "UNIMPLEMENTED";
     }
 
     std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(
-        uint32_t executable_offset ATTRIBUTE_UNUSED) {
+        uint32_t executable_offset ATTRIBUTE_UNUSED) override {
       LOG(FATAL) << "UNIMPLEMENTED";
       UNREACHABLE();
     }
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index f88d8d4..e2db11f 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -1671,7 +1671,7 @@
     }
   }
 
-  virtual bool VisitComplete() {
+  bool VisitComplete() override {
     offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
     if (UNLIKELY(offset_ == 0u)) {
       PLOG(ERROR) << "Failed to write final relative call thunks";
diff --git a/dex2oat/linker/relative_patcher.cc b/dex2oat/linker/relative_patcher.cc
index 564cf30..45a4a22 100644
--- a/dex2oat/linker/relative_patcher.cc
+++ b/dex2oat/linker/relative_patcher.cc
@@ -79,7 +79,7 @@
 
     void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
                                      const LinkerPatch& patch ATTRIBUTE_UNUSED,
-                                     uint32_t patch_offset ATTRIBUTE_UNUSED) {
+                                     uint32_t patch_offset ATTRIBUTE_UNUSED) override {
       LOG(FATAL) << "Unexpected baker read barrier branch patch.";
     }
 
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index ac9a9a2..3e576c8 100644
--- a/dexdump/Android.bp
+++ b/dexdump/Android.bp
@@ -38,13 +38,13 @@
 
 art_cc_binary {
     name: "dexdumps",
-    defaults: ["dexdump_defaults"],
+    defaults: [
+        "dexdump_defaults",
+        "libartbase_static_defaults",
+        "libdexfile_static_defaults",
+    ],
     host_supported: true,
     device_supported: false,
-    static_libs: [
-        "libdexfile",
-        "libartbase",
-    ] + art_static_dependencies,
     target: {
         darwin: {
             enabled: false,
diff --git a/dexdump/dexdump_test.cc b/dexdump/dexdump_test.cc
index 3a2d38d..bb6d4a4 100644
--- a/dexdump/dexdump_test.cc
+++ b/dexdump/dexdump_test.cc
@@ -31,7 +31,7 @@
 
 class DexDumpTest : public CommonRuntimeTest {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     CommonRuntimeTest::SetUp();
     // Dogfood our own lib core dex file.
     dex_file_ = GetLibCoreDexFileNames()[0];
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 147af0c..24ee5f8 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -32,6 +32,14 @@
     static_libs: ["libz"],
 }
 
+cc_defaults {
+    name: "libart-dexlayout_static_base_defaults",
+    static_libs: [
+        "libbase",
+        "libz",
+    ],
+}
+
 art_cc_library {
     name: "libart-dexlayout",
     defaults: [
@@ -53,6 +61,17 @@
     },
 }
 
+cc_defaults {
+    name: "libart-dexlayout_static_defaults",
+    defaults: [
+        "libart-dexlayout_static_base_defaults",
+        "libartbase_static_defaults",
+        "libdexfile_static_defaults",
+        "libprofile_static_defaults",
+    ],
+    static_libs: ["libart-dexlayout"],
+}
+
 art_cc_library {
     name: "libartd-dexlayout",
     defaults: [
@@ -67,6 +86,17 @@
 }
 
 cc_defaults {
+    name: "libartd-dexlayout_static_defaults",
+    defaults: [
+        "libart-dexlayout_static_base_defaults",
+        "libartbased_static_defaults",
+        "libdexfiled_static_defaults",
+        "libprofiled_static_defaults",
+    ],
+    static_libs: ["libartd-dexlayout"],
+}
+
+cc_defaults {
     name: "dexlayout-defaults",
     defaults: ["art_defaults"],
     host_supported: true,
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 178a4d4..598f7df 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -215,7 +215,7 @@
 
   uint32_t GetOffset() const { return offset_; }
   void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
-  virtual uint32_t Size() const { return 0U; }
+  virtual uint32_t Size() const = 0;
 
  private:
   // Start out unassigned.
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index ca6ff9e..947d3d5 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -115,6 +115,8 @@
     return it != collection_.end() ? it->second : nullptr;
   }
 
+  uint32_t Size() const override { return size(); }
+
   // Lower case for template interop with std::map.
   uint32_t size() const { return collection_.size(); }
   std::map<uint32_t, T*>& Collection() { return collection_; }
diff --git a/dexlayout/dexdiag_test.cc b/dexlayout/dexdiag_test.cc
index 60dd7e4..f936ff9 100644
--- a/dexlayout/dexdiag_test.cc
+++ b/dexlayout/dexdiag_test.cc
@@ -34,7 +34,7 @@
 
 class DexDiagTest : public CommonRuntimeTest {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     CommonRuntimeTest::SetUp();
   }
 
diff --git a/dexlist/dexlist_test.cc b/dexlist/dexlist_test.cc
index 68e6713..39e5f8c 100644
--- a/dexlist/dexlist_test.cc
+++ b/dexlist/dexlist_test.cc
@@ -33,7 +33,7 @@
 
 class DexListTest : public CommonRuntimeTest {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     CommonRuntimeTest::SetUp();
     // Dogfood our own lib core dex file.
     dex_file_ = GetLibCoreDexFileNames()[0];
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index ebc18fc..51b3d75 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -26,6 +26,7 @@
 #include <unordered_set>
 #include <vector>
 
+#include <android-base/parseint.h>
 #include "android-base/stringprintf.h"
 
 #include "art_field-inl.h"
@@ -1682,14 +1683,14 @@
     if (option.starts_with("--image-diff-pid=")) {
       const char* image_diff_pid = option.substr(strlen("--image-diff-pid=")).data();
 
-      if (!ParseInt(image_diff_pid, &image_diff_pid_)) {
+      if (!android::base::ParseInt(image_diff_pid, &image_diff_pid_)) {
         *error_msg = "Image diff pid out of range";
         return kParseError;
       }
     } else if (option.starts_with("--zygote-diff-pid=")) {
       const char* zygote_diff_pid = option.substr(strlen("--zygote-diff-pid=")).data();
 
-      if (!ParseInt(zygote_diff_pid, &zygote_diff_pid_)) {
+      if (!android::base::ParseInt(zygote_diff_pid, &zygote_diff_pid_)) {
         *error_msg = "Zygote diff pid out of range";
         return kParseError;
       }
@@ -1730,7 +1731,7 @@
     return kParseOk;
   }
 
-  virtual std::string GetUsage() const {
+  std::string GetUsage() const override {
     std::string usage;
 
     usage +=
@@ -1760,7 +1761,7 @@
 };
 
 struct ImgDiagMain : public CmdlineMain<ImgDiagArgs> {
-  virtual bool ExecuteWithRuntime(Runtime* runtime) {
+  bool ExecuteWithRuntime(Runtime* runtime) override {
     CHECK(args_ != nullptr);
 
     return DumpImage(runtime,
diff --git a/imgdiag/imgdiag_test.cc b/imgdiag/imgdiag_test.cc
index cb40c7d..73df2a2 100644
--- a/imgdiag/imgdiag_test.cc
+++ b/imgdiag/imgdiag_test.cc
@@ -47,7 +47,7 @@
 
 class ImgDiagTest : public CommonRuntimeTest {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     CommonRuntimeTest::SetUp();
 
     // We loaded the runtime with an explicit image. Therefore the image space must exist.
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 4ee48da..1b603b5 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -79,6 +79,30 @@
     export_shared_lib_headers: ["libbase"],
 }
 
+cc_defaults {
+    name: "libartbase_static_base_defaults",
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libz",
+        "libziparchive",
+    ],
+}
+
+cc_defaults {
+    name: "libartbase_static_defaults",
+    defaults: ["libartbase_static_base_defaults"],
+    static_libs: ["libartbase"],
+}
+
+cc_defaults {
+    name: "libartbased_static_defaults",
+    defaults: ["libartbase_static_base_defaults"],
+    static_libs: ["libartbased"],
+}
+
 gensrcs {
     name: "art_libartbase_operator_srcs",
     cmd: "$(location generate_operator_out) art/libartbase $(in) > $(out)",
diff --git a/libartbase/base/allocator.cc b/libartbase/base/allocator.cc
index 1bcfe87..6393672 100644
--- a/libartbase/base/allocator.cc
+++ b/libartbase/base/allocator.cc
@@ -30,11 +30,11 @@
   MallocAllocator() {}
   ~MallocAllocator() {}
 
-  void* Alloc(size_t size) {
+  void* Alloc(size_t size) override {
     return calloc(sizeof(uint8_t), size);
   }
 
-  void Free(void* p) {
+  void Free(void* p) override {
     free(p);
   }
 
@@ -49,12 +49,12 @@
   NoopAllocator() {}
   ~NoopAllocator() {}
 
-  void* Alloc(size_t size ATTRIBUTE_UNUSED) {
+  void* Alloc(size_t size ATTRIBUTE_UNUSED) override {
     LOG(FATAL) << "NoopAllocator::Alloc should not be called";
     UNREACHABLE();
   }
 
-  void Free(void* p ATTRIBUTE_UNUSED) {
+  void Free(void* p ATTRIBUTE_UNUSED) override {
     // Noop.
   }
 
diff --git a/libartbase/base/arena_bit_vector.cc b/libartbase/base/arena_bit_vector.cc
index c6d8993..138a5df 100644
--- a/libartbase/base/arena_bit_vector.cc
+++ b/libartbase/base/arena_bit_vector.cc
@@ -62,11 +62,11 @@
     UNREACHABLE();
   }
 
-  virtual void* Alloc(size_t size) {
+  void* Alloc(size_t size) override {
     return allocator_->Alloc(size, this->Kind());
   }
 
-  virtual void Free(void*) {}  // Nop.
+  void Free(void*) override {}  // Nop.
 
  private:
   ArenaBitVectorAllocator(ArenaAlloc* allocator, ArenaAllocKind kind)
diff --git a/libartbase/base/unix_file/fd_file_test.cc b/libartbase/base/unix_file/fd_file_test.cc
index 298b2d7..9c39bb5 100644
--- a/libartbase/base/unix_file/fd_file_test.cc
+++ b/libartbase/base/unix_file/fd_file_test.cc
@@ -23,7 +23,7 @@
 
 class FdFileTest : public RandomAccessFileTest {
  protected:
-  virtual RandomAccessFile* MakeTestFile() {
+  RandomAccessFile* MakeTestFile() override {
     FILE* tmp = tmpfile();
     int fd = dup(fileno(tmp));
     fclose(tmp);
diff --git a/libartbase/base/utils.cc b/libartbase/base/utils.cc
index 761c611..74cc5b9 100644
--- a/libartbase/base/utils.cc
+++ b/libartbase/base/utils.cc
@@ -38,6 +38,12 @@
 #include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
 #endif
 
+#if defined(__BIONIC__)
+// membarrier(2) is only supported for target builds (b/111199492).
+#include <linux/membarrier.h>
+#include <sys/syscall.h>
+#endif
+
 #if defined(__linux__)
 #include <linux/unistd.h>
 #endif
@@ -207,4 +213,42 @@
   }
 }
 
+bool FlushInstructionPipeline() {
+  // membarrier(2) is only supported for target builds (b/111199492).
+#if defined(__BIONIC__)
+  static constexpr int kSyncCoreMask =
+      MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE |
+      MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE;
+  static bool have_probed = false;
+  static bool have_sync_core = false;
+
+  if (UNLIKELY(!have_probed)) {
+    // Probe membarrier(2) commands supported by kernel.
+    int commands = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
+    if (commands >= 0) {
+      have_sync_core = (commands & kSyncCoreMask) == kSyncCoreMask;
+      if (have_sync_core) {
+        // Register with kernel that we'll be using the private expedited sync core command.
+        CheckedCall(syscall,
+                    "membarrier register sync core",
+                    __NR_membarrier,
+                    MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,
+                    0);
+      }
+    }
+    have_probed = true;
+  }
+
+  if (have_sync_core) {
+    CheckedCall(syscall,
+                "membarrier sync core",
+                __NR_membarrier,
+                MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE,
+                0);
+    return true;
+  }
+#endif  // defined(__BIONIC__)
+  return false;
+}
+
 }  // namespace art
diff --git a/libartbase/base/utils.h b/libartbase/base/utils.h
index ba61e1b..d85960d 100644
--- a/libartbase/base/utils.h
+++ b/libartbase/base/utils.h
@@ -24,6 +24,7 @@
 #include <string>
 
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 
 #include "casts.h"
 #include "enums.h"
@@ -33,34 +34,6 @@
 
 namespace art {
 
-template <typename T>
-bool ParseUint(const char *in, T* out) {
-  char* end;
-  unsigned long long int result = strtoull(in, &end, 0);  // NOLINT(runtime/int)
-  if (in == end || *end != '\0') {
-    return false;
-  }
-  if (std::numeric_limits<T>::max() < result) {
-    return false;
-  }
-  *out = static_cast<T>(result);
-  return true;
-}
-
-template <typename T>
-bool ParseInt(const char* in, T* out) {
-  char* end;
-  long long int result = strtoll(in, &end, 0);  // NOLINT(runtime/int)
-  if (in == end || *end != '\0') {
-    return false;
-  }
-  if (result < std::numeric_limits<T>::min() || std::numeric_limits<T>::max() < result) {
-    return false;
-  }
-  *out = static_cast<T>(result);
-  return true;
-}
-
 static inline uint32_t PointerToLowMemUInt32(const void* p) {
   uintptr_t intp = reinterpret_cast<uintptr_t>(p);
   DCHECK_LE(intp, 0xFFFFFFFFU);
@@ -130,7 +103,7 @@
   DCHECK(option.starts_with(option_prefix)) << option << " " << option_prefix;
   const char* value_string = option.substr(option_prefix.size()).data();
   int64_t parsed_integer_value = 0;
-  if (!ParseInt(value_string, &parsed_integer_value)) {
+  if (!android::base::ParseInt(value_string, &parsed_integer_value)) {
     usage("Failed to parse %s '%s' as an integer", option_name.c_str(), value_string);
   }
   *out = dchecked_integral_cast<T>(parsed_integer_value);
@@ -179,16 +152,19 @@
 // Sleep forever and never come back.
 NO_RETURN void SleepForever();
 
-inline void FlushInstructionCache(char* begin, char* end) {
-  __builtin___clear_cache(begin, end);
+inline void FlushDataCache(void* begin, void* end) {
+  __builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
 }
 
-inline void FlushDataCache(char* begin, char* end) {
+inline void FlushInstructionCache(void* begin, void* end) {
   // Same as FlushInstructionCache for lack of other builtin. __builtin___clear_cache
   // flushes both caches.
-  __builtin___clear_cache(begin, end);
+  __builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end));
 }
 
+// Flush instruction pipeline. Returns true on success, false if feature is unsupported.
+bool FlushInstructionPipeline();
+
 template <typename T>
 constexpr PointerSize ConvertToPointerSize(T any) {
   if (any == 4 || any == 8) {
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 06fd19e..49b1278 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -72,6 +72,36 @@
     ],
 }
 
+cc_defaults {
+    name: "libdexfile_static_base_defaults",
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libz",
+        "libziparchive",
+    ],
+}
+
+cc_defaults {
+    name: "libdexfile_static_defaults",
+    defaults: [
+        "libartbase_static_defaults",
+        "libdexfile_static_base_defaults",
+    ],
+    static_libs: ["libdexfile"],
+}
+
+cc_defaults {
+    name: "libdexfiled_static_defaults",
+    defaults: [
+        "libartbased_static_defaults",
+        "libdexfile_static_base_defaults",
+    ],
+    static_libs: ["libdexfiled"],
+}
+
 gensrcs {
     name: "dexfile_operator_srcs",
     cmd: "$(location generate_operator_out) art/libdexfile $(in) > $(out)",
diff --git a/libprofile/Android.bp b/libprofile/Android.bp
index b9883f6..edd9fa8 100644
--- a/libprofile/Android.bp
+++ b/libprofile/Android.bp
@@ -56,6 +56,37 @@
     export_shared_lib_headers: ["libbase"],
 }
 
+cc_defaults {
+    name: "libprofile_static_base_defaults",
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "libutils",
+        "libz",
+        "libziparchive",
+    ],
+}
+
+cc_defaults {
+    name: "libprofile_static_defaults",
+    defaults: [
+        "libprofile_static_base_defaults",
+        "libartbase_static_defaults",
+        "libdexfile_static_defaults",
+    ],
+    static_libs: ["libprofile"],
+}
+
+cc_defaults {
+    name: "libprofiled_static_defaults",
+    defaults: [
+        "libprofile_static_base_defaults",
+        "libartbased_static_defaults",
+        "libdexfiled_static_defaults",
+    ],
+    static_libs: ["libprofiled"],
+}
+
 art_cc_library {
     name: "libprofile",
     defaults: ["libprofile_defaults"],
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
index 3cd8ae0..7d82ebf 100644
--- a/oatdump/Android.bp
+++ b/oatdump/Android.bp
@@ -66,7 +66,9 @@
     name: "oatdumps-defaults",
     device_supported: false,
     static_executable: true,
-    defaults: ["oatdump-defaults"],
+    defaults: [
+        "oatdump-defaults",
+    ],
     target: {
         darwin: {
             enabled: false,
@@ -80,18 +82,20 @@
         // Try to get rid of it.
         "-z muldefs",
     ],
-    static_libs: art_static_dependencies,
+    static_libs: ["libsigchain_dummy"],
 }
 
 art_cc_binary {
     name: "oatdumps",
-    defaults: ["oatdumps-defaults"],
+    defaults: [
+        "libart_static_defaults",
+        "libartbase_static_defaults",
+        "libdexfile_static_defaults",
+        "libprofile_static_defaults",
+        "libart-compiler_static_defaults",
+        "oatdumps-defaults",
+    ],
     static_libs: [
-        "libart",
-        "libdexfile",
-        "libprofile",
-        "libartbase",
-        "libart-compiler",
         "libart-disassembler",
         "libvixl-arm",
         "libvixl-arm64",
@@ -102,6 +106,11 @@
     name: "oatdumpds",
     defaults: [
         "art_debug_defaults",
+        "libartd_static_defaults",
+        "libartbased_static_defaults",
+        "libdexfiled_static_defaults",
+        "libprofiled_static_defaults",
+        "libartd-compiler_static_defaults",
         "oatdumps-defaults",
     ],
     target: {
@@ -110,15 +119,11 @@
         },
     },
     static_libs: [
-        "libartd",
-        "libdexfiled",
-        "libprofiled",
-        "libartbased",
-        "libartd-compiler",
         "libartd-disassembler",
         "libvixld-arm",
         "libvixld-arm64",
     ],
+    group_static_libs: true,
 }
 
 art_cc_test {
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index fc7f5b7..51abaf4 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -28,6 +28,7 @@
 #include <vector>
 
 #include "android-base/logging.h"
+#include "android-base/parseint.h"
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
@@ -3380,7 +3381,7 @@
     } else if (option.starts_with("--export-dex-to=")) {
       export_dex_location_ = option.substr(strlen("--export-dex-to=")).data();
     } else if (option.starts_with("--addr2instr=")) {
-      if (!ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
+      if (!android::base::ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
         *error_msg = "Address conversion failed";
         return kParseError;
       }
@@ -3423,7 +3424,7 @@
     return kParseOk;
   }
 
-  virtual std::string GetUsage() const {
+  std::string GetUsage() const override {
     std::string usage;
 
     usage +=
@@ -3577,7 +3578,7 @@
     }
   }
 
-  virtual bool ExecuteWithRuntime(Runtime* runtime) {
+  bool ExecuteWithRuntime(Runtime* runtime) override {
     CHECK(args_ != nullptr);
 
     if (!args_->imt_dump_.empty() || args_->imt_stat_dump_) {
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index f1d6fb0..1ed615b 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -267,7 +267,8 @@
     }
   }
 
-  void ClassLoad(art::Handle<art::mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  void ClassLoad(art::Handle<art::mirror::Class> klass) override
+      REQUIRES_SHARED(art::Locks::mutator_lock_) {
     if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kClassLoad)) {
       art::Thread* thread = art::Thread::Current();
       ScopedLocalRef<jclass> jklass(thread->GetJniEnv(),
@@ -289,7 +290,7 @@
 
   void ClassPrepare(art::Handle<art::mirror::Class> temp_klass,
                     art::Handle<art::mirror::Class> klass)
-      REQUIRES_SHARED(art::Locks::mutator_lock_) {
+      override REQUIRES_SHARED(art::Locks::mutator_lock_) {
     if (event_handler->IsEventEnabledAnywhere(ArtJvmtiEvent::kClassPrepare)) {
       art::Thread* thread = art::Thread::Current();
       if (temp_klass.Get() != klass.Get()) {
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 1588df4..6764538 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -689,7 +689,7 @@
         val_(val),
         obj_val_(nullptr) {}
 
-  virtual jvmtiError GetResult() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  jvmtiError GetResult() override REQUIRES_SHARED(art::Locks::mutator_lock_) {
     if (result_ == OK && type_ == art::Primitive::kPrimNot) {
       val_->l = obj_val_.IsNull()
           ? nullptr
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index 6d3a37e..df29098 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -370,7 +370,7 @@
    public:
     GetContendedMonitorClosure() : out_(nullptr) {}
 
-    void Run(art::Thread* target_thread) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    void Run(art::Thread* target_thread) override REQUIRES_SHARED(art::Locks::mutator_lock_) {
       art::ScopedAssertNoThreadSuspension sants("GetContendedMonitorClosure::Run");
       switch (target_thread->GetState()) {
         // These three we are actually currently waiting on a monitor and have sent the appropriate
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index b6969af..e2b98b3 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -79,7 +79,7 @@
   GetStackTraceVisitor(const GetStackTraceVisitor&) = default;
   GetStackTraceVisitor(GetStackTraceVisitor&&) = default;
 
-  bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(art::Locks::mutator_lock_) {
     art::ArtMethod* m = GetMethod();
     if (m->IsRuntimeMethod()) {
       return true;
@@ -662,7 +662,7 @@
       : art::StackVisitor(thread, nullptr, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
         count(0) {}
 
-  bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(art::Locks::mutator_lock_) {
     art::ArtMethod* m = GetMethod();
     const bool do_count = !(m == nullptr || m->IsRuntimeMethod());
     if (do_count) {
@@ -734,7 +734,7 @@
         caller(nullptr),
         caller_dex_pc(0) {}
 
-  bool VisitFrame() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(art::Locks::mutator_lock_) {
     art::ArtMethod* m = GetMethod();
     const bool do_count = !(m == nullptr || m->IsRuntimeMethod());
     if (do_count) {
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index e533094..41ef6c2 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -1110,7 +1110,7 @@
    public:
     explicit StopThreadClosure(art::Handle<art::mirror::Throwable> except) : exception_(except) { }
 
-    void Run(art::Thread* me) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    void Run(art::Thread* me) override REQUIRES_SHARED(art::Locks::mutator_lock_) {
       // Make sure the thread is prepared to notice the exception.
       art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(me);
       me->SetAsyncException(exception_.Get());
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index aaa3e83..5d38e8b 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -26,6 +26,7 @@
 #include <vector>
 
 #include "android-base/file.h"
+#include <android-base/parseint.h>
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
@@ -630,7 +631,7 @@
       std::string image_relocation_filename =
           output_image_relocation_directory
               + (android::base::StartsWith(original_image_filename, "/") ? "" : "/")
-              + original_image_filename.substr(original_image_filename.find_last_of("/"));
+              + original_image_filename.substr(original_image_filename.find_last_of('/'));
       int64_t input_image_size = input_image->GetLength();
       if (input_image_size < 0) {
         LOG(ERROR) << "Error while getting input image size";
@@ -1272,7 +1273,7 @@
     } else if (option.starts_with("--base-offset-delta=")) {
       const char* base_delta_str = option.substr(strlen("--base-offset-delta=")).data();
       base_delta_set = true;
-      if (!ParseInt(base_delta_str, &base_delta)) {
+      if (!android::base::ParseInt(base_delta_str, &base_delta)) {
         Usage("Failed to parse --base-offset-delta argument '%s' as an off_t", base_delta_str);
       }
     } else if (option == "--dump-timings") {
diff --git a/patchoat/patchoat_test.cc b/patchoat/patchoat_test.cc
index 08bf31c..6492b96 100644
--- a/patchoat/patchoat_test.cc
+++ b/patchoat/patchoat_test.cc
@@ -529,7 +529,7 @@
     ASSERT_EQ(rel_shortened_basenames, relocated_image_shortened_basenames);
   }
 
-  virtual void TearDown() {
+  void TearDown() override {
     if (!dex2oat_orig_dir_.empty()) {
       ClearDirectory(dex2oat_orig_dir_.c_str(), /*recursive*/ true);
       rmdir(dex2oat_orig_dir_.c_str());
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 6ec6265..1cebb06 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -408,6 +408,49 @@
     export_shared_lib_headers: ["libbase"],
 }
 
+libart_static_cc_defaults {
+    name: "libart_static_base_defaults",
+    target: {
+        android: {
+            static_libs: ["libtombstoned_client_static"],
+        },
+    },
+    static_libs: [
+        "libbacktrace",
+        "libbase",
+        "libcutils",
+        "liblog",
+        "liblz4",
+        "liblzma",
+        "libnativebridge",
+        "libnativeloader",
+        "libunwindstack",
+        "libz",
+    ],
+}
+
+cc_defaults {
+    name: "libart_static_defaults",
+    defaults: [
+        "libart_static_base_defaults",
+        "libartbase_static_defaults",
+        "libdexfile_static_defaults",
+        "libprofile_static_defaults",
+    ],
+    static_libs: ["libart"],
+}
+
+cc_defaults {
+    name: "libartd_static_defaults",
+    defaults: [
+        "libart_static_base_defaults",
+        "libartbased_static_defaults",
+        "libdexfiled_static_defaults",
+        "libprofiled_static_defaults",
+    ],
+    static_libs: ["libartd"],
+}
+
 gensrcs {
     name: "art_operator_srcs",
     cmd: "$(location generate_operator_out) art/runtime $(in) > $(out)",
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index f693524..9b69166 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -417,7 +417,6 @@
       case Intrinsics::kMemoryPokeIntNative:
       case Intrinsics::kMemoryPokeLongNative:
       case Intrinsics::kMemoryPokeShortNative:
-        return HiddenApiAccessFlags::kDarkGreylist;
       case Intrinsics::kVarHandleFullFence:
       case Intrinsics::kVarHandleAcquireFence:
       case Intrinsics::kVarHandleReleaseFence:
diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc
index 88075ba..5ec24bc 100644
--- a/runtime/barrier_test.cc
+++ b/runtime/barrier_test.cc
@@ -32,7 +32,7 @@
         count1_(count1),
         count2_(count2) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     LOG(INFO) << "Before barrier" << *self;
     ++*count1_;
     barrier_->Wait(self);
@@ -40,7 +40,7 @@
     LOG(INFO) << "After barrier" << *self;
   }
 
-  virtual void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
@@ -91,7 +91,7 @@
         count_(count),
         subtasks_(subtasks) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     for (size_t i = 0; i < subtasks_; ++i) {
       ++*count_;
       // Pass through to next subtask.
@@ -99,7 +99,7 @@
     }
   }
 
-  void Finalize() {
+  void Finalize() override {
     delete this;
   }
  private:
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e19dedc..f355f5b 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -431,6 +431,8 @@
   heap->IncrementDisableMovingGC(self);
   StackHandleScope<64> hs(self);  // 64 is picked arbitrarily.
   auto class_class_size = mirror::Class::ClassClassSize(image_pointer_size_);
+  // Allocate the object as non-movable so that there are no cases where Object::IsClass returns
+  // the incorrect result when comparing to-space vs from-space.
   Handle<mirror::Class> java_lang_Class(hs.NewHandle(ObjPtr<mirror::Class>::DownCast(MakeObjPtr(
       heap->AllocNonMovableObject<true>(self, nullptr, class_class_size, VoidFunctor())))));
   CHECK(java_lang_Class != nullptr);
@@ -483,9 +485,17 @@
                  mirror::ObjectArray<mirror::Object>::ClassSize(image_pointer_size_))));
   object_array_class->SetComponentType(java_lang_Object.Get());
 
-  // Setup String.
+  // Setup java.lang.String.
+  //
+  // We make this class non-movable for the unlikely case where it were to be
+  // moved by a sticky-bit (minor) collection when using the Generational
+  // Concurrent Copying (CC) collector, potentially creating a stale reference
+  // in the `klass_` field of one of its instances allocated in the Large-Object
+  // Space (LOS) -- see the comment about the dirty card scanning logic in
+  // art::gc::collector::ConcurrentCopying::MarkingPhase.
   Handle<mirror::Class> java_lang_String(hs.NewHandle(
-      AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
+      AllocClass</* kMovable */ false>(
+          self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
   java_lang_String->SetStringClass();
   mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self);
 
@@ -528,13 +538,13 @@
 
   // Create int array type for native pointer arrays (for example vtables) on 32-bit archs.
   Handle<mirror::Class> int_array_class(hs.NewHandle(
-      AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
+      AllocPrimitiveArrayClass(self, java_lang_Class.Get())));
   int_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveInt, this));
   SetClassRoot(ClassRoot::kIntArrayClass, int_array_class.Get());
 
   // Create long array type for native pointer arrays (for example vtables) on 64-bit archs.
   Handle<mirror::Class> long_array_class(hs.NewHandle(
-      AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
+      AllocPrimitiveArrayClass(self, java_lang_Class.Get())));
   long_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveLong, this));
   SetClassRoot(ClassRoot::kLongArrayClass, long_array_class.Get());
 
@@ -610,20 +620,29 @@
   CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize());
 
   // Setup the primitive array type classes - can't be done until Object has a vtable.
-  SetClassRoot(ClassRoot::kBooleanArrayClass, FindSystemClass(self, "[Z"));
+  AllocAndSetPrimitiveArrayClassRoot(self,
+                                     java_lang_Class.Get(),
+                                     ClassRoot::kBooleanArrayClass,
+                                     ClassRoot::kPrimitiveBoolean,
+                                     "[Z");
 
-  SetClassRoot(ClassRoot::kByteArrayClass, FindSystemClass(self, "[B"));
+  AllocAndSetPrimitiveArrayClassRoot(
+      self, java_lang_Class.Get(), ClassRoot::kByteArrayClass, ClassRoot::kPrimitiveByte, "[B");
 
-  SetClassRoot(ClassRoot::kCharArrayClass, FindSystemClass(self, "[C"));
+  AllocAndSetPrimitiveArrayClassRoot(
+      self, java_lang_Class.Get(), ClassRoot::kCharArrayClass, ClassRoot::kPrimitiveChar, "[C");
 
-  SetClassRoot(ClassRoot::kShortArrayClass, FindSystemClass(self, "[S"));
+  AllocAndSetPrimitiveArrayClassRoot(
+      self, java_lang_Class.Get(), ClassRoot::kShortArrayClass, ClassRoot::kPrimitiveShort, "[S");
 
   CheckSystemClass(self, int_array_class, "[I");
   CheckSystemClass(self, long_array_class, "[J");
 
-  SetClassRoot(ClassRoot::kFloatArrayClass, FindSystemClass(self, "[F"));
+  AllocAndSetPrimitiveArrayClassRoot(
+      self, java_lang_Class.Get(), ClassRoot::kFloatArrayClass, ClassRoot::kPrimitiveFloat, "[F");
 
-  SetClassRoot(ClassRoot::kDoubleArrayClass, FindSystemClass(self, "[D"));
+  AllocAndSetPrimitiveArrayClassRoot(
+      self, java_lang_Class.Get(), ClassRoot::kDoubleArrayClass, ClassRoot::kPrimitiveDouble, "[D");
 
   // Run Class through FindSystemClass. This initializes the dex_cache_ fields and register it
   // in class_table_.
@@ -1140,7 +1159,7 @@
   VerifyDeclaringClassVisitor() REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_)
       : live_bitmap_(Runtime::Current()->GetHeap()->GetLiveBitmap()) {}
 
-  virtual void Visit(ArtMethod* method)
+  void Visit(ArtMethod* method) override
       REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
     ObjPtr<mirror::Class> klass = method->GetDeclaringClassUnchecked();
     if (klass != nullptr) {
@@ -1540,7 +1559,7 @@
      public:
       explicit VerifyClassInTableArtMethodVisitor(ClassTable* table) : table_(table) {}
 
-      virtual void Visit(ArtMethod* method)
+      void Visit(ArtMethod* method) override
           REQUIRES_SHARED(Locks::mutator_lock_, Locks::classlinker_classes_lock_) {
         ObjPtr<mirror::Class> klass = method->GetDeclaringClass();
         if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
@@ -2165,13 +2184,14 @@
   return dex_cache;
 }
 
+template <bool kMovable>
 ObjPtr<mirror::Class> ClassLinker::AllocClass(Thread* self,
                                               ObjPtr<mirror::Class> java_lang_Class,
                                               uint32_t class_size) {
   DCHECK_GE(class_size, sizeof(mirror::Class));
   gc::Heap* heap = Runtime::Current()->GetHeap();
   mirror::Class::InitializeClassVisitor visitor(class_size);
-  ObjPtr<mirror::Object> k = kMovingClasses ?
+  ObjPtr<mirror::Object> k = (kMovingClasses && kMovable) ?
       heap->AllocObject<true>(self, java_lang_Class, class_size, visitor) :
       heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size, visitor);
   if (UNLIKELY(k == nullptr)) {
@@ -2185,6 +2205,18 @@
   return AllocClass(self, GetClassRoot<mirror::Class>(this), class_size);
 }
 
+ObjPtr<mirror::Class> ClassLinker::AllocPrimitiveArrayClass(Thread* self,
+                                                            ObjPtr<mirror::Class> java_lang_Class) {
+  // We make this class non-movable for the unlikely case where it were to be
+  // moved by a sticky-bit (minor) collection when using the Generational
+  // Concurrent Copying (CC) collector, potentially creating a stale reference
+  // in the `klass_` field of one of its instances allocated in the Large-Object
+  // Space (LOS) -- see the comment about the dirty card scanning logic in
+  // art::gc::collector::ConcurrentCopying::MarkingPhase.
+  return AllocClass</* kMovable */ false>(
+      self, java_lang_Class, mirror::Array::ClassSize(image_pointer_size_));
+}
+
 ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> ClassLinker::AllocStackTraceElementArray(
     Thread* self,
     size_t length) {
@@ -3648,10 +3680,22 @@
       new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::Object>>(this));
     } else if (strcmp(descriptor, "[Ljava/lang/String;") == 0) {
       new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::String>>(this));
+    } else if (strcmp(descriptor, "[Z") == 0) {
+      new_class.Assign(GetClassRoot<mirror::BooleanArray>(this));
+    } else if (strcmp(descriptor, "[B") == 0) {
+      new_class.Assign(GetClassRoot<mirror::ByteArray>(this));
+    } else if (strcmp(descriptor, "[C") == 0) {
+      new_class.Assign(GetClassRoot<mirror::CharArray>(this));
+    } else if (strcmp(descriptor, "[S") == 0) {
+      new_class.Assign(GetClassRoot<mirror::ShortArray>(this));
     } else if (strcmp(descriptor, "[I") == 0) {
       new_class.Assign(GetClassRoot<mirror::IntArray>(this));
     } else if (strcmp(descriptor, "[J") == 0) {
       new_class.Assign(GetClassRoot<mirror::LongArray>(this));
+    } else if (strcmp(descriptor, "[F") == 0) {
+      new_class.Assign(GetClassRoot<mirror::FloatArray>(this));
+    } else if (strcmp(descriptor, "[D") == 0) {
+      new_class.Assign(GetClassRoot<mirror::DoubleArray>(this));
     }
   }
   if (new_class == nullptr) {
@@ -8607,6 +8651,19 @@
   class_roots->Set<false>(index, klass);
 }
 
+void ClassLinker::AllocAndSetPrimitiveArrayClassRoot(Thread* self,
+                                                     ObjPtr<mirror::Class> java_lang_Class,
+                                                     ClassRoot primitive_array_class_root,
+                                                     ClassRoot primitive_class_root,
+                                                     const char* descriptor) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> primitive_array_class(hs.NewHandle(
+      AllocPrimitiveArrayClass(self, java_lang_Class)));
+  primitive_array_class->SetComponentType(GetClassRoot(primitive_class_root, this));
+  SetClassRoot(primitive_array_class_root, primitive_array_class.Get());
+  CheckSystemClass(self, primitive_array_class, descriptor);
+}
+
 jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
                                                 const std::vector<const DexFile*>& dex_files,
                                                 jclass loader_class,
@@ -8941,7 +8998,7 @@
                              ifcount * mirror::IfTable::kMax)));
 }
 
-// Instantiate ResolveMethod.
+// Instantiate ClassLinker::ResolveMethod.
 template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
     uint32_t method_idx,
     Handle<mirror::DexCache> dex_cache,
@@ -8955,4 +9012,14 @@
     ArtMethod* referrer,
     InvokeType type);
 
+// Instantiate ClassLinker::AllocClass.
+template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable */ true>(
+    Thread* self,
+    ObjPtr<mirror::Class> java_lang_Class,
+    uint32_t class_size);
+template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable */ false>(
+    Thread* self,
+    ObjPtr<mirror::Class> java_lang_Class,
+    uint32_t class_size);
+
 }  // namespace art
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index e4d9c96..efe29d3 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -775,7 +775,11 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
 
-  // For early bootstrapping by Init
+  // For early bootstrapping by Init.
+  // If we do not allow moving classes (`art::kMovingClass` is false) or if
+  // parameter `kMovable` is false (or both), the class object is allocated in
+  // the non-moving space.
+  template <bool kMovable = true>
   ObjPtr<mirror::Class> AllocClass(Thread* self,
                                    ObjPtr<mirror::Class> java_lang_Class,
                                    uint32_t class_size)
@@ -789,6 +793,12 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
+  // Allocate a primitive array class.
+  ObjPtr<mirror::Class> AllocPrimitiveArrayClass(Thread* self,
+                                                 ObjPtr<mirror::Class> java_lang_Class)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!Roles::uninterruptible_);
+
   ObjPtr<mirror::DexCache> AllocDexCache(/*out*/ ObjPtr<mirror::String>* out_location,
                                          Thread* self,
                                          const DexFile& dex_file)
@@ -1206,6 +1216,20 @@
   void SetClassRoot(ClassRoot class_root, ObjPtr<mirror::Class> klass)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Allocate primitive array class for primitive with class root
+  // `primitive_class_root`, and associate it to class root
+  // `primitive_array_class_root`.
+  //
+  // Also check this class returned when searching system classes for
+  // `descriptor` matches the allocated class.
+  void AllocAndSetPrimitiveArrayClassRoot(Thread* self,
+                                          ObjPtr<mirror::Class> java_lang_Class,
+                                          ClassRoot primitive_array_class_root,
+                                          ClassRoot primitive_class_root,
+                                          const char* descriptor)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!Roles::uninterruptible_);
+
   // Return the quick generic JNI stub for testing.
   const void* GetRuntimeQuickGenericJniStub() const;
 
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 2bd5411..f6b764d 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -16,6 +16,8 @@
 
 #include "class_loader_context.h"
 
+#include <android-base/parseint.h>
+
 #include "art_field-inl.h"
 #include "base/dchecked_vector.h"
 #include "base/stl_util.h"
@@ -120,7 +122,7 @@
         return false;
       }
       uint32_t checksum = 0;
-      if (!ParseInt(dex_file_with_checksum[1].c_str(), &checksum)) {
+      if (!android::base::ParseInt(dex_file_with_checksum[1].c_str(), &checksum)) {
         return false;
       }
       class_loader_chain_.back().classpath.push_back(dex_file_with_checksum[0]);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 366b5ec..7103214 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -897,7 +897,7 @@
 
     // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
     // annotalysis.
-    bool VisitFrame() NO_THREAD_SAFETY_ANALYSIS {
+    bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
       if (!GetMethod()->IsRuntimeMethod()) {
         Monitor::VisitLocks(this, AppendOwnedMonitors, this);
         ++current_stack_depth;
@@ -2406,7 +2406,7 @@
 
     // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
     // annotalysis.
-    bool VisitFrame() NO_THREAD_SAFETY_ANALYSIS {
+    bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
       if (!GetMethod()->IsRuntimeMethod()) {
         ++depth;
       }
@@ -2576,7 +2576,7 @@
 
   // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
   // annotalysis.
-  virtual bool VisitFrame() NO_THREAD_SAFETY_ANALYSIS {
+  bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
     if (frame_id != GetFrameId()) {
       return true;  // continue
     } else {
@@ -2618,7 +2618,7 @@
 
   // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
   // annotalysis.
-  bool VisitFrame() NO_THREAD_SAFETY_ANALYSIS {
+  bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
     if (GetFrameId() != frame_id_) {
       return true;  // Not our frame, carry on.
     }
@@ -3831,7 +3831,7 @@
 
     // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
     // annotalysis.
-    bool VisitFrame() NO_THREAD_SAFETY_ANALYSIS {
+    bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
       ArtMethod* m = GetMethod();
       if (!m->IsRuntimeMethod()) {
         ++stack_depth;
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index e6f3d0b..1045d2a 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -317,20 +317,9 @@
                                    ArtMethod* referrer,
                                    Thread* self,
                                    size_t expected_size) {
-  bool is_primitive;
-  bool is_set;
-  bool is_static;
-  switch (type) {
-    case InstanceObjectRead:     is_primitive = false; is_set = false; is_static = false; break;
-    case InstanceObjectWrite:    is_primitive = false; is_set = true;  is_static = false; break;
-    case InstancePrimitiveRead:  is_primitive = true;  is_set = false; is_static = false; break;
-    case InstancePrimitiveWrite: is_primitive = true;  is_set = true;  is_static = false; break;
-    case StaticObjectRead:       is_primitive = false; is_set = false; is_static = true;  break;
-    case StaticObjectWrite:      is_primitive = false; is_set = true;  is_static = true;  break;
-    case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break;
-    case StaticPrimitiveWrite:   // Keep GCC happy by having a default handler, fall-through.
-    default:                     is_primitive = true;  is_set = true;  is_static = true;  break;
-  }
+  constexpr bool is_primitive = (type & FindFieldFlags::PrimitiveBit) != 0;
+  constexpr bool is_set = (type & FindFieldFlags::WriteBit) != 0;
+  constexpr bool is_static = (type & FindFieldFlags::StaticBit) != 0;
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
   ArtField* resolved_field;
@@ -611,22 +600,9 @@
     return nullptr;
   }
   // Check for incompatible class change.
-  bool is_primitive;
-  bool is_set;
-  bool is_static;
-  switch (type) {
-    case InstanceObjectRead:     is_primitive = false; is_set = false; is_static = false; break;
-    case InstanceObjectWrite:    is_primitive = false; is_set = true;  is_static = false; break;
-    case InstancePrimitiveRead:  is_primitive = true;  is_set = false; is_static = false; break;
-    case InstancePrimitiveWrite: is_primitive = true;  is_set = true;  is_static = false; break;
-    case StaticObjectRead:       is_primitive = false; is_set = false; is_static = true;  break;
-    case StaticObjectWrite:      is_primitive = false; is_set = true;  is_static = true;  break;
-    case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break;
-    case StaticPrimitiveWrite:   is_primitive = true;  is_set = true;  is_static = true;  break;
-    default:
-      LOG(FATAL) << "UNREACHABLE";
-      UNREACHABLE();
-  }
+  const bool is_primitive = (type & FindFieldFlags::PrimitiveBit) != 0;
+  const bool is_set = (type & FindFieldFlags::WriteBit) != 0;
+  const bool is_static = (type & FindFieldFlags::StaticBit) != 0;
   if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
     // Incompatible class change.
     return nullptr;
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 9d70b03..c8bf6d0 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -103,16 +103,25 @@
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
+enum FindFieldFlags {
+  InstanceBit = 1 << 0,
+  StaticBit = 1 << 1,
+  ObjectBit = 1 << 2,
+  PrimitiveBit = 1 << 3,
+  ReadBit = 1 << 4,
+  WriteBit = 1 << 5,
+};
+
 // Type of find field operation for fast and slow case.
 enum FindFieldType {
-  InstanceObjectRead,
-  InstanceObjectWrite,
-  InstancePrimitiveRead,
-  InstancePrimitiveWrite,
-  StaticObjectRead,
-  StaticObjectWrite,
-  StaticPrimitiveRead,
-  StaticPrimitiveWrite,
+  InstanceObjectRead = InstanceBit | ObjectBit | ReadBit,
+  InstanceObjectWrite = InstanceBit | ObjectBit | WriteBit,
+  InstancePrimitiveRead = InstanceBit | PrimitiveBit | ReadBit,
+  InstancePrimitiveWrite = InstanceBit | PrimitiveBit | WriteBit,
+  StaticObjectRead = StaticBit | ObjectBit | ReadBit,
+  StaticObjectWrite = StaticBit | ObjectBit | WriteBit,
+  StaticPrimitiveRead = StaticBit | PrimitiveBit | ReadBit,
+  StaticPrimitiveWrite = StaticBit | PrimitiveBit | WriteBit,
 };
 
 template<FindFieldType type, bool access_check>
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index 62cc9de..d38e3ed 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -28,13 +28,6 @@
 
 namespace art {
 
-inline constexpr bool FindFieldTypeIsRead(FindFieldType type) {
-  return type == InstanceObjectRead ||
-         type == InstancePrimitiveRead ||
-         type == StaticObjectRead ||
-         type == StaticPrimitiveRead;
-}
-
 // Helper function to do a null check after trying to resolve the field. Not for statics since obj
 // does not exist there. There is a suspend check, object is a double pointer to update the value
 // in the caller in case it moves.
@@ -50,7 +43,7 @@
   HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(obj));
   ArtField* field = FindFieldFromCode<type, kAccessCheck>(field_idx, referrer, self, size);
   if (LIKELY(field != nullptr) && UNLIKELY(h == nullptr)) {
-    ThrowNullPointerExceptionForFieldAccess(field, /*is_read*/FindFieldTypeIsRead(type));
+    ThrowNullPointerExceptionForFieldAccess(field, (type & FindFieldFlags::ReadBit) != 0);
     return nullptr;
   }
   return field;
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 3a80008..d91cc24 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -423,7 +423,7 @@
 
   void VisitRoots(mirror::Object*** roots,
                   size_t count,
-                  const RootInfo& info ATTRIBUTE_UNUSED)
+                  const RootInfo& info ATTRIBUTE_UNUSED) override
       REQUIRES_SHARED(Locks::mutator_lock_) {
     Thread* self = Thread::Current();
     for (size_t i = 0; i < count; ++i) {
@@ -440,7 +440,7 @@
 
   void VisitRoots(mirror::CompressedReference<mirror::Object>** roots,
                   size_t count,
-                  const RootInfo& info ATTRIBUTE_UNUSED)
+                  const RootInfo& info ATTRIBUTE_UNUSED) override
       REQUIRES_SHARED(Locks::mutator_lock_) {
     Thread* self = Thread::Current();
     for (size_t i = 0; i < count; ++i) {
@@ -905,13 +905,8 @@
       // during a minor (young-generation) collection:
       // - In the case where we run with a boot image, these classes are part of the image space,
       //   which is an immune space.
-      // - In the case where we run without a boot image, these classes are allocated in the region
-      //   space (main space), but they are not expected to move during a minor collection (this
-      //   would only happen if those classes were allocated between a major and a minor
-      //   collections, which is unlikely -- we don't expect any GC to happen before these
-      //   fundamental classes are initialized). Note that these classes could move during a major
-      //   collection though, but this is fine: in that case, the whole heap is traced and the card
-      //   table logic below is not used.
+      // - In the case where we run without a boot image, these classes are allocated in the
+      //   non-moving space (see art::ClassLinker::InitWithoutImage).
       Runtime::Current()->GetHeap()->GetCardTable()->Scan<false>(
           space->GetMarkBitmap(),
           space->Begin(),
@@ -2331,6 +2326,7 @@
   CHECK(!region_space_->HasAddress(ref)) << "obj=" << obj << " ref=" << ref;
   // In a non-moving space. Check that the ref is marked.
   if (immune_spaces_.ContainsObject(ref)) {
+    // Immune space case.
     if (kUseBakerReadBarrier) {
       // Immune object may not be gray if called from the GC.
       if (Thread::Current() == thread_running_gc_ && !gc_grays_immune_objects_) {
@@ -2344,28 +2340,68 @@
           << " updated_all_immune_objects=" << updated_all_immune_objects;
     }
   } else {
+    // Non-moving space and large-object space (LOS) cases.
     accounting::ContinuousSpaceBitmap* mark_bitmap =
         heap_mark_bitmap_->GetContinuousSpaceBitmap(ref);
     accounting::LargeObjectBitmap* los_bitmap =
         heap_mark_bitmap_->GetLargeObjectBitmap(ref);
-    bool is_los = mark_bitmap == nullptr;
-    if ((!is_los && mark_bitmap->Test(ref)) ||
-        (is_los && los_bitmap->Test(ref))) {
-      // OK.
-    } else {
-      // If `ref` is on the allocation stack, then it may not be
-      // marked live, but considered marked/alive (but not
-      // necessarily on the live stack).
-      CHECK(IsOnAllocStack(ref))
-          << "Unmarked ref that's not on the allocation stack."
-          << " obj=" << obj
-          << " ref=" << ref
-          << " rb_state=" << ref->GetReadBarrierState()
-          << " is_los=" << std::boolalpha << is_los << std::noboolalpha
-          << " is_marking=" << std::boolalpha << is_marking_ << std::noboolalpha
-          << " young_gen=" << std::boolalpha << young_gen_ << std::noboolalpha
-          << " self=" << Thread::Current();
-    }
+    bool is_los = (mark_bitmap == nullptr);
+
+    bool marked_in_non_moving_space_or_los =
+        (kUseBakerReadBarrier
+         && kEnableGenerationalConcurrentCopyingCollection
+         && young_gen_
+         && !done_scanning_.load(std::memory_order_acquire))
+        // Don't use the mark bitmap to ensure `ref` is marked: check that the
+        // read barrier state is gray instead. This is to take into account a
+        // potential race between two read barriers on the same reference when the
+        // young-generation collector is still scanning the dirty cards.
+        //
+        // For instance consider two concurrent read barriers on the same GC root
+        // reference during the dirty-card-scanning step of a young-generation
+        // collection. Both threads would call ReadBarrier::BarrierForRoot, which
+        // would:
+        // a. mark the reference (leading to a call to
+        //    ConcurrentCopying::MarkNonMoving); then
+        // b. check the to-space invariant (leading to a call this
+        //    ConcurrentCopying::AssertToSpaceInvariantInNonMovingSpace -- this
+        //    method).
+        //
+        // In this situation, the following race could happen:
+        // 1. Thread A successfully changes `ref`'s read barrier state from
+        //    non-gray (white) to gray (with AtomicSetReadBarrierState) in
+        //    ConcurrentCopying::MarkNonMoving, then gets preempted.
+        // 2. Thread B also tries to change `ref`'s read barrier state with
+        //    AtomicSetReadBarrierState from non-gray to gray in
+        //    ConcurrentCopying::MarkNonMoving, but fails, as Thread A already
+        //    changed it.
+        // 3. Because Thread B failed the previous CAS, it does *not* set the
+        //    bit in the mark bitmap for `ref`.
+        // 4. Thread B checks the to-space invariant and calls
+        //    ConcurrentCopying::AssertToSpaceInvariantInNonMovingSpace: the bit
+        //    is not set in the mark bitmap for `ref`; checking that this bit is
+        //    set to check the to-space invariant is therefore not a reliable
+        //    test.
+        // 5. (Note that eventually, Thread A will resume its execution and set
+        //    the bit for `ref` in the mark bitmap.)
+        ? (ref->GetReadBarrierState() == ReadBarrier::GrayState())
+        // It is safe to use the heap mark bitmap otherwise.
+        : (!is_los && mark_bitmap->Test(ref)) || (is_los && los_bitmap->Test(ref));
+
+    // If `ref` is on the allocation stack, then it may not be
+    // marked live, but considered marked/alive (but not
+    // necessarily on the live stack).
+    CHECK(marked_in_non_moving_space_or_los || IsOnAllocStack(ref))
+        << "Unmarked ref that's not on the allocation stack."
+        << " obj=" << obj
+        << " ref=" << ref
+        << " rb_state=" << ref->GetReadBarrierState()
+        << " is_los=" << std::boolalpha << is_los << std::noboolalpha
+        << " is_marking=" << std::boolalpha << is_marking_ << std::noboolalpha
+        << " young_gen=" << std::boolalpha << young_gen_ << std::noboolalpha
+        << " done_scanning="
+        << std::boolalpha << done_scanning_.load(std::memory_order_acquire) << std::noboolalpha
+        << " self=" << Thread::Current();
   }
 }
 
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 23b2719..5f44a72 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -789,12 +789,12 @@
     mark_stack_[mark_stack_pos_++].Assign(obj);
   }
 
-  virtual void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
   // Scans all of the objects
-  virtual void Run(Thread* self ATTRIBUTE_UNUSED)
+  void Run(Thread* self ATTRIBUTE_UNUSED) override
       REQUIRES(Locks::heap_bitmap_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     ScanObjectParallelVisitor visitor(this);
@@ -852,11 +852,11 @@
   const uint8_t minimum_age_;
   const bool clear_card_;
 
-  virtual void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
-  virtual void Run(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
+  void Run(Thread* self) override NO_THREAD_SAFETY_ANALYSIS {
     ScanObjectParallelVisitor visitor(this);
     accounting::CardTable* card_table = mark_sweep_->GetHeap()->GetCardTable();
     size_t cards_scanned = clear_card_
@@ -1009,12 +1009,12 @@
   const uintptr_t begin_;
   const uintptr_t end_;
 
-  virtual void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
   // Scans all of the objects
-  virtual void Run(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
+  void Run(Thread* self) override NO_THREAD_SAFETY_ANALYSIS {
     ScanObjectParallelVisitor visitor(this);
     bitmap_->VisitMarkedRange(begin_, end_, visitor);
     // Finish by emptying our local mark stack.
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 589e9a4..b6610b7 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -450,6 +450,7 @@
     // Non moving space is always dlmalloc since we currently don't have support for multiple
     // active rosalloc spaces.
     const size_t size = non_moving_space_mem_map.Size();
+    const void* non_moving_space_mem_map_begin = non_moving_space_mem_map.Begin();
     non_moving_space_ = space::DlMallocSpace::CreateFromMemMap(std::move(non_moving_space_mem_map),
                                                                "zygote / non moving space",
                                                                kDefaultStartingSize,
@@ -457,9 +458,9 @@
                                                                size,
                                                                size,
                                                                /* can_move_objects */ false);
-    non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
     CHECK(non_moving_space_ != nullptr) << "Failed creating non moving space "
-        << non_moving_space_mem_map.Begin();
+        << non_moving_space_mem_map_begin;
+    non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
     AddSpace(non_moving_space_);
   }
   // Create other spaces based on whether or not we have a moving GC.
@@ -2279,13 +2280,13 @@
     }
   }
 
-  virtual bool ShouldSweepSpace(space::ContinuousSpace* space ATTRIBUTE_UNUSED) const {
+  bool ShouldSweepSpace(space::ContinuousSpace* space ATTRIBUTE_UNUSED) const override {
     // Don't sweep any spaces since we probably blasted the internal accounting of the free list
     // allocator.
     return false;
   }
 
-  virtual mirror::Object* MarkNonForwardedObject(mirror::Object* obj)
+  mirror::Object* MarkNonForwardedObject(mirror::Object* obj) override
       REQUIRES(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
     size_t obj_size = obj->SizeOf<kDefaultVerifyFlags>();
     size_t alloc_size = RoundUp(obj_size, kObjectAlignment);
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index 7cbad3b..05a04f2 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -96,7 +96,7 @@
 }
 
 class ZygoteHeapTest : public CommonRuntimeTest {
-  void SetUpRuntimeOptions(RuntimeOptions* options) {
+  void SetUpRuntimeOptions(RuntimeOptions* options) override {
     CommonRuntimeTest::SetUpRuntimeOptions(options);
     options->push_back(std::make_pair("-Xzygote", nullptr));
   }
diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc
index 6caca84..3754129 100644
--- a/runtime/gc/heap_verification_test.cc
+++ b/runtime/gc/heap_verification_test.cc
@@ -83,7 +83,12 @@
 }
 
 TEST_F(VerificationTest, IsValidClassInHeap) {
-  TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING();
+  // Now that the String class is allocated in the non-moving space when the
+  // runtime is running without a boot image (which is the case in this gtest),
+  // and we run with AddressSanizer, it is possible that the (presumably
+  // invalid) memory location `uint_klass - kObjectAlignment` tested below is
+  // poisoned when running with AddressSanizer. Disable this test in that case.
+  TEST_DISABLED_FOR_MEMORY_TOOL();
   ScopedObjectAccess soa(Thread::Current());
   VariableSizedHandleScope hs(soa.Self());
   Handle<mirror::String> string(
@@ -106,7 +111,13 @@
 }
 
 TEST_F(VerificationTest, DumpValidObjectInfo) {
-  TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING();
+  // Now that the String class is allocated in the non-moving space when the
+  // runtime is running without a boot image (which is the case in this gtest),
+  // and we run with AddressSanizer, it is possible that the calls to
+  // Verification::DumpObjectInfo below involving the String class object
+  // (`string->GetClass()`, `uint_klass`, etc.) access poisoned memory when they
+  // call Verification::DumpRAMAroundAddress. Disable this test in that case.
+  TEST_DISABLED_FOR_MEMORY_TOOL();
   ScopedLogSeverity sls(LogSeverity::INFO);
   ScopedObjectAccess soa(Thread::Current());
   Runtime* const runtime = Runtime::Current();
@@ -126,7 +137,13 @@
 }
 
 TEST_F(VerificationTest, LogHeapCorruption) {
-  TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING();
+  // Now that the String class is allocated in the non-moving space when the
+  // runtime is running without a boot image (which is the case in this gtest),
+  // and we run with AddressSanizer, it is possible that the call to
+  // Verification::LogHeapCorruption below involving the String class object
+  // (`string->GetClass()`) accesses poisoned memory when it calls
+  // Verification::DumpRAMAroundAddress. Disable this test in that case.
+  TEST_DISABLED_FOR_MEMORY_TOOL();
   ScopedLogSeverity sls(LogSeverity::INFO);
   ScopedObjectAccess soa(Thread::Current());
   Runtime* const runtime = Runtime::Current();
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index fe4124d..c212bad 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -276,7 +276,7 @@
   explicit ClearedReferenceTask(jobject cleared_references)
       : HeapTask(NanoTime()), cleared_references_(cleared_references) {
   }
-  virtual void Run(Thread* thread) {
+  void Run(Thread* thread) override {
     ScopedObjectAccess soa(thread);
     jvalue args[1];
     args[0].l = cleared_references_;
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 3999e27..316bfe1 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1008,7 +1008,7 @@
       }
 
       if (obj->IsClass()) {
-        mirror::Class* klass = obj->AsClass<kVerifyNone, kWithoutReadBarrier>();
+        mirror::Class* klass = obj->AsClass<kVerifyNone>();
         // Fixup super class before visiting instance fields which require
         // information from their super class to calculate offsets.
         mirror::Class* super_class = klass->GetSuperClass<kVerifyNone, kWithoutReadBarrier>();
@@ -1026,8 +1026,8 @@
           *this);
       // Note that this code relies on no circular dependencies.
       // We want to use our own class loader and not the one in the image.
-      if (obj->IsClass<kVerifyNone, kWithoutReadBarrier>()) {
-        mirror::Class* as_klass = obj->AsClass<kVerifyNone, kWithoutReadBarrier>();
+      if (obj->IsClass<kVerifyNone>()) {
+        mirror::Class* as_klass = obj->AsClass<kVerifyNone>();
         FixupObjectAdapter visitor(boot_image_, boot_oat_, app_image_, app_oat_);
         as_klass->FixupNativePointers<kVerifyNone, kWithoutReadBarrier>(as_klass,
                                                                         pointer_size_,
@@ -1099,7 +1099,7 @@
           fixup_heap_objects_(fixup_heap_objects),
           pointer_size_(pointer_size) {}
 
-    virtual void Visit(ArtMethod* method) NO_THREAD_SAFETY_ANALYSIS {
+    void Visit(ArtMethod* method) override NO_THREAD_SAFETY_ANALYSIS {
       // TODO: Separate visitor for runtime vs normal methods.
       if (UNLIKELY(method->IsRuntimeMethod())) {
         ImtConflictTable* table = method->GetImtConflictTable(pointer_size_);
@@ -1132,7 +1132,7 @@
     template<typename... Args>
     explicit FixupArtFieldVisitor(Args... args) : FixupVisitor(args...) {}
 
-    virtual void Visit(ArtField* field) NO_THREAD_SAFETY_ANALYSIS {
+    void Visit(ArtField* field) override NO_THREAD_SAFETY_ANALYSIS {
       field->UpdateObjects(ForwardObjectAdapter(this));
     }
   };
diff --git a/runtime/gc/space/large_object_space_test.cc b/runtime/gc/space/large_object_space_test.cc
index 9baa016..d55ccd6 100644
--- a/runtime/gc/space/large_object_space_test.cc
+++ b/runtime/gc/space/large_object_space_test.cc
@@ -128,7 +128,7 @@
   AllocRaceTask(size_t id, size_t iterations, size_t size, LargeObjectSpace* los) :
     id_(id), iterations_(iterations), size_(size), los_(los) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     for (size_t i = 0; i < iterations_ ; ++i) {
       size_t alloc_size, bytes_tl_bulk_allocated;
       mirror::Object* ptr = los_->Alloc(self, size_, &alloc_size, nullptr,
@@ -140,7 +140,7 @@
     }
   }
 
-  virtual void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index b42433c..03fd964 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -1385,7 +1385,7 @@
       : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
         shorty('V') {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     if (m != nullptr && !m->IsRuntimeMethod()) {
       // The first Java method.
diff --git a/runtime/interpreter/mterp/arm/field.S b/runtime/interpreter/mterp/arm/field.S
new file mode 100644
index 0000000..c468788
--- /dev/null
+++ b/runtime/interpreter/mterp/arm/field.S
@@ -0,0 +1,16 @@
+%default { }
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern $helper
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       $helper
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
diff --git a/runtime/interpreter/mterp/arm/op_iget.S b/runtime/interpreter/mterp/arm/op_iget.S
index 1684a76..1fa32fa 100644
--- a/runtime/interpreter/mterp/arm/op_iget.S
+++ b/runtime/interpreter/mterp/arm/op_iget.S
@@ -1,26 +1,2 @@
 %default { "is_object":"0", "helper":"MterpIGetU32"}
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    EXPORT_PC
-    FETCH    r0, 1                         @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12            @ r1<- B
-    GET_VREG r1, r1                        @ r1<- fp[B], the object pointer
-    ldr      r2, [rFP, #OFF_FP_METHOD]     @ r2<- referrer
-    mov      r3, rSELF                     @ r3<- self
-    bl       $helper
-    ldr      r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     r2, rINST, #8, #4             @ r2<- A
-    PREFETCH_INST 2
-    cmp      r3, #0
-    bne      MterpPossibleException        @ bail out
-    .if $is_object
-    SET_VREG_OBJECT r0, r2                 @ fp[A]<- r0
-    .else
-    SET_VREG r0, r2                        @ fp[A]<- r0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE ip                     @ extract opcode from rINST
-    GOTO_OPCODE ip                         @ jump to next instruction
+%include "arm/field.S" { }
diff --git a/runtime/interpreter/mterp/arm/op_iget_wide.S b/runtime/interpreter/mterp/arm/op_iget_wide.S
index 46e9ec8..ede21eb 100644
--- a/runtime/interpreter/mterp/arm/op_iget_wide.S
+++ b/runtime/interpreter/mterp/arm/op_iget_wide.S
@@ -1,23 +1 @@
-    /*
-     * 64-bit instance field get.
-     *
-     * for: iget-wide
-     */
-    EXPORT_PC
-    FETCH    r0, 1                         @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12            @ r1<- B
-    GET_VREG r1, r1                        @ r1<- fp[B], the object pointer
-    ldr      r2, [rFP, #OFF_FP_METHOD]     @ r2<- referrer
-    mov      r3, rSELF                     @ r3<- self
-    bl       MterpIGetU64
-    ldr      r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     r2, rINST, #8, #4             @ r2<- A
-    PREFETCH_INST 2
-    cmp      r3, #0
-    bne      MterpException                @ bail out
-    CLEAR_SHADOW_PAIR r2, ip, lr           @ Zero out the shadow regs
-    VREG_INDEX_TO_ADDR r3, r2              @ r3<- &fp[A]
-    stmia    r3, {r0-r1}                   @ fp[A]<- r0/r1
-    ADVANCE 2
-    GET_INST_OPCODE ip                     @ extract opcode from rINST
-    GOTO_OPCODE ip                         @ jump to next instruction
+%include "arm/op_iget.S" { "helper":"MterpIGetU64" }
diff --git a/runtime/interpreter/mterp/arm/op_iput.S b/runtime/interpreter/mterp/arm/op_iput.S
index a16795d..6201d80 100644
--- a/runtime/interpreter/mterp/arm/op_iput.S
+++ b/runtime/interpreter/mterp/arm/op_iput.S
@@ -1,22 +1,2 @@
 %default { "is_object":"0", "helper":"MterpIPutU32" }
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field@CCCC */
-    .extern $helper
-    EXPORT_PC
-    FETCH    r0, 1                      @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12         @ r1<- B
-    GET_VREG r1, r1                     @ r1<- fp[B], the object pointer
-    ubfx     r2, rINST, #8, #4          @ r2<- A
-    GET_VREG r2, r2                     @ r2<- fp[A]
-    ldr      r3, [rFP, #OFF_FP_METHOD]  @ r3<- referrer
-    PREFETCH_INST 2
-    bl       $helper
-    cmp      r0, #0
-    bne      MterpPossibleException
-    ADVANCE  2                          @ advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+%include "arm/field.S" { }
diff --git a/runtime/interpreter/mterp/arm/op_iput_object.S b/runtime/interpreter/mterp/arm/op_iput_object.S
index 4f401eb..1003d10 100644
--- a/runtime/interpreter/mterp/arm/op_iput_object.S
+++ b/runtime/interpreter/mterp/arm/op_iput_object.S
@@ -1,11 +1 @@
-    EXPORT_PC
-    add     r0, rFP, #OFF_FP_SHADOWFRAME
-    mov     r1, rPC
-    mov     r2, rINST
-    mov     r3, rSELF
-    bl      MterpIPutObj
-    cmp     r0, #0
-    beq     MterpException
-    FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+%include "arm/op_iput.S" { "is_object":"1", "helper":"MterpIPutObj" }
diff --git a/runtime/interpreter/mterp/arm/op_iput_wide.S b/runtime/interpreter/mterp/arm/op_iput_wide.S
index 6a41473..f2845ad 100644
--- a/runtime/interpreter/mterp/arm/op_iput_wide.S
+++ b/runtime/interpreter/mterp/arm/op_iput_wide.S
@@ -1,16 +1 @@
-    /* iput-wide vA, vB, field@CCCC */
-    .extern MterpIPutU64
-    EXPORT_PC
-    FETCH    r0, 1                      @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12         @ r1<- B
-    GET_VREG r1, r1                     @ r1<- fp[B], the object pointer
-    ubfx     r2, rINST, #8, #4          @ r2<- A
-    VREG_INDEX_TO_ADDR r2, r2           @ r2<- &fp[A]
-    ldr      r3, [rFP, #OFF_FP_METHOD]  @ r3<- referrer
-    PREFETCH_INST 2
-    bl       MterpIPutU64
-    cmp      r0, #0
-    bne      MterpPossibleException
-    ADVANCE  2                          @ advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+%include "arm/op_iput.S" { "helper":"MterpIPutU64" }
diff --git a/runtime/interpreter/mterp/arm/op_sget.S b/runtime/interpreter/mterp/arm/op_sget.S
index 575a8c0..b382de4 100644
--- a/runtime/interpreter/mterp/arm/op_sget.S
+++ b/runtime/interpreter/mterp/arm/op_sget.S
@@ -1,27 +1,2 @@
 %default { "is_object":"0", "helper":"MterpSGetU32" }
-    /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field@BBBB */
-
-    .extern $helper
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- field ref BBBB
-    ldr   r1, [rFP, #OFF_FP_METHOD]
-    mov   r2, rSELF
-    bl    $helper
-    ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    mov   r2, rINST, lsr #8             @ r2<- AA
-    PREFETCH_INST 2
-    cmp   r3, #0                        @ Fail to resolve?
-    bne   MterpException                @ bail out
-.if $is_object
-    SET_VREG_OBJECT r0, r2              @ fp[AA]<- r0
-.else
-    SET_VREG r0, r2                     @ fp[AA]<- r0
-.endif
-    ADVANCE 2
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip
+%include "arm/field.S" { }
diff --git a/runtime/interpreter/mterp/arm/op_sget_wide.S b/runtime/interpreter/mterp/arm/op_sget_wide.S
index 5981ec4..d6905df 100644
--- a/runtime/interpreter/mterp/arm/op_sget_wide.S
+++ b/runtime/interpreter/mterp/arm/op_sget_wide.S
@@ -1,22 +1 @@
-    /*
-     * SGET_WIDE handler wrapper.
-     *
-     */
-    /* sget-wide vAA, field@BBBB */
-
-    .extern MterpSGetU64
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- field ref BBBB
-    ldr   r1, [rFP, #OFF_FP_METHOD]
-    mov   r2, rSELF
-    bl    MterpSGetU64
-    ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    mov   r9, rINST, lsr #8             @ r9<- AA
-    VREG_INDEX_TO_ADDR lr, r9           @ r9<- &fp[AA]
-    cmp   r3, #0                        @ Fail to resolve?
-    bne   MterpException                @ bail out
-    FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    CLEAR_SHADOW_PAIR r9, r2, ip        @ Zero out the shadow regs
-    stmia lr, {r0-r1}                   @ vAA/vAA+1<- r0/r1
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+%include "arm/op_sget.S" {"helper":"MterpSGetU64"}
diff --git a/runtime/interpreter/mterp/arm/op_sput.S b/runtime/interpreter/mterp/arm/op_sput.S
index c4a8978..171f024 100644
--- a/runtime/interpreter/mterp/arm/op_sput.S
+++ b/runtime/interpreter/mterp/arm/op_sput.S
@@ -1,20 +1,2 @@
-%default { "helper":"MterpSPutU32"}
-    /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field@BBBB */
-    EXPORT_PC
-    FETCH   r0, 1                       @ r0<- field ref BBBB
-    mov     r3, rINST, lsr #8           @ r3<- AA
-    GET_VREG r1, r3                     @ r1<= fp[AA]
-    ldr     r2, [rFP, #OFF_FP_METHOD]
-    mov     r3, rSELF
-    PREFETCH_INST 2                     @ Get next inst, but don't advance rPC
-    bl      $helper
-    cmp     r0, #0                      @ 0 on success, -1 on failure
-    bne     MterpException
-    ADVANCE 2                           @ Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+%default { "is_object":"0", "helper":"MterpSPutU32"}
+%include "arm/field.S" { }
diff --git a/runtime/interpreter/mterp/arm/op_sput_object.S b/runtime/interpreter/mterp/arm/op_sput_object.S
index c58918f..8fcd52e 100644
--- a/runtime/interpreter/mterp/arm/op_sput_object.S
+++ b/runtime/interpreter/mterp/arm/op_sput_object.S
@@ -1,11 +1 @@
-    EXPORT_PC
-    add     r0, rFP, #OFF_FP_SHADOWFRAME
-    mov     r1, rPC
-    mov     r2, rINST
-    mov     r3, rSELF
-    bl      MterpSPutObj
-    cmp     r0, #0
-    beq     MterpException
-    FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+%include "arm/op_sput.S" {"is_object":"1", "helper":"MterpSPutObj"}
diff --git a/runtime/interpreter/mterp/arm/op_sput_wide.S b/runtime/interpreter/mterp/arm/op_sput_wide.S
index 0ed4017..c254f78 100644
--- a/runtime/interpreter/mterp/arm/op_sput_wide.S
+++ b/runtime/interpreter/mterp/arm/op_sput_wide.S
@@ -1,19 +1 @@
-    /*
-     * SPUT_WIDE handler wrapper.
-     *
-     */
-    /* sput-wide vAA, field@BBBB */
-    .extern MterpSPutU64
-    EXPORT_PC
-    FETCH   r0, 1                       @ r0<- field ref BBBB
-    mov     r1, rINST, lsr #8           @ r1<- AA
-    VREG_INDEX_TO_ADDR r1, r1
-    ldr     r2, [rFP, #OFF_FP_METHOD]
-    mov     r3, rSELF
-    PREFETCH_INST 2                     @ Get next inst, but don't advance rPC
-    bl      MterpSPutU64
-    cmp     r0, #0                      @ 0 on success, -1 on failure
-    bne     MterpException
-    ADVANCE 2                           @ Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+%include "arm/op_sput.S" {"helper":"MterpSPutU64"}
diff --git a/runtime/interpreter/mterp/arm64/field.S b/runtime/interpreter/mterp/arm64/field.S
new file mode 100644
index 0000000..631c8d1
--- /dev/null
+++ b/runtime/interpreter/mterp/arm64/field.S
@@ -0,0 +1,15 @@
+%default { }
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern $helper
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       $helper
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
diff --git a/runtime/interpreter/mterp/arm64/op_iget.S b/runtime/interpreter/mterp/arm64/op_iget.S
index cb453ac..48b9cad 100644
--- a/runtime/interpreter/mterp/arm64/op_iget.S
+++ b/runtime/interpreter/mterp/arm64/op_iget.S
@@ -1,26 +1,2 @@
-%default { "extend":"", "is_object":"0", "helper":"MterpIGetU32"}
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    EXPORT_PC
-    FETCH    w0, 1                         // w0<- field ref CCCC
-    lsr      w1, wINST, #12                // w1<- B
-    GET_VREG w1, w1                        // w1<- fp[B], the object pointer
-    ldr      x2, [xFP, #OFF_FP_METHOD]     // w2<- referrer
-    mov      x3, xSELF                     // w3<- self
-    bl       $helper
-    ldr      x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    $extend
-    ubfx     w2, wINST, #8, #4             // w2<- A
-    PREFETCH_INST 2
-    cbnz     x3, MterpPossibleException    // bail out
-    .if $is_object
-    SET_VREG_OBJECT w0, w2                 // fp[A]<- w0
-    .else
-    SET_VREG w0, w2                        // fp[A]<- w0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE ip                     // extract opcode from rINST
-    GOTO_OPCODE ip                         // jump to next instruction
+%default { "is_object":"0", "helper":"MterpIGetU32"}
+%include "arm64/field.S" { }
diff --git a/runtime/interpreter/mterp/arm64/op_iget_boolean.S b/runtime/interpreter/mterp/arm64/op_iget_boolean.S
index 3b17144..9a83b2a 100644
--- a/runtime/interpreter/mterp/arm64/op_iget_boolean.S
+++ b/runtime/interpreter/mterp/arm64/op_iget_boolean.S
@@ -1 +1 @@
-%include "arm64/op_iget.S" { "helper":"MterpIGetU8", "extend":"uxtb w0, w0" }
+%include "arm64/op_iget.S" { "helper":"MterpIGetU8" }
diff --git a/runtime/interpreter/mterp/arm64/op_iget_byte.S b/runtime/interpreter/mterp/arm64/op_iget_byte.S
index d5ef1d3..f73e634 100644
--- a/runtime/interpreter/mterp/arm64/op_iget_byte.S
+++ b/runtime/interpreter/mterp/arm64/op_iget_byte.S
@@ -1 +1 @@
-%include "arm64/op_iget.S" { "helper":"MterpIGetI8", "extend":"sxtb w0, w0" }
+%include "arm64/op_iget.S" { "helper":"MterpIGetI8" }
diff --git a/runtime/interpreter/mterp/arm64/op_iget_char.S b/runtime/interpreter/mterp/arm64/op_iget_char.S
index 68e1435..a5efd9e 100644
--- a/runtime/interpreter/mterp/arm64/op_iget_char.S
+++ b/runtime/interpreter/mterp/arm64/op_iget_char.S
@@ -1 +1 @@
-%include "arm64/op_iget.S" { "helper":"MterpIGetU16", "extend":"uxth w0, w0" }
+%include "arm64/op_iget.S" { "helper":"MterpIGetU16" }
diff --git a/runtime/interpreter/mterp/arm64/op_iget_short.S b/runtime/interpreter/mterp/arm64/op_iget_short.S
index 714f4b9..bb81c17 100644
--- a/runtime/interpreter/mterp/arm64/op_iget_short.S
+++ b/runtime/interpreter/mterp/arm64/op_iget_short.S
@@ -1 +1 @@
-%include "arm64/op_iget.S" { "helper":"MterpIGetI16", "extend":"sxth w0, w0" }
+%include "arm64/op_iget.S" { "helper":"MterpIGetI16" }
diff --git a/runtime/interpreter/mterp/arm64/op_iget_wide.S b/runtime/interpreter/mterp/arm64/op_iget_wide.S
index 4fc735c..70061d6 100644
--- a/runtime/interpreter/mterp/arm64/op_iget_wide.S
+++ b/runtime/interpreter/mterp/arm64/op_iget_wide.S
@@ -1,21 +1 @@
-    /*
-     * 64-bit instance field get.
-     *
-     * for: iget-wide
-     */
-    EXPORT_PC
-    FETCH    w0, 1                         // w0<- field ref CCCC
-    lsr      w1, wINST, #12                // w1<- B
-    GET_VREG w1, w1                        // w1<- fp[B], the object pointer
-    ldr      x2, [xFP, #OFF_FP_METHOD]     // w2<- referrer
-    mov      x3, xSELF                     // w3<- self
-    bl       MterpIGetU64
-    ldr      x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     w2, wINST, #8, #4             // w2<- A
-    PREFETCH_INST 2
-    cmp      w3, #0
-    cbnz     w3, MterpException            // bail out
-    SET_VREG_WIDE x0, w2
-    ADVANCE 2
-    GET_INST_OPCODE ip                     // extract opcode from wINST
-    GOTO_OPCODE ip                         // jump to next instruction
+%include "arm64/op_iget.S" { "helper":"MterpIGetU64" }
diff --git a/runtime/interpreter/mterp/arm64/op_iput.S b/runtime/interpreter/mterp/arm64/op_iput.S
index 5e21d5c..2bc3db9 100644
--- a/runtime/interpreter/mterp/arm64/op_iput.S
+++ b/runtime/interpreter/mterp/arm64/op_iput.S
@@ -1,21 +1,2 @@
 %default { "is_object":"0", "helper":"MterpIPutU32" }
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field//CCCC */
-    .extern $helper
-    EXPORT_PC
-    FETCH    w0, 1                      // w0<- field ref CCCC
-    lsr      w1, wINST, #12             // w1<- B
-    GET_VREG w1, w1                     // w1<- fp[B], the object pointer
-    ubfx     w2, wINST, #8, #4          // w2<- A
-    GET_VREG w2, w2                     // w2<- fp[A]
-    ldr      x3, [xFP, #OFF_FP_METHOD]  // w3<- referrer
-    PREFETCH_INST 2
-    bl       $helper
-    cbnz     w0, MterpPossibleException
-    ADVANCE  2                          // advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+%include "arm64/field.S" { }
diff --git a/runtime/interpreter/mterp/arm64/op_iput_object.S b/runtime/interpreter/mterp/arm64/op_iput_object.S
index 0c0441a..e9bb93f 100644
--- a/runtime/interpreter/mterp/arm64/op_iput_object.S
+++ b/runtime/interpreter/mterp/arm64/op_iput_object.S
@@ -1,10 +1 @@
-    EXPORT_PC
-    add     x0, xFP, #OFF_FP_SHADOWFRAME
-    mov     x1, xPC
-    mov     w2, wINST
-    mov     x3, xSELF
-    bl      MterpIPutObj
-    cbz     w0, MterpException
-    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+%include "arm64/op_iput.S" { "is_object":"1", "helper":"MterpIPutObj" }
diff --git a/runtime/interpreter/mterp/arm64/op_iput_wide.S b/runtime/interpreter/mterp/arm64/op_iput_wide.S
index be6aeb0..e1fafad 100644
--- a/runtime/interpreter/mterp/arm64/op_iput_wide.S
+++ b/runtime/interpreter/mterp/arm64/op_iput_wide.S
@@ -1,15 +1 @@
-    /* iput-wide vA, vB, field//CCCC */
-    .extern MterpIPutU64
-    EXPORT_PC
-    FETCH    w0, 1                      // w0<- field ref CCCC
-    lsr      w1, wINST, #12             // w1<- B
-    GET_VREG w1, w1                     // w1<- fp[B], the object pointer
-    ubfx     w2, wINST, #8, #4          // w2<- A
-    VREG_INDEX_TO_ADDR x2, x2           // w2<- &fp[A]
-    ldr      x3, [xFP, #OFF_FP_METHOD]  // w3<- referrer
-    PREFETCH_INST 2
-    bl       MterpIPutU64
-    cbnz     w0, MterpPossibleException
-    ADVANCE  2                          // advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from wINST
-    GOTO_OPCODE ip                      // jump to next instruction
+%include "arm64/op_iput.S" { "helper":"MterpIPutU64" }
diff --git a/runtime/interpreter/mterp/arm64/op_sget.S b/runtime/interpreter/mterp/arm64/op_sget.S
index 00b07fa..78e95b2 100644
--- a/runtime/interpreter/mterp/arm64/op_sget.S
+++ b/runtime/interpreter/mterp/arm64/op_sget.S
@@ -1,27 +1,2 @@
-%default { "is_object":"0", "helper":"MterpSGetU32", "extend":"" }
-    /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field//BBBB */
-
-    .extern $helper
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- field ref BBBB
-    ldr   x1, [xFP, #OFF_FP_METHOD]
-    mov   x2, xSELF
-    bl    $helper
-    ldr   x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    lsr   w2, wINST, #8                 // w2<- AA
-    $extend
-    PREFETCH_INST 2
-    cbnz  x3, MterpException            // bail out
-.if $is_object
-    SET_VREG_OBJECT w0, w2              // fp[AA]<- w0
-.else
-    SET_VREG w0, w2                     // fp[AA]<- w0
-.endif
-    ADVANCE 2
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip
+%default { "is_object":"0", "helper":"MterpSGetU32" }
+%include "arm64/field.S" { }
diff --git a/runtime/interpreter/mterp/arm64/op_sget_boolean.S b/runtime/interpreter/mterp/arm64/op_sget_boolean.S
index 73f3a10..0cf9f09 100644
--- a/runtime/interpreter/mterp/arm64/op_sget_boolean.S
+++ b/runtime/interpreter/mterp/arm64/op_sget_boolean.S
@@ -1 +1 @@
-%include "arm64/op_sget.S" {"helper":"MterpSGetU8", "extend":"uxtb w0, w0"}
+%include "arm64/op_sget.S" {"helper":"MterpSGetU8"}
diff --git a/runtime/interpreter/mterp/arm64/op_sget_byte.S b/runtime/interpreter/mterp/arm64/op_sget_byte.S
index 38c0da6..7c88a81 100644
--- a/runtime/interpreter/mterp/arm64/op_sget_byte.S
+++ b/runtime/interpreter/mterp/arm64/op_sget_byte.S
@@ -1 +1 @@
-%include "arm64/op_sget.S" {"helper":"MterpSGetI8", "extend":"sxtb w0, w0"}
+%include "arm64/op_sget.S" {"helper":"MterpSGetI8"}
diff --git a/runtime/interpreter/mterp/arm64/op_sget_char.S b/runtime/interpreter/mterp/arm64/op_sget_char.S
index c0801bf..883e944 100644
--- a/runtime/interpreter/mterp/arm64/op_sget_char.S
+++ b/runtime/interpreter/mterp/arm64/op_sget_char.S
@@ -1 +1 @@
-%include "arm64/op_sget.S" {"helper":"MterpSGetU16", "extend":"uxth w0, w0"}
+%include "arm64/op_sget.S" {"helper":"MterpSGetU16"}
diff --git a/runtime/interpreter/mterp/arm64/op_sget_short.S b/runtime/interpreter/mterp/arm64/op_sget_short.S
index 81e0434..6cb9184 100644
--- a/runtime/interpreter/mterp/arm64/op_sget_short.S
+++ b/runtime/interpreter/mterp/arm64/op_sget_short.S
@@ -1 +1 @@
-%include "arm64/op_sget.S" {"helper":"MterpSGetI16", "extend":"sxth w0, w0"}
+%include "arm64/op_sget.S" {"helper":"MterpSGetI16"}
diff --git a/runtime/interpreter/mterp/arm64/op_sget_wide.S b/runtime/interpreter/mterp/arm64/op_sget_wide.S
index 546ab94..f5d182e 100644
--- a/runtime/interpreter/mterp/arm64/op_sget_wide.S
+++ b/runtime/interpreter/mterp/arm64/op_sget_wide.S
@@ -1,19 +1 @@
-    /*
-     * SGET_WIDE handler wrapper.
-     *
-     */
-    /* sget-wide vAA, field//BBBB */
-
-    .extern MterpSGetU64
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- field ref BBBB
-    ldr   x1, [xFP, #OFF_FP_METHOD]
-    mov   x2, xSELF
-    bl    MterpSGetU64
-    ldr   x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    lsr   w4, wINST, #8                 // w4<- AA
-    cbnz  x3, MterpException            // bail out
-    FETCH_ADVANCE_INST 2                // advance rPC, load wINST
-    SET_VREG_WIDE x0, w4
-    GET_INST_OPCODE ip                  // extract opcode from wINST
-    GOTO_OPCODE ip                      // jump to next instruction
+%include "arm64/op_sget.S" {"helper":"MterpSGetU64"}
diff --git a/runtime/interpreter/mterp/arm64/op_sput.S b/runtime/interpreter/mterp/arm64/op_sput.S
index 7a0dc30..d229d0d 100644
--- a/runtime/interpreter/mterp/arm64/op_sput.S
+++ b/runtime/interpreter/mterp/arm64/op_sput.S
@@ -1,19 +1,2 @@
-%default { "helper":"MterpSPutU32"}
-    /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field//BBBB */
-    EXPORT_PC
-    FETCH   w0, 1                       // r0<- field ref BBBB
-    lsr     w3, wINST, #8               // r3<- AA
-    GET_VREG w1, w3                     // r1<= fp[AA]
-    ldr     x2, [xFP, #OFF_FP_METHOD]
-    mov     x3, xSELF
-    PREFETCH_INST 2                     // Get next inst, but don't advance rPC
-    bl      $helper
-    cbnz    w0, MterpException          // 0 on success
-    ADVANCE 2                           // Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+%default { "is_object":"0", "helper":"MterpSPutU32"}
+%include "arm64/field.S" { }
diff --git a/runtime/interpreter/mterp/arm64/op_sput_object.S b/runtime/interpreter/mterp/arm64/op_sput_object.S
index a649656..536f1b1 100644
--- a/runtime/interpreter/mterp/arm64/op_sput_object.S
+++ b/runtime/interpreter/mterp/arm64/op_sput_object.S
@@ -1,10 +1 @@
-    EXPORT_PC
-    add     x0, xFP, #OFF_FP_SHADOWFRAME
-    mov     x1, xPC
-    mov     x2, xINST
-    mov     x3, xSELF
-    bl      MterpSPutObj
-    cbz     w0, MterpException
-    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+%include "arm64/op_sput.S" {"is_object":"1", "helper":"MterpSPutObj"}
diff --git a/runtime/interpreter/mterp/arm64/op_sput_wide.S b/runtime/interpreter/mterp/arm64/op_sput_wide.S
index 58b3c42..b4be6b2 100644
--- a/runtime/interpreter/mterp/arm64/op_sput_wide.S
+++ b/runtime/interpreter/mterp/arm64/op_sput_wide.S
@@ -1,18 +1 @@
-    /*
-     * SPUT_WIDE handler wrapper.
-     *
-     */
-    /* sput-wide vAA, field//BBBB */
-    .extern MterpSPutU64
-    EXPORT_PC
-    FETCH   w0, 1                       // w0<- field ref BBBB
-    lsr     w1, wINST, #8               // w1<- AA
-    VREG_INDEX_TO_ADDR x1, w1
-    ldr     x2, [xFP, #OFF_FP_METHOD]
-    mov     x3, xSELF
-    PREFETCH_INST 2                     // Get next inst, but don't advance rPC
-    bl      MterpSPutU64
-    cbnz    w0, MterpException          // 0 on success, -1 on failure
-    ADVANCE 2                           // Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from wINST
-    GOTO_OPCODE ip                      // jump to next instruction
+%include "arm64/op_sput.S" {"helper":"MterpSPutU64"}
diff --git a/runtime/interpreter/mterp/mips/field.S b/runtime/interpreter/mterp/mips/field.S
new file mode 100644
index 0000000..1333ed7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips/field.S
@@ -0,0 +1 @@
+TODO
diff --git a/runtime/interpreter/mterp/mips/op_iget.S b/runtime/interpreter/mterp/mips/op_iget.S
index 33717de..e218272 100644
--- a/runtime/interpreter/mterp/mips/op_iget.S
+++ b/runtime/interpreter/mterp/mips/op_iget.S
@@ -1,25 +1,2 @@
 %default { "is_object":"0", "helper":"MterpIGetU32"}
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- referrer
-    move  a3, rSELF                        # a3 <- self
-    JAL($helper)
-    lw   a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA4(a2)                           # a2<- A+
-    PREFETCH_INST(2)                       # load rINST
-    bnez  a3, MterpPossibleException        # bail out
-    ADVANCE(2)                             #  advance rPC
-    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
-    .if $is_object
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[A] <- v0
-    .else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[A] <- v0
-    .endif
+%include "mips/field.S" { }
diff --git a/runtime/interpreter/mterp/mips/op_iget_wide.S b/runtime/interpreter/mterp/mips/op_iget_wide.S
index 858a889..885372a 100644
--- a/runtime/interpreter/mterp/mips/op_iget_wide.S
+++ b/runtime/interpreter/mterp/mips/op_iget_wide.S
@@ -1,20 +1 @@
-    /*
-     * 64-bit instance field get.
-     *
-     * for: iget-wide
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field byte offset
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- referrer
-    move  a3, rSELF                        # a3 <- self
-    JAL(MterpIGetU64)
-    lw   a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA4(a2)                           # a2<- A+
-    PREFETCH_INST(2)                       # load rINST
-    bnez a3, MterpException                # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    SET_VREG64_GOTO(v0, v1, a2, t0)        # fp[A] <- v0/v1
+%include "mips/op_iget.S" { "helper":"MterpIGetU64" }
diff --git a/runtime/interpreter/mterp/mips/op_iput.S b/runtime/interpreter/mterp/mips/op_iput.S
index 4dd4075..efbdfba 100644
--- a/runtime/interpreter/mterp/mips/op_iput.S
+++ b/runtime/interpreter/mterp/mips/op_iput.S
@@ -1,21 +1,2 @@
-%default { "helper":"MterpIPutU32" }
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field@CCCC */
-    .extern $helper
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    GET_OPA4(a2)                           # a2 <- A+
-    GET_VREG(a2, a2)                       # a2 <- fp[A]
-    lw    a3, OFF_FP_METHOD(rFP)           # a3 <- referrer
-    PREFETCH_INST(2)                       # load rINST
-    JAL($helper)
-    bnez  v0, MterpPossibleException       # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+%default { "is_object":"0", "helper":"MterpIPutU32" }
+%include "mips/field.S" { }
diff --git a/runtime/interpreter/mterp/mips/op_iput_object.S b/runtime/interpreter/mterp/mips/op_iput_object.S
index c96a4d4..6f7e7b7 100644
--- a/runtime/interpreter/mterp/mips/op_iput_object.S
+++ b/runtime/interpreter/mterp/mips/op_iput_object.S
@@ -1,16 +1 @@
-    /*
-     * 32-bit instance field put.
-     *
-     * for: iput-object, iput-object-volatile
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    addu   a0, rFP, OFF_FP_SHADOWFRAME
-    move   a1, rPC
-    move   a2, rINST
-    move   a3, rSELF
-    JAL(MterpIPutObj)
-    beqz   v0, MterpException
-    FETCH_ADVANCE_INST(2)               # advance rPC, load rINST
-    GET_INST_OPCODE(t0)                 # extract opcode from rINST
-    GOTO_OPCODE(t0)                     # jump to next instruction
+%include "mips/op_iput.S" { "is_object":"1", "helper":"MterpIPutObj" }
diff --git a/runtime/interpreter/mterp/mips/op_iput_wide.S b/runtime/interpreter/mterp/mips/op_iput_wide.S
index dccb6b7..fc862e4 100644
--- a/runtime/interpreter/mterp/mips/op_iput_wide.S
+++ b/runtime/interpreter/mterp/mips/op_iput_wide.S
@@ -1,15 +1 @@
-    /* iput-wide vA, vB, field@CCCC */
-    .extern MterpIPutU64
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    GET_OPA4(a2)                           # a2 <- A+
-    EAS2(a2, rFP, a2)                      # a2 <- &fp[A]
-    lw    a3, OFF_FP_METHOD(rFP)           # a3 <- referrer
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpIPutU64)
-    bnez  v0, MterpPossibleException       # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+%include "mips/op_iput.S" { "helper":"MterpIPutU64" }
diff --git a/runtime/interpreter/mterp/mips/op_sget.S b/runtime/interpreter/mterp/mips/op_sget.S
index 8750a17..92d6673 100644
--- a/runtime/interpreter/mterp/mips/op_sget.S
+++ b/runtime/interpreter/mterp/mips/op_sget.S
@@ -1,24 +1,2 @@
 %default { "is_object":"0", "helper":"MterpSGetU32" }
-    /*
-     * General SGET handler.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field@BBBB */
-    .extern $helper
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    lw    a1, OFF_FP_METHOD(rFP)           # a1 <- method
-    move  a2, rSELF                        # a2 <- self
-    JAL($helper)
-    lw    a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA(a2)                            # a2 <- AA
-    PREFETCH_INST(2)
-    bnez  a3, MterpException               # bail out
-    ADVANCE(2)
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-.if $is_object
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[AA] <- v0
-.else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[AA] <- v0
-.endif
+%include "mips/field.S" { }
diff --git a/runtime/interpreter/mterp/mips/op_sget_wide.S b/runtime/interpreter/mterp/mips/op_sget_wide.S
index 76f78cb..be4ae02 100644
--- a/runtime/interpreter/mterp/mips/op_sget_wide.S
+++ b/runtime/interpreter/mterp/mips/op_sget_wide.S
@@ -1,16 +1 @@
-    /*
-     * 64-bit SGET handler.
-     */
-    /* sget-wide vAA, field@BBBB */
-    .extern MterpSGetU64
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    lw    a1, OFF_FP_METHOD(rFP)           # a1 <- method
-    move  a2, rSELF                        # a2 <- self
-    JAL(MterpSGetU64)
-    lw    a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    bnez  a3, MterpException
-    GET_OPA(a1)                            # a1 <- AA
-    FETCH_ADVANCE_INST(2)                  # advance rPC, load rINST
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    SET_VREG64_GOTO(v0, v1, a1, t0)        # vAA/vAA+1 <- v0/v1
+%include "mips/op_sget.S" {"helper":"MterpSGetU64"}
diff --git a/runtime/interpreter/mterp/mips/op_sput.S b/runtime/interpreter/mterp/mips/op_sput.S
index 547de39..c858679 100644
--- a/runtime/interpreter/mterp/mips/op_sput.S
+++ b/runtime/interpreter/mterp/mips/op_sput.S
@@ -1,19 +1,2 @@
-%default { "helper":"MterpSPutU32"}
-    /*
-     * General SPUT handler.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field@BBBB */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    GET_OPA(a3)                            # a3 <- AA
-    GET_VREG(a1, a3)                       # a1 <- fp[AA], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- method
-    move  a3, rSELF                        # a3 <- self
-    PREFETCH_INST(2)                       # load rINST
-    JAL($helper)
-    bnez  v0, MterpException               # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+%default { "is_object":"0", "helper":"MterpSPutU32"}
+%include "mips/field.S" { }
diff --git a/runtime/interpreter/mterp/mips/op_sput_object.S b/runtime/interpreter/mterp/mips/op_sput_object.S
index 55c88a6..683b767 100644
--- a/runtime/interpreter/mterp/mips/op_sput_object.S
+++ b/runtime/interpreter/mterp/mips/op_sput_object.S
@@ -1,16 +1 @@
-    /*
-     * General 32-bit SPUT handler.
-     *
-     * for: sput-object,
-     */
-    /* op vAA, field@BBBB */
-    EXPORT_PC()
-    addu   a0, rFP, OFF_FP_SHADOWFRAME
-    move   a1, rPC
-    move   a2, rINST
-    move   a3, rSELF
-    JAL(MterpSPutObj)
-    beqz   v0, MterpException
-    FETCH_ADVANCE_INST(2)               # advance rPC, load rINST
-    GET_INST_OPCODE(t0)                 # extract opcode from rINST
-    GOTO_OPCODE(t0)                     # jump to next instruction
+%include "mips/op_sput.S" {"is_object":"1", "helper":"MterpSPutObj"}
diff --git a/runtime/interpreter/mterp/mips/op_sput_wide.S b/runtime/interpreter/mterp/mips/op_sput_wide.S
index cfaaaee..1d2ed19 100644
--- a/runtime/interpreter/mterp/mips/op_sput_wide.S
+++ b/runtime/interpreter/mterp/mips/op_sput_wide.S
@@ -1,17 +1 @@
-    /*
-     * 64-bit SPUT handler.
-     */
-    /* sput-wide vAA, field@BBBB */
-    .extern MterpSPutU64
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPA(a1)                            # a1 <- AA
-    EAS2(a1, rFP, a1)                      # a1 <- &fp[AA]
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- method
-    move  a3, rSELF                        # a3 <- self
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpSPutU64)
-    bnez  v0, MterpException               # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+%include "mips/op_sput.S" {"helper":"MterpSPutU64"}
diff --git a/runtime/interpreter/mterp/mips64/field.S b/runtime/interpreter/mterp/mips64/field.S
new file mode 100644
index 0000000..1333ed7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/field.S
@@ -0,0 +1 @@
+TODO
diff --git a/runtime/interpreter/mterp/mips64/op_iget.S b/runtime/interpreter/mterp/mips64/op_iget.S
index a8ce94c..e91f099 100644
--- a/runtime/interpreter/mterp/mips64/op_iget.S
+++ b/runtime/interpreter/mterp/mips64/op_iget.S
@@ -1,26 +1,2 @@
 %default { "is_object":"0", "helper":"MterpIGetU32"}
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    .extern $helper
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
-    move     a3, rSELF                  # a3 <- self
-    jal      $helper
-    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    ext      a2, rINST, 8, 4            # a2 <- A
-    PREFETCH_INST 2
-    bnez     a3, MterpPossibleException # bail out
-    .if $is_object
-    SET_VREG_OBJECT v0, a2              # fp[A] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[A] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/field.S" { }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_wide.S b/runtime/interpreter/mterp/mips64/op_iget_wide.S
index 08bf544..40f3645 100644
--- a/runtime/interpreter/mterp/mips64/op_iget_wide.S
+++ b/runtime/interpreter/mterp/mips64/op_iget_wide.S
@@ -1,21 +1 @@
-    /*
-     * 64-bit instance field get.
-     *
-     * for: iget-wide
-     */
-    .extern MterpIGetU64
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
-    move     a3, rSELF                  # a3 <- self
-    jal      MterpIGetU64
-    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    ext      a2, rINST, 8, 4            # a2 <- A
-    PREFETCH_INST 2
-    bnez     a3, MterpPossibleException # bail out
-    SET_VREG_WIDE v0, a2                # fp[A] <- v0
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/op_iget.S" { "helper":"MterpIGetU64" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput.S b/runtime/interpreter/mterp/mips64/op_iput.S
index 9a789e6..81ab911 100644
--- a/runtime/interpreter/mterp/mips64/op_iput.S
+++ b/runtime/interpreter/mterp/mips64/op_iput.S
@@ -1,21 +1,2 @@
-%default { "helper":"MterpIPutU32" }
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field//CCCC */
-    .extern $helper
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref CCCC
-    srl     a1, rINST, 12               # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ext     a2, rINST, 8, 4             # a2 <- A
-    GET_VREG a2, a2                     # a2 <- fp[A]
-    ld      a3, OFF_FP_METHOD(rFP)      # a3 <- referrer
-    PREFETCH_INST 2
-    jal     $helper
-    bnez    v0, MterpPossibleException  # bail out
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%default { "is_object":"0", "helper":"MterpIPutU32" }
+%include "mips64/field.S" { }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_object.S b/runtime/interpreter/mterp/mips64/op_iput_object.S
index dd1938e..d3316dd 100644
--- a/runtime/interpreter/mterp/mips64/op_iput_object.S
+++ b/runtime/interpreter/mterp/mips64/op_iput_object.S
@@ -1,11 +1 @@
-    .extern MterpIPutObj
-    EXPORT_PC
-    daddu   a0, rFP, OFF_FP_SHADOWFRAME
-    move    a1, rPC
-    move    a2, rINST
-    move    a3, rSELF
-    jal     MterpIPutObj
-    beqzc   v0, MterpException
-    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/op_iput.S" { "is_object":"1", "helper":"MterpIPutObj" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_wide.S b/runtime/interpreter/mterp/mips64/op_iput_wide.S
index 6272690..05194b3 100644
--- a/runtime/interpreter/mterp/mips64/op_iput_wide.S
+++ b/runtime/interpreter/mterp/mips64/op_iput_wide.S
@@ -1,15 +1 @@
-    /* iput-wide vA, vB, field//CCCC */
-    .extern MterpIPutU64
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ext      a2, rINST, 8, 4            # a2 <- A
-    dlsa     a2, a2, rFP, 2             # a2 <- &fp[A]
-    ld       a3, OFF_FP_METHOD(rFP)     # a3 <- referrer
-    PREFETCH_INST 2
-    jal      MterpIPutU64
-    bnez     v0, MterpPossibleException # bail out
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/op_iput.S" { "helper":"MterpIPutU64" }
diff --git a/runtime/interpreter/mterp/mips64/op_sget.S b/runtime/interpreter/mterp/mips64/op_sget.S
index b7b0382..200da35 100644
--- a/runtime/interpreter/mterp/mips64/op_sget.S
+++ b/runtime/interpreter/mterp/mips64/op_sget.S
@@ -1,26 +1,2 @@
-%default { "is_object":"0", "helper":"MterpSGetU32", "extend":"" }
-    /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field//BBBB */
-    .extern $helper
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    ld      a1, OFF_FP_METHOD(rFP)
-    move    a2, rSELF
-    jal     $helper
-    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    srl     a2, rINST, 8                # a2 <- AA
-    $extend
-    PREFETCH_INST 2
-    bnez    a3, MterpException          # bail out
-    .if $is_object
-    SET_VREG_OBJECT v0, a2              # fp[AA] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[AA] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0
+%default { "is_object":"0", "helper":"MterpSGetU32" }
+%include "mips64/field.S" { }
diff --git a/runtime/interpreter/mterp/mips64/op_sget_boolean.S b/runtime/interpreter/mterp/mips64/op_sget_boolean.S
index fe2deb1..8abb396 100644
--- a/runtime/interpreter/mterp/mips64/op_sget_boolean.S
+++ b/runtime/interpreter/mterp/mips64/op_sget_boolean.S
@@ -1 +1 @@
-%include "mips64/op_sget.S" {"helper":"MterpSGetU8", "extend":"and v0, v0, 0xff"}
+%include "mips64/op_sget.S" {"helper":"MterpSGetU8"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget_byte.S b/runtime/interpreter/mterp/mips64/op_sget_byte.S
index a7e2bef..68623f6 100644
--- a/runtime/interpreter/mterp/mips64/op_sget_byte.S
+++ b/runtime/interpreter/mterp/mips64/op_sget_byte.S
@@ -1 +1 @@
-%include "mips64/op_sget.S" {"helper":"MterpSGetI8", "extend":"seb v0, v0"}
+%include "mips64/op_sget.S" {"helper":"MterpSGetI8"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget_char.S b/runtime/interpreter/mterp/mips64/op_sget_char.S
index ed86f32..3c7b962 100644
--- a/runtime/interpreter/mterp/mips64/op_sget_char.S
+++ b/runtime/interpreter/mterp/mips64/op_sget_char.S
@@ -1 +1 @@
-%include "mips64/op_sget.S" {"helper":"MterpSGetU16", "extend":"and v0, v0, 0xffff"}
+%include "mips64/op_sget.S" {"helper":"MterpSGetU16"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget_short.S b/runtime/interpreter/mterp/mips64/op_sget_short.S
index f708a20..9a8579b 100644
--- a/runtime/interpreter/mterp/mips64/op_sget_short.S
+++ b/runtime/interpreter/mterp/mips64/op_sget_short.S
@@ -1 +1 @@
-%include "mips64/op_sget.S" {"helper":"MterpSGetI16", "extend":"seh v0, v0"}
+%include "mips64/op_sget.S" {"helper":"MterpSGetI16"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget_wide.S b/runtime/interpreter/mterp/mips64/op_sget_wide.S
index 7c31252..14f232c 100644
--- a/runtime/interpreter/mterp/mips64/op_sget_wide.S
+++ b/runtime/interpreter/mterp/mips64/op_sget_wide.S
@@ -1,18 +1 @@
-    /*
-     * SGET_WIDE handler wrapper.
-     *
-     */
-    /* sget-wide vAA, field//BBBB */
-    .extern MterpSGetU64
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    ld      a1, OFF_FP_METHOD(rFP)
-    move    a2, rSELF
-    jal     MterpSGetU64
-    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    srl     a4, rINST, 8                # a4 <- AA
-    bnez    a3, MterpException          # bail out
-    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
-    SET_VREG_WIDE v0, a4
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/op_sget.S" {"helper":"MterpSGetU64"}
diff --git a/runtime/interpreter/mterp/mips64/op_sput.S b/runtime/interpreter/mterp/mips64/op_sput.S
index 28b8c3e..0bd6837 100644
--- a/runtime/interpreter/mterp/mips64/op_sput.S
+++ b/runtime/interpreter/mterp/mips64/op_sput.S
@@ -1,20 +1,2 @@
-%default { "helper":"MterpSPutU32" }
-    /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field//BBBB */
-    .extern $helper
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    srl     a3, rINST, 8                # a3 <- AA
-    GET_VREG a1, a3                     # a1 <- fp[AA]
-    ld      a2, OFF_FP_METHOD(rFP)
-    move    a3, rSELF
-    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
-    jal     $helper
-    bnezc   v0, MterpException          # 0 on success
-    ADVANCE 2                           # Past exception point - now advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%default { "is_object":"0", "helper":"MterpSPutU32"}
+%include "mips64/field.S" { }
diff --git a/runtime/interpreter/mterp/mips64/op_sput_object.S b/runtime/interpreter/mterp/mips64/op_sput_object.S
index ff43967..09bd0fb 100644
--- a/runtime/interpreter/mterp/mips64/op_sput_object.S
+++ b/runtime/interpreter/mterp/mips64/op_sput_object.S
@@ -1,11 +1 @@
-    .extern MterpSPutObj
-    EXPORT_PC
-    daddu   a0, rFP, OFF_FP_SHADOWFRAME
-    move    a1, rPC
-    move    a2, rINST
-    move    a3, rSELF
-    jal     MterpSPutObj
-    beqzc   v0, MterpException
-    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/op_sput.S" {"is_object":"1", "helper":"MterpSPutObj"}
diff --git a/runtime/interpreter/mterp/mips64/op_sput_wide.S b/runtime/interpreter/mterp/mips64/op_sput_wide.S
index bfb6983..070d17f 100644
--- a/runtime/interpreter/mterp/mips64/op_sput_wide.S
+++ b/runtime/interpreter/mterp/mips64/op_sput_wide.S
@@ -1,18 +1 @@
-    /*
-     * SPUT_WIDE handler wrapper.
-     *
-     */
-    /* sput-wide vAA, field//BBBB */
-    .extern MterpSPutU64
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    srl     a1, rINST, 8                # a2 <- AA
-    dlsa    a1, a1, rFP, 2
-    ld      a2, OFF_FP_METHOD(rFP)
-    move    a3, rSELF
-    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
-    jal     MterpSPutU64
-    bnezc   v0, MterpException          # 0 on success, -1 on failure
-    ADVANCE 2                           # Past exception point - now advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/op_sput.S" {"helper":"MterpSPutU64"}
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 7b37c9a..65c1aa8 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -490,24 +490,6 @@
   return true;
 }
 
-extern "C" size_t MterpSPutObj(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
-                                uint32_t inst_data, Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  const Instruction* inst = Instruction::At(dex_pc_ptr);
-  return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
-      (self, *shadow_frame, inst, inst_data);
-}
-
-extern "C" size_t MterpIPutObj(ShadowFrame* shadow_frame,
-                                  uint16_t* dex_pc_ptr,
-                                  uint32_t inst_data,
-                                  Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  const Instruction* inst = Instruction::At(dex_pc_ptr);
-  return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
-      (self, *shadow_frame, inst, inst_data);
-}
-
 extern "C" size_t MterpIputObjectQuick(ShadowFrame* shadow_frame,
                                        uint16_t* dex_pc_ptr,
                                        uint32_t inst_data)
@@ -681,352 +663,159 @@
   return MterpShouldSwitchInterpreters();
 }
 
-template<typename PrimType, typename RetType, typename Getter, FindFieldType kType>
-NO_INLINE RetType artGetInstanceFromMterp(uint32_t field_idx,
-                                          mirror::Object* obj,
-                                          ArtMethod* referrer,
-                                          Thread* self)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-  StackHandleScope<1> hs(self);
-  HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(&obj));  // GC might move the object.
-  ArtField* field = FindFieldFromCode<kType, /* access_checks */ false>(
-      field_idx, referrer, self, sizeof(PrimType));
-  if (UNLIKELY(field == nullptr)) {
-    return 0;  // Will throw exception by checking with Thread::Current.
+// Execute single field access instruction (get/put, static/instance).
+// The template arguments reduce this to fairly small amount of code.
+// It requires the target object and field to be already resolved.
+template<typename PrimType, FindFieldType kAccessType>
+ALWAYS_INLINE void MterpFieldAccess(Instruction* inst,
+                                    uint16_t inst_data,
+                                    ShadowFrame* shadow_frame,
+                                    ObjPtr<mirror::Object> obj,
+                                    MemberOffset offset,
+                                    bool is_volatile)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  static_assert(std::is_integral<PrimType>::value, "Unexpected primitive type");
+  constexpr bool kIsStatic = (kAccessType & FindFieldFlags::StaticBit) != 0;
+  constexpr bool kIsPrimitive = (kAccessType & FindFieldFlags::PrimitiveBit) != 0;
+  constexpr bool kIsRead = (kAccessType & FindFieldFlags::ReadBit) != 0;
+
+  uint16_t vRegA = kIsStatic ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
+  if (kIsPrimitive) {
+    if (kIsRead) {
+      PrimType value = UNLIKELY(is_volatile)
+          ? obj->GetFieldPrimitive<PrimType, /*kIsVolatile*/ true>(offset)
+          : obj->GetFieldPrimitive<PrimType, /*kIsVolatile*/ false>(offset);
+      if (sizeof(PrimType) == sizeof(uint64_t)) {
+        shadow_frame->SetVRegLong(vRegA, value);  // Set two consecutive registers.
+      } else {
+        shadow_frame->SetVReg(vRegA, static_cast<int32_t>(value));  // Sign/zero extend.
+      }
+    } else {  // Write.
+      uint64_t value = (sizeof(PrimType) == sizeof(uint64_t))
+          ? shadow_frame->GetVRegLong(vRegA)
+          : shadow_frame->GetVReg(vRegA);
+      if (UNLIKELY(is_volatile)) {
+        obj->SetFieldPrimitive<PrimType, /*kIsVolatile*/ true>(offset, value);
+      } else {
+        obj->SetFieldPrimitive<PrimType, /*kIsVolatile*/ false>(offset, value);
+      }
+    }
+  } else {  // Object.
+    if (kIsRead) {
+      ObjPtr<mirror::Object> value = UNLIKELY(is_volatile)
+          ? obj->GetFieldObjectVolatile<mirror::Object>(offset)
+          : obj->GetFieldObject<mirror::Object>(offset);
+      shadow_frame->SetVRegReference(vRegA, value);
+    } else {  // Write.
+      ObjPtr<mirror::Object> value = shadow_frame->GetVRegReference(vRegA);
+      if (UNLIKELY(is_volatile)) {
+        obj->SetFieldObjectVolatile</*kTransactionActive*/ false>(offset, value);
+      } else {
+        obj->SetFieldObject</*kTransactionActive*/ false>(offset, value);
+      }
+    }
   }
-  if (UNLIKELY(h == nullptr)) {
-    ThrowNullPointerExceptionForFieldAccess(field, /*is_read*/ true);
-    return 0;  // Will throw exception by checking with Thread::Current.
-  }
-  return Getter::Get(obj, field);
 }
 
-template<typename PrimType, typename RetType, typename Getter>
-ALWAYS_INLINE RetType artGetInstanceFromMterpFast(uint32_t field_idx,
-                                                  mirror::Object* obj,
-                                                  ArtMethod* referrer,
-                                                  Thread* self)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-  constexpr bool kIsObject = std::is_same<RetType, mirror::Object*>::value;
-  constexpr FindFieldType kType = kIsObject ? InstanceObjectRead : InstancePrimitiveRead;
+template<typename PrimType, FindFieldType kAccessType>
+NO_INLINE bool MterpFieldAccessSlow(Instruction* inst,
+                                    uint16_t inst_data,
+                                    ShadowFrame* shadow_frame,
+                                    Thread* self)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  constexpr bool kIsStatic = (kAccessType & FindFieldFlags::StaticBit) != 0;
+  constexpr bool kIsRead = (kAccessType & FindFieldFlags::ReadBit) != 0;
+
+  // Update the dex pc in shadow frame, just in case anything throws.
+  shadow_frame->SetDexPCPtr(reinterpret_cast<uint16_t*>(inst));
+  ArtMethod* referrer = shadow_frame->GetMethod();
+  uint32_t field_idx = kIsStatic ? inst->VRegB_21c() : inst->VRegC_22c();
+  ArtField* field = FindFieldFromCode<kAccessType, /* access_checks */ false>(
+      field_idx, referrer, self, sizeof(PrimType));
+  if (UNLIKELY(field == nullptr)) {
+    DCHECK(self->IsExceptionPending());
+    return false;
+  }
+  ObjPtr<mirror::Object> obj = kIsStatic
+      ? field->GetDeclaringClass().Ptr()
+      : shadow_frame->GetVRegReference(inst->VRegB_22c(inst_data));
+  if (UNLIKELY(obj == nullptr)) {
+    ThrowNullPointerExceptionForFieldAccess(field, kIsRead);
+    return false;
+  }
+  MterpFieldAccess<PrimType, kAccessType>(
+      inst, inst_data, shadow_frame, obj, field->GetOffset(), field->IsVolatile());
+  return true;
+}
+
+template<typename PrimType, FindFieldType kAccessType>
+ALWAYS_INLINE bool MterpFieldAccessFast(Instruction* inst,
+                                        uint16_t inst_data,
+                                        ShadowFrame* shadow_frame,
+                                        Thread* self)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  constexpr bool kIsStatic = (kAccessType & FindFieldFlags::StaticBit) != 0;
 
   // This effectively inlines the fast path from ArtMethod::GetDexCache.
   // It avoids non-inlined call which in turn allows elimination of the prologue and epilogue.
+  ArtMethod* referrer = shadow_frame->GetMethod();
   if (LIKELY(!referrer->IsObsolete())) {
     // Avoid read barriers, since we need only the pointer to the native (non-movable)
     // DexCache field array which we can get even through from-space objects.
     ObjPtr<mirror::Class> klass = referrer->GetDeclaringClass<kWithoutReadBarrier>();
     mirror::DexCache* dex_cache = klass->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>();
+
     // Try to find the desired field in DexCache.
+    uint32_t field_idx = kIsStatic ? inst->VRegB_21c() : inst->VRegC_22c();
     ArtField* field = dex_cache->GetResolvedField(field_idx, kRuntimePointerSize);
-    if (LIKELY(field != nullptr & obj != nullptr)) {
-      if (kIsDebugBuild) {
-        // Compare the fast path and slow path.
-        StackHandleScope<1> hs(self);
-        HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(&obj));  // GC might move the object.
-        DCHECK_EQ(field, (FindFieldFromCode<kType, /* access_checks */ false>(
+    if (LIKELY(field != nullptr)) {
+      bool initialized = !kIsStatic || field->GetDeclaringClass()->IsInitialized();
+      if (LIKELY(initialized)) {
+        DCHECK_EQ(field, (FindFieldFromCode<kAccessType, /* access_checks */ false>(
             field_idx, referrer, self, sizeof(PrimType))));
+        ObjPtr<mirror::Object> obj = kIsStatic
+            ? field->GetDeclaringClass().Ptr()
+            : shadow_frame->GetVRegReference(inst->VRegB_22c(inst_data));
+        if (LIKELY(kIsStatic || obj != nullptr)) {
+          MterpFieldAccess<PrimType, kAccessType>(
+              inst, inst_data, shadow_frame, obj, field->GetOffset(), field->IsVolatile());
+          return true;
+        }
       }
-      return Getter::Get(obj, field);
     }
   }
+
   // Slow path. Last and with identical arguments so that it becomes single instruction tail call.
-  return artGetInstanceFromMterp<PrimType, RetType, Getter, kType>(field_idx, obj, referrer, self);
+  return MterpFieldAccessSlow<PrimType, kAccessType>(inst, inst_data, shadow_frame, self);
 }
 
-#define ART_GET_FIELD_FROM_MTERP(Suffix, Kind, PrimType, RetType, Ptr)                            \
-extern "C" RetType MterpIGet ## Suffix(uint32_t field_idx,                                        \
-                                       mirror::Object* obj,                                       \
-                                       ArtMethod* referrer,                                       \
-                                       Thread* self)                                              \
-      REQUIRES_SHARED(Locks::mutator_lock_) {                                                     \
-  struct Getter { /* Specialize the field load depending on the field type */                     \
-    static RetType Get(mirror::Object* o, ArtField* f) REQUIRES_SHARED(Locks::mutator_lock_) {    \
-      return f->Get##Kind(o)Ptr;                                                                  \
-    }                                                                                             \
-  };                                                                                              \
-  return artGetInstanceFromMterpFast<PrimType, RetType, Getter>(field_idx, obj, referrer, self);  \
-}                                                                                                 \
-
-ART_GET_FIELD_FROM_MTERP(I8, Byte, int8_t, ssize_t, )
-ART_GET_FIELD_FROM_MTERP(U8, Boolean, uint8_t, size_t, )
-ART_GET_FIELD_FROM_MTERP(I16, Short, int16_t, ssize_t, )
-ART_GET_FIELD_FROM_MTERP(U16, Char, uint16_t, size_t, )
-ART_GET_FIELD_FROM_MTERP(U32, 32, uint32_t, size_t, )
-ART_GET_FIELD_FROM_MTERP(U64, 64, uint64_t, uint64_t, )
-ART_GET_FIELD_FROM_MTERP(Obj, Obj, mirror::HeapReference<mirror::Object>, mirror::Object*, .Ptr())
-
-#undef ART_GET_FIELD_FROM_MTERP
-
-extern "C" ssize_t MterpIPutU8(uint32_t field_idx,
-                               mirror::Object* obj,
-                               uint8_t new_value,
-                               ArtMethod* referrer)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ArtField* field = referrer->GetDexCache()->GetResolvedField(field_idx, kRuntimePointerSize);
-  if (LIKELY(field != nullptr && obj != nullptr)) {
-    field->SetBoolean<false>(obj, new_value);
-    return 0;  // success
-  }
-  return -1;  // failure
+#define MTERP_FIELD_ACCESSOR(Name, PrimType, AccessType)                                          \
+extern "C" bool Name(Instruction* inst, uint16_t inst_data, ShadowFrame* sf, Thread* self)        \
+    REQUIRES_SHARED(Locks::mutator_lock_) {                                                       \
+  return MterpFieldAccessFast<PrimType, AccessType>(inst, inst_data, sf, self);                   \
 }
 
-extern "C" ssize_t MterpIPutI8(uint32_t field_idx,
-                               mirror::Object* obj,
-                               uint8_t new_value,
-                               ArtMethod* referrer)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ArtField* field = referrer->GetDexCache()->GetResolvedField(field_idx, kRuntimePointerSize);
-  if (LIKELY(field != nullptr && obj != nullptr)) {
-    field->SetByte<false>(obj, new_value);
-    return 0;  // success
-  }
-  return -1;  // failure
-}
+#define MTERP_FIELD_ACCESSORS_FOR_TYPE(Sufix, PrimType, Kind)                                     \
+  MTERP_FIELD_ACCESSOR(MterpIGet##Sufix, PrimType, Instance##Kind##Read)                          \
+  MTERP_FIELD_ACCESSOR(MterpIPut##Sufix, PrimType, Instance##Kind##Write)                         \
+  MTERP_FIELD_ACCESSOR(MterpSGet##Sufix, PrimType, Static##Kind##Read)                            \
+  MTERP_FIELD_ACCESSOR(MterpSPut##Sufix, PrimType, Static##Kind##Write)
 
-extern "C" ssize_t MterpIPutU16(uint32_t field_idx,
-                                mirror::Object* obj,
-                                uint16_t new_value,
-                                ArtMethod* referrer)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ArtField* field = referrer->GetDexCache()->GetResolvedField(field_idx, kRuntimePointerSize);
-  if (LIKELY(field != nullptr && obj != nullptr)) {
-    field->SetChar<false>(obj, new_value);
-    return 0;  // success
-  }
-  return -1;  // failure
-}
+MTERP_FIELD_ACCESSORS_FOR_TYPE(I8, int8_t, Primitive)
+MTERP_FIELD_ACCESSORS_FOR_TYPE(U8, uint8_t, Primitive)
+MTERP_FIELD_ACCESSORS_FOR_TYPE(I16, int16_t, Primitive)
+MTERP_FIELD_ACCESSORS_FOR_TYPE(U16, uint16_t, Primitive)
+MTERP_FIELD_ACCESSORS_FOR_TYPE(U32, uint32_t, Primitive)
+MTERP_FIELD_ACCESSORS_FOR_TYPE(U64, uint64_t, Primitive)
+MTERP_FIELD_ACCESSORS_FOR_TYPE(Obj, uint32_t, Object)
 
-extern "C" ssize_t MterpIPutI16(uint32_t field_idx,
-                                mirror::Object* obj,
-                                uint16_t new_value,
-                                ArtMethod* referrer)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ArtField* field = referrer->GetDexCache()->GetResolvedField(field_idx, kRuntimePointerSize);
-  if (LIKELY(field != nullptr && obj != nullptr)) {
-    field->SetShort<false>(obj, new_value);
-    return 0;  // success
-  }
-  return -1;  // failure
-}
+// Check that the primitive type for Obj variant above is correct.
+// It really must be primitive type for the templates to compile.
+// In the case of objects, it is only used to get the field size.
+static_assert(kHeapReferenceSize == sizeof(uint32_t), "Unexpected kHeapReferenceSize");
 
-extern "C" ssize_t MterpIPutU32(uint32_t field_idx,
-                                mirror::Object* obj,
-                                uint32_t new_value,
-                                ArtMethod* referrer)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ArtField* field = referrer->GetDexCache()->GetResolvedField(field_idx, kRuntimePointerSize);
-  if (LIKELY(field != nullptr && obj != nullptr)) {
-    field->Set32<false>(obj, new_value);
-    return 0;  // success
-  }
-  return -1;  // failure
-}
-
-extern "C" ssize_t MterpIPutU64(uint32_t field_idx,
-                                mirror::Object* obj,
-                                uint64_t* new_value,
-                                ArtMethod* referrer)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ArtField* field = referrer->GetDexCache()->GetResolvedField(field_idx, kRuntimePointerSize);
-  if (LIKELY(field != nullptr  && obj != nullptr)) {
-    field->Set64<false>(obj, *new_value);
-    return 0;  // success
-  }
-  return -1;  // failure
-}
-
-extern "C" ssize_t artSetObjInstanceFromMterp(uint32_t field_idx,
-                                              mirror::Object* obj,
-                                              mirror::Object* new_value,
-                                              ArtMethod* referrer)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ArtField* field = referrer->GetDexCache()->GetResolvedField(field_idx, kRuntimePointerSize);
-  if (LIKELY(field != nullptr && obj != nullptr)) {
-    field->SetObj<false>(obj, new_value);
-    return 0;  // success
-  }
-  return -1;  // failure
-}
-
-template <typename return_type, Primitive::Type primitive_type>
-ALWAYS_INLINE return_type MterpGetStatic(uint32_t field_idx,
-                                         ArtMethod* referrer,
-                                         Thread* self,
-                                         return_type (ArtField::*func)(ObjPtr<mirror::Object>))
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return_type res = 0;  // On exception, the result will be ignored.
-  ArtField* f =
-      FindFieldFromCode<StaticPrimitiveRead, false>(field_idx,
-                                                    referrer,
-                                                    self,
-                                                    primitive_type);
-  if (LIKELY(f != nullptr)) {
-    ObjPtr<mirror::Object> obj = f->GetDeclaringClass();
-    res = (f->*func)(obj);
-  }
-  return res;
-}
-
-extern "C" int32_t MterpSGetU8(uint32_t field_idx,
-                               ArtMethod* referrer,
-                               Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpGetStatic<uint8_t, Primitive::kPrimBoolean>(field_idx,
-                                                          referrer,
-                                                          self,
-                                                          &ArtField::GetBoolean);
-}
-
-extern "C" int32_t MterpSGetI8(uint32_t field_idx,
-                               ArtMethod* referrer,
-                               Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpGetStatic<int8_t, Primitive::kPrimByte>(field_idx,
-                                                      referrer,
-                                                      self,
-                                                      &ArtField::GetByte);
-}
-
-extern "C" uint32_t MterpSGetU16(uint32_t field_idx,
-                                 ArtMethod* referrer,
-                                 Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpGetStatic<uint16_t, Primitive::kPrimChar>(field_idx,
-                                                        referrer,
-                                                        self,
-                                                        &ArtField::GetChar);
-}
-
-extern "C" int32_t MterpSGetI16(uint32_t field_idx,
-                                ArtMethod* referrer,
-                                Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpGetStatic<int16_t, Primitive::kPrimShort>(field_idx,
-                                                        referrer,
-                                                        self,
-                                                        &ArtField::GetShort);
-}
-
-extern "C" mirror::Object* MterpSGetObj(uint32_t field_idx,
-                                        ArtMethod* referrer,
-                                        Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpGetStatic<ObjPtr<mirror::Object>, Primitive::kPrimNot>(field_idx,
-                                                                     referrer,
-                                                                     self,
-                                                                     &ArtField::GetObject).Ptr();
-}
-
-extern "C" int32_t MterpSGetU32(uint32_t field_idx,
-                                ArtMethod* referrer,
-                                Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpGetStatic<int32_t, Primitive::kPrimInt>(field_idx,
-                                                      referrer,
-                                                      self,
-                                                      &ArtField::GetInt);
-}
-
-extern "C" int64_t MterpSGetU64(uint32_t field_idx, ArtMethod* referrer, Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpGetStatic<int64_t, Primitive::kPrimLong>(field_idx,
-                                                       referrer,
-                                                       self,
-                                                       &ArtField::GetLong);
-}
-
-
-template <typename field_type, Primitive::Type primitive_type>
-int MterpSetStatic(uint32_t field_idx,
-                   field_type new_value,
-                   ArtMethod* referrer,
-                   Thread* self,
-                   void (ArtField::*func)(ObjPtr<mirror::Object>, field_type val))
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  int res = 0;  // Assume success (following quick_field_entrypoints conventions)
-  ArtField* f =
-      FindFieldFromCode<StaticPrimitiveWrite, false>(field_idx, referrer, self, primitive_type);
-  if (LIKELY(f != nullptr)) {
-    ObjPtr<mirror::Object> obj = f->GetDeclaringClass();
-    (f->*func)(obj, new_value);
-  } else {
-    res = -1;  // Failure
-  }
-  return res;
-}
-
-extern "C" int MterpSPutU8(uint32_t field_idx,
-                           uint8_t new_value,
-                           ArtMethod* referrer,
-                           Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpSetStatic<uint8_t, Primitive::kPrimBoolean>(field_idx,
-                                                          new_value,
-                                                          referrer,
-                                                          self,
-                                                          &ArtField::SetBoolean<false>);
-}
-
-extern "C" int MterpSPutI8(uint32_t field_idx,
-                           int8_t new_value,
-                           ArtMethod* referrer,
-                           Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpSetStatic<int8_t, Primitive::kPrimByte>(field_idx,
-                                                      new_value,
-                                                      referrer,
-                                                      self,
-                                                      &ArtField::SetByte<false>);
-}
-
-extern "C" int MterpSPutU16(uint32_t field_idx,
-                            uint16_t new_value,
-                            ArtMethod* referrer,
-                            Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpSetStatic<uint16_t, Primitive::kPrimChar>(field_idx,
-                                                        new_value,
-                                                        referrer,
-                                                        self,
-                                                        &ArtField::SetChar<false>);
-}
-
-extern "C" int MterpSPutI16(uint32_t field_idx,
-                            int16_t new_value,
-                            ArtMethod* referrer,
-                            Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpSetStatic<int16_t, Primitive::kPrimShort>(field_idx,
-                                                        new_value,
-                                                        referrer,
-                                                        self,
-                                                        &ArtField::SetShort<false>);
-}
-
-extern "C" int MterpSPutU32(uint32_t field_idx,
-                            int32_t new_value,
-                            ArtMethod* referrer,
-                            Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpSetStatic<int32_t, Primitive::kPrimInt>(field_idx,
-                                                      new_value,
-                                                      referrer,
-                                                      self,
-                                                      &ArtField::SetInt<false>);
-}
-
-extern "C" int MterpSPutU64(uint32_t field_idx,
-                            int64_t* new_value,
-                            ArtMethod* referrer,
-                            Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return MterpSetStatic<int64_t, Primitive::kPrimLong>(field_idx,
-                                                       *new_value,
-                                                       referrer,
-                                                       self,
-                                                       &ArtField::SetLong<false>);
-}
+#undef MTERP_FIELD_ACCESSORS_FOR_TYPE
+#undef MTERP_FIELD_ACCESSOR
 
 extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr,
                                                   int32_t index)
diff --git a/runtime/interpreter/mterp/out/mterp_arm.S b/runtime/interpreter/mterp/out/mterp_arm.S
index 394a849..25512ae 100644
--- a/runtime/interpreter/mterp/out/mterp_arm.S
+++ b/runtime/interpreter/mterp/out/mterp_arm.S
@@ -2246,215 +2246,185 @@
     .balign 128
 .L_op_iget: /* 0x52 */
 /* File: arm/op_iget.S */
+/* File: arm/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    r0, 1                         @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12            @ r1<- B
-    GET_VREG r1, r1                        @ r1<- fp[B], the object pointer
-    ldr      r2, [rFP, #OFF_FP_METHOD]     @ r2<- referrer
-    mov      r3, rSELF                     @ r3<- self
+    .extern MterpIGetU32
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIGetU32
-    ldr      r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     r2, rINST, #8, #4             @ r2<- A
-    PREFETCH_INST 2
-    cmp      r3, #0
-    bne      MterpPossibleException        @ bail out
-    .if 0
-    SET_VREG_OBJECT r0, r2                 @ fp[A]<- r0
-    .else
-    SET_VREG r0, r2                        @ fp[A]<- r0
-    .endif
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     @ extract opcode from rINST
     GOTO_OPCODE ip                         @ jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_wide: /* 0x53 */
 /* File: arm/op_iget_wide.S */
+/* File: arm/op_iget.S */
+/* File: arm/field.S */
     /*
-     * 64-bit instance field get.
-     *
-     * for: iget-wide
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    r0, 1                         @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12            @ r1<- B
-    GET_VREG r1, r1                        @ r1<- fp[B], the object pointer
-    ldr      r2, [rFP, #OFF_FP_METHOD]     @ r2<- referrer
-    mov      r3, rSELF                     @ r3<- self
+    .extern MterpIGetU64
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIGetU64
-    ldr      r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     r2, rINST, #8, #4             @ r2<- A
-    PREFETCH_INST 2
-    cmp      r3, #0
-    bne      MterpException                @ bail out
-    CLEAR_SHADOW_PAIR r2, ip, lr           @ Zero out the shadow regs
-    VREG_INDEX_TO_ADDR r3, r2              @ r3<- &fp[A]
-    stmia    r3, {r0-r1}                   @ fp[A]<- r0/r1
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     @ extract opcode from rINST
     GOTO_OPCODE ip                         @ jump to next instruction
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_object: /* 0x54 */
 /* File: arm/op_iget_object.S */
 /* File: arm/op_iget.S */
+/* File: arm/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    r0, 1                         @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12            @ r1<- B
-    GET_VREG r1, r1                        @ r1<- fp[B], the object pointer
-    ldr      r2, [rFP, #OFF_FP_METHOD]     @ r2<- referrer
-    mov      r3, rSELF                     @ r3<- self
+    .extern MterpIGetObj
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIGetObj
-    ldr      r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     r2, rINST, #8, #4             @ r2<- A
-    PREFETCH_INST 2
-    cmp      r3, #0
-    bne      MterpPossibleException        @ bail out
-    .if 1
-    SET_VREG_OBJECT r0, r2                 @ fp[A]<- r0
-    .else
-    SET_VREG r0, r2                        @ fp[A]<- r0
-    .endif
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     @ extract opcode from rINST
     GOTO_OPCODE ip                         @ jump to next instruction
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_boolean: /* 0x55 */
 /* File: arm/op_iget_boolean.S */
 /* File: arm/op_iget.S */
+/* File: arm/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    r0, 1                         @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12            @ r1<- B
-    GET_VREG r1, r1                        @ r1<- fp[B], the object pointer
-    ldr      r2, [rFP, #OFF_FP_METHOD]     @ r2<- referrer
-    mov      r3, rSELF                     @ r3<- self
+    .extern MterpIGetU8
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIGetU8
-    ldr      r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     r2, rINST, #8, #4             @ r2<- A
-    PREFETCH_INST 2
-    cmp      r3, #0
-    bne      MterpPossibleException        @ bail out
-    .if 0
-    SET_VREG_OBJECT r0, r2                 @ fp[A]<- r0
-    .else
-    SET_VREG r0, r2                        @ fp[A]<- r0
-    .endif
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     @ extract opcode from rINST
     GOTO_OPCODE ip                         @ jump to next instruction
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_byte: /* 0x56 */
 /* File: arm/op_iget_byte.S */
 /* File: arm/op_iget.S */
+/* File: arm/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    r0, 1                         @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12            @ r1<- B
-    GET_VREG r1, r1                        @ r1<- fp[B], the object pointer
-    ldr      r2, [rFP, #OFF_FP_METHOD]     @ r2<- referrer
-    mov      r3, rSELF                     @ r3<- self
+    .extern MterpIGetI8
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIGetI8
-    ldr      r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     r2, rINST, #8, #4             @ r2<- A
-    PREFETCH_INST 2
-    cmp      r3, #0
-    bne      MterpPossibleException        @ bail out
-    .if 0
-    SET_VREG_OBJECT r0, r2                 @ fp[A]<- r0
-    .else
-    SET_VREG r0, r2                        @ fp[A]<- r0
-    .endif
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     @ extract opcode from rINST
     GOTO_OPCODE ip                         @ jump to next instruction
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_char: /* 0x57 */
 /* File: arm/op_iget_char.S */
 /* File: arm/op_iget.S */
+/* File: arm/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    r0, 1                         @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12            @ r1<- B
-    GET_VREG r1, r1                        @ r1<- fp[B], the object pointer
-    ldr      r2, [rFP, #OFF_FP_METHOD]     @ r2<- referrer
-    mov      r3, rSELF                     @ r3<- self
+    .extern MterpIGetU16
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIGetU16
-    ldr      r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     r2, rINST, #8, #4             @ r2<- A
-    PREFETCH_INST 2
-    cmp      r3, #0
-    bne      MterpPossibleException        @ bail out
-    .if 0
-    SET_VREG_OBJECT r0, r2                 @ fp[A]<- r0
-    .else
-    SET_VREG r0, r2                        @ fp[A]<- r0
-    .endif
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     @ extract opcode from rINST
     GOTO_OPCODE ip                         @ jump to next instruction
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_short: /* 0x58 */
 /* File: arm/op_iget_short.S */
 /* File: arm/op_iget.S */
+/* File: arm/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    r0, 1                         @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12            @ r1<- B
-    GET_VREG r1, r1                        @ r1<- fp[B], the object pointer
-    ldr      r2, [rFP, #OFF_FP_METHOD]     @ r2<- referrer
-    mov      r3, rSELF                     @ r3<- self
+    .extern MterpIGetI16
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIGetI16
-    ldr      r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     r2, rINST, #8, #4             @ r2<- A
-    PREFETCH_INST 2
-    cmp      r3, #0
-    bne      MterpPossibleException        @ bail out
-    .if 0
-    SET_VREG_OBJECT r0, r2                 @ fp[A]<- r0
-    .else
-    SET_VREG r0, r2                        @ fp[A]<- r0
-    .endif
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 128
+.L_op_iput: /* 0x59 */
+/* File: arm/op_iput.S */
+/* File: arm/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIPutU32
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpIPutU32
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     @ extract opcode from rINST
     GOTO_OPCODE ip                         @ jump to next instruction
@@ -2462,93 +2432,74 @@
 
 /* ------------------------------ */
     .balign 128
-.L_op_iput: /* 0x59 */
-/* File: arm/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field@CCCC */
-    .extern MterpIPutU32
-    EXPORT_PC
-    FETCH    r0, 1                      @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12         @ r1<- B
-    GET_VREG r1, r1                     @ r1<- fp[B], the object pointer
-    ubfx     r2, rINST, #8, #4          @ r2<- A
-    GET_VREG r2, r2                     @ r2<- fp[A]
-    ldr      r3, [rFP, #OFF_FP_METHOD]  @ r3<- referrer
-    PREFETCH_INST 2
-    bl       MterpIPutU32
-    cmp      r0, #0
-    bne      MterpPossibleException
-    ADVANCE  2                          @ advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
-
-/* ------------------------------ */
-    .balign 128
 .L_op_iput_wide: /* 0x5a */
 /* File: arm/op_iput_wide.S */
-    /* iput-wide vA, vB, field@CCCC */
+/* File: arm/op_iput.S */
+/* File: arm/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU64
-    EXPORT_PC
-    FETCH    r0, 1                      @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12         @ r1<- B
-    GET_VREG r1, r1                     @ r1<- fp[B], the object pointer
-    ubfx     r2, rINST, #8, #4          @ r2<- A
-    VREG_INDEX_TO_ADDR r2, r2           @ r2<- &fp[A]
-    ldr      r3, [rFP, #OFF_FP_METHOD]  @ r3<- referrer
-    PREFETCH_INST 2
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIPutU64
     cmp      r0, #0
-    bne      MterpPossibleException
-    ADVANCE  2                          @ advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_object: /* 0x5b */
 /* File: arm/op_iput_object.S */
-    EXPORT_PC
-    add     r0, rFP, #OFF_FP_SHADOWFRAME
-    mov     r1, rPC
-    mov     r2, rINST
-    mov     r3, rSELF
-    bl      MterpIPutObj
-    cmp     r0, #0
-    beq     MterpException
-    FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+/* File: arm/op_iput.S */
+/* File: arm/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIPutObj
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpIPutObj
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_boolean: /* 0x5c */
 /* File: arm/op_iput_boolean.S */
 /* File: arm/op_iput.S */
+/* File: arm/field.S */
     /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vA, vB, field@CCCC */
     .extern MterpIPutU8
-    EXPORT_PC
-    FETCH    r0, 1                      @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12         @ r1<- B
-    GET_VREG r1, r1                     @ r1<- fp[B], the object pointer
-    ubfx     r2, rINST, #8, #4          @ r2<- A
-    GET_VREG r2, r2                     @ r2<- fp[A]
-    ldr      r3, [rFP, #OFF_FP_METHOD]  @ r3<- referrer
-    PREFETCH_INST 2
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIPutU8
     cmp      r0, #0
-    bne      MterpPossibleException
-    ADVANCE  2                          @ advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2556,27 +2507,23 @@
 .L_op_iput_byte: /* 0x5d */
 /* File: arm/op_iput_byte.S */
 /* File: arm/op_iput.S */
+/* File: arm/field.S */
     /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vA, vB, field@CCCC */
     .extern MterpIPutI8
-    EXPORT_PC
-    FETCH    r0, 1                      @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12         @ r1<- B
-    GET_VREG r1, r1                     @ r1<- fp[B], the object pointer
-    ubfx     r2, rINST, #8, #4          @ r2<- A
-    GET_VREG r2, r2                     @ r2<- fp[A]
-    ldr      r3, [rFP, #OFF_FP_METHOD]  @ r3<- referrer
-    PREFETCH_INST 2
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIPutI8
     cmp      r0, #0
-    bne      MterpPossibleException
-    ADVANCE  2                          @ advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2584,27 +2531,23 @@
 .L_op_iput_char: /* 0x5e */
 /* File: arm/op_iput_char.S */
 /* File: arm/op_iput.S */
+/* File: arm/field.S */
     /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vA, vB, field@CCCC */
     .extern MterpIPutU16
-    EXPORT_PC
-    FETCH    r0, 1                      @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12         @ r1<- B
-    GET_VREG r1, r1                     @ r1<- fp[B], the object pointer
-    ubfx     r2, rINST, #8, #4          @ r2<- A
-    GET_VREG r2, r2                     @ r2<- fp[A]
-    ldr      r3, [rFP, #OFF_FP_METHOD]  @ r3<- referrer
-    PREFETCH_INST 2
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIPutU16
     cmp      r0, #0
-    bne      MterpPossibleException
-    ADVANCE  2                          @ advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2612,118 +2555,93 @@
 .L_op_iput_short: /* 0x5f */
 /* File: arm/op_iput_short.S */
 /* File: arm/op_iput.S */
+/* File: arm/field.S */
     /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vA, vB, field@CCCC */
     .extern MterpIPutI16
-    EXPORT_PC
-    FETCH    r0, 1                      @ r0<- field ref CCCC
-    mov      r1, rINST, lsr #12         @ r1<- B
-    GET_VREG r1, r1                     @ r1<- fp[B], the object pointer
-    ubfx     r2, rINST, #8, #4          @ r2<- A
-    GET_VREG r2, r2                     @ r2<- fp[A]
-    ldr      r3, [rFP, #OFF_FP_METHOD]  @ r3<- referrer
-    PREFETCH_INST 2
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
     bl       MterpIPutI16
     cmp      r0, #0
-    bne      MterpPossibleException
-    ADVANCE  2                          @ advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget: /* 0x60 */
 /* File: arm/op_sget.S */
+/* File: arm/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-
     .extern MterpSGetU32
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- field ref BBBB
-    ldr   r1, [rFP, #OFF_FP_METHOD]
-    mov   r2, rSELF
-    bl    MterpSGetU32
-    ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    mov   r2, rINST, lsr #8             @ r2<- AA
-    PREFETCH_INST 2
-    cmp   r3, #0                        @ Fail to resolve?
-    bne   MterpException                @ bail out
-.if 0
-    SET_VREG_OBJECT r0, r2              @ fp[AA]<- r0
-.else
-    SET_VREG r0, r2                     @ fp[AA]<- r0
-.endif
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSGetU32
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget_wide: /* 0x61 */
 /* File: arm/op_sget_wide.S */
+/* File: arm/op_sget.S */
+/* File: arm/field.S */
     /*
-     * SGET_WIDE handler wrapper.
-     *
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* sget-wide vAA, field@BBBB */
-
     .extern MterpSGetU64
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- field ref BBBB
-    ldr   r1, [rFP, #OFF_FP_METHOD]
-    mov   r2, rSELF
-    bl    MterpSGetU64
-    ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    mov   r9, rINST, lsr #8             @ r9<- AA
-    VREG_INDEX_TO_ADDR lr, r9           @ r9<- &fp[AA]
-    cmp   r3, #0                        @ Fail to resolve?
-    bne   MterpException                @ bail out
-    FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    CLEAR_SHADOW_PAIR r9, r2, ip        @ Zero out the shadow regs
-    stmia lr, {r0-r1}                   @ vAA/vAA+1<- r0/r1
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSGetU64
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget_object: /* 0x62 */
 /* File: arm/op_sget_object.S */
 /* File: arm/op_sget.S */
+/* File: arm/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-
     .extern MterpSGetObj
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- field ref BBBB
-    ldr   r1, [rFP, #OFF_FP_METHOD]
-    mov   r2, rSELF
-    bl    MterpSGetObj
-    ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    mov   r2, rINST, lsr #8             @ r2<- AA
-    PREFETCH_INST 2
-    cmp   r3, #0                        @ Fail to resolve?
-    bne   MterpException                @ bail out
-.if 1
-    SET_VREG_OBJECT r0, r2              @ fp[AA]<- r0
-.else
-    SET_VREG r0, r2                     @ fp[AA]<- r0
-.endif
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSGetObj
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2731,32 +2649,23 @@
 .L_op_sget_boolean: /* 0x63 */
 /* File: arm/op_sget_boolean.S */
 /* File: arm/op_sget.S */
+/* File: arm/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-
     .extern MterpSGetU8
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- field ref BBBB
-    ldr   r1, [rFP, #OFF_FP_METHOD]
-    mov   r2, rSELF
-    bl    MterpSGetU8
-    ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    mov   r2, rINST, lsr #8             @ r2<- AA
-    PREFETCH_INST 2
-    cmp   r3, #0                        @ Fail to resolve?
-    bne   MterpException                @ bail out
-.if 0
-    SET_VREG_OBJECT r0, r2              @ fp[AA]<- r0
-.else
-    SET_VREG r0, r2                     @ fp[AA]<- r0
-.endif
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSGetU8
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2764,32 +2673,23 @@
 .L_op_sget_byte: /* 0x64 */
 /* File: arm/op_sget_byte.S */
 /* File: arm/op_sget.S */
+/* File: arm/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-
     .extern MterpSGetI8
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- field ref BBBB
-    ldr   r1, [rFP, #OFF_FP_METHOD]
-    mov   r2, rSELF
-    bl    MterpSGetI8
-    ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    mov   r2, rINST, lsr #8             @ r2<- AA
-    PREFETCH_INST 2
-    cmp   r3, #0                        @ Fail to resolve?
-    bne   MterpException                @ bail out
-.if 0
-    SET_VREG_OBJECT r0, r2              @ fp[AA]<- r0
-.else
-    SET_VREG r0, r2                     @ fp[AA]<- r0
-.endif
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSGetI8
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2797,32 +2697,23 @@
 .L_op_sget_char: /* 0x65 */
 /* File: arm/op_sget_char.S */
 /* File: arm/op_sget.S */
+/* File: arm/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-
     .extern MterpSGetU16
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- field ref BBBB
-    ldr   r1, [rFP, #OFF_FP_METHOD]
-    mov   r2, rSELF
-    bl    MterpSGetU16
-    ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    mov   r2, rINST, lsr #8             @ r2<- AA
-    PREFETCH_INST 2
-    cmp   r3, #0                        @ Fail to resolve?
-    bne   MterpException                @ bail out
-.if 0
-    SET_VREG_OBJECT r0, r2              @ fp[AA]<- r0
-.else
-    SET_VREG r0, r2                     @ fp[AA]<- r0
-.endif
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSGetU16
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2830,122 +2721,117 @@
 .L_op_sget_short: /* 0x66 */
 /* File: arm/op_sget_short.S */
 /* File: arm/op_sget.S */
+/* File: arm/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-
     .extern MterpSGetI16
-    EXPORT_PC
-    FETCH r0, 1                         @ r0<- field ref BBBB
-    ldr   r1, [rFP, #OFF_FP_METHOD]
-    mov   r2, rSELF
-    bl    MterpSGetI16
-    ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
-    mov   r2, rINST, lsr #8             @ r2<- AA
-    PREFETCH_INST 2
-    cmp   r3, #0                        @ Fail to resolve?
-    bne   MterpException                @ bail out
-.if 0
-    SET_VREG_OBJECT r0, r2              @ fp[AA]<- r0
-.else
-    SET_VREG r0, r2                     @ fp[AA]<- r0
-.endif
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSGetI16
+    cmp      r0, #0
+    beq      MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput: /* 0x67 */
 /* File: arm/op_sput.S */
+/* File: arm/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-    EXPORT_PC
-    FETCH   r0, 1                       @ r0<- field ref BBBB
-    mov     r3, rINST, lsr #8           @ r3<- AA
-    GET_VREG r1, r3                     @ r1<= fp[AA]
-    ldr     r2, [rFP, #OFF_FP_METHOD]
-    mov     r3, rSELF
-    PREFETCH_INST 2                     @ Get next inst, but don't advance rPC
-    bl      MterpSPutU32
-    cmp     r0, #0                      @ 0 on success, -1 on failure
-    bne     MterpException
-    ADVANCE 2                           @ Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    .extern MterpSPutU32
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSPutU32
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_wide: /* 0x68 */
 /* File: arm/op_sput_wide.S */
+/* File: arm/op_sput.S */
+/* File: arm/field.S */
     /*
-     * SPUT_WIDE handler wrapper.
-     *
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* sput-wide vAA, field@BBBB */
     .extern MterpSPutU64
-    EXPORT_PC
-    FETCH   r0, 1                       @ r0<- field ref BBBB
-    mov     r1, rINST, lsr #8           @ r1<- AA
-    VREG_INDEX_TO_ADDR r1, r1
-    ldr     r2, [rFP, #OFF_FP_METHOD]
-    mov     r3, rSELF
-    PREFETCH_INST 2                     @ Get next inst, but don't advance rPC
-    bl      MterpSPutU64
-    cmp     r0, #0                      @ 0 on success, -1 on failure
-    bne     MterpException
-    ADVANCE 2                           @ Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSPutU64
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_object: /* 0x69 */
 /* File: arm/op_sput_object.S */
-    EXPORT_PC
-    add     r0, rFP, #OFF_FP_SHADOWFRAME
-    mov     r1, rPC
-    mov     r2, rINST
-    mov     r3, rSELF
-    bl      MterpSPutObj
-    cmp     r0, #0
-    beq     MterpException
-    FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+/* File: arm/op_sput.S */
+/* File: arm/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpSPutObj
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSPutObj
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_boolean: /* 0x6a */
 /* File: arm/op_sput_boolean.S */
 /* File: arm/op_sput.S */
+/* File: arm/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-    EXPORT_PC
-    FETCH   r0, 1                       @ r0<- field ref BBBB
-    mov     r3, rINST, lsr #8           @ r3<- AA
-    GET_VREG r1, r3                     @ r1<= fp[AA]
-    ldr     r2, [rFP, #OFF_FP_METHOD]
-    mov     r3, rSELF
-    PREFETCH_INST 2                     @ Get next inst, but don't advance rPC
-    bl      MterpSPutU8
-    cmp     r0, #0                      @ 0 on success, -1 on failure
-    bne     MterpException
-    ADVANCE 2                           @ Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    .extern MterpSPutU8
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSPutU8
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2953,25 +2839,23 @@
 .L_op_sput_byte: /* 0x6b */
 /* File: arm/op_sput_byte.S */
 /* File: arm/op_sput.S */
+/* File: arm/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-    EXPORT_PC
-    FETCH   r0, 1                       @ r0<- field ref BBBB
-    mov     r3, rINST, lsr #8           @ r3<- AA
-    GET_VREG r1, r3                     @ r1<= fp[AA]
-    ldr     r2, [rFP, #OFF_FP_METHOD]
-    mov     r3, rSELF
-    PREFETCH_INST 2                     @ Get next inst, but don't advance rPC
-    bl      MterpSPutI8
-    cmp     r0, #0                      @ 0 on success, -1 on failure
-    bne     MterpException
-    ADVANCE 2                           @ Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    .extern MterpSPutI8
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSPutI8
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2979,25 +2863,23 @@
 .L_op_sput_char: /* 0x6c */
 /* File: arm/op_sput_char.S */
 /* File: arm/op_sput.S */
+/* File: arm/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-    EXPORT_PC
-    FETCH   r0, 1                       @ r0<- field ref BBBB
-    mov     r3, rINST, lsr #8           @ r3<- AA
-    GET_VREG r1, r3                     @ r1<= fp[AA]
-    ldr     r2, [rFP, #OFF_FP_METHOD]
-    mov     r3, rSELF
-    PREFETCH_INST 2                     @ Get next inst, but don't advance rPC
-    bl      MterpSPutU16
-    cmp     r0, #0                      @ 0 on success, -1 on failure
-    bne     MterpException
-    ADVANCE 2                           @ Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    .extern MterpSPutU16
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSPutU16
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -3005,25 +2887,23 @@
 .L_op_sput_short: /* 0x6d */
 /* File: arm/op_sput_short.S */
 /* File: arm/op_sput.S */
+/* File: arm/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field@BBBB */
-    EXPORT_PC
-    FETCH   r0, 1                       @ r0<- field ref BBBB
-    mov     r3, rINST, lsr #8           @ r3<- AA
-    GET_VREG r1, r3                     @ r1<= fp[AA]
-    ldr     r2, [rFP, #OFF_FP_METHOD]
-    mov     r3, rSELF
-    PREFETCH_INST 2                     @ Get next inst, but don't advance rPC
-    bl      MterpSPutI16
-    cmp     r0, #0                      @ 0 on success, -1 on failure
-    bne     MterpException
-    ADVANCE 2                           @ Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  @ extract opcode from rINST
-    GOTO_OPCODE ip                      @ jump to next instruction
+    .extern MterpSPutI16
+    mov      r0, rPC                       @ arg0: Instruction* inst
+    mov      r1, rINST                     @ arg1: uint16_t inst_data
+    add      r2, rFP, #OFF_FP_SHADOWFRAME  @ arg2: ShadowFrame* sf
+    mov      r3, rSELF                     @ arg3: Thread* self
+    PREFETCH_INST 2                        @ prefetch next opcode
+    bl       MterpSPutI16
+    cmp      r0, #0
+    beq      MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     @ extract opcode from rINST
+    GOTO_OPCODE ip                         @ jump to next instruction
+
 
 
 /* ------------------------------ */
diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S
index 5f4aa4f..fd60c95 100644
--- a/runtime/interpreter/mterp/out/mterp_arm64.S
+++ b/runtime/interpreter/mterp/out/mterp_arm64.S
@@ -2183,213 +2183,177 @@
     .balign 128
 .L_op_iget: /* 0x52 */
 /* File: arm64/op_iget.S */
+/* File: arm64/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    w0, 1                         // w0<- field ref CCCC
-    lsr      w1, wINST, #12                // w1<- B
-    GET_VREG w1, w1                        // w1<- fp[B], the object pointer
-    ldr      x2, [xFP, #OFF_FP_METHOD]     // w2<- referrer
-    mov      x3, xSELF                     // w3<- self
+    .extern MterpIGetU32
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIGetU32
-    ldr      x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    
-    ubfx     w2, wINST, #8, #4             // w2<- A
-    PREFETCH_INST 2
-    cbnz     x3, MterpPossibleException    // bail out
-    .if 0
-    SET_VREG_OBJECT w0, w2                 // fp[A]<- w0
-    .else
-    SET_VREG w0, w2                        // fp[A]<- w0
-    .endif
+    cbz      x0, MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     // extract opcode from rINST
     GOTO_OPCODE ip                         // jump to next instruction
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_wide: /* 0x53 */
 /* File: arm64/op_iget_wide.S */
+/* File: arm64/op_iget.S */
+/* File: arm64/field.S */
     /*
-     * 64-bit instance field get.
-     *
-     * for: iget-wide
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    w0, 1                         // w0<- field ref CCCC
-    lsr      w1, wINST, #12                // w1<- B
-    GET_VREG w1, w1                        // w1<- fp[B], the object pointer
-    ldr      x2, [xFP, #OFF_FP_METHOD]     // w2<- referrer
-    mov      x3, xSELF                     // w3<- self
+    .extern MterpIGetU64
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIGetU64
-    ldr      x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    ubfx     w2, wINST, #8, #4             // w2<- A
-    PREFETCH_INST 2
-    cmp      w3, #0
-    cbnz     w3, MterpException            // bail out
-    SET_VREG_WIDE x0, w2
+    cbz      x0, MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                     // extract opcode from wINST
+    GET_INST_OPCODE ip                     // extract opcode from rINST
     GOTO_OPCODE ip                         // jump to next instruction
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_object: /* 0x54 */
 /* File: arm64/op_iget_object.S */
 /* File: arm64/op_iget.S */
+/* File: arm64/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    w0, 1                         // w0<- field ref CCCC
-    lsr      w1, wINST, #12                // w1<- B
-    GET_VREG w1, w1                        // w1<- fp[B], the object pointer
-    ldr      x2, [xFP, #OFF_FP_METHOD]     // w2<- referrer
-    mov      x3, xSELF                     // w3<- self
+    .extern MterpIGetObj
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIGetObj
-    ldr      x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    
-    ubfx     w2, wINST, #8, #4             // w2<- A
-    PREFETCH_INST 2
-    cbnz     x3, MterpPossibleException    // bail out
-    .if 1
-    SET_VREG_OBJECT w0, w2                 // fp[A]<- w0
-    .else
-    SET_VREG w0, w2                        // fp[A]<- w0
-    .endif
+    cbz      x0, MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     // extract opcode from rINST
     GOTO_OPCODE ip                         // jump to next instruction
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_boolean: /* 0x55 */
 /* File: arm64/op_iget_boolean.S */
 /* File: arm64/op_iget.S */
+/* File: arm64/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    w0, 1                         // w0<- field ref CCCC
-    lsr      w1, wINST, #12                // w1<- B
-    GET_VREG w1, w1                        // w1<- fp[B], the object pointer
-    ldr      x2, [xFP, #OFF_FP_METHOD]     // w2<- referrer
-    mov      x3, xSELF                     // w3<- self
+    .extern MterpIGetU8
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIGetU8
-    ldr      x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    uxtb w0, w0
-    ubfx     w2, wINST, #8, #4             // w2<- A
-    PREFETCH_INST 2
-    cbnz     x3, MterpPossibleException    // bail out
-    .if 0
-    SET_VREG_OBJECT w0, w2                 // fp[A]<- w0
-    .else
-    SET_VREG w0, w2                        // fp[A]<- w0
-    .endif
+    cbz      x0, MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     // extract opcode from rINST
     GOTO_OPCODE ip                         // jump to next instruction
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_byte: /* 0x56 */
 /* File: arm64/op_iget_byte.S */
 /* File: arm64/op_iget.S */
+/* File: arm64/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    w0, 1                         // w0<- field ref CCCC
-    lsr      w1, wINST, #12                // w1<- B
-    GET_VREG w1, w1                        // w1<- fp[B], the object pointer
-    ldr      x2, [xFP, #OFF_FP_METHOD]     // w2<- referrer
-    mov      x3, xSELF                     // w3<- self
+    .extern MterpIGetI8
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIGetI8
-    ldr      x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    sxtb w0, w0
-    ubfx     w2, wINST, #8, #4             // w2<- A
-    PREFETCH_INST 2
-    cbnz     x3, MterpPossibleException    // bail out
-    .if 0
-    SET_VREG_OBJECT w0, w2                 // fp[A]<- w0
-    .else
-    SET_VREG w0, w2                        // fp[A]<- w0
-    .endif
+    cbz      x0, MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     // extract opcode from rINST
     GOTO_OPCODE ip                         // jump to next instruction
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_char: /* 0x57 */
 /* File: arm64/op_iget_char.S */
 /* File: arm64/op_iget.S */
+/* File: arm64/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    w0, 1                         // w0<- field ref CCCC
-    lsr      w1, wINST, #12                // w1<- B
-    GET_VREG w1, w1                        // w1<- fp[B], the object pointer
-    ldr      x2, [xFP, #OFF_FP_METHOD]     // w2<- referrer
-    mov      x3, xSELF                     // w3<- self
+    .extern MterpIGetU16
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIGetU16
-    ldr      x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    uxth w0, w0
-    ubfx     w2, wINST, #8, #4             // w2<- A
-    PREFETCH_INST 2
-    cbnz     x3, MterpPossibleException    // bail out
-    .if 0
-    SET_VREG_OBJECT w0, w2                 // fp[A]<- w0
-    .else
-    SET_VREG w0, w2                        // fp[A]<- w0
-    .endif
+    cbz      x0, MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     // extract opcode from rINST
     GOTO_OPCODE ip                         // jump to next instruction
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_short: /* 0x58 */
 /* File: arm64/op_iget_short.S */
 /* File: arm64/op_iget.S */
+/* File: arm64/field.S */
     /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    EXPORT_PC
-    FETCH    w0, 1                         // w0<- field ref CCCC
-    lsr      w1, wINST, #12                // w1<- B
-    GET_VREG w1, w1                        // w1<- fp[B], the object pointer
-    ldr      x2, [xFP, #OFF_FP_METHOD]     // w2<- referrer
-    mov      x3, xSELF                     // w3<- self
+    .extern MterpIGetI16
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIGetI16
-    ldr      x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    sxth w0, w0
-    ubfx     w2, wINST, #8, #4             // w2<- A
-    PREFETCH_INST 2
-    cbnz     x3, MterpPossibleException    // bail out
-    .if 0
-    SET_VREG_OBJECT w0, w2                 // fp[A]<- w0
-    .else
-    SET_VREG w0, w2                        // fp[A]<- w0
-    .endif
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 128
+.L_op_iput: /* 0x59 */
+/* File: arm64/op_iput.S */
+/* File: arm64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIPutU32
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpIPutU32
+    cbz      x0, MterpPossibleException
     ADVANCE 2
     GET_INST_OPCODE ip                     // extract opcode from rINST
     GOTO_OPCODE ip                         // jump to next instruction
@@ -2397,89 +2361,71 @@
 
 /* ------------------------------ */
     .balign 128
-.L_op_iput: /* 0x59 */
-/* File: arm64/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field//CCCC */
-    .extern MterpIPutU32
-    EXPORT_PC
-    FETCH    w0, 1                      // w0<- field ref CCCC
-    lsr      w1, wINST, #12             // w1<- B
-    GET_VREG w1, w1                     // w1<- fp[B], the object pointer
-    ubfx     w2, wINST, #8, #4          // w2<- A
-    GET_VREG w2, w2                     // w2<- fp[A]
-    ldr      x3, [xFP, #OFF_FP_METHOD]  // w3<- referrer
-    PREFETCH_INST 2
-    bl       MterpIPutU32
-    cbnz     w0, MterpPossibleException
-    ADVANCE  2                          // advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
-
-/* ------------------------------ */
-    .balign 128
 .L_op_iput_wide: /* 0x5a */
 /* File: arm64/op_iput_wide.S */
-    /* iput-wide vA, vB, field//CCCC */
+/* File: arm64/op_iput.S */
+/* File: arm64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU64
-    EXPORT_PC
-    FETCH    w0, 1                      // w0<- field ref CCCC
-    lsr      w1, wINST, #12             // w1<- B
-    GET_VREG w1, w1                     // w1<- fp[B], the object pointer
-    ubfx     w2, wINST, #8, #4          // w2<- A
-    VREG_INDEX_TO_ADDR x2, x2           // w2<- &fp[A]
-    ldr      x3, [xFP, #OFF_FP_METHOD]  // w3<- referrer
-    PREFETCH_INST 2
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIPutU64
-    cbnz     w0, MterpPossibleException
-    ADVANCE  2                          // advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from wINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_object: /* 0x5b */
 /* File: arm64/op_iput_object.S */
-    EXPORT_PC
-    add     x0, xFP, #OFF_FP_SHADOWFRAME
-    mov     x1, xPC
-    mov     w2, wINST
-    mov     x3, xSELF
-    bl      MterpIPutObj
-    cbz     w0, MterpException
-    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+/* File: arm64/op_iput.S */
+/* File: arm64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIPutObj
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpIPutObj
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_boolean: /* 0x5c */
 /* File: arm64/op_iput_boolean.S */
 /* File: arm64/op_iput.S */
+/* File: arm64/field.S */
     /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vA, vB, field//CCCC */
     .extern MterpIPutU8
-    EXPORT_PC
-    FETCH    w0, 1                      // w0<- field ref CCCC
-    lsr      w1, wINST, #12             // w1<- B
-    GET_VREG w1, w1                     // w1<- fp[B], the object pointer
-    ubfx     w2, wINST, #8, #4          // w2<- A
-    GET_VREG w2, w2                     // w2<- fp[A]
-    ldr      x3, [xFP, #OFF_FP_METHOD]  // w3<- referrer
-    PREFETCH_INST 2
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIPutU8
-    cbnz     w0, MterpPossibleException
-    ADVANCE  2                          // advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2487,26 +2433,22 @@
 .L_op_iput_byte: /* 0x5d */
 /* File: arm64/op_iput_byte.S */
 /* File: arm64/op_iput.S */
+/* File: arm64/field.S */
     /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vA, vB, field//CCCC */
     .extern MterpIPutI8
-    EXPORT_PC
-    FETCH    w0, 1                      // w0<- field ref CCCC
-    lsr      w1, wINST, #12             // w1<- B
-    GET_VREG w1, w1                     // w1<- fp[B], the object pointer
-    ubfx     w2, wINST, #8, #4          // w2<- A
-    GET_VREG w2, w2                     // w2<- fp[A]
-    ldr      x3, [xFP, #OFF_FP_METHOD]  // w3<- referrer
-    PREFETCH_INST 2
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIPutI8
-    cbnz     w0, MterpPossibleException
-    ADVANCE  2                          // advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2514,26 +2456,22 @@
 .L_op_iput_char: /* 0x5e */
 /* File: arm64/op_iput_char.S */
 /* File: arm64/op_iput.S */
+/* File: arm64/field.S */
     /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vA, vB, field//CCCC */
     .extern MterpIPutU16
-    EXPORT_PC
-    FETCH    w0, 1                      // w0<- field ref CCCC
-    lsr      w1, wINST, #12             // w1<- B
-    GET_VREG w1, w1                     // w1<- fp[B], the object pointer
-    ubfx     w2, wINST, #8, #4          // w2<- A
-    GET_VREG w2, w2                     // w2<- fp[A]
-    ldr      x3, [xFP, #OFF_FP_METHOD]  // w3<- referrer
-    PREFETCH_INST 2
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIPutU16
-    cbnz     w0, MterpPossibleException
-    ADVANCE  2                          // advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2541,114 +2479,89 @@
 .L_op_iput_short: /* 0x5f */
 /* File: arm64/op_iput_short.S */
 /* File: arm64/op_iput.S */
+/* File: arm64/field.S */
     /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vA, vB, field//CCCC */
     .extern MterpIPutI16
-    EXPORT_PC
-    FETCH    w0, 1                      // w0<- field ref CCCC
-    lsr      w1, wINST, #12             // w1<- B
-    GET_VREG w1, w1                     // w1<- fp[B], the object pointer
-    ubfx     w2, wINST, #8, #4          // w2<- A
-    GET_VREG w2, w2                     // w2<- fp[A]
-    ldr      x3, [xFP, #OFF_FP_METHOD]  // w3<- referrer
-    PREFETCH_INST 2
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
     bl       MterpIPutI16
-    cbnz     w0, MterpPossibleException
-    ADVANCE  2                          // advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget: /* 0x60 */
 /* File: arm64/op_sget.S */
+/* File: arm64/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-
     .extern MterpSGetU32
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- field ref BBBB
-    ldr   x1, [xFP, #OFF_FP_METHOD]
-    mov   x2, xSELF
-    bl    MterpSGetU32
-    ldr   x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    lsr   w2, wINST, #8                 // w2<- AA
-    
-    PREFETCH_INST 2
-    cbnz  x3, MterpException            // bail out
-.if 0
-    SET_VREG_OBJECT w0, w2              // fp[AA]<- w0
-.else
-    SET_VREG w0, w2                     // fp[AA]<- w0
-.endif
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSGetU32
+    cbz      x0, MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget_wide: /* 0x61 */
 /* File: arm64/op_sget_wide.S */
+/* File: arm64/op_sget.S */
+/* File: arm64/field.S */
     /*
-     * SGET_WIDE handler wrapper.
-     *
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* sget-wide vAA, field//BBBB */
+    .extern MterpSGetU64
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSGetU64
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
 
-    .extern MterpGet64StaticFromCode
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- field ref BBBB
-    ldr   x1, [xFP, #OFF_FP_METHOD]
-    mov   x2, xSELF
-    bl    MterpSGetU64
-    ldr   x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    lsr   w4, wINST, #8                 // w4<- AA
-    cbnz  x3, MterpException            // bail out
-    FETCH_ADVANCE_INST 2                // advance rPC, load wINST
-    SET_VREG_WIDE x0, w4
-    GET_INST_OPCODE ip                  // extract opcode from wINST
-    GOTO_OPCODE ip                      // jump to next instruction
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget_object: /* 0x62 */
 /* File: arm64/op_sget_object.S */
 /* File: arm64/op_sget.S */
+/* File: arm64/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-
     .extern MterpSGetObj
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- field ref BBBB
-    ldr   x1, [xFP, #OFF_FP_METHOD]
-    mov   x2, xSELF
-    bl    MterpSGetObj
-    ldr   x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    lsr   w2, wINST, #8                 // w2<- AA
-    
-    PREFETCH_INST 2
-    cbnz  x3, MterpException            // bail out
-.if 1
-    SET_VREG_OBJECT w0, w2              // fp[AA]<- w0
-.else
-    SET_VREG w0, w2                     // fp[AA]<- w0
-.endif
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSGetObj
+    cbz      x0, MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2656,32 +2569,22 @@
 .L_op_sget_boolean: /* 0x63 */
 /* File: arm64/op_sget_boolean.S */
 /* File: arm64/op_sget.S */
+/* File: arm64/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-
     .extern MterpSGetU8
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- field ref BBBB
-    ldr   x1, [xFP, #OFF_FP_METHOD]
-    mov   x2, xSELF
-    bl    MterpSGetU8
-    ldr   x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    lsr   w2, wINST, #8                 // w2<- AA
-    uxtb w0, w0
-    PREFETCH_INST 2
-    cbnz  x3, MterpException            // bail out
-.if 0
-    SET_VREG_OBJECT w0, w2              // fp[AA]<- w0
-.else
-    SET_VREG w0, w2                     // fp[AA]<- w0
-.endif
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSGetU8
+    cbz      x0, MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2689,32 +2592,22 @@
 .L_op_sget_byte: /* 0x64 */
 /* File: arm64/op_sget_byte.S */
 /* File: arm64/op_sget.S */
+/* File: arm64/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-
     .extern MterpSGetI8
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- field ref BBBB
-    ldr   x1, [xFP, #OFF_FP_METHOD]
-    mov   x2, xSELF
-    bl    MterpSGetI8
-    ldr   x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    lsr   w2, wINST, #8                 // w2<- AA
-    sxtb w0, w0
-    PREFETCH_INST 2
-    cbnz  x3, MterpException            // bail out
-.if 0
-    SET_VREG_OBJECT w0, w2              // fp[AA]<- w0
-.else
-    SET_VREG w0, w2                     // fp[AA]<- w0
-.endif
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSGetI8
+    cbz      x0, MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2722,32 +2615,22 @@
 .L_op_sget_char: /* 0x65 */
 /* File: arm64/op_sget_char.S */
 /* File: arm64/op_sget.S */
+/* File: arm64/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-
     .extern MterpSGetU16
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- field ref BBBB
-    ldr   x1, [xFP, #OFF_FP_METHOD]
-    mov   x2, xSELF
-    bl    MterpSGetU16
-    ldr   x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    lsr   w2, wINST, #8                 // w2<- AA
-    uxth w0, w0
-    PREFETCH_INST 2
-    cbnz  x3, MterpException            // bail out
-.if 0
-    SET_VREG_OBJECT w0, w2              // fp[AA]<- w0
-.else
-    SET_VREG w0, w2                     // fp[AA]<- w0
-.endif
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSGetU16
+    cbz      x0, MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2755,118 +2638,112 @@
 .L_op_sget_short: /* 0x66 */
 /* File: arm64/op_sget_short.S */
 /* File: arm64/op_sget.S */
+/* File: arm64/field.S */
     /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-
     .extern MterpSGetI16
-    EXPORT_PC
-    FETCH w0, 1                         // w0<- field ref BBBB
-    ldr   x1, [xFP, #OFF_FP_METHOD]
-    mov   x2, xSELF
-    bl    MterpSGetI16
-    ldr   x3, [xSELF, #THREAD_EXCEPTION_OFFSET]
-    lsr   w2, wINST, #8                 // w2<- AA
-    sxth w0, w0
-    PREFETCH_INST 2
-    cbnz  x3, MterpException            // bail out
-.if 0
-    SET_VREG_OBJECT w0, w2              // fp[AA]<- w0
-.else
-    SET_VREG w0, w2                     // fp[AA]<- w0
-.endif
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSGetI16
+    cbz      x0, MterpPossibleException
     ADVANCE 2
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput: /* 0x67 */
 /* File: arm64/op_sput.S */
+/* File: arm64/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-    EXPORT_PC
-    FETCH   w0, 1                       // r0<- field ref BBBB
-    lsr     w3, wINST, #8               // r3<- AA
-    GET_VREG w1, w3                     // r1<= fp[AA]
-    ldr     x2, [xFP, #OFF_FP_METHOD]
-    mov     x3, xSELF
-    PREFETCH_INST 2                     // Get next inst, but don't advance rPC
-    bl      MterpSPutU32
-    cbnz    w0, MterpException          // 0 on success
-    ADVANCE 2                           // Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    .extern MterpSPutU32
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSPutU32
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_wide: /* 0x68 */
 /* File: arm64/op_sput_wide.S */
+/* File: arm64/op_sput.S */
+/* File: arm64/field.S */
     /*
-     * SPUT_WIDE handler wrapper.
-     *
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* sput-wide vAA, field//BBBB */
     .extern MterpSPutU64
-    EXPORT_PC
-    FETCH   w0, 1                       // w0<- field ref BBBB
-    lsr     w1, wINST, #8               // w1<- AA
-    VREG_INDEX_TO_ADDR x1, w1
-    ldr     x2, [xFP, #OFF_FP_METHOD]
-    mov     x3, xSELF
-    PREFETCH_INST 2                     // Get next inst, but don't advance rPC
-    bl      MterpSPutU64
-    cbnz    w0, MterpException          // 0 on success, -1 on failure
-    ADVANCE 2                           // Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from wINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSPutU64
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_object: /* 0x69 */
 /* File: arm64/op_sput_object.S */
-    EXPORT_PC
-    add     x0, xFP, #OFF_FP_SHADOWFRAME
-    mov     x1, xPC
-    mov     x2, xINST
-    mov     x3, xSELF
-    bl      MterpSPutObj
-    cbz     w0, MterpException
-    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+/* File: arm64/op_sput.S */
+/* File: arm64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpSPutObj
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSPutObj
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_boolean: /* 0x6a */
 /* File: arm64/op_sput_boolean.S */
 /* File: arm64/op_sput.S */
+/* File: arm64/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-    EXPORT_PC
-    FETCH   w0, 1                       // r0<- field ref BBBB
-    lsr     w3, wINST, #8               // r3<- AA
-    GET_VREG w1, w3                     // r1<= fp[AA]
-    ldr     x2, [xFP, #OFF_FP_METHOD]
-    mov     x3, xSELF
-    PREFETCH_INST 2                     // Get next inst, but don't advance rPC
-    bl      MterpSPutU8
-    cbnz    w0, MterpException          // 0 on success
-    ADVANCE 2                           // Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    .extern MterpSPutU8
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSPutU8
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2874,24 +2751,22 @@
 .L_op_sput_byte: /* 0x6b */
 /* File: arm64/op_sput_byte.S */
 /* File: arm64/op_sput.S */
+/* File: arm64/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-    EXPORT_PC
-    FETCH   w0, 1                       // r0<- field ref BBBB
-    lsr     w3, wINST, #8               // r3<- AA
-    GET_VREG w1, w3                     // r1<= fp[AA]
-    ldr     x2, [xFP, #OFF_FP_METHOD]
-    mov     x3, xSELF
-    PREFETCH_INST 2                     // Get next inst, but don't advance rPC
-    bl      MterpSPutI8
-    cbnz    w0, MterpException          // 0 on success
-    ADVANCE 2                           // Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    .extern MterpSPutI8
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSPutI8
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2899,24 +2774,22 @@
 .L_op_sput_char: /* 0x6c */
 /* File: arm64/op_sput_char.S */
 /* File: arm64/op_sput.S */
+/* File: arm64/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-    EXPORT_PC
-    FETCH   w0, 1                       // r0<- field ref BBBB
-    lsr     w3, wINST, #8               // r3<- AA
-    GET_VREG w1, w3                     // r1<= fp[AA]
-    ldr     x2, [xFP, #OFF_FP_METHOD]
-    mov     x3, xSELF
-    PREFETCH_INST 2                     // Get next inst, but don't advance rPC
-    bl      MterpSPutU16
-    cbnz    w0, MterpException          // 0 on success
-    ADVANCE 2                           // Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    .extern MterpSPutU16
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSPutU16
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
@@ -2924,24 +2797,22 @@
 .L_op_sput_short: /* 0x6d */
 /* File: arm64/op_sput_short.S */
 /* File: arm64/op_sput.S */
+/* File: arm64/field.S */
     /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     * General field read / write (iget-* iput-* sget-* sput-*).
      */
-    /* op vAA, field//BBBB */
-    EXPORT_PC
-    FETCH   w0, 1                       // r0<- field ref BBBB
-    lsr     w3, wINST, #8               // r3<- AA
-    GET_VREG w1, w3                     // r1<= fp[AA]
-    ldr     x2, [xFP, #OFF_FP_METHOD]
-    mov     x3, xSELF
-    PREFETCH_INST 2                     // Get next inst, but don't advance rPC
-    bl      MterpSPutI16
-    cbnz    w0, MterpException          // 0 on success
-    ADVANCE 2                           // Past exception point - now advance rPC
-    GET_INST_OPCODE ip                  // extract opcode from rINST
-    GOTO_OPCODE ip                      // jump to next instruction
+    .extern MterpSPutI16
+    mov      x0, xPC                       // arg0: Instruction* inst
+    mov      x1, xINST                     // arg1: uint16_t inst_data
+    add      x2, xFP, #OFF_FP_SHADOWFRAME  // arg2: ShadowFrame* sf
+    mov      x3, xSELF                     // arg3: Thread* self
+    PREFETCH_INST 2                        // prefetch next opcode
+    bl       MterpSPutI16
+    cbz      x0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE ip                     // extract opcode from rINST
+    GOTO_OPCODE ip                         // jump to next instruction
+
 
 
 /* ------------------------------ */
diff --git a/runtime/interpreter/mterp/out/mterp_mips.S b/runtime/interpreter/mterp/out/mterp_mips.S
index fb7d52e..1f5bea0 100644
--- a/runtime/interpreter/mterp/out/mterp_mips.S
+++ b/runtime/interpreter/mterp/out/mterp_mips.S
@@ -2665,85 +2665,28 @@
     .balign 128
 .L_op_iget: /* 0x52 */
 /* File: mips/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- referrer
-    move  a3, rSELF                        # a3 <- self
-    JAL(MterpIGetU32)
-    lw   a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA4(a2)                           # a2<- A+
-    PREFETCH_INST(2)                       # load rINST
-    bnez  a3, MterpPossibleException        # bail out
-    ADVANCE(2)                             #  advance rPC
-    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[A] <- v0
-    .else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[A] <- v0
-    .endif
+/* File: mips/field.S */
+TODO
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iget_wide: /* 0x53 */
 /* File: mips/op_iget_wide.S */
-    /*
-     * 64-bit instance field get.
-     *
-     * for: iget-wide
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field byte offset
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- referrer
-    move  a3, rSELF                        # a3 <- self
-    JAL(MterpIGetU64)
-    lw   a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA4(a2)                           # a2<- A+
-    PREFETCH_INST(2)                       # load rINST
-    bnez a3, MterpException                # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    SET_VREG64_GOTO(v0, v1, a2, t0)        # fp[A] <- v0/v1
+/* File: mips/op_iget.S */
+/* File: mips/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iget_object: /* 0x54 */
 /* File: mips/op_iget_object.S */
 /* File: mips/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- referrer
-    move  a3, rSELF                        # a3 <- self
-    JAL(MterpIGetObj)
-    lw   a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA4(a2)                           # a2<- A+
-    PREFETCH_INST(2)                       # load rINST
-    bnez  a3, MterpPossibleException        # bail out
-    ADVANCE(2)                             #  advance rPC
-    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
-    .if 1
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[A] <- v0
-    .else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[A] <- v0
-    .endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2751,30 +2694,9 @@
 .L_op_iget_boolean: /* 0x55 */
 /* File: mips/op_iget_boolean.S */
 /* File: mips/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- referrer
-    move  a3, rSELF                        # a3 <- self
-    JAL(MterpIGetU8)
-    lw   a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA4(a2)                           # a2<- A+
-    PREFETCH_INST(2)                       # load rINST
-    bnez  a3, MterpPossibleException        # bail out
-    ADVANCE(2)                             #  advance rPC
-    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[A] <- v0
-    .else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[A] <- v0
-    .endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2782,30 +2704,9 @@
 .L_op_iget_byte: /* 0x56 */
 /* File: mips/op_iget_byte.S */
 /* File: mips/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- referrer
-    move  a3, rSELF                        # a3 <- self
-    JAL(MterpIGetI8)
-    lw   a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA4(a2)                           # a2<- A+
-    PREFETCH_INST(2)                       # load rINST
-    bnez  a3, MterpPossibleException        # bail out
-    ADVANCE(2)                             #  advance rPC
-    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[A] <- v0
-    .else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[A] <- v0
-    .endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2813,30 +2714,9 @@
 .L_op_iget_char: /* 0x57 */
 /* File: mips/op_iget_char.S */
 /* File: mips/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- referrer
-    move  a3, rSELF                        # a3 <- self
-    JAL(MterpIGetU16)
-    lw   a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA4(a2)                           # a2<- A+
-    PREFETCH_INST(2)                       # load rINST
-    bnez  a3, MterpPossibleException        # bail out
-    ADVANCE(2)                             #  advance rPC
-    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[A] <- v0
-    .else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[A] <- v0
-    .endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2844,123 +2724,47 @@
 .L_op_iget_short: /* 0x58 */
 /* File: mips/op_iget_short.S */
 /* File: mips/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- referrer
-    move  a3, rSELF                        # a3 <- self
-    JAL(MterpIGetI16)
-    lw   a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA4(a2)                           # a2<- A+
-    PREFETCH_INST(2)                       # load rINST
-    bnez  a3, MterpPossibleException        # bail out
-    ADVANCE(2)                             #  advance rPC
-    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
-    .if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[A] <- v0
-    .else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[A] <- v0
-    .endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput: /* 0x59 */
 /* File: mips/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field@CCCC */
-    .extern MterpIPutU32
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    GET_OPA4(a2)                           # a2 <- A+
-    GET_VREG(a2, a2)                       # a2 <- fp[A]
-    lw    a3, OFF_FP_METHOD(rFP)           # a3 <- referrer
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpIPutU32)
-    bnez  v0, MterpPossibleException       # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_wide: /* 0x5a */
 /* File: mips/op_iput_wide.S */
-    /* iput-wide vA, vB, field@CCCC */
-    .extern MterpIPutU64
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    GET_OPA4(a2)                           # a2 <- A+
-    EAS2(a2, rFP, a2)                      # a2 <- &fp[A]
-    lw    a3, OFF_FP_METHOD(rFP)           # a3 <- referrer
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpIPutU64)
-    bnez  v0, MterpPossibleException       # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/op_iput.S */
+/* File: mips/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_object: /* 0x5b */
 /* File: mips/op_iput_object.S */
-    /*
-     * 32-bit instance field put.
-     *
-     * for: iput-object, iput-object-volatile
-     */
-    /* op vA, vB, field@CCCC */
-    EXPORT_PC()
-    addu   a0, rFP, OFF_FP_SHADOWFRAME
-    move   a1, rPC
-    move   a2, rINST
-    move   a3, rSELF
-    JAL(MterpIPutObj)
-    beqz   v0, MterpException
-    FETCH_ADVANCE_INST(2)               # advance rPC, load rINST
-    GET_INST_OPCODE(t0)                 # extract opcode from rINST
-    GOTO_OPCODE(t0)                     # jump to next instruction
+/* File: mips/op_iput.S */
+/* File: mips/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_boolean: /* 0x5c */
 /* File: mips/op_iput_boolean.S */
 /* File: mips/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field@CCCC */
-    .extern MterpIPutU8
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    GET_OPA4(a2)                           # a2 <- A+
-    GET_VREG(a2, a2)                       # a2 <- fp[A]
-    lw    a3, OFF_FP_METHOD(rFP)           # a3 <- referrer
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpIPutU8)
-    bnez  v0, MterpPossibleException       # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2968,26 +2772,9 @@
 .L_op_iput_byte: /* 0x5d */
 /* File: mips/op_iput_byte.S */
 /* File: mips/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field@CCCC */
-    .extern MterpIPutI8
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    GET_OPA4(a2)                           # a2 <- A+
-    GET_VREG(a2, a2)                       # a2 <- fp[A]
-    lw    a3, OFF_FP_METHOD(rFP)           # a3 <- referrer
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpIPutI8)
-    bnez  v0, MterpPossibleException       # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2995,26 +2782,9 @@
 .L_op_iput_char: /* 0x5e */
 /* File: mips/op_iput_char.S */
 /* File: mips/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field@CCCC */
-    .extern MterpIPutU16
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    GET_OPA4(a2)                           # a2 <- A+
-    GET_VREG(a2, a2)                       # a2 <- fp[A]
-    lw    a3, OFF_FP_METHOD(rFP)           # a3 <- referrer
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpIPutU16)
-    bnez  v0, MterpPossibleException       # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -3022,105 +2792,37 @@
 .L_op_iput_short: /* 0x5f */
 /* File: mips/op_iput_short.S */
 /* File: mips/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field@CCCC */
-    .extern MterpIPutI16
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPB(a1)                            # a1 <- B
-    GET_VREG(a1, a1)                       # a1 <- fp[B], the object pointer
-    GET_OPA4(a2)                           # a2 <- A+
-    GET_VREG(a2, a2)                       # a2 <- fp[A]
-    lw    a3, OFF_FP_METHOD(rFP)           # a3 <- referrer
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpIPutI16)
-    bnez  v0, MterpPossibleException       # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget: /* 0x60 */
 /* File: mips/op_sget.S */
-    /*
-     * General SGET handler.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field@BBBB */
-    .extern MterpSGetU32
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    lw    a1, OFF_FP_METHOD(rFP)           # a1 <- method
-    move  a2, rSELF                        # a2 <- self
-    JAL(MterpSGetU32)
-    lw    a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA(a2)                            # a2 <- AA
-    PREFETCH_INST(2)
-    bnez  a3, MterpException               # bail out
-    ADVANCE(2)
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-.if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[AA] <- v0
-.else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[AA] <- v0
-.endif
+/* File: mips/field.S */
+TODO
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget_wide: /* 0x61 */
 /* File: mips/op_sget_wide.S */
-    /*
-     * 64-bit SGET handler.
-     */
-    /* sget-wide vAA, field@BBBB */
-    .extern MterpSGetU64
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    lw    a1, OFF_FP_METHOD(rFP)           # a1 <- method
-    move  a2, rSELF                        # a2 <- self
-    JAL(MterpSGetU64)
-    lw    a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    bnez  a3, MterpException
-    GET_OPA(a1)                            # a1 <- AA
-    FETCH_ADVANCE_INST(2)                  # advance rPC, load rINST
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    SET_VREG64_GOTO(v0, v1, a1, t0)        # vAA/vAA+1 <- v0/v1
+/* File: mips/op_sget.S */
+/* File: mips/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget_object: /* 0x62 */
 /* File: mips/op_sget_object.S */
 /* File: mips/op_sget.S */
-    /*
-     * General SGET handler.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field@BBBB */
-    .extern MterpSGetObj
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    lw    a1, OFF_FP_METHOD(rFP)           # a1 <- method
-    move  a2, rSELF                        # a2 <- self
-    JAL(MterpSGetObj)
-    lw    a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA(a2)                            # a2 <- AA
-    PREFETCH_INST(2)
-    bnez  a3, MterpException               # bail out
-    ADVANCE(2)
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-.if 1
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[AA] <- v0
-.else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[AA] <- v0
-.endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -3128,29 +2830,9 @@
 .L_op_sget_boolean: /* 0x63 */
 /* File: mips/op_sget_boolean.S */
 /* File: mips/op_sget.S */
-    /*
-     * General SGET handler.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field@BBBB */
-    .extern MterpSGetU8
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    lw    a1, OFF_FP_METHOD(rFP)           # a1 <- method
-    move  a2, rSELF                        # a2 <- self
-    JAL(MterpSGetU8)
-    lw    a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA(a2)                            # a2 <- AA
-    PREFETCH_INST(2)
-    bnez  a3, MterpException               # bail out
-    ADVANCE(2)
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-.if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[AA] <- v0
-.else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[AA] <- v0
-.endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -3158,29 +2840,9 @@
 .L_op_sget_byte: /* 0x64 */
 /* File: mips/op_sget_byte.S */
 /* File: mips/op_sget.S */
-    /*
-     * General SGET handler.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field@BBBB */
-    .extern MterpSGetI8
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    lw    a1, OFF_FP_METHOD(rFP)           # a1 <- method
-    move  a2, rSELF                        # a2 <- self
-    JAL(MterpSGetI8)
-    lw    a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA(a2)                            # a2 <- AA
-    PREFETCH_INST(2)
-    bnez  a3, MterpException               # bail out
-    ADVANCE(2)
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-.if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[AA] <- v0
-.else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[AA] <- v0
-.endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -3188,29 +2850,9 @@
 .L_op_sget_char: /* 0x65 */
 /* File: mips/op_sget_char.S */
 /* File: mips/op_sget.S */
-    /*
-     * General SGET handler.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field@BBBB */
-    .extern MterpSGetU16
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    lw    a1, OFF_FP_METHOD(rFP)           # a1 <- method
-    move  a2, rSELF                        # a2 <- self
-    JAL(MterpSGetU16)
-    lw    a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA(a2)                            # a2 <- AA
-    PREFETCH_INST(2)
-    bnez  a3, MterpException               # bail out
-    ADVANCE(2)
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-.if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[AA] <- v0
-.else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[AA] <- v0
-.endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -3218,120 +2860,47 @@
 .L_op_sget_short: /* 0x66 */
 /* File: mips/op_sget_short.S */
 /* File: mips/op_sget.S */
-    /*
-     * General SGET handler.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field@BBBB */
-    .extern MterpSGetI16
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    lw    a1, OFF_FP_METHOD(rFP)           # a1 <- method
-    move  a2, rSELF                        # a2 <- self
-    JAL(MterpSGetI16)
-    lw    a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    GET_OPA(a2)                            # a2 <- AA
-    PREFETCH_INST(2)
-    bnez  a3, MterpException               # bail out
-    ADVANCE(2)
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-.if 0
-    SET_VREG_OBJECT_GOTO(v0, a2, t0)       # fp[AA] <- v0
-.else
-    SET_VREG_GOTO(v0, a2, t0)              # fp[AA] <- v0
-.endif
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput: /* 0x67 */
 /* File: mips/op_sput.S */
-    /*
-     * General SPUT handler.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field@BBBB */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    GET_OPA(a3)                            # a3 <- AA
-    GET_VREG(a1, a3)                       # a1 <- fp[AA], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- method
-    move  a3, rSELF                        # a3 <- self
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpSPutU32)
-    bnez  v0, MterpException               # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_wide: /* 0x68 */
 /* File: mips/op_sput_wide.S */
-    /*
-     * 64-bit SPUT handler.
-     */
-    /* sput-wide vAA, field@BBBB */
-    .extern MterpSPutU64
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref CCCC
-    GET_OPA(a1)                            # a1 <- AA
-    EAS2(a1, rFP, a1)                      # a1 <- &fp[AA]
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- method
-    move  a3, rSELF                        # a3 <- self
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpSPutU64)
-    bnez  v0, MterpException               # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/op_sput.S */
+/* File: mips/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_object: /* 0x69 */
 /* File: mips/op_sput_object.S */
-    /*
-     * General 32-bit SPUT handler.
-     *
-     * for: sput-object,
-     */
-    /* op vAA, field@BBBB */
-    EXPORT_PC()
-    addu   a0, rFP, OFF_FP_SHADOWFRAME
-    move   a1, rPC
-    move   a2, rINST
-    move   a3, rSELF
-    JAL(MterpSPutObj)
-    beqz   v0, MterpException
-    FETCH_ADVANCE_INST(2)               # advance rPC, load rINST
-    GET_INST_OPCODE(t0)                 # extract opcode from rINST
-    GOTO_OPCODE(t0)                     # jump to next instruction
+/* File: mips/op_sput.S */
+/* File: mips/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_boolean: /* 0x6a */
 /* File: mips/op_sput_boolean.S */
 /* File: mips/op_sput.S */
-    /*
-     * General SPUT handler.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field@BBBB */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    GET_OPA(a3)                            # a3 <- AA
-    GET_VREG(a1, a3)                       # a1 <- fp[AA], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- method
-    move  a3, rSELF                        # a3 <- self
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpSPutU8)
-    bnez  v0, MterpException               # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -3339,24 +2908,9 @@
 .L_op_sput_byte: /* 0x6b */
 /* File: mips/op_sput_byte.S */
 /* File: mips/op_sput.S */
-    /*
-     * General SPUT handler.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field@BBBB */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    GET_OPA(a3)                            # a3 <- AA
-    GET_VREG(a1, a3)                       # a1 <- fp[AA], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- method
-    move  a3, rSELF                        # a3 <- self
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpSPutI8)
-    bnez  v0, MterpException               # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -3364,24 +2918,9 @@
 .L_op_sput_char: /* 0x6c */
 /* File: mips/op_sput_char.S */
 /* File: mips/op_sput.S */
-    /*
-     * General SPUT handler.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field@BBBB */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    GET_OPA(a3)                            # a3 <- AA
-    GET_VREG(a1, a3)                       # a1 <- fp[AA], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- method
-    move  a3, rSELF                        # a3 <- self
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpSPutU16)
-    bnez  v0, MterpException               # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -3389,24 +2928,9 @@
 .L_op_sput_short: /* 0x6d */
 /* File: mips/op_sput_short.S */
 /* File: mips/op_sput.S */
-    /*
-     * General SPUT handler.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field@BBBB */
-    EXPORT_PC()
-    FETCH(a0, 1)                           # a0 <- field ref BBBB
-    GET_OPA(a3)                            # a3 <- AA
-    GET_VREG(a1, a3)                       # a1 <- fp[AA], the object pointer
-    lw    a2, OFF_FP_METHOD(rFP)           # a2 <- method
-    move  a3, rSELF                        # a3 <- self
-    PREFETCH_INST(2)                       # load rINST
-    JAL(MterpSPutI16)
-    bnez  v0, MterpException               # bail out
-    ADVANCE(2)                             # advance rPC
-    GET_INST_OPCODE(t0)                    # extract opcode from rINST
-    GOTO_OPCODE(t0)                        # jump to next instruction
+/* File: mips/field.S */
+TODO
+
 
 
 /* ------------------------------ */
diff --git a/runtime/interpreter/mterp/out/mterp_mips64.S b/runtime/interpreter/mterp/out/mterp_mips64.S
index 6561691..40a8396 100644
--- a/runtime/interpreter/mterp/out/mterp_mips64.S
+++ b/runtime/interpreter/mterp/out/mterp_mips64.S
@@ -2241,88 +2241,28 @@
     .balign 128
 .L_op_iget: /* 0x52 */
 /* File: mips64/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    .extern MterpIGetU32
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
-    move     a3, rSELF                  # a3 <- self
-    jal      MterpIGetU32
-    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    ext      a2, rINST, 8, 4            # a2 <- A
-    PREFETCH_INST 2
-    bnez     a3, MterpPossibleException # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[A] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[A] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iget_wide: /* 0x53 */
 /* File: mips64/op_iget_wide.S */
-    /*
-     * 64-bit instance field get.
-     *
-     * for: iget-wide
-     */
-    .extern MterpIGetU64
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
-    move     a3, rSELF                  # a3 <- self
-    jal      MterpIGetU64
-    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    ext      a2, rINST, 8, 4            # a2 <- A
-    PREFETCH_INST 2
-    bnez     a3, MterpPossibleException # bail out
-    SET_VREG_WIDE v0, a2                # fp[A] <- v0
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/op_iget.S */
+/* File: mips64/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iget_object: /* 0x54 */
 /* File: mips64/op_iget_object.S */
 /* File: mips64/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    .extern MterpIGetObj
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
-    move     a3, rSELF                  # a3 <- self
-    jal      MterpIGetObj
-    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    ext      a2, rINST, 8, 4            # a2 <- A
-    PREFETCH_INST 2
-    bnez     a3, MterpPossibleException # bail out
-    .if 1
-    SET_VREG_OBJECT v0, a2              # fp[A] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[A] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2330,31 +2270,9 @@
 .L_op_iget_boolean: /* 0x55 */
 /* File: mips64/op_iget_boolean.S */
 /* File: mips64/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    .extern MterpIGetU8
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
-    move     a3, rSELF                  # a3 <- self
-    jal      MterpIGetU8
-    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    ext      a2, rINST, 8, 4            # a2 <- A
-    PREFETCH_INST 2
-    bnez     a3, MterpPossibleException # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[A] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[A] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2362,31 +2280,9 @@
 .L_op_iget_byte: /* 0x56 */
 /* File: mips64/op_iget_byte.S */
 /* File: mips64/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    .extern MterpIGetI8
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
-    move     a3, rSELF                  # a3 <- self
-    jal      MterpIGetI8
-    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    ext      a2, rINST, 8, 4            # a2 <- A
-    PREFETCH_INST 2
-    bnez     a3, MterpPossibleException # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[A] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[A] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2394,31 +2290,9 @@
 .L_op_iget_char: /* 0x57 */
 /* File: mips64/op_iget_char.S */
 /* File: mips64/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    .extern MterpIGetU16
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
-    move     a3, rSELF                  # a3 <- self
-    jal      MterpIGetU16
-    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    ext      a2, rINST, 8, 4            # a2 <- A
-    PREFETCH_INST 2
-    bnez     a3, MterpPossibleException # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[A] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[A] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2426,119 +2300,47 @@
 .L_op_iget_short: /* 0x58 */
 /* File: mips64/op_iget_short.S */
 /* File: mips64/op_iget.S */
-    /*
-     * General instance field get.
-     *
-     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
-     */
-    .extern MterpIGetI16
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
-    move     a3, rSELF                  # a3 <- self
-    jal      MterpIGetI16
-    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    ext      a2, rINST, 8, 4            # a2 <- A
-    PREFETCH_INST 2
-    bnez     a3, MterpPossibleException # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[A] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[A] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput: /* 0x59 */
 /* File: mips64/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field//CCCC */
-    .extern MterpIPutU32
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref CCCC
-    srl     a1, rINST, 12               # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ext     a2, rINST, 8, 4             # a2 <- A
-    GET_VREG a2, a2                     # a2 <- fp[A]
-    ld      a3, OFF_FP_METHOD(rFP)      # a3 <- referrer
-    PREFETCH_INST 2
-    jal     MterpIPutU32
-    bnez    v0, MterpPossibleException  # bail out
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_wide: /* 0x5a */
 /* File: mips64/op_iput_wide.S */
-    /* iput-wide vA, vB, field//CCCC */
-    .extern MterpIPutU64
-    EXPORT_PC
-    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
-    srl      a1, rINST, 12              # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ext      a2, rINST, 8, 4            # a2 <- A
-    dlsa     a2, a2, rFP, 2             # a2 <- &fp[A]
-    ld       a3, OFF_FP_METHOD(rFP)     # a3 <- referrer
-    PREFETCH_INST 2
-    jal      MterpIPutU64
-    bnez     v0, MterpPossibleException # bail out
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/op_iput.S */
+/* File: mips64/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_object: /* 0x5b */
 /* File: mips64/op_iput_object.S */
-    .extern MterpIPutObj
-    EXPORT_PC
-    daddu   a0, rFP, OFF_FP_SHADOWFRAME
-    move    a1, rPC
-    move    a2, rINST
-    move    a3, rSELF
-    jal     MterpIPutObj
-    beqzc   v0, MterpException
-    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/op_iput.S */
+/* File: mips64/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_iput_boolean: /* 0x5c */
 /* File: mips64/op_iput_boolean.S */
 /* File: mips64/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field//CCCC */
-    .extern MterpIPutU8
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref CCCC
-    srl     a1, rINST, 12               # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ext     a2, rINST, 8, 4             # a2 <- A
-    GET_VREG a2, a2                     # a2 <- fp[A]
-    ld      a3, OFF_FP_METHOD(rFP)      # a3 <- referrer
-    PREFETCH_INST 2
-    jal     MterpIPutU8
-    bnez    v0, MterpPossibleException  # bail out
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2546,26 +2348,9 @@
 .L_op_iput_byte: /* 0x5d */
 /* File: mips64/op_iput_byte.S */
 /* File: mips64/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field//CCCC */
-    .extern MterpIPutI8
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref CCCC
-    srl     a1, rINST, 12               # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ext     a2, rINST, 8, 4             # a2 <- A
-    GET_VREG a2, a2                     # a2 <- fp[A]
-    ld      a3, OFF_FP_METHOD(rFP)      # a3 <- referrer
-    PREFETCH_INST 2
-    jal     MterpIPutI8
-    bnez    v0, MterpPossibleException  # bail out
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2573,26 +2358,9 @@
 .L_op_iput_char: /* 0x5e */
 /* File: mips64/op_iput_char.S */
 /* File: mips64/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field//CCCC */
-    .extern MterpIPutU16
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref CCCC
-    srl     a1, rINST, 12               # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ext     a2, rINST, 8, 4             # a2 <- A
-    GET_VREG a2, a2                     # a2 <- fp[A]
-    ld      a3, OFF_FP_METHOD(rFP)      # a3 <- referrer
-    PREFETCH_INST 2
-    jal     MterpIPutU16
-    bnez    v0, MterpPossibleException  # bail out
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2600,111 +2368,37 @@
 .L_op_iput_short: /* 0x5f */
 /* File: mips64/op_iput_short.S */
 /* File: mips64/op_iput.S */
-    /*
-     * General 32-bit instance field put.
-     *
-     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
-     */
-    /* op vA, vB, field//CCCC */
-    .extern MterpIPutI16
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref CCCC
-    srl     a1, rINST, 12               # a1 <- B
-    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
-    ext     a2, rINST, 8, 4             # a2 <- A
-    GET_VREG a2, a2                     # a2 <- fp[A]
-    ld      a3, OFF_FP_METHOD(rFP)      # a3 <- referrer
-    PREFETCH_INST 2
-    jal     MterpIPutI16
-    bnez    v0, MterpPossibleException  # bail out
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget: /* 0x60 */
 /* File: mips64/op_sget.S */
-    /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSGetU32
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    ld      a1, OFF_FP_METHOD(rFP)
-    move    a2, rSELF
-    jal     MterpSGetU32
-    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    srl     a2, rINST, 8                # a2 <- AA
-    
-    PREFETCH_INST 2
-    bnez    a3, MterpException          # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[AA] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[AA] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0
+/* File: mips64/field.S */
+TODO
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget_wide: /* 0x61 */
 /* File: mips64/op_sget_wide.S */
-    /*
-     * SGET_WIDE handler wrapper.
-     *
-     */
-    /* sget-wide vAA, field//BBBB */
-    .extern MterpSGetU64
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    ld      a1, OFF_FP_METHOD(rFP)
-    move    a2, rSELF
-    jal     MterpSGetU64
-    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    srl     a4, rINST, 8                # a4 <- AA
-    bnez    a3, MterpException          # bail out
-    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
-    SET_VREG_WIDE v0, a4
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/op_sget.S */
+/* File: mips64/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sget_object: /* 0x62 */
 /* File: mips64/op_sget_object.S */
 /* File: mips64/op_sget.S */
-    /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSGetObj
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    ld      a1, OFF_FP_METHOD(rFP)
-    move    a2, rSELF
-    jal     MterpSGetObj
-    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    srl     a2, rINST, 8                # a2 <- AA
-    
-    PREFETCH_INST 2
-    bnez    a3, MterpException          # bail out
-    .if 1
-    SET_VREG_OBJECT v0, a2              # fp[AA] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[AA] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2712,31 +2406,9 @@
 .L_op_sget_boolean: /* 0x63 */
 /* File: mips64/op_sget_boolean.S */
 /* File: mips64/op_sget.S */
-    /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSGetU8
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    ld      a1, OFF_FP_METHOD(rFP)
-    move    a2, rSELF
-    jal     MterpSGetU8
-    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    srl     a2, rINST, 8                # a2 <- AA
-    and v0, v0, 0xff
-    PREFETCH_INST 2
-    bnez    a3, MterpException          # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[AA] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[AA] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2744,31 +2416,9 @@
 .L_op_sget_byte: /* 0x64 */
 /* File: mips64/op_sget_byte.S */
 /* File: mips64/op_sget.S */
-    /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSGetI8
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    ld      a1, OFF_FP_METHOD(rFP)
-    move    a2, rSELF
-    jal     MterpSGetI8
-    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    srl     a2, rINST, 8                # a2 <- AA
-    seb v0, v0
-    PREFETCH_INST 2
-    bnez    a3, MterpException          # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[AA] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[AA] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2776,31 +2426,9 @@
 .L_op_sget_char: /* 0x65 */
 /* File: mips64/op_sget_char.S */
 /* File: mips64/op_sget.S */
-    /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSGetU16
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    ld      a1, OFF_FP_METHOD(rFP)
-    move    a2, rSELF
-    jal     MterpSGetU16
-    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    srl     a2, rINST, 8                # a2 <- AA
-    and v0, v0, 0xffff
-    PREFETCH_INST 2
-    bnez    a3, MterpException          # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[AA] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[AA] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2808,120 +2436,47 @@
 .L_op_sget_short: /* 0x66 */
 /* File: mips64/op_sget_short.S */
 /* File: mips64/op_sget.S */
-    /*
-     * General SGET handler wrapper.
-     *
-     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSGetI16
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    ld      a1, OFF_FP_METHOD(rFP)
-    move    a2, rSELF
-    jal     MterpSGetI16
-    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
-    srl     a2, rINST, 8                # a2 <- AA
-    seh v0, v0
-    PREFETCH_INST 2
-    bnez    a3, MterpException          # bail out
-    .if 0
-    SET_VREG_OBJECT v0, a2              # fp[AA] <- v0
-    .else
-    SET_VREG v0, a2                     # fp[AA] <- v0
-    .endif
-    ADVANCE 2
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput: /* 0x67 */
 /* File: mips64/op_sput.S */
-    /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSPutU32
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    srl     a3, rINST, 8                # a3 <- AA
-    GET_VREG a1, a3                     # a1 <- fp[AA]
-    ld      a2, OFF_FP_METHOD(rFP)
-    move    a3, rSELF
-    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
-    jal     MterpSPutU32
-    bnezc   v0, MterpException          # 0 on success
-    ADVANCE 2                           # Past exception point - now advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_wide: /* 0x68 */
 /* File: mips64/op_sput_wide.S */
-    /*
-     * SPUT_WIDE handler wrapper.
-     *
-     */
-    /* sput-wide vAA, field//BBBB */
-    .extern MterpSPutU64
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    srl     a1, rINST, 8                # a2 <- AA
-    dlsa    a1, a1, rFP, 2
-    ld      a2, OFF_FP_METHOD(rFP)
-    move    a3, rSELF
-    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
-    jal     MterpSPutU64
-    bnezc   v0, MterpException          # 0 on success, -1 on failure
-    ADVANCE 2                           # Past exception point - now advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/op_sput.S */
+/* File: mips64/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_object: /* 0x69 */
 /* File: mips64/op_sput_object.S */
-    .extern MterpSPutObj
-    EXPORT_PC
-    daddu   a0, rFP, OFF_FP_SHADOWFRAME
-    move    a1, rPC
-    move    a2, rINST
-    move    a3, rSELF
-    jal     MterpSPutObj
-    beqzc   v0, MterpException
-    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/op_sput.S */
+/* File: mips64/field.S */
+TODO
+
+
 
 /* ------------------------------ */
     .balign 128
 .L_op_sput_boolean: /* 0x6a */
 /* File: mips64/op_sput_boolean.S */
 /* File: mips64/op_sput.S */
-    /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSPutU8
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    srl     a3, rINST, 8                # a3 <- AA
-    GET_VREG a1, a3                     # a1 <- fp[AA]
-    ld      a2, OFF_FP_METHOD(rFP)
-    move    a3, rSELF
-    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
-    jal     MterpSPutU8
-    bnezc   v0, MterpException          # 0 on success
-    ADVANCE 2                           # Past exception point - now advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2929,25 +2484,9 @@
 .L_op_sput_byte: /* 0x6b */
 /* File: mips64/op_sput_byte.S */
 /* File: mips64/op_sput.S */
-    /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSPutI8
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    srl     a3, rINST, 8                # a3 <- AA
-    GET_VREG a1, a3                     # a1 <- fp[AA]
-    ld      a2, OFF_FP_METHOD(rFP)
-    move    a3, rSELF
-    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
-    jal     MterpSPutI8
-    bnezc   v0, MterpException          # 0 on success
-    ADVANCE 2                           # Past exception point - now advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2955,25 +2494,9 @@
 .L_op_sput_char: /* 0x6c */
 /* File: mips64/op_sput_char.S */
 /* File: mips64/op_sput.S */
-    /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSPutU16
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    srl     a3, rINST, 8                # a3 <- AA
-    GET_VREG a1, a3                     # a1 <- fp[AA]
-    ld      a2, OFF_FP_METHOD(rFP)
-    move    a3, rSELF
-    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
-    jal     MterpSPutU16
-    bnezc   v0, MterpException          # 0 on success
-    ADVANCE 2                           # Past exception point - now advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
@@ -2981,25 +2504,9 @@
 .L_op_sput_short: /* 0x6d */
 /* File: mips64/op_sput_short.S */
 /* File: mips64/op_sput.S */
-    /*
-     * General SPUT handler wrapper.
-     *
-     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
-     */
-    /* op vAA, field//BBBB */
-    .extern MterpSPutI16
-    EXPORT_PC
-    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
-    srl     a3, rINST, 8                # a3 <- AA
-    GET_VREG a1, a3                     # a1 <- fp[AA]
-    ld      a2, OFF_FP_METHOD(rFP)
-    move    a3, rSELF
-    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
-    jal     MterpSPutI16
-    bnezc   v0, MterpException          # 0 on success
-    ADVANCE 2                           # Past exception point - now advance rPC
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    GOTO_OPCODE v0                      # jump to next instruction
+/* File: mips64/field.S */
+TODO
+
 
 
 /* ------------------------------ */
diff --git a/runtime/interpreter/mterp/out/mterp_x86.S b/runtime/interpreter/mterp/out/mterp_x86.S
index 3f70919..32811ff 100644
--- a/runtime/interpreter/mterp/out/mterp_x86.S
+++ b/runtime/interpreter/mterp/out/mterp_x86.S
@@ -2120,832 +2120,694 @@
     .balign 128
 .L_op_iget: /* 0x52 */
 /* File: x86/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
- */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx <- BA
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    mov     rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetU32
+    REFRESH_INST 82                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIGetU32)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <-value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_wide: /* 0x53 */
 /* File: x86/op_iget_wide.S */
-/*
- * 64-bit instance field get.
- *
- * for: iget-wide
- */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx <- BA
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    mov     rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+/* File: x86/op_iget.S */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetU64
+    REFRESH_INST 83                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIGetU64)
-    mov     rSELF, %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    SET_VREG %eax, rINST
-    SET_VREG_HIGH %edx, rINST
-    RESTORE_IBASE_FROM_SELF %ecx
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_object: /* 0x54 */
 /* File: x86/op_iget_object.S */
 /* File: x86/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
- */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx <- BA
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    mov     rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetObj
+    REFRESH_INST 84                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIGetObj)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 1
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <-value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_boolean: /* 0x55 */
 /* File: x86/op_iget_boolean.S */
 /* File: x86/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
- */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx <- BA
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    mov     rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetU8
+    REFRESH_INST 85                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIGetU8)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <-value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_byte: /* 0x56 */
 /* File: x86/op_iget_byte.S */
 /* File: x86/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
- */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx <- BA
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    mov     rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetI8
+    REFRESH_INST 86                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIGetI8)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <-value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_char: /* 0x57 */
 /* File: x86/op_iget_char.S */
 /* File: x86/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
- */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx <- BA
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    mov     rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetU16
+    REFRESH_INST 87                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIGetU16)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <-value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_short: /* 0x58 */
 /* File: x86/op_iget_short.S */
 /* File: x86/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
- */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx <- BA
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    mov     rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetI16
+    REFRESH_INST 88                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIGetI16)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <-value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput: /* 0x59 */
 /* File: x86/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU32
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax<- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG %eax, rINST
-    movl    %eax, OUT_ARG2(%esp)            # fp[A]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG3(%esp)            # referrer
+    REFRESH_INST 89                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIPutU32)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_wide: /* 0x5a */
 /* File: x86/op_iput_wide.S */
-    /* iput-wide vA, vB, field@CCCC */
+/* File: x86/op_iput.S */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU64
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl,%ecx                    # ecx <- BA
-    sarl    $4,%ecx                        # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    andb    $0xf,rINSTbl                   # rINST <- A
-    leal    VREG_ADDRESS(rINST), %eax
-    movl    %eax, OUT_ARG2(%esp)            # &fp[A]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG3(%esp)            # referrer
+    REFRESH_INST 90                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIPutU64)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_object: /* 0x5b */
 /* File: x86/op_iput_object.S */
-    EXPORT_PC
+/* File: x86/op_iput.S */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIPutObj
+    REFRESH_INST 91                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
-    movl    %eax, OUT_ARG0(%esp)
-    movl    rPC, OUT_ARG1(%esp)
-    REFRESH_INST 91
-    movl    rINST, OUT_ARG2(%esp)
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
     movl    rSELF, %eax
-    movl    %eax, OUT_ARG3(%esp)
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIPutObj)
     testb   %al, %al
-    jz      MterpException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_boolean: /* 0x5c */
 /* File: x86/op_iput_boolean.S */
 /* File: x86/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU8
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax<- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG %eax, rINST
-    movl    %eax, OUT_ARG2(%esp)            # fp[A]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG3(%esp)            # referrer
+    REFRESH_INST 92                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIPutU8)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_byte: /* 0x5d */
 /* File: x86/op_iput_byte.S */
 /* File: x86/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutI8
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax<- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG %eax, rINST
-    movl    %eax, OUT_ARG2(%esp)            # fp[A]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG3(%esp)            # referrer
+    REFRESH_INST 93                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIPutI8)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_char: /* 0x5e */
 /* File: x86/op_iput_char.S */
 /* File: x86/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU16
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax<- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG %eax, rINST
-    movl    %eax, OUT_ARG2(%esp)            # fp[A]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG3(%esp)            # referrer
+    REFRESH_INST 94                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIPutU16)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_short: /* 0x5f */
 /* File: x86/op_iput_short.S */
 /* File: x86/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutI16
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax<- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG %eax, rINST
-    movl    %eax, OUT_ARG2(%esp)            # fp[A]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG3(%esp)            # referrer
+    REFRESH_INST 95                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpIPutI16)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget: /* 0x60 */
 /* File: x86/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetU32
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG1(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG2(%esp)            # self
+    REFRESH_INST 96                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSGetU32)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <- value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_wide: /* 0x61 */
 /* File: x86/op_sget_wide.S */
-/*
- * SGET_WIDE handler wrapper.
- *
- */
-    /* sget-wide vAA, field@BBBB */
+/* File: x86/op_sget.S */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetU64
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG1(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG2(%esp)            # self
+    REFRESH_INST 97                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSGetU64)
-    movl    rSELF, %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException
-    SET_VREG %eax, rINST                    # fp[A]<- low part
-    SET_VREG_HIGH %edx, rINST               # fp[A+1]<- high part
-    RESTORE_IBASE_FROM_SELF %ecx
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_object: /* 0x62 */
 /* File: x86/op_sget_object.S */
 /* File: x86/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetObj
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG1(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG2(%esp)            # self
+    REFRESH_INST 98                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSGetObj)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException
-    .if 1
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <- value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_boolean: /* 0x63 */
 /* File: x86/op_sget_boolean.S */
 /* File: x86/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetU8
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG1(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG2(%esp)            # self
+    REFRESH_INST 99                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSGetU8)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <- value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_byte: /* 0x64 */
 /* File: x86/op_sget_byte.S */
 /* File: x86/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetI8
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG1(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG2(%esp)            # self
+    REFRESH_INST 100                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSGetI8)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <- value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_char: /* 0x65 */
 /* File: x86/op_sget_char.S */
 /* File: x86/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetU16
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG1(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG2(%esp)            # self
+    REFRESH_INST 101                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSGetU16)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <- value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_short: /* 0x66 */
 /* File: x86/op_sget_short.S */
 /* File: x86/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetI16
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG1(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG2(%esp)            # self
+    REFRESH_INST 102                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSGetI16)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <- value
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput: /* 0x67 */
 /* File: x86/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutU32
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST, rINST
-    movl    rINST, OUT_ARG1(%esp)           # fp[AA]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+    REFRESH_INST 103                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSPutU32)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_wide: /* 0x68 */
 /* File: x86/op_sput_wide.S */
-/*
- * SPUT_WIDE handler wrapper.
- *
- */
-    /* sput-wide vAA, field@BBBB */
+/* File: x86/op_sput.S */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutU64
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    leal    VREG_ADDRESS(rINST), %eax
-    movl    %eax, OUT_ARG1(%esp)            # &fp[AA]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+    REFRESH_INST 104                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSPutU64)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_object: /* 0x69 */
 /* File: x86/op_sput_object.S */
-    EXPORT_PC
+/* File: x86/op_sput.S */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpSPutObj
+    REFRESH_INST 105                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
-    movl    %eax, OUT_ARG0(%esp)
-    movl    rPC, OUT_ARG1(%esp)
-    REFRESH_INST 105
-    movl    rINST, OUT_ARG2(%esp)
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSPutObj)
     testb   %al, %al
-    jz      MterpException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_boolean: /* 0x6a */
 /* File: x86/op_sput_boolean.S */
 /* File: x86/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutU8
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST, rINST
-    movl    rINST, OUT_ARG1(%esp)           # fp[AA]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+    REFRESH_INST 106                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSPutU8)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_byte: /* 0x6b */
 /* File: x86/op_sput_byte.S */
 /* File: x86/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutI8
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST, rINST
-    movl    rINST, OUT_ARG1(%esp)           # fp[AA]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+    REFRESH_INST 107                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSPutI8)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_char: /* 0x6c */
 /* File: x86/op_sput_char.S */
 /* File: x86/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutU16
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST, rINST
-    movl    rINST, OUT_ARG1(%esp)           # fp[AA]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+    REFRESH_INST 108                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSPutU16)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_short: /* 0x6d */
 /* File: x86/op_sput_short.S */
 /* File: x86/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutI16
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST, rINST
-    movl    rINST, OUT_ARG1(%esp)           # fp[AA]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
+    REFRESH_INST 109                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
     call    SYMBOL(MterpSPutI16)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     RESTORE_IBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_virtual: /* 0x6e */
diff --git a/runtime/interpreter/mterp/out/mterp_x86_64.S b/runtime/interpreter/mterp/out/mterp_x86_64.S
index 89d5637..6d8bb4c 100644
--- a/runtime/interpreter/mterp/out/mterp_x86_64.S
+++ b/runtime/interpreter/mterp/out/mterp_x86_64.S
@@ -2067,770 +2067,610 @@
     .balign 128
 .L_op_iget: /* 0x52 */
 /* File: x86_64/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short, iget-wide
- */
-    EXPORT_PC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    movzwl  2(rPC), OUT_32_ARG0             # eax <- field ref CCCC
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetU32
+    REFRESH_INST 82                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIGetU32)
-    movq    rSELF, %rcx
-    cmpq    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <-value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <-value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <-value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_wide: /* 0x53 */
 /* File: x86_64/op_iget_wide.S */
 /* File: x86_64/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short, iget-wide
- */
-    EXPORT_PC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    movzwl  2(rPC), OUT_32_ARG0             # eax <- field ref CCCC
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetU64
+    REFRESH_INST 83                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIGetU64)
-    movq    rSELF, %rcx
-    cmpq    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <-value
-    .else
-    .if 1
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <-value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <-value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_object: /* 0x54 */
 /* File: x86_64/op_iget_object.S */
 /* File: x86_64/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short, iget-wide
- */
-    EXPORT_PC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    movzwl  2(rPC), OUT_32_ARG0             # eax <- field ref CCCC
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetObj
+    REFRESH_INST 84                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIGetObj)
-    movq    rSELF, %rcx
-    cmpq    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 1
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <-value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <-value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <-value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_boolean: /* 0x55 */
 /* File: x86_64/op_iget_boolean.S */
 /* File: x86_64/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short, iget-wide
- */
-    EXPORT_PC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    movzwl  2(rPC), OUT_32_ARG0             # eax <- field ref CCCC
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetU8
+    REFRESH_INST 85                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIGetU8)
-    movq    rSELF, %rcx
-    cmpq    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <-value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <-value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <-value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_byte: /* 0x56 */
 /* File: x86_64/op_iget_byte.S */
 /* File: x86_64/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short, iget-wide
- */
-    EXPORT_PC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    movzwl  2(rPC), OUT_32_ARG0             # eax <- field ref CCCC
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetI8
+    REFRESH_INST 86                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIGetI8)
-    movq    rSELF, %rcx
-    cmpq    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <-value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <-value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <-value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_char: /* 0x57 */
 /* File: x86_64/op_iget_char.S */
 /* File: x86_64/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short, iget-wide
- */
-    EXPORT_PC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    movzwl  2(rPC), OUT_32_ARG0             # eax <- field ref CCCC
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetU16
+    REFRESH_INST 87                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIGetU16)
-    movq    rSELF, %rcx
-    cmpq    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <-value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <-value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <-value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iget_short: /* 0x58 */
 /* File: x86_64/op_iget_short.S */
 /* File: x86_64/op_iget.S */
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short, iget-wide
- */
-    EXPORT_PC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    movzwl  2(rPC), OUT_32_ARG0             # eax <- field ref CCCC
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIGetI16
+    REFRESH_INST 88                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIGetI16)
-    movq    rSELF, %rcx
-    cmpq    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException                  # bail out
-    andb    $0xf, rINSTbl                  # rINST <- A
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <-value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <-value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <-value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput: /* 0x59 */
 /* File: x86_64/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU32
-    EXPORT_PC
-    movzwl  2(rPC), OUT_32_ARG0             # field ref <- 0000CCCC
-    movzbq  rINSTbl, %rcx                   # rcx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG OUT_32_ARG2, rINSTq            # fp[A]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG3    # referrer
+    REFRESH_INST 89                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIPutU32)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_wide: /* 0x5a */
 /* File: x86_64/op_iput_wide.S */
-    /* iput-wide vA, vB, field@CCCC */
+/* File: x86_64/op_iput.S */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU64
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    sarl    $4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    andb    $0xf, rINSTbl                  # rINST <- A
-    leaq    VREG_ADDRESS(rINSTq), OUT_ARG2  # &fp[A]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG3    # referrer
+    REFRESH_INST 90                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIPutU64)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_object: /* 0x5b */
 /* File: x86_64/op_iput_object.S */
-    EXPORT_PC
-    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG0
-    movq    rPC, OUT_ARG1
-    REFRESH_INST 91
-    movl    rINST, OUT_32_ARG2
-    movq    rSELF, OUT_ARG3
+/* File: x86_64/op_iput.S */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpIPutObj
+    REFRESH_INST 91                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIPutObj)
     testb   %al, %al
-    jz      MterpException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_boolean: /* 0x5c */
 /* File: x86_64/op_iput_boolean.S */
 /* File: x86_64/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU8
-    EXPORT_PC
-    movzwl  2(rPC), OUT_32_ARG0             # field ref <- 0000CCCC
-    movzbq  rINSTbl, %rcx                   # rcx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG OUT_32_ARG2, rINSTq            # fp[A]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG3    # referrer
+    REFRESH_INST 92                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIPutU8)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_byte: /* 0x5d */
 /* File: x86_64/op_iput_byte.S */
 /* File: x86_64/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutI8
-    EXPORT_PC
-    movzwl  2(rPC), OUT_32_ARG0             # field ref <- 0000CCCC
-    movzbq  rINSTbl, %rcx                   # rcx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG OUT_32_ARG2, rINSTq            # fp[A]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG3    # referrer
+    REFRESH_INST 93                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIPutI8)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_char: /* 0x5e */
 /* File: x86_64/op_iput_char.S */
 /* File: x86_64/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutU16
-    EXPORT_PC
-    movzwl  2(rPC), OUT_32_ARG0             # field ref <- 0000CCCC
-    movzbq  rINSTbl, %rcx                   # rcx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG OUT_32_ARG2, rINSTq            # fp[A]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG3    # referrer
+    REFRESH_INST 94                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIPutU16)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_iput_short: /* 0x5f */
 /* File: x86_64/op_iput_short.S */
 /* File: x86_64/op_iput.S */
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpIPutI16
-    EXPORT_PC
-    movzwl  2(rPC), OUT_32_ARG0             # field ref <- 0000CCCC
-    movzbq  rINSTbl, %rcx                   # rcx<- BA
-    sarl    $4, %ecx                       # ecx<- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    andb    $0xf, rINSTbl                  # rINST<- A
-    GET_VREG OUT_32_ARG2, rINSTq            # fp[A]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG3    # referrer
+    REFRESH_INST 95                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpIPutI16)
     testb   %al, %al
-    jnz     MterpPossibleException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget: /* 0x60 */
 /* File: x86_64/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short, sget-wide
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetU32
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movq    OFF_FP_METHOD(rFP), OUT_ARG1    # referrer
-    movq    rSELF, OUT_ARG2                 # self
+    REFRESH_INST 96                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSGetU32)
-    movq    rSELF, %rcx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <- value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_wide: /* 0x61 */
 /* File: x86_64/op_sget_wide.S */
 /* File: x86_64/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short, sget-wide
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetU64
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movq    OFF_FP_METHOD(rFP), OUT_ARG1    # referrer
-    movq    rSELF, OUT_ARG2                 # self
+    REFRESH_INST 97                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSGetU64)
-    movq    rSELF, %rcx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
-    .else
-    .if 1
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <- value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_object: /* 0x62 */
 /* File: x86_64/op_sget_object.S */
 /* File: x86_64/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short, sget-wide
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetObj
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movq    OFF_FP_METHOD(rFP), OUT_ARG1    # referrer
-    movq    rSELF, OUT_ARG2                 # self
+    REFRESH_INST 98                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSGetObj)
-    movq    rSELF, %rcx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException
-    .if 1
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <- value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_boolean: /* 0x63 */
 /* File: x86_64/op_sget_boolean.S */
 /* File: x86_64/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short, sget-wide
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetU8
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movq    OFF_FP_METHOD(rFP), OUT_ARG1    # referrer
-    movq    rSELF, OUT_ARG2                 # self
+    REFRESH_INST 99                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSGetU8)
-    movq    rSELF, %rcx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <- value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_byte: /* 0x64 */
 /* File: x86_64/op_sget_byte.S */
 /* File: x86_64/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short, sget-wide
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetI8
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movq    OFF_FP_METHOD(rFP), OUT_ARG1    # referrer
-    movq    rSELF, OUT_ARG2                 # self
+    REFRESH_INST 100                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSGetI8)
-    movq    rSELF, %rcx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <- value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_char: /* 0x65 */
 /* File: x86_64/op_sget_char.S */
 /* File: x86_64/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short, sget-wide
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetU16
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movq    OFF_FP_METHOD(rFP), OUT_ARG1    # referrer
-    movq    rSELF, OUT_ARG2                 # self
+    REFRESH_INST 101                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSGetU16)
-    movq    rSELF, %rcx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <- value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sget_short: /* 0x66 */
 /* File: x86_64/op_sget_short.S */
 /* File: x86_64/op_sget.S */
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short, sget-wide
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSGetI16
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movq    OFF_FP_METHOD(rFP), OUT_ARG1    # referrer
-    movq    rSELF, OUT_ARG2                 # self
+    REFRESH_INST 102                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSGetI16)
-    movq    rSELF, %rcx
-    cmpl    $0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException
-    .if 0
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
-    .else
-    .if 0
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <- value
-    .endif
-    .endif
+    testb   %al, %al
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput: /* 0x67 */
 /* File: x86_64/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutU32
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref BBBB
-    GET_VREG OUT_32_ARG1, rINSTq            # fp[AA]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3                 # self
+    REFRESH_INST 103                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSPutU32)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_wide: /* 0x68 */
 /* File: x86_64/op_sput_wide.S */
-/*
- * SPUT_WIDE handler wrapper.
- *
- */
-    /* sput-wide vAA, field@BBBB */
+/* File: x86_64/op_sput.S */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutU64
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref BBBB
-    leaq    VREG_ADDRESS(rINSTq), OUT_ARG1  # &fp[AA]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3                 # self
+    REFRESH_INST 104                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSPutU64)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_object: /* 0x69 */
 /* File: x86_64/op_sput_object.S */
-    EXPORT_PC
-    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG0
-    movq    rPC, OUT_ARG1
-    REFRESH_INST 105
-    movq    rINSTq, OUT_ARG2
-    movq    rSELF, OUT_ARG3
+/* File: x86_64/op_sput.S */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern MterpSPutObj
+    REFRESH_INST 105                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSPutObj)
     testb   %al, %al
-    jz      MterpException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
+
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_boolean: /* 0x6a */
 /* File: x86_64/op_sput_boolean.S */
 /* File: x86_64/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutU8
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref BBBB
-    GET_VREG OUT_32_ARG1, rINSTq            # fp[AA]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3                 # self
+    REFRESH_INST 106                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSPutU8)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_byte: /* 0x6b */
 /* File: x86_64/op_sput_byte.S */
 /* File: x86_64/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutI8
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref BBBB
-    GET_VREG OUT_32_ARG1, rINSTq            # fp[AA]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3                 # self
+    REFRESH_INST 107                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSPutI8)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_char: /* 0x6c */
 /* File: x86_64/op_sput_char.S */
 /* File: x86_64/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutU16
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref BBBB
-    GET_VREG OUT_32_ARG1, rINSTq            # fp[AA]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3                 # self
+    REFRESH_INST 108                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSPutU16)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_sput_short: /* 0x6d */
 /* File: x86_64/op_sput_short.S */
 /* File: x86_64/op_sput.S */
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
+/* File: x86_64/field.S */
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
     .extern MterpSPutI16
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref BBBB
-    GET_VREG OUT_32_ARG1, rINSTq            # fp[AA]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3                 # self
+    REFRESH_INST 109                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
     call    SYMBOL(MterpSPutI16)
     testb   %al, %al
-    jnz     MterpException
+    jz      MterpPossibleException
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
+
 /* ------------------------------ */
     .balign 128
 .L_op_invoke_virtual: /* 0x6e */
diff --git a/runtime/interpreter/mterp/x86/field.S b/runtime/interpreter/mterp/x86/field.S
new file mode 100644
index 0000000..8432c74
--- /dev/null
+++ b/runtime/interpreter/mterp/x86/field.S
@@ -0,0 +1,17 @@
+%default { }
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern $helper
+    REFRESH_INST ${opnum}                   # fix rINST to include opcode
+    movl    rPC, OUT_ARG0(%esp)             # arg0: Instruction* inst
+    movl    rINST, OUT_ARG1(%esp)           # arg1: uint16_t inst_data
+    leal    OFF_FP_SHADOWFRAME(rFP), %eax
+    movl    %eax, OUT_ARG2(%esp)            # arg2: ShadowFrame* sf
+    movl    rSELF, %eax
+    movl    %eax, OUT_ARG3(%esp)            # arg3: Thread* self
+    call    SYMBOL($helper)
+    testb   %al, %al
+    jz      MterpPossibleException
+    RESTORE_IBASE
+    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_iget.S b/runtime/interpreter/mterp/x86/op_iget.S
index 0af1bec..d85d54c 100644
--- a/runtime/interpreter/mterp/x86/op_iget.S
+++ b/runtime/interpreter/mterp/x86/op_iget.S
@@ -1,29 +1,2 @@
 %default { "is_object":"0", "helper":"MterpIGetU32"}
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
- */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx <- BA
-    sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    mov     rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
-    call    SYMBOL($helper)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException                  # bail out
-    andb    $$0xf, rINSTbl                  # rINST <- A
-    .if $is_object
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <-value
-    .endif
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/field.S" { }
diff --git a/runtime/interpreter/mterp/x86/op_iget_wide.S b/runtime/interpreter/mterp/x86/op_iget_wide.S
index da27df9..741a64e 100644
--- a/runtime/interpreter/mterp/x86/op_iget_wide.S
+++ b/runtime/interpreter/mterp/x86/op_iget_wide.S
@@ -1,25 +1 @@
-/*
- * 64-bit instance field get.
- *
- * for: iget-wide
- */
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx <- BA
-    sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    mov     rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
-    call    SYMBOL(MterpIGetU64)
-    mov     rSELF, %ecx
-    cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException                  # bail out
-    andb    $$0xf, rINSTbl                  # rINST <- A
-    SET_VREG %eax, rINST
-    SET_VREG_HIGH %edx, rINST
-    RESTORE_IBASE_FROM_SELF %ecx
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/op_iget.S" { "helper":"MterpIGetU64" }
diff --git a/runtime/interpreter/mterp/x86/op_iput.S b/runtime/interpreter/mterp/x86/op_iput.S
index 4c6603a..3628ffd 100644
--- a/runtime/interpreter/mterp/x86/op_iput.S
+++ b/runtime/interpreter/mterp/x86/op_iput.S
@@ -1,25 +1,2 @@
-%default { "helper":"MterpIPutU32" }
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
-    .extern $helper
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax<- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl, %ecx                   # ecx<- BA
-    sarl    $$4, %ecx                       # ecx<- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    andb    $$0xf, rINSTbl                  # rINST<- A
-    GET_VREG %eax, rINST
-    movl    %eax, OUT_ARG2(%esp)            # fp[A]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    SYMBOL($helper)
-    testb   %al, %al
-    jnz     MterpPossibleException
-    RESTORE_IBASE
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%default { "is_object":"0", "helper":"MterpIPutU32" }
+%include "x86/field.S" { }
diff --git a/runtime/interpreter/mterp/x86/op_iput_object.S b/runtime/interpreter/mterp/x86/op_iput_object.S
index 56e026e..a124b7e 100644
--- a/runtime/interpreter/mterp/x86/op_iput_object.S
+++ b/runtime/interpreter/mterp/x86/op_iput_object.S
@@ -1,13 +1 @@
-    EXPORT_PC
-    leal    OFF_FP_SHADOWFRAME(rFP), %eax
-    movl    %eax, OUT_ARG0(%esp)
-    movl    rPC, OUT_ARG1(%esp)
-    REFRESH_INST ${opnum}
-    movl    rINST, OUT_ARG2(%esp)
-    movl    rSELF, %eax
-    movl    %eax, OUT_ARG3(%esp)
-    call    SYMBOL(MterpIPutObj)
-    testb   %al, %al
-    jz      MterpException
-    RESTORE_IBASE
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/op_iput.S" { "is_object":"1", "helper":"MterpIPutObj" }
diff --git a/runtime/interpreter/mterp/x86/op_iput_wide.S b/runtime/interpreter/mterp/x86/op_iput_wide.S
index ea22b91..2820ede 100644
--- a/runtime/interpreter/mterp/x86/op_iput_wide.S
+++ b/runtime/interpreter/mterp/x86/op_iput_wide.S
@@ -1,19 +1 @@
-    /* iput-wide vA, vB, field@CCCC */
-    .extern MterpIPutU64
-    EXPORT_PC
-    movzwl  2(rPC), %eax                    # eax <- 0000CCCC
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movzbl  rINSTbl,%ecx                    # ecx <- BA
-    sarl    $$4,%ecx                        # ecx <- B
-    GET_VREG %ecx, %ecx
-    movl    %ecx, OUT_ARG1(%esp)            # the object pointer
-    andb    $$0xf,rINSTbl                   # rINST <- A
-    leal    VREG_ADDRESS(rINST), %eax
-    movl    %eax, OUT_ARG2(%esp)            # &fp[A]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    SYMBOL(MterpIPutU64)
-    testb   %al, %al
-    jnz     MterpPossibleException
-    RESTORE_IBASE
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/op_iput.S" { "helper":"MterpIPutU64" }
diff --git a/runtime/interpreter/mterp/x86/op_sget.S b/runtime/interpreter/mterp/x86/op_sget.S
index 66c7b0b..ada4e0e 100644
--- a/runtime/interpreter/mterp/x86/op_sget.S
+++ b/runtime/interpreter/mterp/x86/op_sget.S
@@ -1,26 +1,2 @@
 %default { "is_object":"0", "helper":"MterpSGetU32" }
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
- */
-    /* op vAA, field@BBBB */
-    .extern $helper
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG1(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG2(%esp)            # self
-    call    SYMBOL($helper)
-    movl    rSELF, %ecx
-    RESTORE_IBASE_FROM_SELF %ecx
-    cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException
-    .if $is_object
-    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
-    .else
-    SET_VREG %eax, rINST                    # fp[A] <- value
-    .endif
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/field.S" { }
diff --git a/runtime/interpreter/mterp/x86/op_sget_wide.S b/runtime/interpreter/mterp/x86/op_sget_wide.S
index 994cc3a..5923274 100644
--- a/runtime/interpreter/mterp/x86/op_sget_wide.S
+++ b/runtime/interpreter/mterp/x86/op_sget_wide.S
@@ -1,21 +1 @@
-/*
- * SGET_WIDE handler wrapper.
- *
- */
-    /* sget-wide vAA, field@BBBB */
-    .extern MterpSGetU64
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref CCCC
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG1(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG2(%esp)            # self
-    call    SYMBOL(MterpSGetU64)
-    movl    rSELF, %ecx
-    cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
-    jnz     MterpException
-    SET_VREG %eax, rINST                    # fp[A]<- low part
-    SET_VREG_HIGH %edx, rINST               # fp[A+1]<- high part
-    RESTORE_IBASE_FROM_SELF %ecx
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/op_sget.S" {"helper":"MterpSGetU64"}
diff --git a/runtime/interpreter/mterp/x86/op_sput.S b/runtime/interpreter/mterp/x86/op_sput.S
index e99e7a7..2ad68e7 100644
--- a/runtime/interpreter/mterp/x86/op_sput.S
+++ b/runtime/interpreter/mterp/x86/op_sput.S
@@ -1,22 +1,2 @@
-%default { "helper":"MterpSPutU32"}
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
-    .extern $helper
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST, rINST
-    movl    rINST, OUT_ARG1(%esp)           # fp[AA]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
-    call    SYMBOL($helper)
-    testb   %al, %al
-    jnz     MterpException
-    RESTORE_IBASE
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%default { "is_object":"0", "helper":"MterpSPutU32"}
+%include "x86/field.S" { }
diff --git a/runtime/interpreter/mterp/x86/op_sput_object.S b/runtime/interpreter/mterp/x86/op_sput_object.S
index 941b072..4452dba 100644
--- a/runtime/interpreter/mterp/x86/op_sput_object.S
+++ b/runtime/interpreter/mterp/x86/op_sput_object.S
@@ -1,13 +1 @@
-    EXPORT_PC
-    leal    OFF_FP_SHADOWFRAME(rFP), %eax
-    movl    %eax, OUT_ARG0(%esp)
-    movl    rPC, OUT_ARG1(%esp)
-    REFRESH_INST ${opnum}
-    movl    rINST, OUT_ARG2(%esp)
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)
-    call    SYMBOL(MterpSPutObj)
-    testb   %al, %al
-    jz      MterpException
-    RESTORE_IBASE
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/op_sput.S" {"is_object":"1", "helper":"MterpSPutObj"}
diff --git a/runtime/interpreter/mterp/x86/op_sput_wide.S b/runtime/interpreter/mterp/x86/op_sput_wide.S
index f581507..d79b068 100644
--- a/runtime/interpreter/mterp/x86/op_sput_wide.S
+++ b/runtime/interpreter/mterp/x86/op_sput_wide.S
@@ -1,20 +1 @@
-/*
- * SPUT_WIDE handler wrapper.
- *
- */
-    /* sput-wide vAA, field@BBBB */
-    .extern MterpSPutU64
-    EXPORT_PC
-    movzwl  2(rPC), %eax
-    movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    leal    VREG_ADDRESS(rINST), %eax
-    movl    %eax, OUT_ARG1(%esp)            # &fp[AA]
-    movl    OFF_FP_METHOD(rFP), %eax
-    movl    %eax, OUT_ARG2(%esp)            # referrer
-    movl    rSELF, %ecx
-    movl    %ecx, OUT_ARG3(%esp)            # self
-    call    SYMBOL(MterpSPutU64)
-    testb   %al, %al
-    jnz     MterpException
-    RESTORE_IBASE
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86/op_sput.S" {"helper":"MterpSPutU64"}
diff --git a/runtime/interpreter/mterp/x86_64/field.S b/runtime/interpreter/mterp/x86_64/field.S
new file mode 100644
index 0000000..f8b0588
--- /dev/null
+++ b/runtime/interpreter/mterp/x86_64/field.S
@@ -0,0 +1,14 @@
+%default { }
+    /*
+     * General field read / write (iget-* iput-* sget-* sput-*).
+     */
+    .extern $helper
+    REFRESH_INST ${opnum}                      # fix rINST to include opcode
+    movq    rPC, OUT_ARG0                      # arg0: Instruction* inst
+    movl    rINST, OUT_32_ARG1                 # arg1: uint16_t inst_data
+    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG2  # arg2: ShadowFrame* sf
+    movq    rSELF, OUT_ARG3                    # arg3: Thread* self
+    call    SYMBOL($helper)
+    testb   %al, %al
+    jz      MterpPossibleException
+    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86_64/op_iget.S b/runtime/interpreter/mterp/x86_64/op_iget.S
index 5c6cab6..4ab7c27 100644
--- a/runtime/interpreter/mterp/x86_64/op_iget.S
+++ b/runtime/interpreter/mterp/x86_64/op_iget.S
@@ -1,28 +1,2 @@
-%default { "is_object":"0", "helper":"MterpIGetU32", "wide":"0"}
-/*
- * General instance field get.
- *
- * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short, iget-wide
- */
-    EXPORT_PC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    movzwl  2(rPC), OUT_32_ARG0             # eax <- field ref CCCC
-    sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3
-    call    SYMBOL($helper)
-    movq    rSELF, %rcx
-    cmpq    $$0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException                  # bail out
-    andb    $$0xf, rINSTbl                  # rINST <- A
-    .if $is_object
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <-value
-    .else
-    .if $wide
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <-value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <-value
-    .endif
-    .endif
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%default { "is_object":"0", "helper":"MterpIGetU32"}
+%include "x86_64/field.S" { }
diff --git a/runtime/interpreter/mterp/x86_64/op_iget_wide.S b/runtime/interpreter/mterp/x86_64/op_iget_wide.S
index d9d1744..a85a474 100644
--- a/runtime/interpreter/mterp/x86_64/op_iget_wide.S
+++ b/runtime/interpreter/mterp/x86_64/op_iget_wide.S
@@ -1 +1 @@
-%include "x86_64/op_iget.S" { "helper":"MterpIGetU64", "wide":"1" }
+%include "x86_64/op_iget.S" { "helper":"MterpIGetU64" }
diff --git a/runtime/interpreter/mterp/x86_64/op_iput.S b/runtime/interpreter/mterp/x86_64/op_iput.S
index 12affdb..dad5af6 100644
--- a/runtime/interpreter/mterp/x86_64/op_iput.S
+++ b/runtime/interpreter/mterp/x86_64/op_iput.S
@@ -1,20 +1,2 @@
-%default { "helper":"MterpIPutU32"}
-/*
- * General 32-bit instance field put.
- *
- * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
- */
-    /* op vA, vB, field@CCCC */
-    .extern $helper
-    EXPORT_PC
-    movzwl  2(rPC), OUT_32_ARG0             # field ref <- 0000CCCC
-    movzbq  rINSTbl, %rcx                   # rcx<- BA
-    sarl    $$4, %ecx                       # ecx<- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    andb    $$0xf, rINSTbl                  # rINST<- A
-    GET_VREG OUT_32_ARG2, rINSTq            # fp[A]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG3    # referrer
-    call    SYMBOL($helper)
-    testb   %al, %al
-    jnz     MterpPossibleException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%default { "is_object":"0", "helper":"MterpIPutU32" }
+%include "x86_64/field.S" { }
diff --git a/runtime/interpreter/mterp/x86_64/op_iput_object.S b/runtime/interpreter/mterp/x86_64/op_iput_object.S
index 22648cd..202e33f 100644
--- a/runtime/interpreter/mterp/x86_64/op_iput_object.S
+++ b/runtime/interpreter/mterp/x86_64/op_iput_object.S
@@ -1,10 +1 @@
-    EXPORT_PC
-    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG0
-    movq    rPC, OUT_ARG1
-    REFRESH_INST ${opnum}
-    movl    rINST, OUT_32_ARG2
-    movq    rSELF, OUT_ARG3
-    call    SYMBOL(MterpIPutObj)
-    testb   %al, %al
-    jz      MterpException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86_64/op_iput.S" { "is_object":"1", "helper":"MterpIPutObj" }
diff --git a/runtime/interpreter/mterp/x86_64/op_iput_wide.S b/runtime/interpreter/mterp/x86_64/op_iput_wide.S
index 4f8c47c..db52016 100644
--- a/runtime/interpreter/mterp/x86_64/op_iput_wide.S
+++ b/runtime/interpreter/mterp/x86_64/op_iput_wide.S
@@ -1,14 +1 @@
-    /* iput-wide vA, vB, field@CCCC */
-    .extern MterpIPutU64
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movzbq  rINSTbl, %rcx                   # rcx <- BA
-    sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG OUT_32_ARG1, %rcx              # the object pointer
-    andb    $$0xf, rINSTbl                  # rINST <- A
-    leaq    VREG_ADDRESS(rINSTq), OUT_ARG2  # &fp[A]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG3    # referrer
-    call    SYMBOL(MterpIPutU64)
-    testb   %al, %al
-    jnz     MterpPossibleException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86_64/op_iput.S" { "helper":"MterpIPutU64" }
diff --git a/runtime/interpreter/mterp/x86_64/op_sget.S b/runtime/interpreter/mterp/x86_64/op_sget.S
index c15ac1e..21e8e64 100644
--- a/runtime/interpreter/mterp/x86_64/op_sget.S
+++ b/runtime/interpreter/mterp/x86_64/op_sget.S
@@ -1,26 +1,2 @@
-%default { "is_object":"0", "helper":"MterpSGetU32", "wide":"0" }
-/*
- * General SGET handler wrapper.
- *
- * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short, sget-wide
- */
-    /* op vAA, field@BBBB */
-    .extern $helper
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref CCCC
-    movq    OFF_FP_METHOD(rFP), OUT_ARG1    # referrer
-    movq    rSELF, OUT_ARG2                 # self
-    call    SYMBOL($helper)
-    movq    rSELF, %rcx
-    cmpl    $$0, THREAD_EXCEPTION_OFFSET(%rcx)
-    jnz     MterpException
-    .if $is_object
-    SET_VREG_OBJECT %eax, rINSTq            # fp[A] <- value
-    .else
-    .if $wide
-    SET_WIDE_VREG %rax, rINSTq              # fp[A] <- value
-    .else
-    SET_VREG %eax, rINSTq                   # fp[A] <- value
-    .endif
-    .endif
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%default { "is_object":"0", "helper":"MterpSGetU32" }
+%include "x86_64/field.S" { }
diff --git a/runtime/interpreter/mterp/x86_64/op_sget_wide.S b/runtime/interpreter/mterp/x86_64/op_sget_wide.S
index 65ddb8a..c53c077 100644
--- a/runtime/interpreter/mterp/x86_64/op_sget_wide.S
+++ b/runtime/interpreter/mterp/x86_64/op_sget_wide.S
@@ -1 +1 @@
-%include "x86_64/op_sget.S" {"helper":"MterpSGetU64", "wide":"1"}
+%include "x86_64/op_sget.S" {"helper":"MterpSGetU64"}
diff --git a/runtime/interpreter/mterp/x86_64/op_sput.S b/runtime/interpreter/mterp/x86_64/op_sput.S
index 9a33d52..7dd2498 100644
--- a/runtime/interpreter/mterp/x86_64/op_sput.S
+++ b/runtime/interpreter/mterp/x86_64/op_sput.S
@@ -1,17 +1,2 @@
-%default { "helper":"MterpSPutU32"}
-/*
- * General SPUT handler wrapper.
- *
- * for: sput, sput-boolean, sput-byte, sput-char, sput-short
- */
-    /* op vAA, field@BBBB */
-    .extern $helper
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref BBBB
-    GET_VREG OUT_32_ARG1, rINSTq            # fp[AA]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3                 # self
-    call    SYMBOL($helper)
-    testb   %al, %al
-    jnz     MterpException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%default { "is_object":"0", "helper":"MterpSPutU32"}
+%include "x86_64/field.S" { }
diff --git a/runtime/interpreter/mterp/x86_64/op_sput_object.S b/runtime/interpreter/mterp/x86_64/op_sput_object.S
index 8a47074..c2bd07b 100644
--- a/runtime/interpreter/mterp/x86_64/op_sput_object.S
+++ b/runtime/interpreter/mterp/x86_64/op_sput_object.S
@@ -1,10 +1 @@
-    EXPORT_PC
-    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG0
-    movq    rPC, OUT_ARG1
-    REFRESH_INST ${opnum}
-    movq    rINSTq, OUT_ARG2
-    movq    rSELF, OUT_ARG3
-    call    SYMBOL(MterpSPutObj)
-    testb   %al, %al
-    jz      MterpException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86_64/op_sput.S" {"is_object":"1", "helper":"MterpSPutObj"}
diff --git a/runtime/interpreter/mterp/x86_64/op_sput_wide.S b/runtime/interpreter/mterp/x86_64/op_sput_wide.S
index 464d169..7e77072 100644
--- a/runtime/interpreter/mterp/x86_64/op_sput_wide.S
+++ b/runtime/interpreter/mterp/x86_64/op_sput_wide.S
@@ -1,15 +1 @@
-/*
- * SPUT_WIDE handler wrapper.
- *
- */
-    /* sput-wide vAA, field@BBBB */
-    .extern MterpSPutU64
-    EXPORT_PC
-    movzwq  2(rPC), OUT_ARG0                # field ref BBBB
-    leaq    VREG_ADDRESS(rINSTq), OUT_ARG1  # &fp[AA]
-    movq    OFF_FP_METHOD(rFP), OUT_ARG2    # referrer
-    movq    rSELF, OUT_ARG3                 # self
-    call    SYMBOL(MterpSPutU64)
-    testb   %al, %al
-    jnz     MterpException
-    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
+%include "x86_64/op_sput.S" {"helper":"MterpSPutU64"}
diff --git a/runtime/jdwp/jdwp_adb.cc b/runtime/jdwp/jdwp_adb.cc
index 481aff9..e6043c6 100644
--- a/runtime/jdwp/jdwp_adb.cc
+++ b/runtime/jdwp/jdwp_adb.cc
@@ -87,13 +87,13 @@
     }
   }
 
-  virtual bool Accept() REQUIRES(!state_lock_);
+  bool Accept() override REQUIRES(!state_lock_);
 
-  virtual bool Establish(const JdwpOptions*) {
+  bool Establish(const JdwpOptions*) override {
     return false;
   }
 
-  virtual void Shutdown() REQUIRES(!state_lock_) {
+  void Shutdown() override REQUIRES(!state_lock_) {
     int control_sock;
     int local_clientSock;
     {
@@ -116,7 +116,7 @@
     WakePipe();
   }
 
-  virtual bool ProcessIncoming() REQUIRES(!state_lock_);
+  bool ProcessIncoming() override REQUIRES(!state_lock_);
 
  private:
   int ReceiveClientFd() REQUIRES(!state_lock_);
diff --git a/runtime/jdwp/jdwp_socket.cc b/runtime/jdwp/jdwp_socket.cc
index 673a942..29fa160 100644
--- a/runtime/jdwp/jdwp_socket.cc
+++ b/runtime/jdwp/jdwp_socket.cc
@@ -54,10 +54,10 @@
         remote_port_(0U) {
   }
 
-  virtual bool Accept();
-  virtual bool Establish(const JdwpOptions*);
-  virtual void Shutdown();
-  virtual bool ProcessIncoming();
+  bool Accept() override;
+  bool Establish(const JdwpOptions*) override;
+  void Shutdown() override;
+  bool ProcessIncoming() override;
 
  private:
   in_addr remote_addr_;
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 2b2898c..bcbdc3b 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -28,6 +28,7 @@
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/time_utils.h"
+#include "base/utils.h"
 #include "cha.h"
 #include "debugger_interface.h"
 #include "dex/dex_file_loader.h"
@@ -53,8 +54,9 @@
 namespace art {
 namespace jit {
 
-static constexpr int kProtData = PROT_READ | PROT_WRITE;
 static constexpr int kProtCode = PROT_READ | PROT_EXEC;
+static constexpr int kProtData = PROT_READ | PROT_WRITE;
+static constexpr int kProtProfile = PROT_READ;
 
 static constexpr size_t kCodeSizeLogThreshold = 50 * KB;
 static constexpr size_t kStackMapSizeLogThreshold = 50 * KB;
@@ -192,7 +194,7 @@
   //         to profile system server.
   // NOTE 2: We could just not create the code section at all but we will need to
   //         special case too many cases.
-  int memmap_flags_prot_code = used_only_for_profile_data ? (kProtCode & ~PROT_EXEC) : kProtCode;
+  int memmap_flags_prot_code = used_only_for_profile_data ? kProtProfile : kProtCode;
 
   std::string error_str;
   // Map name specific for android_os_Debug.cpp accounting.
@@ -528,7 +530,7 @@
   // This does not need a read barrier because this is called by GC.
   mirror::Class* cls = root_ptr->Read<kWithoutReadBarrier>();
   if (cls != nullptr && cls != weak_sentinel) {
-    DCHECK((cls->IsClass<kDefaultVerifyFlags, kWithoutReadBarrier>()));
+    DCHECK((cls->IsClass<kDefaultVerifyFlags>()));
     // Look at the classloader of the class to know if it has been unloaded.
     // This does not need a read barrier because this is called by GC.
     mirror::Object* class_loader =
@@ -799,8 +801,18 @@
     //
     // For reference, this behavior is caused by this commit:
     // https://android.googlesource.com/kernel/msm/+/3fbe6bc28a6b9939d0650f2f17eb5216c719950c
-    FlushInstructionCache(reinterpret_cast<char*>(code_ptr),
-                          reinterpret_cast<char*>(code_ptr + code_size));
+    FlushInstructionCache(code_ptr, code_ptr + code_size);
+
+    // Ensure CPU instruction pipelines are flushed for all cores. This is necessary for
+    // correctness as code may still be in instruction pipelines despite the i-cache flush. It is
+    // not safe to assume that changing permissions with mprotect (RX->RWX->RX) will cause a TLB
+    // shootdown (incidentally invalidating the CPU pipelines by sending an IPI to all cores to
+    // notify them of the TLB invalidation). Some architectures, notably ARM and ARM64, have
+    // hardware support that broadcasts TLB invalidations and so their kernels have no software
+    // based TLB shootdown. FlushInstructionPipeline() is a wrapper around the Linux
+    // membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED) syscall which does the appropriate flushing.
+    FlushInstructionPipeline();
+
     DCHECK(!Runtime::Current()->IsAotCompiler());
     if (has_should_deoptimize_flag) {
       method_header->SetHasShouldDeoptimizeFlag();
@@ -858,8 +870,7 @@
       FillRootTable(roots_data, roots);
       {
         // Flush data cache, as compiled code references literals in it.
-        FlushDataCache(reinterpret_cast<char*>(roots_data),
-                       reinterpret_cast<char*>(roots_data + data_size));
+        FlushDataCache(roots_data, roots_data + data_size);
       }
       method_code_map_.Put(code_ptr, method);
       if (osr) {
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index d9ef922..9043f26 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -274,7 +274,7 @@
       : profile_boot_class_path_(profile_boot_class_path),
         out_(out) {}
 
-  virtual bool operator()(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool operator()(ObjPtr<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
     if (klass->IsProxyClass() ||
         klass->IsArrayClass() ||
         klass->IsPrimitive() ||
diff --git a/runtime/jni/java_vm_ext_test.cc b/runtime/jni/java_vm_ext_test.cc
index 4049c6e..dfe50cf 100644
--- a/runtime/jni/java_vm_ext_test.cc
+++ b/runtime/jni/java_vm_ext_test.cc
@@ -27,7 +27,7 @@
 
 class JavaVmExtTest : public CommonRuntimeTest {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     CommonRuntimeTest::SetUp();
 
     vm_ = Runtime::Current()->GetJavaVM();
diff --git a/runtime/jni/jni_internal_test.cc b/runtime/jni/jni_internal_test.cc
index 3040b90..4ad4c14 100644
--- a/runtime/jni/jni_internal_test.cc
+++ b/runtime/jni/jni_internal_test.cc
@@ -34,7 +34,7 @@
 // TODO: Convert to CommonRuntimeTest. Currently MakeExecutable is used.
 class JniInternalTest : public CommonCompilerTest {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     CommonCompilerTest::SetUp();
 
     vm_ = Runtime::Current()->GetJavaVM();
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 51dc1a4..d3f8921 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -378,7 +378,7 @@
 inline bool Class::IsVariableSize() {
   // Classes, arrays, and strings vary in size, and so the object_size_ field cannot
   // be used to Get their instance size
-  return IsClassClass<kVerifyFlags, kReadBarrierOption>() ||
+  return IsClassClass<kVerifyFlags>() ||
          IsArrayClass<kVerifyFlags, kReadBarrierOption>() ||
          IsStringClass();
 }
@@ -853,10 +853,12 @@
   return size;
 }
 
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<VerifyObjectFlags kVerifyFlags>
 inline bool Class::IsClassClass() {
-  ObjPtr<Class> java_lang_Class = GetClass<kVerifyFlags, kReadBarrierOption>()->
-      template GetClass<kVerifyFlags, kReadBarrierOption>();
+  // OK to look at from-space copies since java.lang.Class.class is not movable.
+  // See b/114413743
+  ObjPtr<Class> java_lang_Class = GetClass<kVerifyFlags, kWithoutReadBarrier>()->
+      template GetClass<kVerifyFlags, kWithoutReadBarrier>();
   return this == java_lang_Class;
 }
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 811ee51..4015bd2 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -430,8 +430,7 @@
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArrayClass() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
-           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsClassClass() REQUIRES_SHARED(Locks::mutator_lock_);
 
   bool IsThrowableClass() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index bd89907..1b03956 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -137,17 +137,18 @@
   return klass->IsAssignableFrom(GetClass<kVerifyFlags>());
 }
 
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<VerifyObjectFlags kVerifyFlags>
 inline bool Object::IsClass() {
-  constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
-  Class* java_lang_Class = GetClass<kVerifyFlags, kReadBarrierOption>()->
-      template GetClass<kVerifyFlags, kReadBarrierOption>();
-  return GetClass<kNewFlags, kReadBarrierOption>() == java_lang_Class;
+  // OK to look at from-space copies since java.lang.Class.class is not movable.
+  // See b/114413743
+  ObjPtr<Class> klass = GetClass<kVerifyFlags, kWithoutReadBarrier>();
+  ObjPtr<Class> java_lang_Class = klass->template GetClass<kVerifyFlags, kWithoutReadBarrier>();
+  return klass == java_lang_Class;
 }
 
-template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+template<VerifyObjectFlags kVerifyFlags>
 inline Class* Object::AsClass() {
-  DCHECK((IsClass<kVerifyFlags, kReadBarrierOption>()));
+  DCHECK((IsClass<kVerifyFlags>()));
   return down_cast<Class*>(this);
 }
 
@@ -350,8 +351,8 @@
   constexpr auto kNewFlags = RemoveThisFlags(kVerifyFlags);
   if (IsArrayInstance<kVerifyFlags, kRBO>()) {
     result = AsArray<kNewFlags, kRBO>()->template SizeOf<kNewFlags, kRBO>();
-  } else if (IsClass<kNewFlags, kRBO>()) {
-    result = AsClass<kNewFlags, kRBO>()->template SizeOf<kNewFlags, kRBO>();
+  } else if (IsClass<kNewFlags>()) {
+    result = AsClass<kNewFlags>()->template SizeOf<kNewFlags, kRBO>();
   } else if (GetClass<kNewFlags, kRBO>()->IsStringClass()) {
     result = AsString<kNewFlags, kRBO>()->template SizeOf<kNewFlags>();
   } else {
@@ -364,7 +365,7 @@
 template<VerifyObjectFlags kVerifyFlags, bool kIsVolatile>
 inline int8_t Object::GetFieldByte(MemberOffset field_offset) {
   Verify<kVerifyFlags>();
-  return GetField<int8_t, kIsVolatile>(field_offset);
+  return GetFieldPrimitive<int8_t, kIsVolatile>(field_offset);
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -391,7 +392,7 @@
         kIsVolatile);
   }
   Verify<kVerifyFlags>();
-  SetField<uint8_t, kIsVolatile>(field_offset, new_value);
+  SetFieldPrimitive<uint8_t, kIsVolatile>(field_offset, new_value);
 }
 
 template<bool kTransactionActive,
@@ -407,7 +408,7 @@
                                              kIsVolatile);
   }
   Verify<kVerifyFlags>();
-  SetField<int8_t, kIsVolatile>(field_offset, new_value);
+  SetFieldPrimitive<int8_t, kIsVolatile>(field_offset, new_value);
 }
 
 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
@@ -425,13 +426,13 @@
 template<VerifyObjectFlags kVerifyFlags, bool kIsVolatile>
 inline uint16_t Object::GetFieldChar(MemberOffset field_offset) {
   Verify<kVerifyFlags>();
-  return GetField<uint16_t, kIsVolatile>(field_offset);
+  return GetFieldPrimitive<uint16_t, kIsVolatile>(field_offset);
 }
 
 template<VerifyObjectFlags kVerifyFlags, bool kIsVolatile>
 inline int16_t Object::GetFieldShort(MemberOffset field_offset) {
   Verify<kVerifyFlags>();
-  return GetField<int16_t, kIsVolatile>(field_offset);
+  return GetFieldPrimitive<int16_t, kIsVolatile>(field_offset);
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -457,7 +458,7 @@
                                              kIsVolatile);
   }
   Verify<kVerifyFlags>();
-  SetField<uint16_t, kIsVolatile>(field_offset, new_value);
+  SetFieldPrimitive<uint16_t, kIsVolatile>(field_offset, new_value);
 }
 
 template<bool kTransactionActive,
@@ -473,7 +474,7 @@
                                              kIsVolatile);
   }
   Verify<kVerifyFlags>();
-  SetField<int16_t, kIsVolatile>(field_offset, new_value);
+  SetFieldPrimitive<int16_t, kIsVolatile>(field_offset, new_value);
 }
 
 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
@@ -501,7 +502,7 @@
                                            kIsVolatile);
   }
   Verify<kVerifyFlags>();
-  SetField<int32_t, kIsVolatile>(field_offset, new_value);
+  SetFieldPrimitive<int32_t, kIsVolatile>(field_offset, new_value);
 }
 
 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
@@ -531,7 +532,7 @@
                                            kIsVolatile);
   }
   Verify<kVerifyFlags>();
-  SetField<int64_t, kIsVolatile>(field_offset, new_value);
+  SetFieldPrimitive<int64_t, kIsVolatile>(field_offset, new_value);
 }
 
 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
@@ -867,7 +868,7 @@
     // inheritance hierarchy and find reference offsets the hard way. In the static case, just
     // consider this class.
     for (ObjPtr<Class> klass = kIsStatic
-            ? AsClass<kVerifyFlags, kReadBarrierOption>()
+            ? AsClass<kVerifyFlags>()
             : GetClass<kVerifyFlags, kReadBarrierOption>();
         klass != nullptr;
         klass = kIsStatic ? nullptr : klass->GetSuperClass<kVerifyFlags, kReadBarrierOption>()) {
diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h
index cc375bd..8689e4d 100644
--- a/runtime/mirror/object-readbarrier-inl.h
+++ b/runtime/mirror/object-readbarrier-inl.h
@@ -131,7 +131,7 @@
     UNREACHABLE();
   }
   DCHECK(kUseBakerReadBarrier);
-  LockWord lw(GetField<uint32_t, /*kIsVolatile*/false>(MonitorOffset()));
+  LockWord lw(GetFieldPrimitive<uint32_t, /*kIsVolatile*/false>(MonitorOffset()));
   uint32_t rb_state = lw.ReadBarrierState();
   DCHECK(ReadBarrier::IsValidReadBarrierState(rb_state)) << rb_state;
   return rb_state;
diff --git a/runtime/mirror/object-refvisitor-inl.h b/runtime/mirror/object-refvisitor-inl.h
index 39e32bf..bd23971 100644
--- a/runtime/mirror/object-refvisitor-inl.h
+++ b/runtime/mirror/object-refvisitor-inl.h
@@ -39,7 +39,7 @@
   if (LIKELY(class_flags == kClassFlagNormal)) {
     DCHECK((!klass->IsVariableSize<kVerifyFlags, kReadBarrierOption>()));
     VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor);
-    DCHECK((!klass->IsClassClass<kVerifyFlags, kReadBarrierOption>()));
+    DCHECK((!klass->IsClassClass<kVerifyFlags>()));
     DCHECK(!klass->IsStringClass());
     DCHECK(!klass->IsClassLoaderClass());
     DCHECK((!klass->IsArrayClass<kVerifyFlags, kReadBarrierOption>()));
@@ -47,8 +47,8 @@
     if ((class_flags & kClassFlagNoReferenceFields) == 0) {
       DCHECK(!klass->IsStringClass());
       if (class_flags == kClassFlagClass) {
-        DCHECK((klass->IsClassClass<kVerifyFlags, kReadBarrierOption>()));
-        ObjPtr<Class> as_klass = AsClass<kVerifyNone, kReadBarrierOption>();
+        DCHECK((klass->IsClassClass<kVerifyFlags>()));
+        ObjPtr<Class> as_klass = AsClass<kVerifyNone>();
         as_klass->VisitReferences<kVisitNativeRoots, kVerifyFlags, kReadBarrierOption>(klass,
                                                                                        visitor);
       } else if (class_flags == kClassFlagObjectArray) {
@@ -69,7 +69,7 @@
                                       kReadBarrierOption>(klass, visitor);
       }
     } else if (kIsDebugBuild) {
-      CHECK((!klass->IsClassClass<kVerifyFlags, kReadBarrierOption>()));
+      CHECK((!klass->IsClassClass<kVerifyFlags>()));
       CHECK((!klass->IsObjectArrayClass<kVerifyFlags, kReadBarrierOption>()));
       // String still has instance fields for reflection purposes but these don't exist in
       // actual string instances.
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 47aded3..48ce5c1 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -169,11 +169,9 @@
   void NotifyAll(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
   void Wait(Thread* self, int64_t timeout, int32_t nanos) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
-           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsClass() REQUIRES_SHARED(Locks::mutator_lock_);
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
-           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   Class* AsClass() REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
@@ -349,11 +347,35 @@
   HeapReference<Object>* GetFieldObjectReferenceAddr(MemberOffset field_offset)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  template<typename kType, bool kIsVolatile>
+  ALWAYS_INLINE void SetFieldPrimitive(MemberOffset field_offset, kType new_value)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+    kType* addr = reinterpret_cast<kType*>(raw_addr);
+    if (kIsVolatile) {
+      reinterpret_cast<Atomic<kType>*>(addr)->store(new_value, std::memory_order_seq_cst);
+    } else {
+      reinterpret_cast<Atomic<kType>*>(addr)->StoreJavaData(new_value);
+    }
+  }
+
+  template<typename kType, bool kIsVolatile>
+  ALWAYS_INLINE kType GetFieldPrimitive(MemberOffset field_offset)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    const uint8_t* raw_addr = reinterpret_cast<const uint8_t*>(this) + field_offset.Int32Value();
+    const kType* addr = reinterpret_cast<const kType*>(raw_addr);
+    if (kIsVolatile) {
+      return reinterpret_cast<const Atomic<kType>*>(addr)->load(std::memory_order_seq_cst);
+    } else {
+      return reinterpret_cast<const Atomic<kType>*>(addr)->LoadJavaData();
+    }
+  }
+
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
   ALWAYS_INLINE uint8_t GetFieldBoolean(MemberOffset field_offset)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     Verify<kVerifyFlags>();
-    return GetField<uint8_t, kIsVolatile>(field_offset);
+    return GetFieldPrimitive<uint8_t, kIsVolatile>(field_offset);
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
@@ -440,7 +462,7 @@
   ALWAYS_INLINE int32_t GetField32(MemberOffset field_offset)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     Verify<kVerifyFlags>();
-    return GetField<int32_t, kIsVolatile>(field_offset);
+    return GetFieldPrimitive<int32_t, kIsVolatile>(field_offset);
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -482,7 +504,7 @@
   ALWAYS_INLINE int64_t GetField64(MemberOffset field_offset)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     Verify<kVerifyFlags>();
-    return GetField<int64_t, kIsVolatile>(field_offset);
+    return GetFieldPrimitive<int64_t, kIsVolatile>(field_offset);
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -683,30 +705,6 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  template<typename kSize, bool kIsVolatile>
-  ALWAYS_INLINE void SetField(MemberOffset field_offset, kSize new_value)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
-    kSize* addr = reinterpret_cast<kSize*>(raw_addr);
-    if (kIsVolatile) {
-      reinterpret_cast<Atomic<kSize>*>(addr)->store(new_value, std::memory_order_seq_cst);
-    } else {
-      reinterpret_cast<Atomic<kSize>*>(addr)->StoreJavaData(new_value);
-    }
-  }
-
-  template<typename kSize, bool kIsVolatile>
-  ALWAYS_INLINE kSize GetField(MemberOffset field_offset)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    const uint8_t* raw_addr = reinterpret_cast<const uint8_t*>(this) + field_offset.Int32Value();
-    const kSize* addr = reinterpret_cast<const kSize*>(raw_addr);
-    if (kIsVolatile) {
-      return reinterpret_cast<const Atomic<kSize>*>(addr)->load(std::memory_order_seq_cst);
-    } else {
-      return reinterpret_cast<const Atomic<kSize>*>(addr)->LoadJavaData();
-    }
-  }
-
   // Get a field with acquire semantics.
   template<typename kSize>
   ALWAYS_INLINE kSize GetFieldAcquire(MemberOffset field_offset)
diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc
index c88748f..0b168f8 100644
--- a/runtime/monitor_test.cc
+++ b/runtime/monitor_test.cc
@@ -62,7 +62,7 @@
       monitor_test_(monitor_test), initial_sleep_(initial_sleep), millis_(millis),
       expected_(expected) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     {
       ScopedObjectAccess soa(self);
 
@@ -118,7 +118,7 @@
     }
   }
 
-  void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
@@ -136,7 +136,7 @@
       monitor_test_(monitor_test), initial_sleep_(initial_sleep), millis_(millis),
       expected_(expected) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     monitor_test_->barrier_->Wait(self);  // Wait for the other thread to set up the monitor.
 
     {
@@ -158,7 +158,7 @@
     monitor_test_->complete_barrier_->Wait(self);  // Wait for test completion.
   }
 
-  void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
@@ -174,7 +174,7 @@
   InterruptTask(MonitorTest* monitor_test, uint64_t initial_sleep, uint64_t millis) :
       monitor_test_(monitor_test), initial_sleep_(initial_sleep), millis_(millis) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     monitor_test_->barrier_->Wait(self);  // Wait for the other thread to set up the monitor.
 
     {
@@ -202,7 +202,7 @@
     monitor_test_->complete_barrier_->Wait(self);  // Wait for test completion.
   }
 
-  void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
@@ -216,7 +216,7 @@
  public:
   explicit WatchdogTask(MonitorTest* monitor_test) : monitor_test_(monitor_test) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     ScopedObjectAccess soa(self);
 
     monitor_test_->watchdog_object_.Get()->MonitorEnter(self);        // Lock the object.
@@ -231,7 +231,7 @@
     }
   }
 
-  void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
@@ -326,14 +326,14 @@
  public:
   explicit TryLockTask(Handle<mirror::Object> obj) : obj_(obj) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     ScopedObjectAccess soa(self);
     // Lock is held by other thread, try lock should fail.
     ObjectTryLock<mirror::Object> lock(self, obj_);
     EXPECT_FALSE(lock.Acquired());
   }
 
-  void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 3919227..e3932df 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -113,7 +113,7 @@
       : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
         class_loader(nullptr) {}
 
-    bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+    bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
       DCHECK(class_loader == nullptr);
       ObjPtr<mirror::Class> c = GetMethod()->GetDeclaringClass();
       // c is null for runtime methods.
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 5a5fb16..f5039d1 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -62,7 +62,7 @@
           caller(nullptr) {
     }
 
-    bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+    bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
       ArtMethod *m = GetMethod();
       if (m == nullptr) {
         // Attached native thread. Assume this is *not* boot class path.
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index efdefb1..3a974df 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -1148,7 +1148,7 @@
         loaded_oat_file_(nullptr)
   {}
 
-  void Run(Thread* self ATTRIBUTE_UNUSED) {
+  void Run(Thread* self ATTRIBUTE_UNUSED) override {
     // Load the dex files, and save a pointer to the loaded oat file, so that
     // we can verify only one oat file was loaded for the dex location.
     std::vector<std::unique_ptr<const DexFile>> dex_files;
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 7b92151..e882e73 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -165,7 +165,7 @@
     CHECK_NE(frame_depth_, kInvalidFrameDepth);
   }
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     size_t current_frame_depth = GetFrameDepth();
     if (current_frame_depth < frame_depth_) {
       CHECK(GetMethod() != nullptr);
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 424ee06..00e298e 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -33,7 +33,7 @@
 // TODO: Convert to CommonRuntimeTest. Currently MakeExecutable is used.
 class ReflectionTest : public CommonCompilerTest {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     CommonCompilerTest::SetUp();
 
     vm_ = Runtime::Current()->GetJavaVM();
@@ -73,7 +73,7 @@
     }
   }
 
-  virtual void TearDown() {
+  void TearDown() override {
     CleanUpJniEnv();
     CommonCompilerTest::TearDown();
   }
diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc
index aaedb23..89f3124 100644
--- a/runtime/runtime_callbacks_test.cc
+++ b/runtime/runtime_callbacks_test.cc
@@ -458,20 +458,20 @@
       ref_ = { &k->GetDexFile(), k->GetDexClassDefIndex() };
     }
 
-    void MonitorContendedLocking(Monitor* mon ATTRIBUTE_UNUSED)
+    void MonitorContendedLocking(Monitor* mon ATTRIBUTE_UNUSED) override
         REQUIRES_SHARED(Locks::mutator_lock_) { }
 
-    void MonitorContendedLocked(Monitor* mon ATTRIBUTE_UNUSED)
+    void MonitorContendedLocked(Monitor* mon ATTRIBUTE_UNUSED) override
         REQUIRES_SHARED(Locks::mutator_lock_) { }
 
-    void ObjectWaitStart(Handle<mirror::Object> obj, int64_t millis ATTRIBUTE_UNUSED)
+    void ObjectWaitStart(Handle<mirror::Object> obj, int64_t millis ATTRIBUTE_UNUSED) override
         REQUIRES_SHARED(Locks::mutator_lock_) {
       if (IsInterestingObject(obj.Get())) {
         saw_wait_start_ = true;
       }
     }
 
-    void MonitorWaitFinished(Monitor* m, bool timed_out ATTRIBUTE_UNUSED)
+    void MonitorWaitFinished(Monitor* m, bool timed_out ATTRIBUTE_UNUSED) override
         REQUIRES_SHARED(Locks::mutator_lock_) {
       if (IsInterestingObject(m->GetObject())) {
         saw_wait_finished_ = true;
diff --git a/runtime/subtype_check_info_test.cc b/runtime/subtype_check_info_test.cc
index e40bca5..5323093 100644
--- a/runtime/subtype_check_info_test.cc
+++ b/runtime/subtype_check_info_test.cc
@@ -86,11 +86,11 @@
 
 struct SubtypeCheckInfoTest : public ::testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     android::base::InitLogging(/*argv*/nullptr);
   }
 
-  virtual void TearDown() {
+  void TearDown() override {
   }
 
   static SubtypeCheckInfo MakeSubtypeCheckInfo(BitString path_to_root = {},
diff --git a/runtime/subtype_check_test.cc b/runtime/subtype_check_test.cc
index 666bf81..9aa3032 100644
--- a/runtime/subtype_check_test.cc
+++ b/runtime/subtype_check_test.cc
@@ -301,13 +301,13 @@
 
 struct SubtypeCheckTest : public ::testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     android::base::InitLogging(/*argv*/nullptr);
 
     CreateRootedTree(BitString::kCapacity + 2u, BitString::kCapacity + 2u);
   }
 
-  virtual void TearDown() {
+  void TearDown() override {
   }
 
   void CreateRootedTree(size_t width, size_t height) {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 19fe4ea..8a8f537 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2515,7 +2515,7 @@
         saved_frames_(saved_frames),
         max_saved_frames_(max_saved_frames) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     // We want to skip frames up to and including the exception's constructor.
     // Note we also skip the frame if it doesn't have a method (namely the callee
     // save frame)
@@ -2603,7 +2603,7 @@
     self_->EndAssertNoThreadSuspension(nullptr);
   }
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     if (trace_ == nullptr) {
       return true;  // We're probably trying to fillInStackTrace for an OutOfMemoryError.
     }
@@ -3520,7 +3520,7 @@
       : StackVisitor(thread, context, StackVisitor::StackWalkKind::kSkipInlinedFrames),
         visitor_(visitor) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     if (false) {
       LOG(INFO) << "Visiting stack roots in " << ArtMethod::PrettyMethod(GetMethod())
                 << StringPrintf("@ PC:%04x", GetDexPc());
diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc
index d784200..2600f55 100644
--- a/runtime/thread_pool_test.cc
+++ b/runtime/thread_pool_test.cc
@@ -29,7 +29,7 @@
  public:
   explicit CountTask(AtomicInteger* count) : count_(count), verbose_(false) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     if (verbose_) {
       LOG(INFO) << "Running: " << *self;
     }
@@ -39,7 +39,7 @@
     ++*count_;
   }
 
-  void Finalize() {
+  void Finalize() override {
     if (verbose_) {
       LOG(INFO) << "Finalizing: " << *Thread::Current();
     }
@@ -129,7 +129,7 @@
         count_(count),
         depth_(depth) {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     if (depth_ > 1) {
       thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
       thread_pool_->AddTask(self, new TreeTask(thread_pool_, count_, depth_ - 1));
@@ -138,7 +138,7 @@
     ++*count_;
   }
 
-  void Finalize() {
+  void Finalize() override {
     delete this;
   }
 
@@ -164,12 +164,12 @@
  public:
   PeerTask() {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     ScopedObjectAccess soa(self);
     CHECK(self->GetPeer() != nullptr);
   }
 
-  void Finalize() {
+  void Finalize() override {
     delete this;
   }
 };
@@ -178,12 +178,12 @@
  public:
   NoPeerTask() {}
 
-  void Run(Thread* self) {
+  void Run(Thread* self) override {
     ScopedObjectAccess soa(self);
     CHECK(self->GetPeer() == nullptr);
   }
 
-  void Finalize() {
+  void Finalize() override {
     delete this;
   }
 };
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 949fabe..7e48bae 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -64,7 +64,7 @@
       : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
         method_trace_(Trace::AllocStackTrace()) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     // Ignore runtime frames (in particular callee save).
     if (!m->IsRuntimeMethod()) {
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index 1ce20e2..4c344a3 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -37,7 +37,7 @@
   explicit ReferenceMap2Visitor(Thread* thread) REQUIRES_SHARED(Locks::mutator_lock_)
       : CheckReferenceMapVisitor(thread) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     if (CheckReferenceMapVisitor::VisitFrame()) {
       return true;
     }
diff --git a/test/004-StackWalk/build b/test/004-StackWalk/build
index eeecbfc..3de541c 100644
--- a/test/004-StackWalk/build
+++ b/test/004-StackWalk/build
@@ -18,10 +18,8 @@
 set -e
 
 # This test depends on the exact format of the DEX file. Since dx is deprecated,
-# the classes.dex file is packaged as a test input. It was created with:
-#
-# $ javac -g -Xlint:-options -source 1.7 -target 1.7 -d classes src/Main.java
-# $ dx --debug --dex --output=classes.dex classes
+# the classes.dex file is packaged as a test input. See src/Main.java file
+# to check how it was created.
 
 # Wrapper function for javac which for this test does nothing as the
 # test uses a pre-built DEX file.
diff --git a/test/004-StackWalk/classes.dex b/test/004-StackWalk/classes.dex
index ad45296..61a7277 100644
--- a/test/004-StackWalk/classes.dex
+++ b/test/004-StackWalk/classes.dex
Binary files differ
diff --git a/test/004-StackWalk/src/Main.java b/test/004-StackWalk/src/Main.java
index 072b1d0..2a098f7 100644
--- a/test/004-StackWalk/src/Main.java
+++ b/test/004-StackWalk/src/Main.java
@@ -1,19 +1,36 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This test depends on the exact format of the DEX file. Since dx is deprecated,
+// the classes.dex file is packaged as a test input. It was created with:
+//
+// $ javac -g -Xlint:-options -source 1.7 -target 1.7 -d classes src/Main.java
+// $ dx --debug --dex --output=classes.dex classes
+
 public class Main {
   public Main() {
   }
 
-  boolean doThrow = false;
-
   int $noinline$f() throws Exception {
-    g(1);
-    g(2);
-
-    // This currently defeats inlining of `f`.
-    if (doThrow) { throw new Error(); }
+    $noinline$g(1);
+    $noinline$g(2);
     return 0;
   }
 
-  void g(int num_calls) {
+  void $noinline$g(int num_calls) {
     if (num_calls == 1) {
       System.out.println("1st call");
     } else if (num_calls == 2) {
@@ -81,11 +98,14 @@
     s4 = s18 = s19;
     s += s4;
     s += s18;
-    stackmap(0);
-    return s;
+    // Add a branch to workaround ART's large methods without branches heuristic.
+    if (testStackWalk(0) != 0) {
+      return s;
+    }
+    return s18;
   }
 
-  native int stackmap(int x);
+  native int testStackWalk(int x);
 
   public static void main(String[] args) throws Exception {
     System.loadLibrary(args[0]);
diff --git a/test/004-StackWalk/stack_walk_jni.cc b/test/004-StackWalk/stack_walk_jni.cc
index 89e2e66..81c27ec 100644
--- a/test/004-StackWalk/stack_walk_jni.cc
+++ b/test/004-StackWalk/stack_walk_jni.cc
@@ -20,7 +20,7 @@
 
 namespace art {
 
-#define CHECK_REGS(...) do { \
+#define CHECK_REGS_ARE_REFERENCES(...) do { \
   int t[] = {__VA_ARGS__}; \
   int t_size = sizeof(t) / sizeof(*t); \
   CheckReferences(t, t_size, GetNativePcOffset()); \
@@ -33,7 +33,7 @@
   explicit TestReferenceMapVisitor(Thread* thread) REQUIRES_SHARED(Locks::mutator_lock_)
       : CheckReferenceMapVisitor(thread) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     if (CheckReferenceMapVisitor::VisitFrame()) {
       return true;
     }
@@ -43,40 +43,50 @@
     // Given the method name and the number of times the method has been called,
     // we know the Dex registers with live reference values. Assert that what we
     // find is what is expected.
-    if (m_name == "f") {
+    if (m_name == "$noinline$f") {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(1U, GetDexPc());
-        CHECK_REGS(4);
+        CHECK_REGS_ARE_REFERENCES(1);
       } else {
         CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
         CHECK_EQ(5U, GetDexPc());
-        CHECK_REGS(4);
+        CHECK_REGS_ARE_REFERENCES(1);
       }
-    } else if (m_name == "g") {
+      found_f_ = true;
+    } else if (m_name == "$noinline$g") {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(0xcU, GetDexPc());
-        CHECK_REGS(0, 2);  // Note that v1 is not in the minimal root set
+        CHECK_REGS_ARE_REFERENCES(0, 2);  // Note that v1 is not in the minimal root set
       } else {
         CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
         CHECK_EQ(0xcU, GetDexPc());
-        CHECK_REGS(0, 2);
+        CHECK_REGS_ARE_REFERENCES(0, 2);
       }
+      found_g_ = true;
     } else if (m_name == "shlemiel") {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(0x380U, GetDexPc());
-        CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
+        CHECK_REGS_ARE_REFERENCES(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
       } else {
         CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
         CHECK_EQ(0x380U, GetDexPc());
-        CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
+        CHECK_REGS_ARE_REFERENCES(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
       }
+      found_shlemiel_ = true;
     }
 
     return true;
   }
+
+  ~TestReferenceMapVisitor() {
+  }
+
+  bool found_f_ = false;
+  bool found_g_ = false;
+  bool found_shlemiel_ = false;
 };
 
-extern "C" JNIEXPORT jint JNICALL Java_Main_stackmap(JNIEnv*, jobject, jint count) {
+extern "C" JNIEXPORT jint JNICALL Java_Main_testStackWalk(JNIEnv*, jobject, jint count) {
   ScopedObjectAccess soa(Thread::Current());
   CHECK_EQ(count, 0);
   gJava_StackWalk_refmap_calls++;
@@ -84,17 +94,9 @@
   // Visitor
   TestReferenceMapVisitor mapper(soa.Self());
   mapper.WalkStack();
-
-  return count + 1;
-}
-
-extern "C" JNIEXPORT jint JNICALL Java_Main_refmap2(JNIEnv*, jobject, jint count) {
-  ScopedObjectAccess soa(Thread::Current());
-  gJava_StackWalk_refmap_calls++;
-
-  // Visitor
-  TestReferenceMapVisitor mapper(soa.Self());
-  mapper.WalkStack();
+  CHECK(mapper.found_f_);
+  CHECK(mapper.found_g_);
+  CHECK(mapper.found_shlemiel_);
 
   return count + 1;
 }
diff --git a/test/454-get-vreg/get_vreg_jni.cc b/test/454-get-vreg/get_vreg_jni.cc
index 5fc5464..eb81f3b 100644
--- a/test/454-get-vreg/get_vreg_jni.cc
+++ b/test/454-get-vreg/get_vreg_jni.cc
@@ -34,7 +34,7 @@
         this_value_(this_value),
         found_method_index_(0) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     std::string m_name(m->GetName());
 
diff --git a/test/457-regs/regs_jni.cc b/test/457-regs/regs_jni.cc
index f867bdf..80abb3b 100644
--- a/test/457-regs/regs_jni.cc
+++ b/test/457-regs/regs_jni.cc
@@ -32,7 +32,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     std::string m_name(m->GetName());
 
diff --git a/test/461-get-reference-vreg/get_reference_vreg_jni.cc b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
index 7eb3fe5..ddc86df 100644
--- a/test/461-get-reference-vreg/get_reference_vreg_jni.cc
+++ b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
@@ -33,7 +33,7 @@
         this_value_(this_value),
         found_method_index_(0) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     std::string m_name(m->GetName());
 
diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc
index 58ffe04..905d8e6 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -32,7 +32,7 @@
   TestVisitor(Thread* thread, Context* context) REQUIRES_SHARED(Locks::mutator_lock_)
       : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     std::string m_name(m->GetName());
 
diff --git a/test/543-env-long-ref/env_long_ref.cc b/test/543-env-long-ref/env_long_ref.cc
index ce5602f..165f5bf 100644
--- a/test/543-env-long-ref/env_long_ref.cc
+++ b/test/543-env-long-ref/env_long_ref.cc
@@ -34,7 +34,7 @@
         found_(false),
         soa_(soa) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     std::string m_name(m->GetName());
 
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
index faec3c3..7b88842 100644
--- a/test/570-checker-osr/osr.cc
+++ b/test/570-checker-osr/osr.cc
@@ -35,7 +35,7 @@
         in_osr_method_(false),
         in_interpreter_(false) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     std::string m_name(m->GetName());
 
@@ -95,7 +95,7 @@
       : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
         method_name_(method_name) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     std::string m_name(m->GetName());
 
@@ -129,7 +129,7 @@
       : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
         method_name_(method_name) {}
 
-  bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     std::string m_name(m->GetName());
 
diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java
index ff6e335..4097e33 100644
--- a/test/623-checker-loop-regressions/src/Main.java
+++ b/test/623-checker-loop-regressions/src/Main.java
@@ -304,6 +304,19 @@
     }
   }
 
+  /// CHECK-START-ARM: void Main.$noinline$stringToShorts(short[], java.lang.String) loop_optimization (after)
+  /// CHECK-NOT: VecLoad
+
+  /// CHECK-START-ARM64: void Main.$noinline$stringToShorts(short[], java.lang.String) loop_optimization (after)
+  /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  private static void $noinline$stringToShorts(short[] dest, String src) {
+    int min = Math.min(dest.length, src.length());
+    for (int i = 0; i < min; ++i) {
+      dest[i] = (short) src.charAt(i);
+    }
+  }
+
   // A strange function that does not inline.
   private static void $noinline$foo(boolean x, int n) {
     if (n < 0)
@@ -684,6 +697,12 @@
       expectEquals(aa[i], cc.charAt(i));
     }
 
+    short[] s2s = new short[12];
+    $noinline$stringToShorts(s2s, "abcdefghijkl");
+    for (int i = 0; i < s2s.length; ++i) {
+      expectEquals((short) "abcdefghijkl".charAt(i), s2s[i]);
+    }
+
     envUsesInCond();
 
     short[] dd = new short[23];
diff --git a/test/669-moveable-string-class-equals/expected.txt b/test/669-moveable-string-class-equals/expected.txt
deleted file mode 100644
index 6a5618e..0000000
--- a/test/669-moveable-string-class-equals/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-JNI_OnLoad called
diff --git a/test/669-moveable-string-class-equals/info.txt b/test/669-moveable-string-class-equals/info.txt
deleted file mode 100644
index 1d3202ef..0000000
--- a/test/669-moveable-string-class-equals/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Regression test for String.equals() intrinsic instanceof check
-when the String.class is moveable.
diff --git a/test/669-moveable-string-class-equals/run b/test/669-moveable-string-class-equals/run
deleted file mode 100755
index 7c74d8c..0000000
--- a/test/669-moveable-string-class-equals/run
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 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.
-
-# Run without image, so that String.class is moveable.
-# Reduce heap size to force more frequent GCs.
-${RUN} --no-image --runtime-option -Xmx16m "$@"
diff --git a/test/669-moveable-string-class-equals/src/Main.java b/test/669-moveable-string-class-equals/src/Main.java
deleted file mode 100644
index d182d51..0000000
--- a/test/669-moveable-string-class-equals/src/Main.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-public class Main {
-  public static void main(String[] args) {
-    System.loadLibrary(args[0]);
-    if (!hasJit()) {
-      // Make the test pass if not using JIT.
-      return;
-    }
-    if (hasImage()) {
-      throw new Error("The `run` script should prevent this test from running with an image!");
-    }
-    if (!isClassMoveable(String.class)) {
-      throw new Error("String.class not moveable despite running without image!");
-    }
-
-    // Make sure the Main.test() is JIT-compiled and then call it.
-    ensureJitCompiled(Main.class, "test");
-    test();
-  }
-
-  public static void test() {
-    int length = 5;
-
-    // Hide the type of these strings in an Object array,
-    // so that we treat them as Object for the String.equals() below.
-    Object[] array = new Object[length];
-    for (int i = 0; i != length; ++i) {
-      array[i] = "V" + i;
-    }
-
-    // Continually check string equality between a newly allocated String and an
-    // already allocated String with the same contents while allocating over 128MiB
-    // memory (with heap size limited to 16MiB), ensuring we run GC and stress the
-    // instanceof check in the String.equals() implementation.
-    for (int count = 0; count != 128 * 1024; ++count) {
-      for (int i = 0; i != length; ++i) {
-        allocateAtLeast1KiB();
-        assertTrue(("V" + i).equals(array[i]));
-      }
-    }
-  }
-
-  public static void allocateAtLeast1KiB() {
-    // Give GC more work by allocating Object arrays.
-    memory[allocationIndex] = new Object[1024 / 4];
-    ++allocationIndex;
-    if (allocationIndex == memory.length) {
-      allocationIndex = 0;
-    }
-  }
-
-  public static void assertTrue(boolean value) {
-    if (!value) {
-      throw new Error("Assertion failed!");
-    }
-  }
-
-  private native static boolean hasJit();
-  private native static boolean hasImage();
-  private native static boolean isClassMoveable(Class<?> cls);
-  private static native void ensureJitCompiled(Class<?> itf, String method_name);
-
-  // We shall retain some allocated memory and release old allocations
-  // so that the GC has something to do.
-  public static Object[] memory = new Object[4096];
-  public static int allocationIndex = 0;
-}
diff --git a/test/980-redefine-object/redef_object.cc b/test/980-redefine-object/redef_object.cc
index b4d82ad..a8393dc 100644
--- a/test/980-redefine-object/redef_object.cc
+++ b/test/980-redefine-object/redef_object.cc
@@ -80,13 +80,13 @@
    public:
     explicit JvmtiAllocator(jvmtiEnv* jvmti) : jvmti_(jvmti) {}
 
-    void* Allocate(size_t size) {
+    void* Allocate(size_t size) override {
       unsigned char* res = nullptr;
       jvmti_->Allocate(size, &res);
       return res;
     }
 
-    void Free(void* ptr) {
+    void Free(void* ptr) override {
       jvmti_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
     }
 
diff --git a/test/Android.bp b/test/Android.bp
index e265651..4b61463 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -417,10 +417,11 @@
 
 art_cc_defaults {
     name: "libtistress-static-defaults",
-    defaults: ["libtistress-srcs"],
-    static_libs: art_static_dependencies + [
-        "slicer",
+    defaults: [
+        "libtistress-srcs",
+        "libart_static_defaults",
     ],
+    static_libs: ["slicer"],
 }
 
 art_cc_test_library {
diff --git a/test/StackWalk2/StackWalk2.java b/test/StackWalk2/StackWalk2.java
deleted file mode 100644
index 5e7b22c..0000000
--- a/test/StackWalk2/StackWalk2.java
+++ /dev/null
@@ -1,58 +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.
- */
-
-public class StackWalk2 {
-  // use v1 for this
-
-  String str = new String();  // use v0 for str in <init>
-
-  int f() {
-    g(1);  // use v0 for 1, v1 for this
-    g(2);  // use v0 for 2, v1 for this
-    strTest();  // use v1 for this
-    return 0;
-  }
-
-  void g(int num_calls) throws RuntimeException {
-    if (num_calls == 1) {  // use v0 for 1, v3 for num_calls
-      System.logI("1st call");  // use v0 for PrintStream, v1 for "1st call"
-      refmap2(24);  // use v0 for 24, v2 for this
-    } else if (num_calls == 2) {  // use v0 for 2, v3 for num_calls
-      System.logI("2nd call");  // use v0 for PrintStream, v1 for "2nd call"
-      refmap2(25);  // use v0 for 24, v2 for this
-    }
-    throw new RuntimeException();  // use v0 for new RuntimeException
-  }
-
-  void strTest() {
-    System.logI(str);  // use v1 for PrintStream, v2, v3 for str
-    str = null;  // use v1 for null, v3 for str
-    str = new String("ya");  // use v2 for "ya", v1 for new String
-    String s = str;  // use v0, v1, v3
-    System.logI(str);  // use v1 for PrintStream, v2, v3 for str
-    System.logI(s);  // use v1 for PrintStream, v0 for s
-    s = null;  // use v0
-    System.logI(s);  // use v1 for PrintStream, v0 for s
-  }
-
-  native int refmap2(int x);
-
-  public static void main(String[] args) {
-    System.loadLibrary(args[0]);
-    StackWalk2 st = new StackWalk2();
-    st.f();
-  }
-}
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index da79164..c9b789e 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -292,15 +292,6 @@
   code_cache->GetProfiledMethods(unused_locations, unused_vector);
 }
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isClassMoveable(JNIEnv*,
-                                                                jclass,
-                                                                jclass cls) {
-  Runtime* runtime = Runtime::Current();
-  ScopedObjectAccess soa(Thread::Current());
-  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
-  return runtime->GetHeap()->IsMovableObject(klass);
-}
-
 extern "C" JNIEXPORT void JNICALL Java_Main_waitForCompilation(JNIEnv*, jclass) {
   jit::Jit* jit = Runtime::Current()->GetJit();
   if (jit != nullptr) {
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 6004f25..768bc79 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -697,9 +697,14 @@
         "description": ["Tests that depend on input-vdex are not supported with compact dex"]
     },
     {
-        "tests": "661-oat-writer-layout",
+        "tests": ["661-oat-writer-layout"],
         "variant": "interp-ac | interpreter | jit | no-prebuild | no-image | trace | redefine-stress | jvmti-stress",
-        "description": ["Test is designed to only check --compiler-filter=speed"]
+        "description": ["Test is designed to only check --optimizing"]
+    },
+    {
+        "tests": ["004-StackWalk"],
+        "variant": "interp-ac | interpreter | jit | no-prebuild | no-image | trace | redefine-stress | jvmti-stress | debuggable",
+        "description": ["Test is designed to only check --optimizing"]
     },
     {
         "tests": "674-HelloWorld-Dm",
diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc
index bd320c6..e123e9f 100644
--- a/test/ti-stress/stress.cc
+++ b/test/ti-stress/stress.cc
@@ -92,7 +92,7 @@
 
   struct Allocator : public dex::Writer::Allocator {
     explicit Allocator(jvmtiEnv* jvmti_env) : jvmti_env_(jvmti_env) {}
-    virtual void* Allocate(size_t size) {
+    void* Allocate(size_t size) override {
       unsigned char* out = nullptr;
       if (JVMTI_ERROR_NONE != jvmti_env_->Allocate(size, &out)) {
         return nullptr;
@@ -100,7 +100,7 @@
         return out;
       }
     }
-    virtual void Free(void* ptr) {
+    void Free(void* ptr) override {
       jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
     }
    private:
diff --git a/tools/ahat/etc/ahat_api.txt b/tools/ahat/etc/ahat_api.txt
index 5426f7b..7aa994a 100644
--- a/tools/ahat/etc/ahat_api.txt
+++ b/tools/ahat/etc/ahat_api.txt
@@ -96,6 +96,7 @@
     method public boolean isArrayInstance();
     method public boolean isClassInstance();
     method public boolean isClassObj();
+    method public boolean isInstanceOfClass(java.lang.String);
     method public boolean isPlaceHolder();
     method public boolean isRoot();
     method public boolean isStronglyReachable();
@@ -226,6 +227,7 @@
     method public int getLineNumber();
     method public java.lang.String getMethodName();
     method public void getObjects(java.lang.String, java.lang.String, java.util.Collection<com.android.ahat.heapdump.AhatInstance>);
+    method public void getObjects(java.util.function.Predicate<com.android.ahat.heapdump.AhatInstance>, java.util.function.Consumer<com.android.ahat.heapdump.AhatInstance>);
     method public java.util.List<com.android.ahat.heapdump.Site.ObjectsInfo> getObjectsInfos();
     method public com.android.ahat.heapdump.Site getParent();
     method public java.lang.String getSignature();
diff --git a/tools/ahat/src/main/com/android/ahat/ObjectsHandler.java b/tools/ahat/src/main/com/android/ahat/ObjectsHandler.java
index 1a8f018..81611b6 100644
--- a/tools/ahat/src/main/com/android/ahat/ObjectsHandler.java
+++ b/tools/ahat/src/main/com/android/ahat/ObjectsHandler.java
@@ -16,6 +16,7 @@
 
 package com.android.ahat;
 
+import com.android.ahat.heapdump.AhatHeap;
 import com.android.ahat.heapdump.AhatInstance;
 import com.android.ahat.heapdump.AhatSnapshot;
 import com.android.ahat.heapdump.Site;
@@ -24,6 +25,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Predicate;
 
 class ObjectsHandler implements AhatHandler {
   private static final String OBJECTS_ID = "objects";
@@ -34,32 +36,102 @@
     mSnapshot = snapshot;
   }
 
+  /**
+   * Get the list of instances that match the given site, class, and heap
+   * filters. This method is public to facilitate testing.
+   *
+   * @param site the site to get instances from
+   * @param className non-null name of the class to restrict instances to.
+   * @param subclass if true, include instances of subclasses of the named class.
+   * @param heapName name of the heap to restrict instances to. May be null to
+   *                 allow instances on any heap.
+   * @return list of matching instances
+   */
+  public static List<AhatInstance> getObjects(
+      Site site, String className, boolean subclass, String heapName) {
+    Predicate<AhatInstance> predicate = (x) -> {
+      return (heapName == null || x.getHeap().getName().equals(heapName))
+        && (subclass ? x.isInstanceOfClass(className) : className.equals(x.getClassName()));
+    };
+
+    List<AhatInstance> insts = new ArrayList<AhatInstance>();
+    site.getObjects(predicate, x -> insts.add(x));
+    return insts;
+  }
+
   @Override
   public void handle(Doc doc, Query query) throws IOException {
     int id = query.getInt("id", 0);
-    String className = query.get("class", null);
+    String className = query.get("class", "java.lang.Object");
     String heapName = query.get("heap", null);
+    boolean subclass = (query.getInt("subclass", 0) != 0);
     Site site = mSnapshot.getSite(id);
 
-    List<AhatInstance> insts = new ArrayList<AhatInstance>();
-    site.getObjects(heapName, className, insts);
+    List<AhatInstance> insts = getObjects(site, className, subclass, heapName);
     Collections.sort(insts, Sort.defaultInstanceCompare(mSnapshot));
 
-    doc.title("Objects");
+    doc.title("Instances");
 
-    SizeTable.table(doc, mSnapshot.isDiffed(),
-        new Column("Heap"),
-        new Column("Object"));
+    // Write a description of the current settings, with links to adjust the
+    // settings, such as:
+    //    Site:           ROOT -
+    //    Class:          android.os.Binder
+    //    Subclasses:     excluded (switch to included)
+    //    Heap:           any (switch to app, image, zygote)
+    //    Count:          17,424
+    doc.descriptions();
+    doc.description(DocString.text("Site"), Summarizer.summarize(site));
+    doc.description(DocString.text("Class"), DocString.text(className));
 
-    SubsetSelector<AhatInstance> selector = new SubsetSelector(query, OBJECTS_ID, insts);
-    for (AhatInstance inst : selector.selected()) {
-      AhatInstance base = inst.getBaseline();
-      SizeTable.row(doc, inst.getSize(), base.getSize(),
-          DocString.text(inst.getHeap().getName()),
-          Summarizer.summarize(inst));
+    DocString subclassChoice = DocString.text(subclass ? "included" : "excluded");
+    subclassChoice.append(" (switch to ");
+    subclassChoice.appendLink(query.with("subclass", subclass ? 0 : 1),
+      DocString.text(subclass ? "excluded" : "included"));
+    subclassChoice.append(")");
+    doc.description(DocString.text("Subclasses"), subclassChoice);
+
+    DocString heapChoice = DocString.text(heapName == null ? "any" : heapName);
+    heapChoice.append(" (switch to ");
+    String comma = "";
+    for (AhatHeap heap : mSnapshot.getHeaps()) {
+      if (!heap.getName().equals(heapName)) {
+        heapChoice.append(comma);
+        heapChoice.appendLink(
+            query.with("heap", heap.getName()),
+            DocString.text(heap.getName()));
+        comma = ", ";
+      }
     }
-    SizeTable.end(doc);
-    selector.render(doc);
+    if (heapName != null) {
+      heapChoice.append(comma);
+      heapChoice.appendLink(
+          query.with("heap", null),
+          DocString.text("any"));
+    }
+    heapChoice.append(")");
+    doc.description(DocString.text("Heap"), heapChoice);
+
+    doc.description(DocString.text("Count"), DocString.format("%,14d", insts.size()));
+    doc.end();
+    doc.println(DocString.text(""));
+
+    if (insts.isEmpty()) {
+      doc.println(DocString.text("(none)"));
+    } else {
+      SizeTable.table(doc, mSnapshot.isDiffed(),
+          new Column("Heap"),
+          new Column("Object"));
+
+      SubsetSelector<AhatInstance> selector = new SubsetSelector(query, OBJECTS_ID, insts);
+      for (AhatInstance inst : selector.selected()) {
+        AhatInstance base = inst.getBaseline();
+        SizeTable.row(doc, inst.getSize(), base.getSize(),
+            DocString.text(inst.getHeap().getName()),
+            Summarizer.summarize(inst));
+      }
+      SizeTable.end(doc);
+      selector.render(doc);
+    }
   }
 }
 
diff --git a/tools/ahat/src/main/com/android/ahat/Query.java b/tools/ahat/src/main/com/android/ahat/Query.java
index 9c2783c..5f064cd 100644
--- a/tools/ahat/src/main/com/android/ahat/Query.java
+++ b/tools/ahat/src/main/com/android/ahat/Query.java
@@ -79,7 +79,9 @@
   /**
    * Return a uri suitable for an href target that links to the current
    * page, except with the named query parameter set to the new value.
-   *
+   * <p>
+   * <code>value</code> may be null to remove the named query parameter.
+   * <p>
    * The generated parameters will be sorted alphabetically so it is easier to
    * test.
    */
@@ -92,11 +94,13 @@
     params.put(name, value);
     String and = "";
     for (Map.Entry<String, String> entry : params.entrySet()) {
-      newQuery.append(and);
-      newQuery.append(entry.getKey());
-      newQuery.append('=');
-      newQuery.append(entry.getValue());
-      and = "&";
+      if (entry.getValue() != null) {
+        newQuery.append(and);
+        newQuery.append(entry.getKey());
+        newQuery.append('=');
+        newQuery.append(entry.getValue());
+        and = "&";
+      }
     }
     return DocString.uri(newQuery.toString());
   }
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
index 4c60d8b..0511798 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatClassInstance.java
@@ -107,21 +107,6 @@
     return new ReferenceIterator();
   }
 
-  /**
-   * Returns true if this is an instance of a (subclass of a) class with the
-   * given name.
-   */
-  private boolean isInstanceOfClass(String className) {
-    AhatClassObj cls = getClassObj();
-    while (cls != null) {
-      if (className.equals(cls.getName())) {
-        return true;
-      }
-      cls = cls.getSuperClassObj();
-    }
-    return false;
-  }
-
   @Override public String asString(int maxChars) {
     if (!isInstanceOfClass("java.lang.String")) {
       return null;
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
index 3d691c7..c85a057 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/AhatInstance.java
@@ -330,6 +330,25 @@
   }
 
   /**
+   * Returns true if this is an instance of a (subclass of a) class with the
+   * given name.
+   *
+   * @param className the name of the class to check for
+   * @return true if this is an instance of a (subclass of a) class with the
+   *              given name
+   */
+  public boolean isInstanceOfClass(String className) {
+    AhatClassObj cls = getClassObj();
+    while (cls != null) {
+      if (className.equals(cls.getName())) {
+        return true;
+      }
+      cls = cls.getSuperClassObj();
+    }
+    return false;
+  }
+
+  /**
    * Returns true if the given instance is an array instance.
    *
    * @return true if the given instance is an array instance
diff --git a/tools/ahat/src/main/com/android/ahat/heapdump/Site.java b/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
index 46a1729..4f0660f 100644
--- a/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
+++ b/tools/ahat/src/main/com/android/ahat/heapdump/Site.java
@@ -23,6 +23,8 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 /**
  * Used to collection information about objects allocated at a particular
@@ -259,22 +261,37 @@
    *                 every heap should be collected.
    * @param className the name of the class the collected objects should
    *                  belong to. This may be null to indicate objects of
-   *                  every class should be collected.
+   *                  every class should be collected. Instances of subclasses
+   *                  of this class are not included.
    * @param objects out parameter. A collection of objects that all
    *                collected objects should be added to.
    */
   public void getObjects(String heapName, String className, Collection<AhatInstance> objects) {
+    Predicate<AhatInstance> predicate = x -> {
+      return (heapName == null || x.getHeap().getName().equals(heapName))
+        && (className == null || x.getClassName().equals(className));
+    };
+    getObjects(predicate, x -> objects.add(x));
+  }
+
+  /**
+   * Collects the objects allocated under this site, filtered by the given
+   * predicate.
+   * Includes objects allocated in children sites.
+   * @param predicate limit instances to those satisfying this predicate
+   * @param consumer consumer of the objects
+   */
+  public void getObjects(Predicate<AhatInstance> predicate, Consumer<AhatInstance> consumer) {
     for (AhatInstance inst : mObjects) {
-      if ((heapName == null || inst.getHeap().getName().equals(heapName))
-          && (className == null || inst.getClassName().equals(className))) {
-        objects.add(inst);
+      if (predicate.test(inst)) {
+        consumer.accept(inst);
       }
     }
 
     // Recursively visit children. Recursion should be okay here because the
     // stack depth is limited by a reasonable amount (128 frames or so).
     for (Site child : mChildren) {
-      child.getObjects(heapName, className, objects);
+      child.getObjects(predicate, consumer);
     }
   }
 
diff --git a/tools/ahat/src/test/com/android/ahat/AhatTestSuite.java b/tools/ahat/src/test/com/android/ahat/AhatTestSuite.java
index 3aa52b5..abc3cc7 100644
--- a/tools/ahat/src/test/com/android/ahat/AhatTestSuite.java
+++ b/tools/ahat/src/test/com/android/ahat/AhatTestSuite.java
@@ -29,6 +29,7 @@
   InstanceTest.class,
   NativeAllocationTest.class,
   ObjectHandlerTest.class,
+  ObjectsHandlerTest.class,
   OverviewHandlerTest.class,
   PerformanceTest.class,
   ProguardMapTest.class,
diff --git a/tools/ahat/src/test/com/android/ahat/ObjectsHandlerTest.java b/tools/ahat/src/test/com/android/ahat/ObjectsHandlerTest.java
new file mode 100644
index 0000000..927e017
--- /dev/null
+++ b/tools/ahat/src/test/com/android/ahat/ObjectsHandlerTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.AhatSnapshot;
+import com.android.ahat.heapdump.Site;
+import java.io.IOException;
+import java.util.List;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class ObjectsHandlerTest {
+  @Test
+  public void getObjects() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatSnapshot snapshot = dump.getAhatSnapshot();
+
+    Site root = snapshot.getRootSite();
+
+    // We expect a single instance of DumpedStuff
+    List<AhatInstance> dumped = ObjectsHandler.getObjects(
+        root, "DumpedStuff", /* subclass */ false, /* heapName */ null);
+    assertEquals(1, dumped.size());
+    assertTrue(dumped.get(0).getClassName().equals("DumpedStuff"));
+
+    // We expect no direct instances of SuperDumpedStuff
+    List<AhatInstance> direct = ObjectsHandler.getObjects(
+        root, "SuperDumpedStuff", /* subclass */ false, /* heapName */ null);
+    assertTrue(direct.isEmpty());
+
+    // We expect one subclass instance of SuperDumpedStuff
+    List<AhatInstance> subclass = ObjectsHandler.getObjects(
+        root, "SuperDumpedStuff", /* subclass */ true, /* heapName */ null);
+    assertEquals(1, subclass.size());
+    assertTrue(subclass.get(0).getClassName().equals("DumpedStuff"));
+    assertEquals(dumped.get(0), subclass.get(0));
+  }
+}
diff --git a/tools/ahat/src/test/com/android/ahat/QueryTest.java b/tools/ahat/src/test/com/android/ahat/QueryTest.java
index 5bcf8ea..52cf963 100644
--- a/tools/ahat/src/test/com/android/ahat/QueryTest.java
+++ b/tools/ahat/src/test/com/android/ahat/QueryTest.java
@@ -41,6 +41,7 @@
     assertEquals("/object?answer=43&foo=bar", query.with("answer", "43").toString());
     assertEquals("/object?answer=43&foo=bar", query.with("answer", 43).toString());
     assertEquals("/object?answer=42&bar=finally&foo=bar", query.with("bar", "finally").toString());
+    assertEquals("/object?answer=42", query.with("foo", null).toString());
   }
 
   @Test
@@ -55,6 +56,7 @@
     assertEquals("/object?answer=43&foo=sludge", query.with("answer", "43").toString());
     assertEquals("/object?answer=42&bar=finally&foo=sludge",
         query.with("bar", "finally").toString());
+    assertEquals("/object?answer=42", query.with("foo", null).toString());
   }
 
   @Test
@@ -66,5 +68,6 @@
     assertEquals(2, query.getInt("foo", 2));
     assertEquals("/object?foo=sludge", query.with("foo", "sludge").toString());
     assertEquals("/object?answer=43", query.with("answer", "43").toString());
+    assertEquals("/object?", query.with("foo", null).toString());
   }
 }
diff --git a/tools/amm/Android.bp b/tools/amm/Android.bp
new file mode 100644
index 0000000..e6f6ff7
--- /dev/null
+++ b/tools/amm/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2017 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.
+
+// --- ammtestjni.so -------------
+
+cc_library_shared {
+    name: "libammtestjni",
+
+    srcs: [
+        "AmmTest/jni/ammtest.c",
+    ],
+
+    sdk_version: "current",
+}
diff --git a/tools/amm/Android.mk b/tools/amm/Android.mk
index 47030c5..fa4ca44 100644
--- a/tools/amm/Android.mk
+++ b/tools/amm/Android.mk
@@ -14,13 +14,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-# --- ammtestjni.so -------------
-include $(CLEAR_VARS)
-LOCAL_MODULE := libammtestjni
-LOCAL_SRC_FILES := $(call all-c-files-under, AmmTest/jni)
-LOCAL_SDK_VERSION := current
-include $(BUILD_SHARED_LIBRARY)
-
 # --- AmmTest.apk --------------
 include $(CLEAR_VARS)
 LOCAL_PACKAGE_NAME := AmmTest
@@ -31,4 +24,3 @@
 LOCAL_JAVA_RESOURCE_FILES := $(LOCAL_PATH)/AmmTest/aahat.png
 LOCAL_MANIFEST_FILE := AmmTest/AndroidManifest.xml
 include $(BUILD_PACKAGE)
-
diff --git a/tools/art_verifier/Android.bp b/tools/art_verifier/Android.bp
index afd52fb..6fff27a 100644
--- a/tools/art_verifier/Android.bp
+++ b/tools/art_verifier/Android.bp
@@ -16,7 +16,10 @@
 
 art_cc_defaults {
     name: "art_verifier-defaults",
-    defaults: ["art_defaults"],
+    defaults: [
+        "art_defaults",
+        "libart_static_defaults",
+    ],
     host_supported: true,
     srcs: [
         "art_verifier.cc",
@@ -24,11 +27,8 @@
     header_libs: [
         "art_cmdlineparser_headers",
     ],
-    static_libs: art_static_dependencies + [
-        "libart",
-        "libartbase",
-        "libdexfile",
-        "libprofile",
+    static_libs: [
+        "libsigchain_dummy",
     ],
     target: {
         android: {
diff --git a/tools/art_verifier/art_verifier.cc b/tools/art_verifier/art_verifier.cc
index 8f412bf..45c1a33 100644
--- a/tools/art_verifier/art_verifier.cc
+++ b/tools/art_verifier/art_verifier.cc
@@ -137,7 +137,7 @@
     return kParseOk;
   }
 
-  virtual std::string GetUsage() const {
+  std::string GetUsage() const override {
     std::string usage;
 
     usage +=
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 8305051..b5d39e1 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -68,15 +68,15 @@
   make_command+=" dx-tests"
   mode_suffix="-host"
 elif [[ $mode == "target" ]]; then
-  if [[ -z "$TARGET_PRODUCT" ]]; then
-    echo 'TARGET_PRODUCT environment variable is empty; did you forget to run `lunch`?'
+  if [[ -z "${ANDROID_PRODUCT_OUT}" ]]; then
+    echo 'ANDROID_PRODUCT_OUT environment variable is empty; did you forget to run `lunch`?'
     exit 1
   fi
   make_command="make $j_arg $extra_args $showcommands build-art-target-tests $common_targets"
   make_command+=" libjavacrypto-target libnetd_client-target linker toybox toolbox sh"
   make_command+=" debuggerd su"
   make_command+=" ${out_dir}/host/linux-x86/bin/adb libstdc++ "
-  make_command+=" ${out_dir}/target/product/${TARGET_PRODUCT}/system/etc/public.libraries.txt"
+  make_command+=" ${ANDROID_PRODUCT_OUT#"${ANDROID_BUILD_TOP}/"}/system/etc/public.libraries.txt"
   if [[ -n "$ART_TEST_CHROOT" ]]; then
     # These targets are needed for the chroot environment.
     make_command+=" crash_dump event-log-tags"
diff --git a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java
index 9262076..53157a3 100644
--- a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java
+++ b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java
@@ -33,10 +33,12 @@
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -71,9 +73,10 @@
                 .hasArgs()
                 .withDescription(
                         "Specify file to write greylist to. Can be specified multiple times. " +
-                        "Format is either just a filename, or \"int:filename\". If an integer is " +
-                        "given, members with a matching maxTargetSdk are written to the file; if " +
-                        "no integer is given, members with no maxTargetSdk are written.")
+                        "Format is either just a filename, or \"int[,int,...]:filename\". If " +
+                        "integers are given, members with matching maxTargetSdk values are " +
+                        "written to the file; if no integer or \"none\" is given, members with " +
+                        "no maxTargetSdk are written.")
                 .create("g"));
         options.addOption(OptionBuilder
                 .withLongOpt("write-whitelist")
@@ -204,15 +207,22 @@
     static Map<Integer, String> readGreylistMap(Status status, String[] argValues) {
         Map<Integer, String> map = new HashMap<>();
         for (String sdkFile : argValues) {
-            Integer maxTargetSdk = null;
+            List<Integer> maxTargetSdks = new ArrayList<>();
             String filename;
             int colonPos = sdkFile.indexOf(':');
             if (colonPos != -1) {
-                try {
-                    maxTargetSdk = Integer.valueOf(sdkFile.substring(0, colonPos));
-                } catch (NumberFormatException nfe) {
-                    status.error("Not a valid integer: %s from argument value '%s'",
-                            sdkFile.substring(0, colonPos), sdkFile);
+                String[] targets = sdkFile.substring(0, colonPos).split(",");
+                for (String target : targets) {
+                    if ("none".equals(target)) {
+                        maxTargetSdks.add(null);
+                    } else {
+                        try {
+                            maxTargetSdks.add(Integer.valueOf(target));
+                        } catch (NumberFormatException nfe) {
+                            status.error("Not a valid integer: %s from argument value '%s'",
+                                    sdkFile.substring(0, colonPos), sdkFile);
+                        }
+                    }
                 }
                 filename = sdkFile.substring(colonPos + 1);
                 if (filename.length() == 0) {
@@ -220,13 +230,16 @@
                             filename, sdkFile);
                 }
             } else {
-                maxTargetSdk = null;
+                maxTargetSdks.add(null);
                 filename = sdkFile;
             }
-            if (map.containsKey(maxTargetSdk)) {
-                status.error("Multiple output files for maxTargetSdk %s", maxTargetSdk);
-            } else {
-                map.put(maxTargetSdk, filename);
+            for (Integer maxTargetSdk : maxTargetSdks) {
+                if (map.containsKey(maxTargetSdk)) {
+                    status.error("Multiple output files for maxTargetSdk %s",
+                            maxTargetSdk == null ? "none" : maxTargetSdk);
+                } else {
+                    map.put(maxTargetSdk, filename);
+                }
             }
         }
         return map;
diff --git a/tools/class2greylist/src/com/android/class2greylist/FileWritingGreylistConsumer.java b/tools/class2greylist/src/com/android/class2greylist/FileWritingGreylistConsumer.java
index 9f33467..bfd2310 100644
--- a/tools/class2greylist/src/com/android/class2greylist/FileWritingGreylistConsumer.java
+++ b/tools/class2greylist/src/com/android/class2greylist/FileWritingGreylistConsumer.java
@@ -1,5 +1,7 @@
 package com.android.class2greylist;
 
+import com.google.common.annotations.VisibleForTesting;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -20,11 +22,16 @@
         return new PrintStream(new FileOutputStream(new File(filename)));
     }
 
-    private static Map<Integer, PrintStream> openFiles(
+    @VisibleForTesting
+    public static Map<Integer, PrintStream> openFiles(
             Map<Integer, String> filenames) throws FileNotFoundException {
+        Map<String, PrintStream> streamsByName = new HashMap<>();
         Map<Integer, PrintStream> streams = new HashMap<>();
         for (Map.Entry<Integer, String> entry : filenames.entrySet()) {
-            streams.put(entry.getKey(), openFile(entry.getValue()));
+            if (!streamsByName.containsKey(entry.getValue())) {
+                streamsByName.put(entry.getValue(), openFile(entry.getValue()));
+            }
+            streams.put(entry.getKey(), streamsByName.get(entry.getValue()));
         }
         return streams;
     }
diff --git a/tools/class2greylist/test/src/com/android/class2greylist/Class2GreylistTest.java b/tools/class2greylist/test/src/com/android/class2greylist/Class2GreylistTest.java
index cb75dd3..b87a5b1 100644
--- a/tools/class2greylist/test/src/com/android/class2greylist/Class2GreylistTest.java
+++ b/tools/class2greylist/test/src/com/android/class2greylist/Class2GreylistTest.java
@@ -56,6 +56,31 @@
     }
 
     @Test
+    public void testReadGreylistMapNone() throws IOException {
+        Map<Integer, String> map = Class2Greylist.readGreylistMap(mStatus,
+                new String[]{"none:noApi"});
+        verifyZeroInteractions(mStatus);
+        assertThat(map).containsExactly(null, "noApi");
+    }
+
+    @Test
+    public void testReadGreylistMapMulti() throws IOException {
+        Map<Integer, String> map = Class2Greylist.readGreylistMap(mStatus,
+                new String[]{"1,none:noOr1Api", "3:apiThree"});
+        verifyZeroInteractions(mStatus);
+        assertThat(map).containsExactly(null, "noOr1Api", 1, "noOr1Api", 3, "apiThree");
+    }
+
+    @Test
+    public void testReadGreylistMapMulti2() throws IOException {
+        Map<Integer, String> map = Class2Greylist.readGreylistMap(mStatus,
+                new String[]{"1,none,2,3,4:allApi"});
+        verifyZeroInteractions(mStatus);
+        assertThat(map).containsExactly(
+                null, "allApi", 1, "allApi", 2, "allApi", 3, "allApi", 4, "allApi");
+    }
+
+    @Test
     public void testReadGreylistMapDuplicate() throws IOException {
         Class2Greylist.readGreylistMap(mStatus,
                 new String[]{"noApi", "1:apiOne", "1:anotherOne"});
diff --git a/tools/class2greylist/test/src/com/android/class2greylist/FileWritingGreylistConsumerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/FileWritingGreylistConsumerTest.java
new file mode 100644
index 0000000..1e1b1df
--- /dev/null
+++ b/tools/class2greylist/test/src/com/android/class2greylist/FileWritingGreylistConsumerTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.class2greylist;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.mockito.Mock;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public class FileWritingGreylistConsumerTest {
+
+    @Mock
+    Status mStatus;
+    @Rule
+    public TestName mTestName = new TestName();
+    private int mFileNameSeq = 0;
+    private final List<String> mTempFiles = new ArrayList<>();
+
+    @Before
+    public void setup() throws IOException {
+        System.out.println(String.format("\n============== STARTING TEST: %s ==============\n",
+                mTestName.getMethodName()));
+        initMocks(this);
+    }
+
+    @After
+    public void removeTempFiles() {
+        for (String name : mTempFiles) {
+            new File(name).delete();
+        }
+    }
+
+    private String tempFileName() {
+        String name = String.format(Locale.US, "/tmp/test-%s-%d",
+                mTestName.getMethodName(), mFileNameSeq++);
+        mTempFiles.add(name);
+        return name;
+    }
+
+    @Test
+    public void testSimpleMap() throws FileNotFoundException {
+        Map<Integer, PrintStream> streams = FileWritingGreylistConsumer.openFiles(
+                ImmutableMap.of(1, tempFileName(), 2, tempFileName()));
+        assertThat(streams.keySet()).containsExactly(1, 2);
+        assertThat(streams.get(1)).isNotNull();
+        assertThat(streams.get(2)).isNotNull();
+        assertThat(streams.get(2)).isNotSameAs(streams.get(1));
+    }
+
+    @Test
+    public void testCommonMappings() throws FileNotFoundException {
+        String name = tempFileName();
+        Map<Integer, PrintStream> streams = FileWritingGreylistConsumer.openFiles(
+                ImmutableMap.of(1, name, 2, name));
+        assertThat(streams.keySet()).containsExactly(1, 2);
+        assertThat(streams.get(1)).isNotNull();
+        assertThat(streams.get(2)).isSameAs(streams.get(1));
+    }
+}
diff --git a/tools/field-null-percent/check-null-fields.py b/tools/field-null-percent/check-null-fields.py
new file mode 100755
index 0000000..c11d51a
--- /dev/null
+++ b/tools/field-null-percent/check-null-fields.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 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.
+
+"""
+Retrieves the counts of how many objects have a particular field null on all running processes.
+
+Prints a json map from pid -> (log-tag, field-name, null-count, total-count).
+"""
+
+
+import adb
+import argparse
+import concurrent.futures
+import itertools
+import json
+import logging
+import os
+import os.path
+import signal
+import subprocess
+import time
+
+def main():
+  parser = argparse.ArgumentParser(description="Get counts of null fields from a device.")
+  parser.add_argument("-S", "--serial", metavar="SERIAL", type=str,
+                      required=False,
+                      default=os.environ.get("ANDROID_SERIAL", None),
+                      help="Android serial to use. Defaults to ANDROID_SERIAL")
+  parser.add_argument("-p", "--pid", required=False,
+                      default=[], action="append",
+                      help="Specific pids to check. By default checks all running dalvik processes")
+  has_out = "OUT" in os.environ
+  def_32 = os.path.join(os.environ.get("OUT", ""), "system", "lib", "libfieldnull.so")
+  def_64 = os.path.join(os.environ.get("OUT", ""), "system", "lib64", "libfieldnull.so")
+  has_32 = has_out and os.path.exists(def_32)
+  has_64 = has_out and os.path.exists(def_64)
+  def pushable_lib(name):
+    if os.path.isfile(name):
+      return name
+    else:
+      raise argparse.ArgumentTypeError(name + " is not a file!")
+  parser.add_argument('--lib32', type=pushable_lib,
+                      required=not has_32,
+                      action='store',
+                      default=def_32,
+                      help="Location of 32 bit agent to push")
+  parser.add_argument('--lib64', type=pushable_lib,
+                      required=not has_64,
+                      action='store',
+                      default=def_64 if has_64 else None,
+                      help="Location of 64 bit agent to push")
+  parser.add_argument("fields", nargs="+",
+                      help="fields to check")
+
+  out = parser.parse_args()
+
+  device = adb.device.get_device(out.serial)
+  print("getting root")
+  device.root()
+
+  print("Disabling selinux")
+  device.shell("setenforce 0".split())
+
+  print("Pushing libraries")
+  lib32 = device.shell("mktemp".split())[0].strip()
+  lib64 = device.shell("mktemp".split())[0].strip()
+
+  print(out.lib32 + " -> " + lib32)
+  device.push(out.lib32, lib32)
+
+  print(out.lib64 + " -> " + lib64)
+  device.push(out.lib64, lib64)
+
+  cmd32 = "'{}={}'".format(lib32, ','.join(out.fields))
+  cmd64 = "'{}={}'".format(lib64, ','.join(out.fields))
+
+  if len(out.pid) == 0:
+    print("Getting jdwp pids")
+    new_env = dict(os.environ)
+    new_env["ANDROID_SERIAL"] = device.serial
+    p = subprocess.Popen([device.adb_path, "jdwp"], env=new_env, stdout=subprocess.PIPE)
+    # ADB jdwp doesn't ever exit so just kill it after 1 second to get a list of pids.
+    with concurrent.futures.ProcessPoolExecutor() as ppe:
+      ppe.submit(kill_it, p.pid).result()
+    out.pid = p.communicate()[0].strip().split()
+    p.wait()
+    print(out.pid)
+  print("Clearing logcat")
+  device.shell("logcat -c".split())
+  final = {}
+  print("Getting info from every process dumped to logcat")
+  for p in out.pid:
+    res = check_single_process(p, device, cmd32, cmd64);
+    if res is not None:
+      final[p] = res
+  device.shell('rm {}'.format(lib32).split())
+  device.shell('rm {}'.format(lib64).split())
+  print(json.dumps(final, indent=2))
+
+def kill_it(p):
+  time.sleep(1)
+  os.kill(p, signal.SIGINT)
+
+def check_single_process(pid, device, bit32, bit64):
+  try:
+    # Just try attaching both 32 and 64 bit. Wrong one will fail silently.
+    device.shell(['am', 'attach-agent', str(pid), bit32])
+    device.shell(['am', 'attach-agent', str(pid), bit64])
+    time.sleep(0.5)
+    device.shell('kill -3 {}'.format(pid).split())
+    time.sleep(0.5)
+    out = []
+    all_fields = []
+    lc_cmd = "logcat -d -b main --pid={} -e '^\\t.*\\t[0-9]*\\t[0-9]*$'".format(pid).split(' ')
+    for l in device.shell(lc_cmd)[0].strip().split('\n'):
+      # first 4 are just date and other useless data.
+      data = l.strip().split()[5:]
+      if len(data) < 4:
+        continue
+      # If we run multiple times many copies of the agent will be attached. Just choose one of any
+      # copies for each field.
+      field = data[1]
+      if field not in all_fields:
+        out.append((str(data[0]), str(data[1]), int(data[2]), int(data[3])))
+        all_fields.append(field)
+    if len(out) != 0:
+      print("pid: " + pid + " -> " + str(out))
+      return out
+    else:
+      return None
+  except adb.device.ShellError as e:
+    print("failed on pid " + repr(pid) + " because " + repr(e))
+    return None
+
+if __name__ == '__main__':
+  main()
diff --git a/tools/field-null-percent/fieldnull.cc b/tools/field-null-percent/fieldnull.cc
index 86459d2..1bd122a 100644
--- a/tools/field-null-percent/fieldnull.cc
+++ b/tools/field-null-percent/fieldnull.cc
@@ -147,7 +147,7 @@
   delete list;
 }
 
-static void CreateFieldList(jvmtiEnv* jvmti, JNIEnv* env, std::string args) {
+static void CreateFieldList(jvmtiEnv* jvmti, JNIEnv* env, const std::string& args) {
   RequestList* list = nullptr;
   CHECK_JVMTI(jvmti->Allocate(sizeof(*list), reinterpret_cast<unsigned char**>(&list)));
   new (list) RequestList { .fields_ = GetRequestedFields(env, args), };
diff --git a/tools/libcore_gcstress_failures.txt b/tools/libcore_gcstress_failures.txt
index 965e85c..fff1c70 100644
--- a/tools/libcore_gcstress_failures.txt
+++ b/tools/libcore_gcstress_failures.txt
@@ -29,6 +29,7 @@
   modes: [device],
   names: ["libcore.java.lang.StringTest#testFastPathString_wellFormedUtf8Sequence",
           "org.apache.harmony.tests.java.lang.ref.ReferenceQueueTest#test_remove",
+          "org.apache.harmony.tests.java.text.DateFormatTest#test_getAvailableLocales",
           "org.apache.harmony.tests.java.util.TimerTest#testOverdueTaskExecutesImmediately",
           "org.apache.harmony.tests.java.util.WeakHashMapTest#test_keySet_hasNext",
           "libcore.java.text.DecimalFormatTest#testCurrencySymbolSpacing",
diff --git a/tools/titrace/instruction_decoder.cc b/tools/titrace/instruction_decoder.cc
index d8fb713..7f8b296 100644
--- a/tools/titrace/instruction_decoder.cc
+++ b/tools/titrace/instruction_decoder.cc
@@ -32,7 +32,7 @@
     return Bytecode::ToString(op);
   }
 
-  virtual size_t LocationToOffset(size_t j_location) {
+  size_t LocationToOffset(size_t j_location) override {
     return j_location;
   }
 
@@ -474,7 +474,7 @@
     return Bytecode::ToString(op);
   }
 
-  virtual size_t LocationToOffset(size_t j_location) {
+  size_t LocationToOffset(size_t j_location) override {
     // dex pc is uint16_t*, but offset needs to be in bytes.
     return j_location * (sizeof(uint16_t) / sizeof(uint8_t));
   }
diff --git a/tools/veridex/hidden_api_finder.cc b/tools/veridex/hidden_api_finder.cc
index 4eba10e..d81f133 100644
--- a/tools/veridex/hidden_api_finder.cc
+++ b/tools/veridex/hidden_api_finder.cc
@@ -178,7 +178,8 @@
   stats->linking_count = method_locations_.size() + field_locations_.size();
 
   // Dump methods from hidden APIs linked against.
-  for (const std::pair<std::string, std::vector<MethodReference>>& pair : method_locations_) {
+  for (const std::pair<const std::string,
+                       std::vector<MethodReference>>& pair : method_locations_) {
     HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(pair.first);
     stats->api_counts[api_list]++;
     os << "#" << ++stats->count << ": Linking " << api_list << " " << pair.first << " use(s):";
@@ -190,7 +191,8 @@
   }
 
   // Dump fields from hidden APIs linked against.
-  for (const std::pair<std::string, std::vector<MethodReference>>& pair : field_locations_) {
+  for (const std::pair<const std::string,
+                       std::vector<MethodReference>>& pair : field_locations_) {
     HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(pair.first);
     stats->api_counts[api_list]++;
     os << "#" << ++stats->count << ": Linking " << api_list << " " << pair.first << " use(s):";