Merge "Revert "Revert "ART: Key-Value Store in Oat header"""
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..341df78
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,55 @@
+# Copyright (C) 2007 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# Switching to jemalloc requires deleting these files.
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libart_*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libartd_*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libart_*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libartd_*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/runtime/compiled_class.h b/compiler/compiled_class.h
similarity index 88%
rename from runtime/compiled_class.h
rename to compiler/compiled_class.h
index c53d500..b88d613 100644
--- a/runtime/compiled_class.h
+++ b/compiler/compiled_class.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_COMPILED_CLASS_H_
-#define ART_RUNTIME_COMPILED_CLASS_H_
+#ifndef ART_COMPILER_COMPILED_CLASS_H_
+#define ART_COMPILER_COMPILED_CLASS_H_
 
 #include "mirror/class.h"
 
@@ -34,4 +34,4 @@
 
 }  // namespace art
 
-#endif  // ART_RUNTIME_COMPILED_CLASS_H_
+#endif  // ART_COMPILER_COMPILED_CLASS_H_
diff --git a/compiler/compilers.cc b/compiler/compilers.cc
index f940b54..bac1f12 100644
--- a/compiler/compilers.cc
+++ b/compiler/compilers.cc
@@ -15,6 +15,7 @@
  */
 
 #include "compilers.h"
+
 #include "dex/mir_graph.h"
 #include "dex/quick/mir_to_lir.h"
 #include "elf_writer_quick.h"
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index 799a742..bdedadb 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -440,19 +440,23 @@
 
 /**
  * @brief Memory barrier types (see "The JSR-133 Cookbook for Compiler Writers").
- * @details Without context sensitive analysis, the most conservative set of barriers
- * must be issued to ensure the Java Memory Model. Thus the recipe is as follows:
- * -# Use StoreStore barrier before volatile store.
- * -# Use StoreLoad barrier after volatile store.
- * -# Use LoadLoad and LoadStore barrier after each volatile load.
+ * @details We define the combined barrier types that are actually required
+ * by the Java Memory Model, rather than using exactly the terminology from
+ * the JSR-133 cookbook.  These should, in many cases, be replaced by acquire/release
+ * primitives.  Note that the JSR-133 cookbook generally does not deal with
+ * store atomicity issues, and the recipes there are not always entirely sufficient.
+ * The current recipe is as follows:
+ * -# Use AnyStore ~= (LoadStore | StoreStore) ~= release barrier before volatile store.
+ * -# Use AnyAny barrier after volatile store.  (StoreLoad is as expensive.)
+ * -# Use LoadAny barrier ~= (LoadLoad | LoadStore) ~= acquire barrierafter each volatile load.
  * -# Use StoreStore barrier after all stores but before return from any constructor whose
- * class has final fields.
+ *    class has final fields.
  */
 enum MemBarrierKind {
-  kLoadStore,
-  kLoadLoad,
+  kAnyStore,
+  kLoadAny,
   kStoreStore,
-  kStoreLoad
+  kAnyAny
 };
 
 std::ostream& operator<<(std::ostream& os, const MemBarrierKind& kind);
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 711743d..d097500 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -96,7 +96,6 @@
     ~0U,
     // 2 = kArm64.     TODO(Arm64): enable optimizations once backend is mature enough.
     (1 << kLoadStoreElimination) |
-    (1 << kLoadHoisting) |
     0,
     // 3 = kThumb2.
     0,
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 04d6898..01e17bf 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -218,7 +218,7 @@
 
     LIR* success_target = NewLIR0(kPseudoTargetLabel);
     lock_success_branch->target = success_target;
-    GenMemBarrier(kLoadLoad);
+    GenMemBarrier(kLoadAny);
   } else {
     // Explicit null-check as slow-path is entered using an IT.
     GenNullCheck(rs_r0, opt_flags);
@@ -240,7 +240,7 @@
     LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
     OpEndIT(it);
     MarkSafepointPC(call_inst);
-    GenMemBarrier(kLoadLoad);
+    GenMemBarrier(kLoadAny);
   }
 }
 
@@ -269,7 +269,7 @@
     MarkPossibleNullPointerException(opt_flags);
     LoadConstantNoClobber(rs_r3, 0);
     LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_r1, rs_r2, NULL);
-    GenMemBarrier(kStoreLoad);
+    GenMemBarrier(kAnyStore);
     Store32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r3);
     LIR* unlock_success_branch = OpUnconditionalBranch(NULL);
 
@@ -298,7 +298,7 @@
     OpRegReg(kOpCmp, rs_r1, rs_r2);
 
     LIR* it = OpIT(kCondEq, "EE");
-    if (GenMemBarrier(kStoreLoad)) {
+    if (GenMemBarrier(kAnyStore)) {
       UpdateIT(it, "TEE");
     }
     Store32Disp/*eq*/(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r3);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 95071d9..f4ea592 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -764,6 +764,7 @@
   UNIMPLEMENTED(FATAL) << "Should not be called.";
 }
 
+// Generate a CAS with memory_order_seq_cst semantics.
 bool ArmMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
   DCHECK_EQ(cu_->instruction_set, kThumb2);
   // Unused - RegLocation rl_src_unsafe = info->args[0];
@@ -818,8 +819,8 @@
     }
   }
 
-  // Release store semantics, get the barrier out of the way.  TODO: revisit
-  GenMemBarrier(kStoreLoad);
+  // Prevent reordering with prior memory operations.
+  GenMemBarrier(kAnyStore);
 
   RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
   RegLocation rl_new_value;
@@ -908,6 +909,9 @@
     FreeTemp(rl_expected.reg);  // Now unneeded.
   }
 
+  // Prevent reordering with subsequent memory operations.
+  GenMemBarrier(kLoadAny);
+
   // result := (tmp1 != 0) ? 0 : 1;
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   OpRegRegImm(kOpRsub, rl_result.reg, r_tmp, 1);
@@ -987,10 +991,10 @@
   int dmb_flavor;
   // TODO: revisit Arm barrier kinds
   switch (barrier_kind) {
-    case kLoadStore: dmb_flavor = kISH; break;
-    case kLoadLoad: dmb_flavor = kISH; break;
+    case kAnyStore: dmb_flavor = kISH; break;
+    case kLoadAny: dmb_flavor = kISH; break;
     case kStoreStore: dmb_flavor = kISHST; break;
-    case kStoreLoad: dmb_flavor = kISH; break;
+    case kAnyAny: dmb_flavor = kISH; break;
     default:
       LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
       dmb_flavor = kSY;  // quiet gcc.
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 2d5e291..9cbf7b8 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -986,10 +986,7 @@
   }
 
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // Without context sensitive analysis, we must issue the most conservative barriers.
-    // In this case, either a load or store may follow so we issue both barriers.
-    GenMemBarrier(kLoadLoad);
-    GenMemBarrier(kLoadStore);
+    GenMemBarrier(kLoadAny);
   }
 
   return load;
@@ -1091,8 +1088,8 @@
 LIR* ArmMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
                                OpSize size, VolatileKind is_volatile) {
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // There might have been a store before this volatile one so insert StoreStore barrier.
-    GenMemBarrier(kStoreStore);
+    // Ensure that prior accesses become visible to other threads first.
+    GenMemBarrier(kAnyStore);
   }
 
   LIR* store;
@@ -1135,8 +1132,9 @@
   }
 
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // A load might follow the volatile store so insert a StoreLoad barrier.
-    GenMemBarrier(kStoreLoad);
+    // Preserve order with respect to any subsequent volatile loads.
+    // We need StoreLoad, but that generally requires the most expensive barrier.
+    GenMemBarrier(kAnyAny);
   }
 
   return store;
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index 7490646..ef4c0de 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -376,6 +376,7 @@
   kST = 0xe,
   kISH = 0xb,
   kISHST = 0xa,
+  kISHLD = 0x9,
   kNSH = 0x7,
   kNSHST = 0x6
 };
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index 56dcbe5..d24f419 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -228,7 +228,7 @@
 
   LIR* success_target = NewLIR0(kPseudoTargetLabel);
   lock_success_branch->target = success_target;
-  GenMemBarrier(kLoadLoad);
+  GenMemBarrier(kLoadAny);
 }
 
 /*
@@ -258,7 +258,7 @@
   Load32Disp(rs_x0, mirror::Object::MonitorOffset().Int32Value(), rs_w2);
   MarkPossibleNullPointerException(opt_flags);
   LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_w1, rs_w2, NULL);
-  GenMemBarrier(kStoreLoad);
+  GenMemBarrier(kAnyStore);
   Store32Disp(rs_x0, mirror::Object::MonitorOffset().Int32Value(), rs_wzr);
   LIR* unlock_success_branch = OpUnconditionalBranch(NULL);
 
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index a7ca685..f7aa39f 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -740,10 +740,16 @@
   int dmb_flavor;
   // TODO: revisit Arm barrier kinds
   switch (barrier_kind) {
-    case kLoadStore: dmb_flavor = kISH; break;
-    case kLoadLoad: dmb_flavor = kISH; break;
+    case kAnyStore: dmb_flavor = kISH; break;
+    case kLoadAny: dmb_flavor = kISH; break;
+        // We conjecture that kISHLD is insufficient.  It is documented
+        // to provide LoadLoad | StoreStore ordering.  But if this were used
+        // to implement volatile loads, we suspect that the lack of store
+        // atomicity on ARM would cause us to allow incorrect results for
+        // the canonical IRIW example.  But we're not sure.
+        // We should be using acquire loads instead.
     case kStoreStore: dmb_flavor = kISHST; break;
-    case kStoreLoad: dmb_flavor = kISH; break;
+    case kAnyAny: dmb_flavor = kISH; break;
     default:
       LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
       dmb_flavor = kSY;  // quiet gcc.
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index ef9dbdd..be3cd8e 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -158,7 +158,6 @@
 }
 
 ResourceMask Arm64Mir2Lir::GetPCUseDefEncoding() const {
-  LOG(FATAL) << "Unexpected call to GetPCUseDefEncoding for Arm64";
   return kEncodeNone;
 }
 
diff --git a/compiler/dex/quick/arm64/utility_arm64.cc b/compiler/dex/quick/arm64/utility_arm64.cc
index 22a4ec4..097fcdc 100644
--- a/compiler/dex/quick/arm64/utility_arm64.cc
+++ b/compiler/dex/quick/arm64/utility_arm64.cc
@@ -1145,10 +1145,8 @@
   LIR* load = LoadBaseDispBody(r_base, displacement, r_dest, size);
 
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // Without context sensitive analysis, we must issue the most conservative barriers.
-    // In this case, either a load or store may follow so we issue both barriers.
-    GenMemBarrier(kLoadLoad);
-    GenMemBarrier(kLoadStore);
+    // TODO: This should generate an acquire load instead of the barrier.
+    GenMemBarrier(kLoadAny);
   }
 
   return load;
@@ -1232,9 +1230,10 @@
 
 LIR* Arm64Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
                                  OpSize size, VolatileKind is_volatile) {
+  // TODO: This should generate a release store and no barriers.
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // There might have been a store before this volatile one so insert StoreStore barrier.
-    GenMemBarrier(kStoreStore);
+    // Ensure that prior accesses become visible to other threads first.
+    GenMemBarrier(kAnyStore);
   }
 
   // StoreBaseDisp() will emit correct insn for atomic store on arm64
@@ -1243,8 +1242,9 @@
   LIR* store = StoreBaseDispBody(r_base, displacement, r_src, size);
 
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // A load might follow the volatile store so insert a StoreLoad barrier.
-    GenMemBarrier(kStoreLoad);
+    // Preserve order with respect to any subsequent volatile loads.
+    // We need StoreLoad, but that generally requires the most expensive barrier.
+    GenMemBarrier(kAnyAny);
   }
 
   return store;
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 6dc019a..c266a3c 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -629,8 +629,12 @@
                                                      field_info.StorageIndex(), r_base));
 
         FreeTemp(r_tmp);
-        // Ensure load of status and load of value don't re-order.
-        GenMemBarrier(kLoadLoad);
+        // Ensure load of status and store of value don't re-order.
+        // TODO: Presumably the actual value store is control-dependent on the status load,
+        // and will thus not be reordered in any case, since stores are never speculated.
+        // Does later code "know" that the class is now initialized?  If so, we still
+        // need the barrier to guard later static loads.
+        GenMemBarrier(kLoadAny);
       }
       FreeTemp(r_method);
     }
@@ -723,7 +727,7 @@
 
         FreeTemp(r_tmp);
         // Ensure load of status and load of value don't re-order.
-        GenMemBarrier(kLoadLoad);
+        GenMemBarrier(kLoadAny);
       }
       FreeTemp(r_method);
     }
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 6c0dfe8..3a30430 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -22,6 +22,7 @@
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "invoke_type.h"
 #include "mirror/array.h"
+#include "mirror/class-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/string.h"
 #include "mir_to_lir-inl.h"
@@ -666,25 +667,23 @@
     }
     case 1:  // Is "this" null? [use kArg1]
       cg->GenNullCheck(cg->TargetRefReg(kArg1), info->opt_flags);
-      // get this->klass_ [use kArg1, set kInvokeTgt]
+      // get this->klass_ [use kArg1, set kArg0]
       cg->LoadRefDisp(cg->TargetRefReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
-                      cg->TargetPtrReg(kInvokeTgt),
+                      cg->TargetRefReg(kArg0),
                       kNotVolatile);
       cg->MarkPossibleNullPointerException(info->opt_flags);
       break;
-    case 2:  // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
-      cg->LoadRefDisp(cg->TargetPtrReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
-                      cg->TargetPtrReg(kInvokeTgt),
-                      kNotVolatile);
+    case 2: {
+      // Get this->klass_.embedded_vtable[method_idx] [usr kArg0, set kArg0]
+      int32_t offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
+          method_idx * sizeof(mirror::Class::VTableEntry);
+      // Load target method from embedded vtable to kArg0 [use kArg0, set kArg0]
+      cg->LoadRefDisp(cg->TargetRefReg(kArg0), offset, cg->TargetRefReg(kArg0), kNotVolatile);
       break;
-    case 3:  // Get target method [use kInvokeTgt, set kArg0]
-      cg->LoadRefDisp(cg->TargetPtrReg(kInvokeTgt),
-                      ObjArray::OffsetOfElement(method_idx).Int32Value(),
-                      cg->TargetRefReg(kArg0),
-                      kNotVolatile);
-      break;
-    case 4:  // Get the compiled code address [uses kArg0, sets kInvokeTgt]
+    }
+    case 3:
       if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
+        // Get the compiled code address [use kArg0, set kInvokeTgt]
         cg->LoadWordDisp(cg->TargetRefReg(kArg0),
                          mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(),
                          cg->TargetPtrReg(kInvokeTgt));
@@ -724,27 +723,24 @@
     }
     case 2:  // Is "this" null? [use kArg1]
       cg->GenNullCheck(cg->TargetRefReg(kArg1), info->opt_flags);
-      // Get this->klass_ [use kArg1, set kInvokeTgt]
+      // Get this->klass_ [use kArg1, set kArg0]
       cg->LoadRefDisp(cg->TargetRefReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
-                      cg->TargetPtrReg(kInvokeTgt),
+                      cg->TargetRefReg(kArg0),
                       kNotVolatile);
       cg->MarkPossibleNullPointerException(info->opt_flags);
       break;
-    case 3:  // Get this->klass_->imtable [use kInvokeTgt, set kInvokeTgt]
-      // NOTE: native pointer.
-      cg->LoadRefDisp(cg->TargetPtrReg(kInvokeTgt), mirror::Class::ImTableOffset().Int32Value(),
-                      cg->TargetPtrReg(kInvokeTgt),
+    case 3: {  // Get target method [use kInvokeTgt, set kArg0]
+      int32_t offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
+          (method_idx % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
+      // Load target method from embedded imtable to kArg0 [use kArg0, set kArg0]
+      cg->LoadRefDisp(cg->TargetRefReg(kArg0), offset,
+                      cg->TargetRefReg(kArg0),
                       kNotVolatile);
       break;
-    case 4:  // Get target method [use kInvokeTgt, set kArg0]
-      // NOTE: native pointer.
-      cg->LoadRefDisp(cg->TargetPtrReg(kInvokeTgt),
-                       ObjArray::OffsetOfElement(method_idx % ClassLinker::kImtSize).Int32Value(),
-                       cg->TargetRefReg(kArg0),
-                       kNotVolatile);
-      break;
-    case 5:  // Get the compiled code address [use kArg0, set kInvokeTgt]
+    }
+    case 4:
       if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
+        // Get the compiled code address [use kArg0, set kInvokeTgt]
         cg->LoadWordDisp(cg->TargetRefReg(kArg0),
                          mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(),
                          cg->TargetPtrReg(kInvokeTgt));
@@ -1711,10 +1707,7 @@
   }
 
   if (is_volatile) {
-    // Without context sensitive analysis, we must issue the most conservative barriers.
-    // In this case, either a load or store may follow so we issue both barriers.
-    GenMemBarrier(kLoadLoad);
-    GenMemBarrier(kLoadStore);
+    GenMemBarrier(kLoadAny);
   }
 
   if (is_long) {
@@ -1737,8 +1730,7 @@
   rl_src_offset = NarrowRegLoc(rl_src_offset);  // ignore high half in info->args[3]
   RegLocation rl_src_value = info->args[4];  // value to store
   if (is_volatile || is_ordered) {
-    // There might have been a store before this volatile one so insert StoreStore barrier.
-    GenMemBarrier(kStoreStore);
+    GenMemBarrier(kAnyStore);
   }
   RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
   RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
@@ -1767,8 +1759,9 @@
   FreeTemp(rl_offset.reg);
 
   if (is_volatile) {
-    // A load might follow the volatile store so insert a StoreLoad barrier.
-    GenMemBarrier(kStoreLoad);
+    // Prevent reordering with a subsequent volatile load.
+    // May also be needed to address store atomicity issues.
+    GenMemBarrier(kAnyAny);
   }
   if (is_object) {
     MarkGCCard(rl_value.reg, rl_object.reg);
diff --git a/compiler/dex/quick/local_optimizations.cc b/compiler/dex/quick/local_optimizations.cc
index b97ff2a..2893157 100644
--- a/compiler/dex/quick/local_optimizations.cc
+++ b/compiler/dex/quick/local_optimizations.cc
@@ -121,20 +121,22 @@
     }
 
     ResourceMask stop_def_reg_mask = this_lir->u.m.def_mask->Without(kEncodeMem);
-    ResourceMask stop_use_reg_mask;
-    if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
+
+    /*
+     * Add pc to the resource mask to prevent this instruction
+     * from sinking past branch instructions. Also take out the memory
+     * region bits since stop_mask is used to check data/control
+     * dependencies.
+     *
+     * Note: on x86(-64) and Arm64 we use the IsBranch bit, as the PC is not exposed.
+     */
+    ResourceMask pc_encoding = GetPCUseDefEncoding();
+    if (pc_encoding == kEncodeNone) {
       // TODO: Stop the abuse of kIsBranch as a bit specification for ResourceMask.
-      stop_use_reg_mask = ResourceMask::Bit(kIsBranch).Union(*this_lir->u.m.use_mask).Without(
-          kEncodeMem);
-    } else {
-      /*
-       * Add pc to the resource mask to prevent this instruction
-       * from sinking past branch instructions. Also take out the memory
-       * region bits since stop_mask is used to check data/control
-       * dependencies.
-       */
-      stop_use_reg_mask = GetPCUseDefEncoding().Union(*this_lir->u.m.use_mask).Without(kEncodeMem);
+      pc_encoding = ResourceMask::Bit(kIsBranch);
     }
+    ResourceMask  stop_use_reg_mask = pc_encoding.Union(*this_lir->u.m.use_mask).
+        Without(kEncodeMem);
 
     for (check_lir = NEXT_LIR(this_lir); check_lir != tail_lir; check_lir = NEXT_LIR(check_lir)) {
       /*
@@ -310,16 +312,17 @@
 
     ResourceMask stop_use_all_mask = *this_lir->u.m.use_mask;
 
-    if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) {
-      /*
-       * Branches for null/range checks are marked with the true resource
-       * bits, and loads to Dalvik registers, constant pools, and non-alias
-       * locations are safe to be hoisted. So only mark the heap references
-       * conservatively here.
-       */
-      if (stop_use_all_mask.HasBit(ResourceMask::kHeapRef)) {
-        stop_use_all_mask.SetBits(GetPCUseDefEncoding());
-      }
+    /*
+     * Branches for null/range checks are marked with the true resource
+     * bits, and loads to Dalvik registers, constant pools, and non-alias
+     * locations are safe to be hoisted. So only mark the heap references
+     * conservatively here.
+     *
+     * Note: on x86(-64) and Arm64 this will add kEncodeNone.
+     * TODO: Sanity check. LoadStoreElimination uses kBranchBit to fake a PC.
+     */
+    if (stop_use_all_mask.HasBit(ResourceMask::kHeapRef)) {
+      stop_use_all_mask.SetBits(GetPCUseDefEncoding());
     }
 
     /* Similar as above, but just check for pure register dependency */
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 129a696..75d3c5d 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -563,10 +563,7 @@
   load = LoadBaseDispBody(r_base, displacement, r_dest, size);
 
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // Without context sensitive analysis, we must issue the most conservative barriers.
-    // In this case, either a load or store may follow so we issue both barriers.
-    GenMemBarrier(kLoadLoad);
-    GenMemBarrier(kLoadStore);
+    GenMemBarrier(kLoadAny);
   }
 
   return load;
@@ -658,8 +655,8 @@
                                 OpSize size, VolatileKind is_volatile) {
   if (is_volatile == kVolatile) {
     DCHECK(size != k64 && size != kDouble);
-    // There might have been a store before this volatile one so insert StoreStore barrier.
-    GenMemBarrier(kStoreStore);
+    // Ensure that prior accesses become visible to other threads first.
+    GenMemBarrier(kAnyStore);
   }
 
   // TODO: base this on target.
@@ -670,8 +667,9 @@
   store = StoreBaseDispBody(r_base, displacement, r_src, size);
 
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // A load might follow the volatile store so insert a StoreLoad barrier.
-    GenMemBarrier(kStoreLoad);
+    // Preserve order with respect to any subsequent volatile loads.
+    // We need StoreLoad, but that generally requires the most expensive barrier.
+    GenMemBarrier(kAnyAny);
   }
 
   return store;
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 87509b6..d1e83c2 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1263,6 +1263,9 @@
     virtual const char* GetTargetInstFmt(int opcode) = 0;
     virtual const char* GetTargetInstName(int opcode) = 0;
     virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) = 0;
+
+    // Note: This may return kEncodeNone on architectures that do not expose a PC. The caller must
+    //       take care of this.
     virtual ResourceMask GetPCUseDefEncoding() const = 0;
     virtual uint64_t GetTargetInstFlags(int opcode) = 0;
     virtual size_t GetInsnSize(LIR* lir) = 0;
diff --git a/compiler/dex/quick/resource_mask.h b/compiler/dex/quick/resource_mask.h
index 12ce98a..436cdb5 100644
--- a/compiler/dex/quick/resource_mask.h
+++ b/compiler/dex/quick/resource_mask.h
@@ -63,6 +63,11 @@
   ResourceMask(const ResourceMask& other) = default;
   ResourceMask& operator=(const ResourceMask& other) = default;
 
+  // Comparable by content.
+  bool operator==(const ResourceMask& other) {
+    return masks_[0] == other.masks_[0] && masks_[1] == other.masks_[1];
+  }
+
   static constexpr ResourceMask RawMask(uint64_t mask1, uint64_t mask2) {
     return ResourceMask(mask1, mask2);
   }
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index f1166f6..1c63da4 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -19,6 +19,7 @@
 #include "codegen_x86.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
+#include "mirror/art_method.h"
 #include "mirror/array.h"
 #include "x86_lir.h"
 
@@ -861,7 +862,7 @@
 
     // After a store we need to insert barrier in case of potential load. Since the
     // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
-    GenMemBarrier(kStoreLoad);
+    GenMemBarrier(kAnyAny);
 
     FreeTemp(rs_r0q);
   } else if (is_long) {
@@ -913,10 +914,11 @@
     }
     NewLIR4(kX86LockCmpxchg64A, rs_obj.GetReg(), rs_off.GetReg(), 0, 0);
 
-    // After a store we need to insert barrier in case of potential load. Since the
-    // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
-    GenMemBarrier(kStoreLoad);
-
+    // After a store we need to insert barrier to prevent reordering with either
+    // earlier or later memory accesses.  Since
+    // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated,
+    // and it will be associated with the cmpxchg instruction, preventing both.
+    GenMemBarrier(kAnyAny);
 
     if (push_si) {
       FreeTemp(rs_rSI);
@@ -954,9 +956,11 @@
     LoadValueDirect(rl_src_expected, rs_r0);
     NewLIR5(kX86LockCmpxchgAR, rl_object.reg.GetReg(), rl_offset.reg.GetReg(), 0, 0, rl_new_value.reg.GetReg());
 
-    // After a store we need to insert barrier in case of potential load. Since the
-    // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated.
-    GenMemBarrier(kStoreLoad);
+    // After a store we need to insert barrier to prevent reordering with either
+    // earlier or later memory accesses.  Since
+    // locked cmpxchg has full barrier semantics, only a scheduling barrier will be generated,
+    // and it will be associated with the cmpxchg instruction, preventing both.
+    GenMemBarrier(kAnyAny);
 
     FreeTemp(rs_r0);
   }
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 1ebbbbd..0083128 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -246,11 +246,6 @@
 }
 
 ResourceMask X86Mir2Lir::GetPCUseDefEncoding() const {
-  /*
-   * FIXME: might make sense to use a virtual resource encoding bit for pc.  Might be
-   * able to clean up some of the x86/Arm_Mips differences
-   */
-  LOG(FATAL) << "Unexpected call to GetPCUseDefEncoding for x86";
   return kEncodeNone;
 }
 
@@ -582,11 +577,11 @@
 
   bool ret = false;
   /*
-   * According to the JSR-133 Cookbook, for x86 only StoreLoad barriers need memory fence. All other barriers
-   * (LoadLoad, LoadStore, StoreStore) are nops due to the x86 memory model. For those cases, all we need
-   * to ensure is that there is a scheduling barrier in place.
+   * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
+   * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
+   * For those cases, all we need to ensure is that there is a scheduling barrier in place.
    */
-  if (barrier_kind == kStoreLoad) {
+  if (barrier_kind == kAnyAny) {
     // If no LIR exists already that can be used a barrier, then generate an mfence.
     if (mem_barrier == nullptr) {
       mem_barrier = NewLIR0(kX86Mfence);
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 5c7c91b..045e58e 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -762,10 +762,7 @@
                                   size);
 
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // Without context sensitive analysis, we must issue the most conservative barriers.
-    // In this case, either a load or store may follow so we issue both barriers.
-    GenMemBarrier(kLoadLoad);
-    GenMemBarrier(kLoadStore);
+    GenMemBarrier(kLoadAny);  // Only a scheduling barrier.
   }
 
   return load;
@@ -863,8 +860,7 @@
 LIR* X86Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size,
                                VolatileKind is_volatile) {
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // There might have been a store before this volatile one so insert StoreStore barrier.
-    GenMemBarrier(kStoreStore);
+    GenMemBarrier(kAnyStore);  // Only a scheduling barrier.
   }
 
   // StoreBaseDisp() will emit correct insn for atomic store on x86
@@ -873,8 +869,9 @@
   LIR* store = StoreBaseIndexedDisp(r_base, RegStorage::InvalidReg(), 0, displacement, r_src, size);
 
   if (UNLIKELY(is_volatile == kVolatile)) {
-    // A load might follow the volatile store so insert a StoreLoad barrier.
-    GenMemBarrier(kStoreLoad);
+    // A volatile load might follow the volatile store so insert a StoreLoad barrier.
+    // This does require a fence, even on x86.
+    GenMemBarrier(kAnyAny);
   }
 
   return store;
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 324f717..99fcc26 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -18,6 +18,7 @@
 #define ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
 
 #include "compiler_driver.h"
+
 #include "dex/compiler_ir.h"
 #include "mirror/art_field.h"
 #include "mirror/art_field-inl.h"
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 9bf5135..4b4d0d0 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -25,6 +25,7 @@
 #include "base/stl_util.h"
 #include "base/timing_logger.h"
 #include "class_linker.h"
+#include "compiled_class.h"
 #include "compiler.h"
 #include "compiler_driver-inl.h"
 #include "dex_compilation_unit.h"
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 9903421..ae709f8 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -24,7 +24,6 @@
 #include "base/mutex.h"
 #include "base/timing_logger.h"
 #include "class_reference.h"
-#include "compiled_class.h"
 #include "compiled_method.h"
 #include "compiler.h"
 #include "dex_file.h"
@@ -32,6 +31,7 @@
 #include "instruction_set.h"
 #include "invoke_type.h"
 #include "method_reference.h"
+#include "mirror/class.h"  // For mirror::Class::Status.
 #include "os.h"
 #include "profiler.h"
 #include "runtime.h"
@@ -46,6 +46,7 @@
 class MethodVerifier;
 }  // namespace verifier
 
+class CompiledClass;
 class CompilerOptions;
 class DexCompilationUnit;
 class DexFileToMethodInlinerMap;
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index acfa607..38b4100 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -630,11 +630,33 @@
         mirror::Reference::ReferentOffset(), image_writer_->GetImageAddress(ref->GetReferent()));
   }
 
- private:
+ protected:
   ImageWriter* const image_writer_;
   mirror::Object* const copy_;
 };
 
+class FixupClassVisitor FINAL : public FixupVisitor {
+ public:
+  FixupClassVisitor(ImageWriter* image_writer, Object* copy) : FixupVisitor(image_writer, copy) {
+  }
+
+  void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
+    DCHECK(obj->IsClass());
+    FixupVisitor::operator()(obj, offset, false);
+
+    if (offset.Uint32Value() < mirror::Class::EmbeddedVTableOffset().Uint32Value()) {
+      return;
+    }
+  }
+
+  void operator()(mirror::Class* /*klass*/, mirror::Reference* ref) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+    LOG(FATAL) << "Reference not expected here.";
+  }
+};
+
 void ImageWriter::FixupObject(Object* orig, Object* copy) {
   DCHECK(orig != nullptr);
   DCHECK(copy != nullptr);
@@ -646,13 +668,68 @@
       DCHECK_EQ(copy->GetReadBarrierPointer(), GetImageAddress(orig));
     }
   }
-  FixupVisitor visitor(this, copy);
-  orig->VisitReferences<true /*visit class*/>(visitor, visitor);
+  if (orig->IsClass() && orig->AsClass()->ShouldHaveEmbeddedImtAndVTable()) {
+    FixupClassVisitor visitor(this, copy);
+    orig->VisitReferences<true /*visit class*/>(visitor, visitor);
+  } else {
+    FixupVisitor visitor(this, copy);
+    orig->VisitReferences<true /*visit class*/>(visitor, visitor);
+  }
   if (orig->IsArtMethod<kVerifyNone>()) {
     FixupMethod(orig->AsArtMethod<kVerifyNone>(), down_cast<ArtMethod*>(copy));
   }
 }
 
+const byte* ImageWriter::GetQuickCode(mirror::ArtMethod* method, bool* quick_is_interpreted) {
+  DCHECK(!method->IsResolutionMethod() && !method->IsImtConflictMethod() &&
+         !method->IsAbstract()) << PrettyMethod(method);
+
+  // Use original code if it exists. Otherwise, set the code pointer to the resolution
+  // trampoline.
+
+  // Quick entrypoint:
+  const byte* quick_code = GetOatAddress(method->GetQuickOatCodeOffset());
+  *quick_is_interpreted = false;
+  if (quick_code != nullptr &&
+      (!method->IsStatic() || method->IsConstructor() || method->GetDeclaringClass()->IsInitialized())) {
+    // We have code for a non-static or initialized method, just use the code.
+  } else if (quick_code == nullptr && method->IsNative() &&
+      (!method->IsStatic() || method->GetDeclaringClass()->IsInitialized())) {
+    // Non-static or initialized native method missing compiled code, use generic JNI version.
+    quick_code = GetOatAddress(quick_generic_jni_trampoline_offset_);
+  } else if (quick_code == nullptr && !method->IsNative()) {
+    // We don't have code at all for a non-native method, use the interpreter.
+    quick_code = GetOatAddress(quick_to_interpreter_bridge_offset_);
+    *quick_is_interpreted = true;
+  } else {
+    CHECK(!method->GetDeclaringClass()->IsInitialized());
+    // We have code for a static method, but need to go through the resolution stub for class
+    // initialization.
+    quick_code = GetOatAddress(quick_resolution_trampoline_offset_);
+  }
+  return quick_code;
+}
+
+const byte* ImageWriter::GetQuickEntryPoint(mirror::ArtMethod* method) {
+  // Calculate the quick entry point following the same logic as FixupMethod() below.
+  // The resolution method has a special trampoline to call.
+  if (UNLIKELY(method == Runtime::Current()->GetResolutionMethod())) {
+    return GetOatAddress(quick_resolution_trampoline_offset_);
+  } else if (UNLIKELY(method == Runtime::Current()->GetImtConflictMethod())) {
+    return GetOatAddress(quick_imt_conflict_trampoline_offset_);
+  } else {
+    // We assume all methods have code. If they don't currently then we set them to the use the
+    // resolution trampoline. Abstract methods never have code and so we need to make sure their
+    // use results in an AbstractMethodError. We use the interpreter to achieve this.
+    if (UNLIKELY(method->IsAbstract())) {
+      return GetOatAddress(quick_to_interpreter_bridge_offset_);
+    } else {
+      bool quick_is_interpreted;
+      return GetQuickCode(method, &quick_is_interpreted);
+    }
+  }
+}
+
 void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) {
   // OatWriter replaces the code_ with an offset value. Here we re-adjust to a pointer relative to
   // oat_begin_
@@ -674,29 +751,8 @@
       copy->SetEntryPointFromInterpreter<kVerifyNone>(reinterpret_cast<EntryPointFromInterpreter*>
           (const_cast<byte*>(GetOatAddress(interpreter_to_interpreter_bridge_offset_))));
     } else {
-      // Use original code if it exists. Otherwise, set the code pointer to the resolution
-      // trampoline.
-
-      // Quick entrypoint:
-      const byte* quick_code = GetOatAddress(orig->GetQuickOatCodeOffset());
-      bool quick_is_interpreted = false;
-      if (quick_code != nullptr &&
-          (!orig->IsStatic() || orig->IsConstructor() || orig->GetDeclaringClass()->IsInitialized())) {
-        // We have code for a non-static or initialized method, just use the code.
-      } else if (quick_code == nullptr && orig->IsNative() &&
-          (!orig->IsStatic() || orig->GetDeclaringClass()->IsInitialized())) {
-        // Non-static or initialized native method missing compiled code, use generic JNI version.
-        quick_code = GetOatAddress(quick_generic_jni_trampoline_offset_);
-      } else if (quick_code == nullptr && !orig->IsNative()) {
-        // We don't have code at all for a non-native method, use the interpreter.
-        quick_code = GetOatAddress(quick_to_interpreter_bridge_offset_);
-        quick_is_interpreted = true;
-      } else {
-        CHECK(!orig->GetDeclaringClass()->IsInitialized());
-        // We have code for a static method, but need to go through the resolution stub for class
-        // initialization.
-        quick_code = GetOatAddress(quick_resolution_trampoline_offset_);
-      }
+      bool quick_is_interpreted;
+      const byte* quick_code = GetQuickCode(orig, &quick_is_interpreted);
       copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(quick_code);
 
       // Portable entrypoint:
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 2bcb41e..cf5bc93 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -149,6 +149,13 @@
   void FixupObject(mirror::Object* orig, mirror::Object* copy)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Get quick code for non-resolution/imt_conflict/abstract method.
+  const byte* GetQuickCode(mirror::ArtMethod* method, bool* quick_is_interpreted)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  const byte* GetQuickEntryPoint(mirror::ArtMethod* method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Patches references in OatFile to expect runtime addresses.
   void PatchOatCodeAndMethods(File* elf_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -192,6 +199,7 @@
   uint32_t quick_to_interpreter_bridge_offset_;
 
   friend class FixupVisitor;
+  friend class FixupClassVisitor;
   DISALLOW_COPY_AND_ASSIGN(ImageWriter);
 };
 
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 3bbb723..dec84f1 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -28,6 +28,7 @@
 #include "driver/compiler_driver.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "jni_internal.h"
+#include "mirror/art_method.h"
 #include "utils/assembler.h"
 #include "utils/managed_register.h"
 #include "utils/arm/managed_register_arm.h"
diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc
index f8dca66..902f8dd 100644
--- a/compiler/llvm/gbc_expander.cc
+++ b/compiler/llvm/gbc_expander.cc
@@ -1648,7 +1648,7 @@
     field_value = SignOrZeroExtendCat1Types(field_value, field_jty);
 
     if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kLoadLoad);
+      irb_.CreateMemoryBarrier(art::kLoadAny);
     }
   }
 
@@ -1702,7 +1702,7 @@
     DCHECK_GE(field_offset.Int32Value(), 0);
 
     if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kStoreStore);
+      irb_.CreateMemoryBarrier(art::kAnyStore);
     }
 
     llvm::PointerType* field_type =
@@ -1717,7 +1717,7 @@
     irb_.CreateStore(new_value, field_addr, kTBAAHeapInstance, field_jty);
 
     if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kLoadLoad);
+      irb_.CreateMemoryBarrier(art::kAnyAny);
     }
 
     if (field_jty == kObject) {  // If put an object, mark the GC card table.
@@ -1870,7 +1870,7 @@
   phi->addIncoming(loaded_storage_object_addr, block_after_load_static);
 
   // Ensure load of status and load of value don't re-order.
-  irb_.CreateMemoryBarrier(art::kLoadLoad);
+  irb_.CreateMemoryBarrier(art::kLoadAny);
 
   return phi;
 }
@@ -1948,7 +1948,7 @@
     static_field_value = SignOrZeroExtendCat1Types(static_field_value, field_jty);
 
     if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kLoadLoad);
+      irb_.CreateMemoryBarrier(art::kLoadAny);
     }
   }
 
@@ -2025,7 +2025,7 @@
     }
 
     if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kStoreStore);
+      irb_.CreateMemoryBarrier(art::kAnyStore);
     }
 
     llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset.Int32Value());
@@ -2038,7 +2038,7 @@
     irb_.CreateStore(new_value, static_field_addr, kTBAAHeapStatic, field_jty);
 
     if (is_volatile) {
-      irb_.CreateMemoryBarrier(art::kStoreLoad);
+      irb_.CreateMemoryBarrier(art::kAnyAny);
     }
 
     if (field_jty == kObject) {  // If put an object, mark the GC card table.
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 73f4ba1..63a3c8c 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -22,6 +22,7 @@
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
+#include "compiled_class.h"
 #include "dex_file-inl.h"
 #include "dex/verification_results.h"
 #include "gc/space/space.h"
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 631d538..0fa1a96 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -984,7 +984,7 @@
   const void* GetQuickOatCodeBegin(mirror::ArtMethod* m)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     const void* quick_code = m->GetEntryPointFromQuickCompiledCode();
-    if (quick_code == GetQuickResolutionTrampoline(Runtime::Current()->GetClassLinker())) {
+    if (quick_code == Runtime::Current()->GetClassLinker()->GetQuickResolutionTrampoline()) {
       quick_code = oat_dumper_->GetQuickOatCode(m);
     }
     if (oat_dumper_->GetInstructionSet() == kThumb2) {
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 7f5cf0c..b0c1a9c 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -309,10 +309,10 @@
   LIBART_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
 endif
 
-ifeq ($(MALLOC_IMPL),jemalloc)
-  LIBART_CFLAGS += -DUSE_JEMALLOC
-else
+ifeq ($(MALLOC_IMPL),dlmalloc)
   LIBART_CFLAGS += -DUSE_DLMALLOC
+else
+  LIBART_CFLAGS += -DUSE_JEMALLOC
 endif
 
 # $(1): target or host
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 3fa09cb..cf68c65 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -15,6 +15,7 @@
  */
 
 #include "entrypoints/interpreter/interpreter_entrypoints.h"
+#include "entrypoints/jni/jni_entrypoints.h"
 #include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc
index c19b79e..0c33d9c 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -15,6 +15,7 @@
  */
 
 #include "entrypoints/interpreter/interpreter_entrypoints.h"
+#include "entrypoints/jni/jni_entrypoints.h"
 #include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/entrypoint_utils.h"
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 70a9619..7a2e961 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "entrypoints/interpreter/interpreter_entrypoints.h"
+#include "entrypoints/jni/jni_entrypoints.h"
 #include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index eb490eb..ce8faea 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -1739,8 +1739,8 @@
   // Sanity check: check that there is a conflict for List.contains in ArrayList.
 
   mirror::Class* arraylist_class = soa.Decode<mirror::Class*>(arraylist_jclass);
-  mirror::ArtMethod* m = arraylist_class->GetImTable()->Get(
-      inf_contains->GetDexMethodIndex() % ClassLinker::kImtSize);
+  mirror::ArtMethod* m = arraylist_class->GetEmbeddedImTableEntry(
+      inf_contains->GetDexMethodIndex() % mirror::Class::kImtSize);
 
   if (!m->IsImtConflictMethod()) {
     LOG(WARNING) << "Test is meaningless, no IMT conflict in setup: " <<
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index b217cd6..a072996 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "entrypoints/interpreter/interpreter_entrypoints.h"
+#include "entrypoints/jni/jni_entrypoints.h"
 #include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index 204d52c..35a0cf4 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "entrypoints/interpreter/interpreter_entrypoints.h"
+#include "entrypoints/jni/jni_entrypoints.h"
 #include "entrypoints/portable/portable_entrypoints.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
@@ -27,8 +29,8 @@
                                                   const DexFile::CodeItem* code_item,
                                                   ShadowFrame* shadow_frame, JValue* result);
 extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
-                                           const DexFile::CodeItem* code_item,
-                                           ShadowFrame* shadow_frame, JValue* result);
+                                                   const DexFile::CodeItem* code_item,
+                                                   ShadowFrame* shadow_frame, JValue* result);
 
 // Portable entrypoints.
 extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 7f7226c..885fbfd 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -18,7 +18,7 @@
 
 MACRO0(SETUP_FP_CALLEE_SAVE_FRAME)
     // Create space for ART FP callee-saved registers
-    subq LITERAL(4 * 8), %rsp
+    subq MACRO_LITERAL(4 * 8), %rsp
     CFI_ADJUST_CFA_OFFSET(4 * 8)
     movq %xmm12, 0(%rsp)
     movq %xmm13, 8(%rsp)
@@ -32,7 +32,7 @@
     movq 8(%rsp), %xmm13
     movq 16(%rsp), %xmm14
     movq 24(%rsp), %xmm15
-    addq LITERAL(4 * 8), %rsp
+    addq MACRO_LITERAL(4 * 8), %rsp
     CFI_ADJUST_CFA_OFFSET(- 4 * 8)
 END_MACRO
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 860cbd2..1436810 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -55,6 +55,7 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/proxy.h"
 #include "mirror/stack_trace_element.h"
+#include "mirror/string-inl.h"
 #include "object_utils.h"
 #include "os.h"
 #include "runtime.h"
@@ -207,7 +208,8 @@
   heap->IncrementDisableMovingGC(self);
   StackHandleScope<64> hs(self);  // 64 is picked arbitrarily.
   Handle<mirror::Class> java_lang_Class(hs.NewHandle(down_cast<mirror::Class*>(
-      heap->AllocNonMovableObject<true>(self, nullptr, sizeof(mirror::ClassClass),
+      heap->AllocNonMovableObject<true>(self, nullptr,
+                                        mirror::Class::ClassClassSize(),
                                         VoidFunctor()))));
   CHECK(java_lang_Class.Get() != NULL);
   mirror::Class::SetClassClass(java_lang_Class.Get());
@@ -215,43 +217,44 @@
   if (kUseBakerOrBrooksReadBarrier) {
     java_lang_Class->AssertReadBarrierPointer();
   }
-  java_lang_Class->SetClassSize(sizeof(mirror::ClassClass));
+  java_lang_Class->SetClassSize(mirror::Class::ClassClassSize());
   heap->DecrementDisableMovingGC(self);
   // AllocClass(mirror::Class*) can now be used
 
   // Class[] is used for reflection support.
-  Handle<mirror::Class> class_array_class(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  Handle<mirror::Class> class_array_class(hs.NewHandle(
+     AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray<mirror::Class>::ClassSize())));
   class_array_class->SetComponentType(java_lang_Class.Get());
 
   // java_lang_Object comes next so that object_array_class can be created.
-  Handle<mirror::Class> java_lang_Object(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  Handle<mirror::Class> java_lang_Object(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(), mirror::Object::ClassSize())));
   CHECK(java_lang_Object.Get() != NULL);
   // backfill Object as the super class of Class.
   java_lang_Class->SetSuperClass(java_lang_Object.Get());
   java_lang_Object->SetStatus(mirror::Class::kStatusLoaded, self);
 
   // Object[] next to hold class roots.
-  Handle<mirror::Class> object_array_class(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  Handle<mirror::Class> object_array_class(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray<mirror::Object>::ClassSize())));
   object_array_class->SetComponentType(java_lang_Object.Get());
 
-  // Setup the char class to be used for char[].
-  Handle<mirror::Class> char_class(hs.NewHandle(AllocClass(self, java_lang_Class.Get(),
-                                                           sizeof(mirror::Class))));
+  // Setup the char (primitive) class to be used for char[].
+  Handle<mirror::Class> char_class(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(), mirror::Class::PrimitiveClassSize())));
 
   // Setup the char[] class to be used for String.
-  Handle<mirror::Class> char_array_class(hs.NewHandle(AllocClass(self, java_lang_Class.Get(),
-                                                                 sizeof(mirror::Class))));
+  Handle<mirror::Class> char_array_class(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(),
+                 mirror::Array::ClassSize())));
   char_array_class->SetComponentType(char_class.Get());
   mirror::CharArray::SetArrayClass(char_array_class.Get());
 
   // Setup String.
-  Handle<mirror::Class> java_lang_String(hs.NewHandle(AllocClass(self, java_lang_Class.Get(),
-                                                                 sizeof(mirror::StringClass))));
+  Handle<mirror::Class> java_lang_String(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize())));
   mirror::String::SetClass(java_lang_String.Get());
-  java_lang_String->SetObjectSize(sizeof(mirror::String));
+  java_lang_String->SetObjectSize(mirror::String::InstanceSize());
   java_lang_String->SetStatus(mirror::Class::kStatusResolved, self);
 
   // Create storage for root classes, save away our work so far (requires descriptors).
@@ -279,8 +282,8 @@
   array_iftable_ = AllocIfTable(self, 2);
 
   // Create int array type for AllocDexCache (done in AppendToBootClassPath).
-  Handle<mirror::Class> int_array_class(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  Handle<mirror::Class> int_array_class(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize())));
   int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt));
   mirror::IntArray::SetArrayClass(int_array_class.Get());
   SetClassRoot(kIntArrayClass, int_array_class.Get());
@@ -288,44 +291,47 @@
   // now that these are registered, we can use AllocClass() and AllocObjectArray
 
   // Set up DexCache. This cannot be done later since AppendToBootClassPath calls AllocDexCache.
-  Handle<mirror::Class> java_lang_DexCache(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::DexCacheClass))));
+  Handle<mirror::Class> java_lang_DexCache(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize())));
   SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get());
-  java_lang_DexCache->SetObjectSize(sizeof(mirror::DexCache));
+  java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize());
   java_lang_DexCache->SetStatus(mirror::Class::kStatusResolved, self);
 
   // Constructor, Field, Method, and AbstractMethod are necessary so
   // that FindClass can link members.
-  Handle<mirror::Class> java_lang_reflect_ArtField(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::ArtFieldClass))));
+  Handle<mirror::Class> java_lang_reflect_ArtField(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(), mirror::ArtField::ClassSize())));
   CHECK(java_lang_reflect_ArtField.Get() != NULL);
-  java_lang_reflect_ArtField->SetObjectSize(sizeof(mirror::ArtField));
+  java_lang_reflect_ArtField->SetObjectSize(mirror::ArtField::InstanceSize());
   SetClassRoot(kJavaLangReflectArtField, java_lang_reflect_ArtField.Get());
   java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusResolved, self);
   mirror::ArtField::SetClass(java_lang_reflect_ArtField.Get());
 
-  Handle<mirror::Class> java_lang_reflect_ArtMethod(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::ArtMethodClass))));
+  Handle<mirror::Class> java_lang_reflect_ArtMethod(hs.NewHandle(
+    AllocClass(self, java_lang_Class.Get(), mirror::ArtMethod::ClassSize())));
   CHECK(java_lang_reflect_ArtMethod.Get() != NULL);
-  java_lang_reflect_ArtMethod->SetObjectSize(sizeof(mirror::ArtMethod));
+  java_lang_reflect_ArtMethod->SetObjectSize(mirror::ArtMethod::InstanceSize());
   SetClassRoot(kJavaLangReflectArtMethod, java_lang_reflect_ArtMethod.Get());
   java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusResolved, self);
 
   mirror::ArtMethod::SetClass(java_lang_reflect_ArtMethod.Get());
 
   // Set up array classes for string, field, method
-  Handle<mirror::Class> object_array_string(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  Handle<mirror::Class> object_array_string(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(),
+                 mirror::ObjectArray<mirror::String>::ClassSize())));
   object_array_string->SetComponentType(java_lang_String.Get());
   SetClassRoot(kJavaLangStringArrayClass, object_array_string.Get());
 
-  Handle<mirror::Class> object_array_art_method(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  Handle<mirror::Class> object_array_art_method(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(),
+                 mirror::ObjectArray<mirror::ArtMethod>::ClassSize())));
   object_array_art_method->SetComponentType(java_lang_reflect_ArtMethod.Get());
   SetClassRoot(kJavaLangReflectArtMethodArrayClass, object_array_art_method.Get());
 
-  Handle<mirror::Class> object_array_art_field(
-      hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+  Handle<mirror::Class> object_array_art_field(hs.NewHandle(
+      AllocClass(self, java_lang_Class.Get(),
+                 mirror::ObjectArray<mirror::ArtField>::ClassSize())));
   object_array_art_field->SetComponentType(java_lang_reflect_ArtField.Get());
   SetClassRoot(kJavaLangReflectArtFieldArrayClass, object_array_art_field.Get());
 
@@ -359,16 +365,19 @@
   java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self);
   mirror::Class* Object_class = FindSystemClass(self, "Ljava/lang/Object;");
   CHECK_EQ(java_lang_Object.Get(), Object_class);
-  CHECK_EQ(java_lang_Object->GetObjectSize(), sizeof(mirror::Object));
+  CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize());
   java_lang_String->SetStatus(mirror::Class::kStatusNotReady, self);
   mirror::Class* String_class = FindSystemClass(self, "Ljava/lang/String;");
-  CHECK_EQ(java_lang_String.Get(), String_class);
-  CHECK_EQ(java_lang_String->GetObjectSize(), sizeof(mirror::String));
+  std::ostringstream os1, os2;
+  java_lang_String->DumpClass(os1, mirror::Class::kDumpClassFullDetail);
+  String_class->DumpClass(os2, mirror::Class::kDumpClassFullDetail);
+  CHECK_EQ(java_lang_String.Get(), String_class) << os1.str() << "\n\n" << os2.str();
+  CHECK_EQ(java_lang_String->GetObjectSize(), mirror::String::InstanceSize());
   java_lang_DexCache->SetStatus(mirror::Class::kStatusNotReady, self);
   mirror::Class* DexCache_class = FindSystemClass(self, "Ljava/lang/DexCache;");
   CHECK_EQ(java_lang_String.Get(), String_class);
   CHECK_EQ(java_lang_DexCache.Get(), DexCache_class);
-  CHECK_EQ(java_lang_DexCache->GetObjectSize(), sizeof(mirror::DexCache));
+  CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize());
 
   // Setup the primitive array type classes - can't be done until Object has a vtable.
   SetClassRoot(kBooleanArrayClass, FindSystemClass(self, "[Z"));
@@ -476,7 +485,7 @@
 
   // Setup the ClassLoader, verifying the object_size_.
   mirror::Class* java_lang_ClassLoader = FindSystemClass(self, "Ljava/lang/ClassLoader;");
-  CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), sizeof(mirror::ClassLoader));
+  CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), mirror::ClassLoader::InstanceSize());
   SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader);
 
   // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and
@@ -1402,36 +1411,11 @@
   return dex_cache.Get();
 }
 
-// Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore
-// fence.
-class InitializeClassVisitor {
- public:
-  explicit InitializeClassVisitor(uint32_t class_size) : class_size_(class_size) {
-  }
-
-  void operator()(mirror::Object* obj, size_t usable_size) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK_LE(class_size_, usable_size);
-    // Avoid AsClass as object is not yet in live bitmap or allocation stack.
-    mirror::Class* klass = down_cast<mirror::Class*>(obj);
-    // DCHECK(klass->IsClass());
-    klass->SetClassSize(class_size_);
-    klass->SetPrimitiveType(Primitive::kPrimNot);  // Default to not being primitive.
-    klass->SetDexClassDefIndex(DexFile::kDexNoIndex16);  // Default to no valid class def index.
-    klass->SetDexTypeIndex(DexFile::kDexNoIndex16);  // Default to no valid type index.
-  }
-
- private:
-  const uint32_t class_size_;
-
-  DISALLOW_COPY_AND_ASSIGN(InitializeClassVisitor);
-};
-
 mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Class,
                                        uint32_t class_size) {
   DCHECK_GE(class_size, sizeof(mirror::Class));
   gc::Heap* heap = Runtime::Current()->GetHeap();
-  InitializeClassVisitor visitor(class_size);
+  mirror::Class::InitializeClassVisitor visitor(class_size);
   mirror::Object* k = kMovingClasses ?
       heap->AllocObject<true>(self, java_lang_Class, class_size, visitor) :
       heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size, visitor);
@@ -1462,9 +1446,33 @@
       self, GetClassRoot(kJavaLangStackTraceElementArrayClass), length);
 }
 
-static mirror::Class* EnsureResolved(Thread* self, mirror::Class* klass)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+mirror::Class* ClassLinker::EnsureResolved(Thread* self, const char* descriptor,
+                                           mirror::Class* klass) {
   DCHECK(klass != NULL);
+
+  // For temporary classes we must wait for them to be retired.
+  if (init_done_ && klass->IsTemp()) {
+    CHECK(!klass->IsResolved());
+    if (klass->IsErroneous()) {
+      ThrowEarlierClassFailure(klass);
+      return nullptr;
+    }
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_class(hs.NewHandle(klass));
+    ObjectLock<mirror::Class> lock(self, h_class);
+    // Loop and wait for the resolving thread to retire this class.
+    while (!h_class->IsRetired() && !h_class->IsErroneous()) {
+      lock.WaitIgnoringInterrupts();
+    }
+    if (h_class->IsErroneous()) {
+      ThrowEarlierClassFailure(h_class.Get());
+      return nullptr;
+    }
+    CHECK(h_class->IsRetired());
+    // Get the updated class from class table.
+    klass = LookupClass(descriptor, h_class.Get()->GetClassLoader());
+  }
+
   // Wait for the class if it has not already been linked.
   if (!klass->IsResolved() && !klass->IsErroneous()) {
     StackHandleScope<1> hs(self);
@@ -1481,6 +1489,7 @@
       lock.WaitIgnoringInterrupts();
     }
   }
+
   if (klass->IsErroneous()) {
     ThrowEarlierClassFailure(klass);
     return nullptr;
@@ -1504,7 +1513,7 @@
   // Find the class in the loaded classes table.
   mirror::Class* klass = LookupClass(descriptor, class_loader.Get());
   if (klass != NULL) {
-    return EnsureResolved(self, klass);
+    return EnsureResolved(self, descriptor, klass);
   }
   // Class is not yet loaded.
   if (descriptor[0] == '[') {
@@ -1578,8 +1587,10 @@
                                         const DexFile& dex_file,
                                         const DexFile::ClassDef& dex_class_def) {
   Thread* self = Thread::Current();
-  StackHandleScope<2> hs(self);
+  StackHandleScope<3> hs(self);
   auto klass = hs.NewHandle<mirror::Class>(nullptr);
+  bool should_allocate = false;
+
   // Load the class from the dex file.
   if (UNLIKELY(!init_done_)) {
     // finish up init of hand crafted class_roots_
@@ -1596,10 +1607,18 @@
     } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtMethod;") == 0) {
       klass.Assign(GetClassRoot(kJavaLangReflectArtMethod));
     } else {
-      klass.Assign(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
+      should_allocate = true;
     }
   } else {
-    klass.Assign(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
+    should_allocate = true;
+  }
+
+  if (should_allocate) {
+    // Allocate a class with the status of not ready.
+    // Interface object should get the right size here. Regular class will
+    // figure out the right size later and be replaced with one of the right
+    // size when the class becomes resolved.
+    klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
   }
   if (UNLIKELY(klass.Get() == NULL)) {
     CHECK(self->IsExceptionPending());  // Expect an OOME.
@@ -1614,13 +1633,15 @@
   }
   ObjectLock<mirror::Class> lock(self, klass);
   klass->SetClinitThreadId(self->GetTid());
+
   // Add the newly loaded class to the loaded classes table.
   mirror::Class* existing = InsertClass(descriptor, klass.Get(), Hash(descriptor));
   if (existing != NULL) {
     // We failed to insert because we raced with another thread. Calling EnsureResolved may cause
     // this thread to block.
-    return EnsureResolved(self, existing);
+    return EnsureResolved(self, descriptor, existing);
   }
+
   // Finish loading (if necessary) by finding parents
   CHECK(!klass->IsLoaded());
   if (!LoadSuperAndInterfaces(klass, dex_file)) {
@@ -1633,12 +1654,17 @@
   CHECK(!klass->IsResolved());
   // TODO: Use fast jobjects?
   auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);
-  if (!LinkClass(self, klass, interfaces)) {
+
+  mirror::Class* new_class = nullptr;
+  if (!LinkClass(self, descriptor, klass, interfaces, &new_class)) {
     // Linking failed.
     klass->SetStatus(mirror::Class::kStatusError, self);
     return NULL;
   }
-  CHECK(klass->IsResolved());
+  CHECK(new_class != nullptr) << descriptor;
+  CHECK(new_class->IsResolved()) << descriptor;
+
+  Handle<mirror::Class> new_class_h(hs.NewHandle(new_class));
 
   /*
    * We send CLASS_PREPARE events to the debugger from here.  The
@@ -1651,14 +1677,13 @@
    * The class has been prepared and resolved but possibly not yet verified
    * at this point.
    */
-  Dbg::PostClassPrepare(klass.Get());
+  Dbg::PostClassPrepare(new_class_h.Get());
 
-  return klass.Get();
+  return new_class_h.Get();
 }
 
-// Precomputes size that will be needed for Class, matching LinkStaticFields
-uint32_t ClassLinker::SizeOfClass(const DexFile& dex_file,
-                                const DexFile::ClassDef& dex_class_def) {
+uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
+                                                       const DexFile::ClassDef& dex_class_def) {
   const byte* class_data = dex_file.GetClassData(dex_class_def);
   size_t num_ref = 0;
   size_t num_32 = 0;
@@ -1677,24 +1702,7 @@
       }
     }
   }
-  // start with generic class data
-  uint32_t size = sizeof(mirror::Class);
-  // follow with reference fields which must be contiguous at start
-  size += (num_ref * sizeof(uint32_t));
-  // if there are 64-bit fields to add, make sure they are aligned
-  if (num_64 != 0 && size != RoundUp(size, 8)) {  // for 64-bit alignment
-    if (num_32 != 0) {
-      // use an available 32-bit field for padding
-      num_32--;
-    }
-    size += sizeof(uint32_t);  // either way, we are adding a word
-    DCHECK_EQ(size, RoundUp(size, 8));
-  }
-  // tack on any 64-bit fields now that alignment is assured
-  size += (num_64 * sizeof(uint64_t));
-  // tack on any remaining 32-bit fields
-  size += (num_32 * sizeof(uint32_t));
-  return size;
+  return mirror::Class::ComputeClassSize(false, 0, num_32, num_64, num_ref);
 }
 
 OatFile::OatClass ClassLinker::GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) {
@@ -2308,7 +2316,7 @@
 }
 
 mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) {
-  mirror::Class* klass = AllocClass(self, sizeof(mirror::Class));
+  mirror::Class* klass = AllocClass(self, mirror::Class::PrimitiveClassSize());
   if (UNLIKELY(klass == NULL)) {
     return NULL;
   }
@@ -2413,7 +2421,7 @@
     }
   }
   if (new_class.Get() == nullptr) {
-    new_class.Assign(AllocClass(self, sizeof(mirror::Class)));
+    new_class.Assign(AllocClass(self, mirror::Array::ClassSize()));
     if (new_class.Get() == nullptr) {
       return nullptr;
     }
@@ -2426,6 +2434,8 @@
   new_class->SetVTable(java_lang_Object->GetVTable());
   new_class->SetPrimitiveType(Primitive::kPrimNot);
   new_class->SetClassLoader(component_type->GetClassLoader());
+  new_class->SetStatus(mirror::Class::kStatusLoaded, self);
+  new_class->PopulateEmbeddedImtAndVTable();
   new_class->SetStatus(mirror::Class::kStatusInitialized, self);
   // don't need to set new_class->SetObjectSize(..)
   // because Object::SizeOf delegates to Array::SizeOf
@@ -2519,7 +2529,8 @@
   if (existing != NULL) {
     return existing;
   }
-  if (kIsDebugBuild && klass->GetClassLoader() == NULL && dex_cache_image_class_lookup_required_) {
+  if (kIsDebugBuild && !klass->IsTemp() && klass->GetClassLoader() == NULL &&
+      dex_cache_image_class_lookup_required_) {
     // Check a class loaded with the system class loader matches one in the image if the class
     // is in the image.
     existing = LookupClassFromImage(descriptor);
@@ -2535,6 +2546,50 @@
   return NULL;
 }
 
+mirror::Class* ClassLinker::UpdateClass(const char* descriptor, mirror::Class* klass,
+                                        size_t hash) {
+  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  mirror::Class* existing =
+      LookupClassFromTableLocked(descriptor, klass->GetClassLoader(), hash);
+
+  if (existing == nullptr) {
+    CHECK(klass->IsProxyClass());
+    return nullptr;
+  }
+
+  CHECK_NE(existing, klass) << descriptor;
+  CHECK(!existing->IsResolved()) << descriptor;
+  CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusResolving) << descriptor;
+
+  for (auto it = class_table_.lower_bound(hash), end = class_table_.end(); it != end && it->first == hash;
+       ++it) {
+    mirror::Class* entry = it->second;
+    if (entry == existing) {
+      class_table_.erase(it);
+      break;
+    }
+  }
+
+  CHECK(!klass->IsTemp()) << descriptor;
+  if (kIsDebugBuild && klass->GetClassLoader() == nullptr &&
+      dex_cache_image_class_lookup_required_) {
+    // Check a class loaded with the system class loader matches one in the image if the class
+    // is in the image.
+    existing = LookupClassFromImage(descriptor);
+    if (existing != nullptr) {
+      CHECK(klass == existing) << descriptor;
+    }
+  }
+  VerifyObject(klass);
+
+  class_table_.insert(std::make_pair(hash, klass));
+  if (log_new_class_table_roots_) {
+    new_class_roots_.push_back(std::make_pair(hash, klass));
+  }
+
+  return existing;
+}
+
 bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) {
   size_t hash = Hash(descriptor);
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
@@ -2954,8 +3009,8 @@
                                              jobjectArray methods, jobjectArray throws) {
   Thread* self = soa.Self();
   StackHandleScope<8> hs(self);
-  Handle<mirror::Class> klass(hs.NewHandle(AllocClass(self, GetClassRoot(kJavaLangClass),
-                                                      sizeof(mirror::SynthesizedProxyClass))));
+  Handle<mirror::Class> klass(hs.NewHandle(
+      AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class))));
   if (klass.Get() == NULL) {
     CHECK(self->IsExceptionPending());  // OOME.
     return NULL;
@@ -3046,20 +3101,31 @@
   klass->SetStatus(mirror::Class::kStatusLoaded, self);  // Now effectively in the loaded state.
   self->AssertNoPendingException();
 
+  std::string descriptor(GetDescriptorForProxy(klass.Get()));
+  mirror::Class* new_class = nullptr;
   {
-    ObjectLock<mirror::Class> lock(self, klass);  // Must hold lock on object when resolved.
+    ObjectLock<mirror::Class> resolution_lock(self, klass);  // Must hold lock on object when resolved.
     // Link the fields and virtual methods, creating vtable and iftables
-    Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
+    Handle<mirror::ObjectArray<mirror::Class> > h_interfaces(
         hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)));
-    if (!LinkClass(self, klass, h_interfaces)) {
+    if (!LinkClass(self, descriptor.c_str(), klass, h_interfaces, &new_class)) {
       klass->SetStatus(mirror::Class::kStatusError, self);
       return nullptr;
     }
+  }
 
-    interfaces_sfield->SetObject<false>(
-        klass.Get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
-    throws_sfield->SetObject<false>(
-        klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
+  CHECK(klass->IsRetired());
+  CHECK_NE(klass.Get(), new_class);
+  klass.Assign(new_class);
+
+  CHECK_EQ(interfaces_sfield->GetDeclaringClass(), new_class);
+  interfaces_sfield->SetObject<false>(klass.Get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+  CHECK_EQ(throws_sfield->GetDeclaringClass(), new_class);
+  throws_sfield->SetObject<false>(klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
+
+  {
+    // Lock on klass is released. Lock new class object.
+    ObjectLock<mirror::Class> initialization_lock(self, klass);
     klass->SetStatus(mirror::Class::kStatusInitialized, self);
   }
 
@@ -3085,14 +3151,11 @@
                                                decoded_name->ToModifiedUtf8().c_str()));
     CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name);
 
-    mirror::SynthesizedProxyClass* synth_proxy_class =
-        down_cast<mirror::SynthesizedProxyClass*>(klass.Get());
-    CHECK_EQ(synth_proxy_class->GetInterfaces(),
+    CHECK_EQ(klass.Get()->GetInterfaces(),
              soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
-    CHECK_EQ(synth_proxy_class->GetThrows(),
+    CHECK_EQ(klass.Get()->GetThrows(),
              soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
   }
-  std::string descriptor(GetDescriptorForProxy(klass.Get()));
   mirror::Class* existing = InsertClass(descriptor.c_str(), klass.Get(), Hash(descriptor.c_str()));
   CHECK(existing == nullptr);
   return klass.Get();
@@ -3526,9 +3589,49 @@
   }
 }
 
-bool ClassLinker::LinkClass(Thread* self, Handle<mirror::Class> klass,
-                            Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
+void ClassLinker::FixupTemporaryDeclaringClass(mirror::Class* temp_class, mirror::Class* new_class) {
+  mirror::ObjectArray<mirror::ArtField>* fields = new_class->GetIFields();
+  if (fields != nullptr) {
+    for (int index = 0; index < fields->GetLength(); index ++) {
+      if (fields->Get(index)->GetDeclaringClass() == temp_class) {
+        fields->Get(index)->SetDeclaringClass(new_class);
+      }
+    }
+  }
+
+  fields = new_class->GetSFields();
+  if (fields != nullptr) {
+    for (int index = 0; index < fields->GetLength(); index ++) {
+      if (fields->Get(index)->GetDeclaringClass() == temp_class) {
+        fields->Get(index)->SetDeclaringClass(new_class);
+      }
+    }
+  }
+
+  mirror::ObjectArray<mirror::ArtMethod>* methods = new_class->GetDirectMethods();
+  if (methods != nullptr) {
+    for (int index = 0; index < methods->GetLength(); index ++) {
+      if (methods->Get(index)->GetDeclaringClass() == temp_class) {
+        methods->Get(index)->SetDeclaringClass(new_class);
+      }
+    }
+  }
+
+  methods = new_class->GetVirtualMethods();
+  if (methods != nullptr) {
+    for (int index = 0; index < methods->GetLength(); index ++) {
+      if (methods->Get(index)->GetDeclaringClass() == temp_class) {
+        methods->Get(index)->SetDeclaringClass(new_class);
+      }
+    }
+  }
+}
+
+bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror::Class> klass,
+                            Handle<mirror::ObjectArray<mirror::Class>> interfaces,
+                            mirror::Class** new_class) {
   CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
+
   if (!LinkSuperClass(klass)) {
     return false;
   }
@@ -3538,13 +3641,60 @@
   if (!LinkInstanceFields(klass)) {
     return false;
   }
-  if (!LinkStaticFields(klass)) {
+  size_t class_size;
+  if (!LinkStaticFields(klass, &class_size)) {
     return false;
   }
   CreateReferenceInstanceOffsets(klass);
   CreateReferenceStaticOffsets(klass);
   CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
-  klass->SetStatus(mirror::Class::kStatusResolved, self);
+
+  if (!klass->IsTemp() || (!init_done_ && klass->GetClassSize() == class_size)) {
+    // We don't need to retire this class as it has no embedded tables or it was created the
+    // correct size during class linker initialization.
+    CHECK_EQ(klass->GetClassSize(), class_size) << PrettyDescriptor(klass.Get());
+
+    if (klass->ShouldHaveEmbeddedImtAndVTable()) {
+      klass->PopulateEmbeddedImtAndVTable();
+    }
+
+    // This will notify waiters on klass that saw the not yet resolved
+    // class in the class_table_ during EnsureResolved.
+    klass->SetStatus(mirror::Class::kStatusResolved, self);
+    *new_class = klass.Get();
+  } else {
+    CHECK(!klass->IsResolved());
+    // Retire the temporary class and create the correctly sized resolved class.
+    *new_class = klass->CopyOf(self, class_size);
+    if (UNLIKELY(*new_class == NULL)) {
+      CHECK(self->IsExceptionPending());  // Expect an OOME.
+      klass->SetStatus(mirror::Class::kStatusError, self);
+      return false;
+    }
+
+    CHECK_EQ((*new_class)->GetClassSize(), class_size);
+    StackHandleScope<1> hs(self);
+    auto new_class_h = hs.NewHandleWrapper<mirror::Class>(new_class);
+    ObjectLock<mirror::Class> lock(self, new_class_h);
+
+    FixupTemporaryDeclaringClass(klass.Get(), new_class_h.Get());
+
+    mirror::Class* existing = UpdateClass(descriptor, new_class_h.Get(), Hash(descriptor));
+    CHECK(existing == NULL || existing == klass.Get());
+
+    // This will notify waiters on temp class that saw the not yet resolved class in the
+    // class_table_ during EnsureResolved.
+    klass->SetStatus(mirror::Class::kStatusRetired, self);
+
+    CHECK_EQ(new_class_h->GetStatus(), mirror::Class::kStatusResolving);
+    // This will notify waiters on new_class that saw the not yet resolved
+    // class in the class_table_ during EnsureResolved.
+    new_class_h->SetStatus(mirror::Class::kStatusResolved, self);
+
+    // Only embedded imt should be used from this point.
+    new_class_h->SetImTable(NULL);
+    // TODO: remove vtable and only use embedded vtable.
+  }
   return true;
 }
 
@@ -3565,6 +3715,7 @@
                               PrettyDescriptor(klass.Get()).c_str());
       return false;
     }
+    CHECK(super_class->IsResolved());
     klass->SetSuperClass(super_class);
   }
   const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def);
@@ -3878,7 +4029,7 @@
   // Allocate imtable
   bool imtable_changed = false;
   Handle<mirror::ObjectArray<mirror::ArtMethod>> imtable(
-      hs.NewHandle(AllocArtMethodArray(self, kImtSize)));
+      hs.NewHandle(AllocArtMethodArray(self, mirror::Class::kImtSize)));
   if (UNLIKELY(imtable.Get() == NULL)) {
     CHECK(self->IsExceptionPending());  // OOME.
     return false;
@@ -3925,7 +4076,7 @@
             }
             method_array->Set<false>(j, vtable_method);
             // Place method in imt if entry is empty, place conflict otherwise.
-            uint32_t imt_index = interface_method->GetDexMethodIndex() % kImtSize;
+            uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize;
             if (imtable->Get(imt_index) == NULL) {
               imtable->Set<false>(imt_index, vtable_method);
               imtable_changed = true;
@@ -3963,7 +4114,7 @@
   if (imtable_changed) {
     // Fill in empty entries in interface method table with conflict.
     mirror::ArtMethod* imt_conflict_method = runtime->GetImtConflictMethod();
-    for (size_t i = 0; i < kImtSize; i++) {
+    for (size_t i = 0; i < mirror::Class::kImtSize; i++) {
       if (imtable->Get(i) == NULL) {
         imtable->Set<false>(i, imt_conflict_method);
       }
@@ -4020,15 +4171,12 @@
 
 bool ClassLinker::LinkInstanceFields(Handle<mirror::Class> klass) {
   CHECK(klass.Get() != NULL);
-  return LinkFields(klass, false);
+  return LinkFields(klass, false, nullptr);
 }
 
-bool ClassLinker::LinkStaticFields(Handle<mirror::Class> klass) {
+bool ClassLinker::LinkStaticFields(Handle<mirror::Class> klass, size_t* class_size) {
   CHECK(klass.Get() != NULL);
-  size_t allocated_class_size = klass->GetClassSize();
-  bool success = LinkFields(klass, true);
-  CHECK_EQ(allocated_class_size, klass->GetClassSize());
-  return success;
+  return LinkFields(klass, true, class_size);
 }
 
 struct LinkFieldsComparator {
@@ -4058,19 +4206,23 @@
   }
 };
 
-bool ClassLinker::LinkFields(Handle<mirror::Class> klass, bool is_static) {
+bool ClassLinker::LinkFields(Handle<mirror::Class> klass, bool is_static, size_t* class_size) {
   size_t num_fields =
       is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
 
   mirror::ObjectArray<mirror::ArtField>* fields =
       is_static ? klass->GetSFields() : klass->GetIFields();
 
-  // Initialize size and field_offset
-  size_t size;
+  // Initialize field_offset
   MemberOffset field_offset(0);
   if (is_static) {
-    size = klass->GetClassSize();
-    field_offset = mirror::Class::FieldsOffset();
+    uint32_t base = sizeof(mirror::Class);  // Static fields come after the class.
+    if (klass->ShouldHaveEmbeddedImtAndVTable()) {
+      // Static fields come after the embedded tables.
+      base = mirror::Class::ComputeClassSize(true, klass->GetVTableDuringLinking()->GetLength(),
+                                             0, 0, 0);
+    }
+    field_offset = MemberOffset(base);
   } else {
     mirror::Class* super_class = klass->GetSuperClass();
     if (super_class != NULL) {
@@ -4078,7 +4230,6 @@
           << PrettyClass(klass.Get()) << " " << PrettyClass(super_class);
       field_offset = MemberOffset(super_class->GetObjectSize());
     }
-    size = field_offset.Uint32Value();
   }
 
   CHECK_EQ(num_fields == 0, fields == NULL) << PrettyClass(klass.Get());
@@ -4191,11 +4342,12 @@
       DCHECK_EQ(num_fields, num_reference_fields) << PrettyClass(klass.Get());
     }
   }
-  size = field_offset.Uint32Value();
+
+  size_t size = field_offset.Uint32Value();
   // Update klass
   if (is_static) {
     klass->SetNumReferenceStaticFields(num_reference_fields);
-    klass->SetClassSize(size);
+    *class_size = size;
   } else {
     klass->SetNumReferenceInstanceFields(num_reference_fields);
     if (!klass->IsVariableSize()) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 60dad7b..d9b3d25 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -31,6 +31,7 @@
 #include "read_barrier.h"
 
 namespace art {
+
 namespace gc {
 namespace space {
   class ImageSpace;
@@ -56,11 +57,6 @@
 
 class ClassLinker {
  public:
-  // Interface method table size. Increasing this value reduces the chance of two interface methods
-  // colliding in the interface method table but increases the size of classes that implement
-  // (non-marker) interfaces.
-  static constexpr size_t kImtSize = 64;
-
   explicit ClassLinker(InternTable* intern_table);
   ~ClassLinker();
 
@@ -385,6 +381,14 @@
   // Special code to allocate an art method, use this instead of class->AllocObject.
   mirror::ArtMethod* AllocArtMethod(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  mirror::ObjectArray<mirror::Class>* GetClassRoots() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ObjectArray<mirror::Class>* class_roots =
+        ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
+            &class_roots_);
+    DCHECK(class_roots != NULL);
+    return class_roots;
+  }
+
  private:
   const OatFile::OatMethod GetOatMethodFor(mirror::ArtMethod* method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -427,8 +431,10 @@
                          mirror::Class* c, SafeMap<uint32_t, mirror::ArtField*>& field_map)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  uint32_t SizeOfClass(const DexFile& dex_file,
-                     const DexFile::ClassDef& dex_class_def);
+  // Precomputes size needed for Class, in the case of a non-temporary class this size must be
+  // sufficient to hold all static fields.
+  uint32_t SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
+                                            const DexFile::ClassDef& dex_class_def);
 
   void LoadClass(const DexFile& dex_file,
                  const DexFile::ClassDef& dex_class_def,
@@ -481,8 +487,9 @@
                                                      mirror::Class* klass2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkClass(Thread* self, Handle<mirror::Class> klass,
-                 Handle<mirror::ObjectArray<mirror::Class>> interfaces)
+  bool LinkClass(Thread* self, const char* descriptor, Handle<mirror::Class> klass,
+                 Handle<mirror::ObjectArray<mirror::Class>> interfaces,
+                 mirror::Class** new_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool LinkSuperClass(Handle<mirror::Class> klass)
@@ -502,17 +509,16 @@
                             Handle<mirror::ObjectArray<mirror::Class>> interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkStaticFields(Handle<mirror::Class> klass)
+  bool LinkStaticFields(Handle<mirror::Class> klass, size_t* class_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool LinkInstanceFields(Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool LinkFields(Handle<mirror::Class> klass, bool is_static)
+  bool LinkFields(Handle<mirror::Class> klass, bool is_static, size_t* class_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void LinkCode(Handle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,
                 const DexFile& dex_file, uint32_t dex_method_index, uint32_t method_index)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-
   void CreateReferenceInstanceOffsets(Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void CreateReferenceStaticOffsets(Handle<mirror::Class> klass)
@@ -612,11 +618,27 @@
                                             size_t hash)
       SHARED_LOCKS_REQUIRED(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
 
+  mirror::Class* UpdateClass(const char* descriptor, mirror::Class* klass, size_t hash)
+      LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   void MoveImageClassesToClassTable() LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Class* LookupClassFromImage(const char* descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // EnsureResolved is called to make sure that a class in the class_table_ has been resolved
+  // before returning it to the caller. Its the responsibility of the thread that placed the class
+  // in the table to make it resolved. The thread doing resolution must notify on the class' lock
+  // when resolution has occurred. This happens in mirror::Class::SetStatus. As resolution may
+  // retire a class, the version of the class in the table is returned and this may differ from
+  // the class passed in.
+  mirror::Class* EnsureResolved(Thread* self, const char* descriptor, mirror::Class* klass)
+      __attribute__((warn_unused_result)) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  void FixupTemporaryDeclaringClass(mirror::Class* temp_class, mirror::Class* new_class)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // indexes into class_roots_.
   // needs to be kept in sync with class_roots_descriptors_.
   enum ClassRoot {
@@ -664,14 +686,6 @@
   void SetClassRoot(ClassRoot class_root, mirror::Class* klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  mirror::ObjectArray<mirror::Class>* GetClassRoots() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    mirror::ObjectArray<mirror::Class>* class_roots =
-        ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
-            &class_roots_);
-    DCHECK(class_roots != NULL);
-    return class_roots;
-  }
-
   static const char* class_roots_descriptors_[];
 
   const char* GetClassRootDescriptor(ClassRoot class_root) {
@@ -695,6 +709,8 @@
 
   InternTable* intern_table_;
 
+  // Trampolines within the image the bounce to runtime entrypoints. Done so that there is a single
+  // patch point within the image. TODO: make these proper relocations.
   const void* portable_resolution_trampoline_;
   const void* quick_resolution_trampoline_;
   const void* portable_imt_conflict_trampoline_;
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 04f6946..7b5a502 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -22,7 +22,7 @@
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "dex_file.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "gc/heap.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method.h"
@@ -34,6 +34,7 @@
 #include "mirror/proxy.h"
 #include "mirror/reference.h"
 #include "mirror/stack_trace_element.h"
+#include "mirror/string-inl.h"
 #include "handle_scope-inl.h"
 
 namespace art {
@@ -572,37 +573,6 @@
   };
 };
 
-struct ClassClassOffsets : public CheckOffsets<mirror::ClassClass> {
-  ClassClassOffsets() : CheckOffsets<mirror::ClassClass>(true, "Ljava/lang/Class;") {
-    // alphabetical 64-bit
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassClass, serialVersionUID_), "serialVersionUID"));
-  };
-};
-
-struct StringClassOffsets : public CheckOffsets<mirror::StringClass> {
-  StringClassOffsets() : CheckOffsets<mirror::StringClass>(true, "Ljava/lang/String;") {
-    // alphabetical references
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, ASCII_),                  "ASCII"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER"));
-
-    // alphabetical 32-bit
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_),       "REPLACEMENT_CHAR"));
-
-    // alphabetical 64-bit
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_),       "serialVersionUID"));
-  };
-};
-
-struct ArtFieldClassOffsets : public CheckOffsets<mirror::ArtFieldClass> {
-  ArtFieldClassOffsets() : CheckOffsets<mirror::ArtFieldClass>(true, "Ljava/lang/reflect/ArtField;") {
-  };
-};
-
-struct ArtMethodClassOffsets : public CheckOffsets<mirror::ArtMethodClass> {
-  ArtMethodClassOffsets() : CheckOffsets<mirror::ArtMethodClass>(true, "Ljava/lang/reflect/ArtMethod;") {
-  };
-};
-
 struct DexCacheOffsets : public CheckOffsets<mirror::DexCache> {
   DexCacheOffsets() : CheckOffsets<mirror::DexCache>(false, "Ljava/lang/DexCache;") {
     // alphabetical references
@@ -652,11 +622,6 @@
   EXPECT_TRUE(DexCacheOffsets().Check());
   EXPECT_TRUE(ReferenceOffsets().Check());
   EXPECT_TRUE(FinalizerReferenceOffsets().Check());
-
-  EXPECT_TRUE(ClassClassOffsets().Check());
-  EXPECT_TRUE(StringClassOffsets().Check());
-  EXPECT_TRUE(ArtFieldClassOffsets().Check());
-  EXPECT_TRUE(ArtMethodClassOffsets().Check());
 }
 
 TEST_F(ClassLinkerTest, FindClassNonexistent) {
@@ -1091,4 +1056,28 @@
   }
 }
 
+TEST_F(ClassLinkerTest, ValidatePredefinedClassSizes) {
+  ScopedObjectAccess soa(Thread::Current());
+  NullHandle<mirror::ClassLoader> class_loader;
+  mirror::Class* c;
+
+  c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Class;", class_loader);
+  EXPECT_EQ(c->GetClassSize(), mirror::Class::ClassClassSize());
+
+  c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Object;", class_loader);
+  EXPECT_EQ(c->GetClassSize(), mirror::Object::ClassSize());
+
+  c = class_linker_->FindClass(soa.Self(), "Ljava/lang/String;", class_loader);
+  EXPECT_EQ(c->GetClassSize(), mirror::String::ClassSize());
+
+  c = class_linker_->FindClass(soa.Self(), "Ljava/lang/DexCache;", class_loader);
+  EXPECT_EQ(c->GetClassSize(), mirror::DexCache::ClassSize());
+
+  c = class_linker_->FindClass(soa.Self(), "Ljava/lang/reflect/ArtField;", class_loader);
+  EXPECT_EQ(c->GetClassSize(), mirror::ArtField::ClassSize());
+
+  c = class_linker_->FindClass(soa.Self(), "Ljava/lang/reflect/ArtMethod;", class_loader);
+  EXPECT_EQ(c->GetClassSize(), mirror::ArtMethod::ClassSize());
+}
+
 }  // namespace art
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
new file mode 100644
index 0000000..482ad47
--- /dev/null
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -0,0 +1,696 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_INL_H_
+#define ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_INL_H_
+
+#include "entrypoint_utils.h"
+
+#include "class_linker-inl.h"
+#include "common_throws.h"
+#include "dex_file.h"
+#include "indirect_reference_table.h"
+#include "invoke_type.h"
+#include "jni_internal.h"
+#include "mirror/art_method.h"
+#include "mirror/array.h"
+#include "mirror/class-inl.h"
+#include "mirror/object-inl.h"
+#include "mirror/throwable.h"
+#include "object_utils.h"
+#include "handle_scope-inl.h"
+#include "thread.h"
+
+namespace art {
+
+// TODO: Fix no thread safety analysis when GCC can handle template specialization.
+template <const bool kAccessCheck>
+ALWAYS_INLINE static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
+                                                            mirror::ArtMethod* method,
+                                                            Thread* self, bool* slow_path)
+    NO_THREAD_SAFETY_ANALYSIS {
+  mirror::Class* klass = method->GetDexCacheResolvedTypes()->GetWithoutChecks(type_idx);
+  if (UNLIKELY(klass == NULL)) {
+    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+    *slow_path = true;
+    if (klass == NULL) {
+      DCHECK(self->IsExceptionPending());
+      return nullptr;  // Failure
+    }
+  }
+  if (kAccessCheck) {
+    if (UNLIKELY(!klass->IsInstantiable())) {
+      ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+      self->ThrowNewException(throw_location, "Ljava/lang/InstantiationError;",
+                              PrettyDescriptor(klass).c_str());
+      *slow_path = true;
+      return nullptr;  // Failure
+    }
+    mirror::Class* referrer = method->GetDeclaringClass();
+    if (UNLIKELY(!referrer->CanAccess(klass))) {
+      ThrowIllegalAccessErrorClass(referrer, klass);
+      *slow_path = true;
+      return nullptr;  // Failure
+    }
+  }
+  if (UNLIKELY(!klass->IsInitialized())) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_klass(hs.NewHandle(klass));
+    // EnsureInitialized (the class initializer) might cause a GC.
+    // may cause us to suspend meaning that another thread may try to
+    // change the allocator while we are stuck in the entrypoints of
+    // an old allocator. Also, the class initialization may fail. To
+    // handle these cases we mark the slow path boolean as true so
+    // that the caller knows to check the allocator type to see if it
+    // has changed and to null-check the return value in case the
+    // initialization fails.
+    *slow_path = true;
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) {
+      DCHECK(self->IsExceptionPending());
+      return nullptr;  // Failure
+    }
+    return h_klass.Get();
+  }
+  return klass;
+}
+
+// TODO: Fix no thread safety analysis when annotalysis is smarter.
+ALWAYS_INLINE static inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
+                                                                               Thread* self, bool* slow_path)
+    NO_THREAD_SAFETY_ANALYSIS {
+  if (UNLIKELY(!klass->IsInitialized())) {
+    StackHandleScope<1> hs(self);
+    Handle<mirror::Class> h_class(hs.NewHandle(klass));
+    // EnsureInitialized (the class initializer) might cause a GC.
+    // may cause us to suspend meaning that another thread may try to
+    // change the allocator while we are stuck in the entrypoints of
+    // an old allocator. Also, the class initialization may fail. To
+    // handle these cases we mark the slow path boolean as true so
+    // that the caller knows to check the allocator type to see if it
+    // has changed and to null-check the return value in case the
+    // initialization fails.
+    *slow_path = true;
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
+      DCHECK(self->IsExceptionPending());
+      return nullptr;  // Failure
+    }
+    return h_class.Get();
+  }
+  return klass;
+}
+
+// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
+// cannot be resolved, throw an error. If it can, use it to create an instance.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
+template <bool kAccessCheck, bool kInstrumented>
+ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
+                                                                mirror::ArtMethod* method,
+                                                                Thread* self,
+                                                                gc::AllocatorType allocator_type)
+    NO_THREAD_SAFETY_ANALYSIS {
+  bool slow_path = false;
+  mirror::Class* klass = CheckObjectAlloc<kAccessCheck>(type_idx, method, self, &slow_path);
+  if (UNLIKELY(slow_path)) {
+    if (klass == nullptr) {
+      return nullptr;
+    }
+    return klass->Alloc<kInstrumented>(self, Runtime::Current()->GetHeap()->GetCurrentAllocator());
+  }
+  DCHECK(klass != nullptr);
+  return klass->Alloc<kInstrumented>(self, allocator_type);
+}
+
+// Given the context of a calling Method and a resolved class, create an instance.
+// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
+template <bool kInstrumented>
+ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCodeResolved(mirror::Class* klass,
+                                                                        mirror::ArtMethod* method,
+                                                                        Thread* self,
+                                                                        gc::AllocatorType allocator_type)
+    NO_THREAD_SAFETY_ANALYSIS {
+  DCHECK(klass != nullptr);
+  bool slow_path = false;
+  klass = CheckClassInitializedForObjectAlloc(klass, self, &slow_path);
+  if (UNLIKELY(slow_path)) {
+    if (klass == nullptr) {
+      return nullptr;
+    }
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    // Pass in false since the object can not be finalizable.
+    return klass->Alloc<kInstrumented, false>(self, heap->GetCurrentAllocator());
+  }
+  // Pass in false since the object can not be finalizable.
+  return klass->Alloc<kInstrumented, false>(self, allocator_type);
+}
+
+// Given the context of a calling Method and an initialized class, create an instance.
+// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
+template <bool kInstrumented>
+ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass,
+                                                                           mirror::ArtMethod* method,
+                                                                           Thread* self,
+                                                                           gc::AllocatorType allocator_type)
+    NO_THREAD_SAFETY_ANALYSIS {
+  DCHECK(klass != nullptr);
+  // Pass in false since the object can not be finalizable.
+  return klass->Alloc<kInstrumented, false>(self, allocator_type);
+}
+
+
+// TODO: Fix no thread safety analysis when GCC can handle template specialization.
+template <bool kAccessCheck>
+ALWAYS_INLINE static inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
+                                                           mirror::ArtMethod* method,
+                                                           int32_t component_count,
+                                                           bool* slow_path)
+    NO_THREAD_SAFETY_ANALYSIS {
+  if (UNLIKELY(component_count < 0)) {
+    ThrowNegativeArraySizeException(component_count);
+    *slow_path = true;
+    return nullptr;  // Failure
+  }
+  mirror::Class* klass = method->GetDexCacheResolvedTypes()->GetWithoutChecks(type_idx);
+  if (UNLIKELY(klass == nullptr)) {  // Not in dex cache so try to resolve
+    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+    *slow_path = true;
+    if (klass == nullptr) {  // Error
+      DCHECK(Thread::Current()->IsExceptionPending());
+      return nullptr;  // Failure
+    }
+    CHECK(klass->IsArrayClass()) << PrettyClass(klass);
+  }
+  if (kAccessCheck) {
+    mirror::Class* referrer = method->GetDeclaringClass();
+    if (UNLIKELY(!referrer->CanAccess(klass))) {
+      ThrowIllegalAccessErrorClass(referrer, klass);
+      *slow_path = true;
+      return nullptr;  // Failure
+    }
+  }
+  return klass;
+}
+
+// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
+// it cannot be resolved, throw an error. If it can, use it to create an array.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+// TODO: Fix no thread safety analysis when GCC can handle template specialization.
+template <bool kAccessCheck, bool kInstrumented>
+ALWAYS_INLINE static inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
+                                                              mirror::ArtMethod* method,
+                                                              int32_t component_count,
+                                                              Thread* self,
+                                                              gc::AllocatorType allocator_type)
+    NO_THREAD_SAFETY_ANALYSIS {
+  bool slow_path = false;
+  mirror::Class* klass = CheckArrayAlloc<kAccessCheck>(type_idx, method, component_count,
+                                                       &slow_path);
+  if (UNLIKELY(slow_path)) {
+    if (klass == nullptr) {
+      return nullptr;
+    }
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
+                                               klass->GetComponentSize(),
+                                               heap->GetCurrentAllocator());
+  }
+  return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
+                                             klass->GetComponentSize(), allocator_type);
+}
+
+template <bool kAccessCheck, bool kInstrumented>
+ALWAYS_INLINE static inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass,
+                                                                      mirror::ArtMethod* method,
+                                                                      int32_t component_count,
+                                                                      Thread* self,
+                                                                      gc::AllocatorType allocator_type)
+    NO_THREAD_SAFETY_ANALYSIS {
+  DCHECK(klass != nullptr);
+  if (UNLIKELY(component_count < 0)) {
+    ThrowNegativeArraySizeException(component_count);
+    return nullptr;  // Failure
+  }
+  if (kAccessCheck) {
+    mirror::Class* referrer = method->GetDeclaringClass();
+    if (UNLIKELY(!referrer->CanAccess(klass))) {
+      ThrowIllegalAccessErrorClass(referrer, klass);
+      return nullptr;  // Failure
+    }
+  }
+  // No need to retry a slow-path allocation as the above code won't cause a GC or thread
+  // suspension.
+  return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
+                                             klass->GetComponentSize(), allocator_type);
+}
+
+template<FindFieldType type, bool access_check>
+static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::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;
+  }
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  mirror::ArtField* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
+  if (UNLIKELY(resolved_field == nullptr)) {
+    DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
+    return nullptr;  // Failure.
+  }
+  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  if (access_check) {
+    if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
+      ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
+      return nullptr;
+    }
+    mirror::Class* referring_class = referrer->GetDeclaringClass();
+    if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class, resolved_field,
+                                                            field_idx))) {
+      DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
+      return nullptr;  // Failure.
+    }
+    if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
+      ThrowIllegalAccessErrorFinalField(referrer, resolved_field);
+      return nullptr;  // Failure.
+    } else {
+      if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
+                   resolved_field->FieldSize() != expected_size)) {
+        ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+        DCHECK(throw_location.GetMethod() == referrer);
+        self->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
+                                 "Attempted read of %zd-bit %s on field '%s'",
+                                 expected_size * (32 / sizeof(int32_t)),
+                                 is_primitive ? "primitive" : "non-primitive",
+                                 PrettyField(resolved_field, true).c_str());
+        return nullptr;  // Failure.
+      }
+    }
+  }
+  if (!is_static) {
+    // instance fields must be being accessed on an initialized class
+    return resolved_field;
+  } else {
+    // If the class is initialized we're done.
+    if (LIKELY(fields_class->IsInitialized())) {
+      return resolved_field;
+    } else {
+      StackHandleScope<1> hs(self);
+      Handle<mirror::Class> h_class(hs.NewHandle(fields_class));
+      if (LIKELY(class_linker->EnsureInitialized(h_class, true, true))) {
+        // Otherwise let's ensure the class is initialized before resolving the field.
+        return resolved_field;
+      }
+      DCHECK(self->IsExceptionPending());  // Throw exception and unwind
+      return nullptr;  // Failure.
+    }
+  }
+}
+
+// Explicit template declarations of FindFieldFromCode for all field access types.
+#define EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
+mirror::ArtField* FindFieldFromCode<_type, _access_check>(uint32_t field_idx, \
+                                                          mirror::ArtMethod* referrer, \
+                                                          Thread* self, size_t expected_size) \
+
+#define EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
+    EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, false); \
+    EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, true)
+
+EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectRead);
+EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectWrite);
+EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveRead);
+EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveWrite);
+EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectRead);
+EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectWrite);
+EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveRead);
+EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveWrite);
+
+#undef EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL
+#undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
+
+template<InvokeType type, bool access_check>
+static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
+                                                    mirror::Object** this_object,
+                                                    mirror::ArtMethod** referrer, Thread* self) {
+  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+  mirror::ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, *referrer, type);
+  if (resolved_method == nullptr) {
+    StackHandleScope<1> hs(self);
+    mirror::Object* null_this = nullptr;
+    HandleWrapper<mirror::Object> h_this(
+        hs.NewHandleWrapper(type == kStatic ? &null_this : this_object));
+    resolved_method = class_linker->ResolveMethod(self, method_idx, referrer, type);
+  }
+  if (UNLIKELY(resolved_method == nullptr)) {
+    DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
+    return nullptr;  // Failure.
+  } else if (UNLIKELY(*this_object == nullptr && type != kStatic)) {
+    // Maintain interpreter-like semantics where NullPointerException is thrown
+    // after potential NoSuchMethodError from class linker.
+    ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+    DCHECK_EQ(*referrer, throw_location.GetMethod());
+    ThrowNullPointerExceptionForMethodAccess(throw_location, method_idx, type);
+    return nullptr;  // Failure.
+  } else if (access_check) {
+    // Incompatible class change should have been handled in resolve method.
+    if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
+      ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method,
+                                        *referrer);
+      return nullptr;  // Failure.
+    }
+    mirror::Class* methods_class = resolved_method->GetDeclaringClass();
+    mirror::Class* referring_class = (*referrer)->GetDeclaringClass();
+    bool can_access_resolved_method =
+        referring_class->CheckResolvedMethodAccess<type>(methods_class, resolved_method,
+                                                         method_idx);
+    if (UNLIKELY(!can_access_resolved_method)) {
+      DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
+      return nullptr;  // Failure.
+    }
+  }
+  switch (type) {
+    case kStatic:
+    case kDirect:
+      return resolved_method;
+    case kVirtual: {
+      mirror::ObjectArray<mirror::ArtMethod>* vtable = (*this_object)->GetClass()->GetVTable();
+      uint16_t vtable_index = resolved_method->GetMethodIndex();
+      if (access_check &&
+          (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength()))) {
+        // Behavior to agree with that of the verifier.
+        ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
+                               resolved_method->GetName(), resolved_method->GetSignature());
+        return nullptr;  // Failure.
+      }
+      DCHECK(vtable != nullptr);
+      return vtable->GetWithoutChecks(vtable_index);
+    }
+    case kSuper: {
+      mirror::Class* super_class = (*referrer)->GetDeclaringClass()->GetSuperClass();
+      uint16_t vtable_index = resolved_method->GetMethodIndex();
+      mirror::ObjectArray<mirror::ArtMethod>* vtable;
+      if (access_check) {
+        // Check existence of super class.
+        vtable = (super_class != nullptr) ? super_class->GetVTable() : nullptr;
+        if (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength())) {
+          // Behavior to agree with that of the verifier.
+          ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
+                                 resolved_method->GetName(), resolved_method->GetSignature());
+          return nullptr;  // Failure.
+        }
+      } else {
+        // Super class must exist.
+        DCHECK(super_class != nullptr);
+        vtable = super_class->GetVTable();
+      }
+      DCHECK(vtable != nullptr);
+      return vtable->GetWithoutChecks(vtable_index);
+    }
+    case kInterface: {
+      uint32_t imt_index = resolved_method->GetDexMethodIndex() % mirror::Class::kImtSize;
+      mirror::ArtMethod* imt_method = (*this_object)->GetClass()->GetEmbeddedImTableEntry(imt_index);
+      if (!imt_method->IsImtConflictMethod()) {
+        return imt_method;
+      } else {
+        mirror::ArtMethod* interface_method =
+            (*this_object)->GetClass()->FindVirtualMethodForInterface(resolved_method);
+        if (UNLIKELY(interface_method == nullptr)) {
+          ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method,
+                                                                     *this_object, *referrer);
+          return nullptr;  // Failure.
+        }
+        return interface_method;
+      }
+    }
+    default:
+      LOG(FATAL) << "Unknown invoke type " << type;
+      return nullptr;  // Failure.
+  }
+}
+
+// Explicit template declarations of FindMethodFromCode for all invoke types.
+#define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check)                 \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                       \
+  mirror::ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx,         \
+                                                              mirror::Object** this_object, \
+                                                              mirror::ArtMethod** referrer, \
+                                                              Thread* self)
+#define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
+    EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false);   \
+    EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, true)
+
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kStatic);
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kDirect);
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kVirtual);
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kSuper);
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kInterface);
+
+#undef EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL
+#undef EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL
+
+// Fast path field resolution that can't initialize classes or throw exceptions.
+static inline mirror::ArtField* FindFieldFast(uint32_t field_idx,
+                                              mirror::ArtMethod* referrer,
+                                              FindFieldType type, size_t expected_size)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::ArtField* resolved_field =
+      referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
+  if (UNLIKELY(resolved_field == nullptr)) {
+    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";  // Assignment below to avoid GCC warnings.
+      is_primitive = true;
+      is_set = true;
+      is_static = true;
+      break;
+  }
+  if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
+    // Incompatible class change.
+    return nullptr;
+  }
+  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  if (is_static) {
+    // Check class is initialized else fail so that we can contend to initialize the class with
+    // other threads that may be racing to do this.
+    if (UNLIKELY(!fields_class->IsInitialized())) {
+      return nullptr;
+    }
+  }
+  mirror::Class* referring_class = referrer->GetDeclaringClass();
+  if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
+               !referring_class->CanAccessMember(fields_class,
+                                                 resolved_field->GetAccessFlags()) ||
+               (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
+    // Illegal access.
+    return nullptr;
+  }
+  if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
+               resolved_field->FieldSize() != expected_size)) {
+    return nullptr;
+  }
+  return resolved_field;
+}
+
+// Fast path method resolution that can't throw exceptions.
+static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx,
+                                                mirror::Object* this_object,
+                                                mirror::ArtMethod* referrer,
+                                                bool access_check, InvokeType type)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  bool is_direct = type == kStatic || type == kDirect;
+  if (UNLIKELY(this_object == NULL && !is_direct)) {
+    return NULL;
+  }
+  mirror::ArtMethod* resolved_method =
+      referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
+  if (UNLIKELY(resolved_method == NULL)) {
+    return NULL;
+  }
+  if (access_check) {
+    // Check for incompatible class change errors and access.
+    bool icce = resolved_method->CheckIncompatibleClassChange(type);
+    if (UNLIKELY(icce)) {
+      return NULL;
+    }
+    mirror::Class* methods_class = resolved_method->GetDeclaringClass();
+    mirror::Class* referring_class = referrer->GetDeclaringClass();
+    if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
+                 !referring_class->CanAccessMember(methods_class,
+                                                   resolved_method->GetAccessFlags()))) {
+      // Potential illegal access, may need to refine the method's class.
+      return NULL;
+    }
+  }
+  if (type == kInterface) {  // Most common form of slow path dispatch.
+    return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+  } else if (is_direct) {
+    return resolved_method;
+  } else if (type == kSuper) {
+    return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->
+        Get(resolved_method->GetMethodIndex());
+  } else {
+    DCHECK(type == kVirtual);
+    return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
+  }
+}
+
+static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
+                                                    mirror::ArtMethod* referrer,
+                                                    Thread* self, bool can_run_clinit,
+                                                    bool verify_access)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  mirror::Class* klass = class_linker->ResolveType(type_idx, referrer);
+  if (UNLIKELY(klass == nullptr)) {
+    CHECK(self->IsExceptionPending());
+    return nullptr;  // Failure - Indicate to caller to deliver exception
+  }
+  // Perform access check if necessary.
+  mirror::Class* referring_class = referrer->GetDeclaringClass();
+  if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
+    ThrowIllegalAccessErrorClass(referring_class, klass);
+    return nullptr;  // Failure - Indicate to caller to deliver exception
+  }
+  // If we're just implementing const-class, we shouldn't call <clinit>.
+  if (!can_run_clinit) {
+    return klass;
+  }
+  // If we are the <clinit> of this class, just return our storage.
+  //
+  // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
+  // running.
+  if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) {
+    return klass;
+  }
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> h_class(hs.NewHandle(klass));
+  if (!class_linker->EnsureInitialized(h_class, true, true)) {
+    CHECK(self->IsExceptionPending());
+    return nullptr;  // Failure - Indicate to caller to deliver exception
+  }
+  return h_class.Get();
+}
+
+static inline mirror::String* ResolveStringFromCode(mirror::ArtMethod* referrer,
+                                                    uint32_t string_idx)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  return class_linker->ResolveString(string_idx, referrer);
+}
+
+static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
+    NO_THREAD_SAFETY_ANALYSIS /* SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) */ {
+  // Save any pending exception over monitor exit call.
+  mirror::Throwable* saved_exception = NULL;
+  ThrowLocation saved_throw_location;
+  bool is_exception_reported = self->IsExceptionReportedToInstrumentation();
+  if (UNLIKELY(self->IsExceptionPending())) {
+    saved_exception = self->GetException(&saved_throw_location);
+    self->ClearException();
+  }
+  // Decode locked object and unlock, before popping local references.
+  self->DecodeJObject(locked)->MonitorExit(self);
+  if (UNLIKELY(self->IsExceptionPending())) {
+    LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
+        << saved_exception->Dump()
+        << "\nEncountered second exception during implicit MonitorExit:\n"
+        << self->GetException(NULL)->Dump();
+  }
+  // Restore pending exception.
+  if (saved_exception != NULL) {
+    self->SetException(saved_throw_location, saved_exception);
+    self->SetExceptionReportedToInstrumentation(is_exception_reported);
+  }
+}
+
+static inline void CheckReferenceResult(mirror::Object* o, Thread* self)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (o == NULL) {
+    return;
+  }
+  mirror::ArtMethod* m = self->GetCurrentMethod(NULL);
+  if (o == kInvalidIndirectRefObject) {
+    JniAbortF(NULL, "invalid reference returned from %s", PrettyMethod(m).c_str());
+  }
+  // Make sure that the result is an instance of the type this method was expected to return.
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
+  mirror::Class* return_type = MethodHelper(h_m).GetReturnType();
+
+  if (!o->InstanceOf(return_type)) {
+    JniAbortF(NULL, "attempt to return an instance of %s from %s", PrettyTypeOf(o).c_str(),
+              PrettyMethod(h_m.Get()).c_str());
+  }
+}
+
+static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  for (;;) {
+    if (thread->ReadFlag(kCheckpointRequest)) {
+      thread->RunCheckpointFunction();
+    } else if (thread->ReadFlag(kSuspendRequest)) {
+      thread->FullSuspendCheck();
+    } else {
+      break;
+    }
+  }
+}
+
+template <typename INT_TYPE, typename FLOAT_TYPE>
+static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) {
+  const INT_TYPE kMaxInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::max());
+  const INT_TYPE kMinInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::min());
+  const FLOAT_TYPE kMaxIntAsFloat = static_cast<FLOAT_TYPE>(kMaxInt);
+  const FLOAT_TYPE kMinIntAsFloat = static_cast<FLOAT_TYPE>(kMinInt);
+  if (LIKELY(f > kMinIntAsFloat)) {
+     if (LIKELY(f < kMaxIntAsFloat)) {
+       return static_cast<INT_TYPE>(f);
+     } else {
+       return kMaxInt;
+     }
+  } else {
+    return (f != f) ? 0 : kMinInt;  // f != f implies NaN
+  }
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_INL_H_
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index a0e32f5..d029df2 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -16,6 +16,7 @@
 
 #include "entrypoints/entrypoint_utils.h"
 
+#include "base/mutex.h"
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
 #include "gc/accounting/card_table-inl.h"
@@ -25,7 +26,6 @@
 #include "mirror/object-inl.h"
 #include "object_utils.h"
 #include "mirror/object_array-inl.h"
-#include "mirror/proxy.h"
 #include "reflection.h"
 #include "scoped_thread_state_change.h"
 #include "ScopedLocalRef.h"
@@ -219,8 +219,7 @@
     mirror::Throwable* exception = soa.Self()->GetException(NULL);
     if (exception->IsCheckedException()) {
       mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
-      mirror::SynthesizedProxyClass* proxy_class =
-          down_cast<mirror::SynthesizedProxyClass*>(rcvr->GetClass());
+      mirror::Class* proxy_class = rcvr->GetClass();
       mirror::ArtMethod* interface_method =
           soa.Decode<mirror::ArtMethod*>(interface_method_jobj);
       mirror::ArtMethod* proxy_method =
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index ff836a4..11a67ac 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -17,105 +17,40 @@
 #ifndef ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_
 #define ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_
 
+#include <jni.h>
+#include <stdint.h>
+
 #include "base/macros.h"
-#include "class_linker-inl.h"
-#include "common_throws.h"
-#include "dex_file.h"
-#include "indirect_reference_table.h"
+#include "base/mutex.h"
+#include "gc/allocator_type.h"
 #include "invoke_type.h"
-#include "jni_internal.h"
-#include "mirror/art_method.h"
-#include "mirror/array.h"
-#include "mirror/class-inl.h"
-#include "mirror/object-inl.h"
-#include "mirror/throwable.h"
-#include "object_utils.h"
-#include "handle_scope-inl.h"
-#include "thread.h"
+#include "jvalue.h"
 
 namespace art {
 
 namespace mirror {
   class Class;
+  class Array;
   class ArtField;
+  class ArtMethod;
   class Object;
+  class String;
 }  // namespace mirror
 
+class ScopedObjectAccessAlreadyRunnable;
+class Thread;
+
 // TODO: Fix no thread safety analysis when GCC can handle template specialization.
 template <const bool kAccessCheck>
 ALWAYS_INLINE static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
                                                             mirror::ArtMethod* method,
                                                             Thread* self, bool* slow_path)
-    NO_THREAD_SAFETY_ANALYSIS {
-  mirror::Class* klass = method->GetDexCacheResolvedTypes()->GetWithoutChecks(type_idx);
-  if (UNLIKELY(klass == NULL)) {
-    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
-    *slow_path = true;
-    if (klass == NULL) {
-      DCHECK(self->IsExceptionPending());
-      return nullptr;  // Failure
-    }
-  }
-  if (kAccessCheck) {
-    if (UNLIKELY(!klass->IsInstantiable())) {
-      ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-      self->ThrowNewException(throw_location, "Ljava/lang/InstantiationError;",
-                              PrettyDescriptor(klass).c_str());
-      *slow_path = true;
-      return nullptr;  // Failure
-    }
-    mirror::Class* referrer = method->GetDeclaringClass();
-    if (UNLIKELY(!referrer->CanAccess(klass))) {
-      ThrowIllegalAccessErrorClass(referrer, klass);
-      *slow_path = true;
-      return nullptr;  // Failure
-    }
-  }
-  if (UNLIKELY(!klass->IsInitialized())) {
-    StackHandleScope<1> hs(self);
-    Handle<mirror::Class> h_klass(hs.NewHandle(klass));
-    // EnsureInitialized (the class initializer) might cause a GC.
-    // may cause us to suspend meaning that another thread may try to
-    // change the allocator while we are stuck in the entrypoints of
-    // an old allocator. Also, the class initialization may fail. To
-    // handle these cases we mark the slow path boolean as true so
-    // that the caller knows to check the allocator type to see if it
-    // has changed and to null-check the return value in case the
-    // initialization fails.
-    *slow_path = true;
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) {
-      DCHECK(self->IsExceptionPending());
-      return nullptr;  // Failure
-    }
-    return h_klass.Get();
-  }
-  return klass;
-}
+    NO_THREAD_SAFETY_ANALYSIS;
 
 // TODO: Fix no thread safety analysis when annotalysis is smarter.
 ALWAYS_INLINE static inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
                                                                                Thread* self, bool* slow_path)
-    NO_THREAD_SAFETY_ANALYSIS {
-  if (UNLIKELY(!klass->IsInitialized())) {
-    StackHandleScope<1> hs(self);
-    Handle<mirror::Class> h_class(hs.NewHandle(klass));
-    // EnsureInitialized (the class initializer) might cause a GC.
-    // may cause us to suspend meaning that another thread may try to
-    // change the allocator while we are stuck in the entrypoints of
-    // an old allocator. Also, the class initialization may fail. To
-    // handle these cases we mark the slow path boolean as true so
-    // that the caller knows to check the allocator type to see if it
-    // has changed and to null-check the return value in case the
-    // initialization fails.
-    *slow_path = true;
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
-      DCHECK(self->IsExceptionPending());
-      return nullptr;  // Failure
-    }
-    return h_class.Get();
-  }
-  return klass;
-}
+    NO_THREAD_SAFETY_ANALYSIS;
 
 // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
 // cannot be resolved, throw an error. If it can, use it to create an instance.
@@ -126,19 +61,7 @@
 ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
                                                                 mirror::ArtMethod* method,
                                                                 Thread* self,
-                                                                gc::AllocatorType allocator_type)
-    NO_THREAD_SAFETY_ANALYSIS {
-  bool slow_path = false;
-  mirror::Class* klass = CheckObjectAlloc<kAccessCheck>(type_idx, method, self, &slow_path);
-  if (UNLIKELY(slow_path)) {
-    if (klass == nullptr) {
-      return nullptr;
-    }
-    return klass->Alloc<kInstrumented>(self, Runtime::Current()->GetHeap()->GetCurrentAllocator());
-  }
-  DCHECK(klass != nullptr);
-  return klass->Alloc<kInstrumented>(self, allocator_type);
-}
+                                                                gc::AllocatorType allocator_type);
 
 // Given the context of a calling Method and a resolved class, create an instance.
 // TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
@@ -147,21 +70,7 @@
                                                                         mirror::ArtMethod* method,
                                                                         Thread* self,
                                                                         gc::AllocatorType allocator_type)
-    NO_THREAD_SAFETY_ANALYSIS {
-  DCHECK(klass != nullptr);
-  bool slow_path = false;
-  klass = CheckClassInitializedForObjectAlloc(klass, self, &slow_path);
-  if (UNLIKELY(slow_path)) {
-    if (klass == nullptr) {
-      return nullptr;
-    }
-    gc::Heap* heap = Runtime::Current()->GetHeap();
-    // Pass in false since the object can not be finalizable.
-    return klass->Alloc<kInstrumented, false>(self, heap->GetCurrentAllocator());
-  }
-  // Pass in false since the object can not be finalizable.
-  return klass->Alloc<kInstrumented, false>(self, allocator_type);
-}
+    NO_THREAD_SAFETY_ANALYSIS;
 
 // Given the context of a calling Method and an initialized class, create an instance.
 // TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
@@ -169,12 +78,7 @@
 ALWAYS_INLINE static inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass,
                                                                            mirror::ArtMethod* method,
                                                                            Thread* self,
-                                                                           gc::AllocatorType allocator_type)
-    NO_THREAD_SAFETY_ANALYSIS {
-  DCHECK(klass != nullptr);
-  // Pass in false since the object can not be finalizable.
-  return klass->Alloc<kInstrumented, false>(self, allocator_type);
-}
+                                                                           gc::AllocatorType allocator_type);
 
 
 // TODO: Fix no thread safety analysis when GCC can handle template specialization.
@@ -183,32 +87,7 @@
                                                            mirror::ArtMethod* method,
                                                            int32_t component_count,
                                                            bool* slow_path)
-    NO_THREAD_SAFETY_ANALYSIS {
-  if (UNLIKELY(component_count < 0)) {
-    ThrowNegativeArraySizeException(component_count);
-    *slow_path = true;
-    return nullptr;  // Failure
-  }
-  mirror::Class* klass = method->GetDexCacheResolvedTypes()->GetWithoutChecks(type_idx);
-  if (UNLIKELY(klass == nullptr)) {  // Not in dex cache so try to resolve
-    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
-    *slow_path = true;
-    if (klass == nullptr) {  // Error
-      DCHECK(Thread::Current()->IsExceptionPending());
-      return nullptr;  // Failure
-    }
-    CHECK(klass->IsArrayClass()) << PrettyClass(klass);
-  }
-  if (kAccessCheck) {
-    mirror::Class* referrer = method->GetDeclaringClass();
-    if (UNLIKELY(!referrer->CanAccess(klass))) {
-      ThrowIllegalAccessErrorClass(referrer, klass);
-      *slow_path = true;
-      return nullptr;  // Failure
-    }
-  }
-  return klass;
-}
+    NO_THREAD_SAFETY_ANALYSIS;
 
 // Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
 // it cannot be resolved, throw an error. If it can, use it to create an array.
@@ -221,22 +100,7 @@
                                                               int32_t component_count,
                                                               Thread* self,
                                                               gc::AllocatorType allocator_type)
-    NO_THREAD_SAFETY_ANALYSIS {
-  bool slow_path = false;
-  mirror::Class* klass = CheckArrayAlloc<kAccessCheck>(type_idx, method, component_count,
-                                                       &slow_path);
-  if (UNLIKELY(slow_path)) {
-    if (klass == nullptr) {
-      return nullptr;
-    }
-    gc::Heap* heap = Runtime::Current()->GetHeap();
-    return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
-                                               klass->GetComponentSize(),
-                                               heap->GetCurrentAllocator());
-  }
-  return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
-                                             klass->GetComponentSize(), allocator_type);
-}
+    NO_THREAD_SAFETY_ANALYSIS;
 
 template <bool kAccessCheck, bool kInstrumented>
 ALWAYS_INLINE static inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass,
@@ -244,24 +108,7 @@
                                                                       int32_t component_count,
                                                                       Thread* self,
                                                                       gc::AllocatorType allocator_type)
-    NO_THREAD_SAFETY_ANALYSIS {
-  DCHECK(klass != nullptr);
-  if (UNLIKELY(component_count < 0)) {
-    ThrowNegativeArraySizeException(component_count);
-    return nullptr;  // Failure
-  }
-  if (kAccessCheck) {
-    mirror::Class* referrer = method->GetDeclaringClass();
-    if (UNLIKELY(!referrer->CanAccess(klass))) {
-      ThrowIllegalAccessErrorClass(referrer, klass);
-      return nullptr;  // Failure
-    }
-  }
-  // No need to retry a slow-path allocation as the above code won't cause a GC or thread
-  // suspension.
-  return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
-                                             klass->GetComponentSize(), allocator_type);
-}
+    NO_THREAD_SAFETY_ANALYSIS;
 
 extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::ArtMethod* method,
                                                  int32_t component_count, Thread* self,
@@ -290,422 +137,47 @@
 
 template<FindFieldType type, bool access_check>
 static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::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;
-  }
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  mirror::ArtField* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
-  if (UNLIKELY(resolved_field == nullptr)) {
-    DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
-    return nullptr;  // Failure.
-  }
-  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
-  if (access_check) {
-    if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
-      ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
-      return nullptr;
-    }
-    mirror::Class* referring_class = referrer->GetDeclaringClass();
-    if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class, resolved_field,
-                                                            field_idx))) {
-      DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
-      return nullptr;  // Failure.
-    }
-    if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
-      ThrowIllegalAccessErrorFinalField(referrer, resolved_field);
-      return nullptr;  // Failure.
-    } else {
-      if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
-                   resolved_field->FieldSize() != expected_size)) {
-        ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-        DCHECK(throw_location.GetMethod() == referrer);
-        self->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
-                                 "Attempted read of %zd-bit %s on field '%s'",
-                                 expected_size * (32 / sizeof(int32_t)),
-                                 is_primitive ? "primitive" : "non-primitive",
-                                 PrettyField(resolved_field, true).c_str());
-        return nullptr;  // Failure.
-      }
-    }
-  }
-  if (!is_static) {
-    // instance fields must be being accessed on an initialized class
-    return resolved_field;
-  } else {
-    // If the class is initialized we're done.
-    if (LIKELY(fields_class->IsInitialized())) {
-      return resolved_field;
-    } else {
-      StackHandleScope<1> hs(self);
-      Handle<mirror::Class> h_class(hs.NewHandle(fields_class));
-      if (LIKELY(class_linker->EnsureInitialized(h_class, true, true))) {
-        // Otherwise let's ensure the class is initialized before resolving the field.
-        return resolved_field;
-      }
-      DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-      return nullptr;  // Failure.
-    }
-  }
-}
-
-// Explicit template declarations of FindFieldFromCode for all field access types.
-#define EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \
-template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
-mirror::ArtField* FindFieldFromCode<_type, _access_check>(uint32_t field_idx, \
-                                                          mirror::ArtMethod* referrer, \
-                                                          Thread* self, size_t expected_size) \
-
-#define EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
-    EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, false); \
-    EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, true)
-
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectRead);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectWrite);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveRead);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveWrite);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectRead);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectWrite);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveRead);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveWrite);
-
-#undef EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL
-#undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
+                                                  Thread* self, size_t expected_size)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 template<InvokeType type, bool access_check>
 static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
                                                     mirror::Object** this_object,
-                                                    mirror::ArtMethod** referrer, Thread* self) {
-  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-  mirror::ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, *referrer, type);
-  if (resolved_method == nullptr) {
-    StackHandleScope<1> hs(self);
-    mirror::Object* null_this = nullptr;
-    HandleWrapper<mirror::Object> h_this(
-        hs.NewHandleWrapper(type == kStatic ? &null_this : this_object));
-    resolved_method = class_linker->ResolveMethod(self, method_idx, referrer, type);
-  }
-  if (UNLIKELY(resolved_method == nullptr)) {
-    DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
-    return nullptr;  // Failure.
-  } else if (UNLIKELY(*this_object == nullptr && type != kStatic)) {
-    // Maintain interpreter-like semantics where NullPointerException is thrown
-    // after potential NoSuchMethodError from class linker.
-    ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-    DCHECK_EQ(*referrer, throw_location.GetMethod());
-    ThrowNullPointerExceptionForMethodAccess(throw_location, method_idx, type);
-    return nullptr;  // Failure.
-  } else if (access_check) {
-    // Incompatible class change should have been handled in resolve method.
-    if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
-      ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method,
-                                        *referrer);
-      return nullptr;  // Failure.
-    }
-    mirror::Class* methods_class = resolved_method->GetDeclaringClass();
-    mirror::Class* referring_class = (*referrer)->GetDeclaringClass();
-    bool can_access_resolved_method =
-        referring_class->CheckResolvedMethodAccess<type>(methods_class, resolved_method,
-                                                         method_idx);
-    if (UNLIKELY(!can_access_resolved_method)) {
-      DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
-      return nullptr;  // Failure.
-    }
-  }
-  switch (type) {
-    case kStatic:
-    case kDirect:
-      return resolved_method;
-    case kVirtual: {
-      mirror::ObjectArray<mirror::ArtMethod>* vtable = (*this_object)->GetClass()->GetVTable();
-      uint16_t vtable_index = resolved_method->GetMethodIndex();
-      if (access_check &&
-          (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength()))) {
-        // Behavior to agree with that of the verifier.
-        ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
-                               resolved_method->GetName(), resolved_method->GetSignature());
-        return nullptr;  // Failure.
-      }
-      DCHECK(vtable != nullptr);
-      return vtable->GetWithoutChecks(vtable_index);
-    }
-    case kSuper: {
-      mirror::Class* super_class = (*referrer)->GetDeclaringClass()->GetSuperClass();
-      uint16_t vtable_index = resolved_method->GetMethodIndex();
-      mirror::ObjectArray<mirror::ArtMethod>* vtable;
-      if (access_check) {
-        // Check existence of super class.
-        vtable = (super_class != nullptr) ? super_class->GetVTable() : nullptr;
-        if (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength())) {
-          // Behavior to agree with that of the verifier.
-          ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
-                                 resolved_method->GetName(), resolved_method->GetSignature());
-          return nullptr;  // Failure.
-        }
-      } else {
-        // Super class must exist.
-        DCHECK(super_class != nullptr);
-        vtable = super_class->GetVTable();
-      }
-      DCHECK(vtable != nullptr);
-      return vtable->GetWithoutChecks(vtable_index);
-    }
-    case kInterface: {
-      uint32_t imt_index = resolved_method->GetDexMethodIndex() % ClassLinker::kImtSize;
-      mirror::ObjectArray<mirror::ArtMethod>* imt_table = (*this_object)->GetClass()->GetImTable();
-      mirror::ArtMethod* imt_method = imt_table->Get(imt_index);
-      if (!imt_method->IsImtConflictMethod()) {
-        return imt_method;
-      } else {
-        mirror::ArtMethod* interface_method =
-            (*this_object)->GetClass()->FindVirtualMethodForInterface(resolved_method);
-        if (UNLIKELY(interface_method == nullptr)) {
-          ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method,
-                                                                     *this_object, *referrer);
-          return nullptr;  // Failure.
-        }
-        return interface_method;
-      }
-    }
-    default:
-      LOG(FATAL) << "Unknown invoke type " << type;
-      return nullptr;  // Failure.
-  }
-}
-
-// Explicit template declarations of FindMethodFromCode for all invoke types.
-#define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check)                 \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                       \
-  mirror::ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx,         \
-                                                              mirror::Object** this_object, \
-                                                              mirror::ArtMethod** referrer, \
-                                                              Thread* self)
-#define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
-    EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false);   \
-    EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, true)
-
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kStatic);
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kDirect);
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kVirtual);
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kSuper);
-EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kInterface);
-
-#undef EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL
-#undef EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL
+                                                    mirror::ArtMethod** referrer, Thread* self)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Fast path field resolution that can't initialize classes or throw exceptions.
 static inline mirror::ArtField* FindFieldFast(uint32_t field_idx,
                                               mirror::ArtMethod* referrer,
                                               FindFieldType type, size_t expected_size)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ArtField* resolved_field =
-      referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
-  if (UNLIKELY(resolved_field == nullptr)) {
-    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";  // Assignment below to avoid GCC warnings.
-      is_primitive = true;
-      is_set = true;
-      is_static = true;
-      break;
-  }
-  if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
-    // Incompatible class change.
-    return nullptr;
-  }
-  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
-  if (is_static) {
-    // Check class is initialized else fail so that we can contend to initialize the class with
-    // other threads that may be racing to do this.
-    if (UNLIKELY(!fields_class->IsInitialized())) {
-      return nullptr;
-    }
-  }
-  mirror::Class* referring_class = referrer->GetDeclaringClass();
-  if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
-               !referring_class->CanAccessMember(fields_class,
-                                                 resolved_field->GetAccessFlags()) ||
-               (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
-    // Illegal access.
-    return nullptr;
-  }
-  if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
-               resolved_field->FieldSize() != expected_size)) {
-    return nullptr;
-  }
-  return resolved_field;
-}
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Fast path method resolution that can't throw exceptions.
 static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx,
                                                 mirror::Object* this_object,
                                                 mirror::ArtMethod* referrer,
                                                 bool access_check, InvokeType type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  bool is_direct = type == kStatic || type == kDirect;
-  if (UNLIKELY(this_object == NULL && !is_direct)) {
-    return NULL;
-  }
-  mirror::ArtMethod* resolved_method =
-      referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
-  if (UNLIKELY(resolved_method == NULL)) {
-    return NULL;
-  }
-  if (access_check) {
-    // Check for incompatible class change errors and access.
-    bool icce = resolved_method->CheckIncompatibleClassChange(type);
-    if (UNLIKELY(icce)) {
-      return NULL;
-    }
-    mirror::Class* methods_class = resolved_method->GetDeclaringClass();
-    mirror::Class* referring_class = referrer->GetDeclaringClass();
-    if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
-                 !referring_class->CanAccessMember(methods_class,
-                                                   resolved_method->GetAccessFlags()))) {
-      // Potential illegal access, may need to refine the method's class.
-      return NULL;
-    }
-  }
-  if (type == kInterface) {  // Most common form of slow path dispatch.
-    return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
-  } else if (is_direct) {
-    return resolved_method;
-  } else if (type == kSuper) {
-    return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->
-        Get(resolved_method->GetMethodIndex());
-  } else {
-    DCHECK(type == kVirtual);
-    return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
-  }
-}
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
                                                     mirror::ArtMethod* referrer,
                                                     Thread* self, bool can_run_clinit,
                                                     bool verify_access)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  mirror::Class* klass = class_linker->ResolveType(type_idx, referrer);
-  if (UNLIKELY(klass == nullptr)) {
-    CHECK(self->IsExceptionPending());
-    return nullptr;  // Failure - Indicate to caller to deliver exception
-  }
-  // Perform access check if necessary.
-  mirror::Class* referring_class = referrer->GetDeclaringClass();
-  if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
-    ThrowIllegalAccessErrorClass(referring_class, klass);
-    return nullptr;  // Failure - Indicate to caller to deliver exception
-  }
-  // If we're just implementing const-class, we shouldn't call <clinit>.
-  if (!can_run_clinit) {
-    return klass;
-  }
-  // If we are the <clinit> of this class, just return our storage.
-  //
-  // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
-  // running.
-  if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) {
-    return klass;
-  }
-  StackHandleScope<1> hs(self);
-  Handle<mirror::Class> h_class(hs.NewHandle(klass));
-  if (!class_linker->EnsureInitialized(h_class, true, true)) {
-    CHECK(self->IsExceptionPending());
-    return nullptr;  // Failure - Indicate to caller to deliver exception
-  }
-  return h_class.Get();
-}
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 static inline mirror::String* ResolveStringFromCode(mirror::ArtMethod* referrer,
                                                     uint32_t string_idx)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  return class_linker->ResolveString(string_idx, referrer);
-}
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
-    NO_THREAD_SAFETY_ANALYSIS /* SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) */ {
-  // Save any pending exception over monitor exit call.
-  mirror::Throwable* saved_exception = NULL;
-  ThrowLocation saved_throw_location;
-  bool is_exception_reported = self->IsExceptionReportedToInstrumentation();
-  if (UNLIKELY(self->IsExceptionPending())) {
-    saved_exception = self->GetException(&saved_throw_location);
-    self->ClearException();
-  }
-  // Decode locked object and unlock, before popping local references.
-  self->DecodeJObject(locked)->MonitorExit(self);
-  if (UNLIKELY(self->IsExceptionPending())) {
-    LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
-        << saved_exception->Dump()
-        << "\nEncountered second exception during implicit MonitorExit:\n"
-        << self->GetException(NULL)->Dump();
-  }
-  // Restore pending exception.
-  if (saved_exception != NULL) {
-    self->SetException(saved_throw_location, saved_exception);
-    self->SetExceptionReportedToInstrumentation(is_exception_reported);
-  }
-}
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 static inline void CheckReferenceResult(mirror::Object* o, Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (o == NULL) {
-    return;
-  }
-  mirror::ArtMethod* m = self->GetCurrentMethod(NULL);
-  if (o == kInvalidIndirectRefObject) {
-    JniAbortF(NULL, "invalid reference returned from %s", PrettyMethod(m).c_str());
-  }
-  // Make sure that the result is an instance of the type this method was expected to return.
-  StackHandleScope<1> hs(self);
-  Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
-  mirror::Class* return_type = MethodHelper(h_m).GetReturnType();
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  if (!o->InstanceOf(return_type)) {
-    JniAbortF(NULL, "attempt to return an instance of %s from %s", PrettyTypeOf(o).c_str(),
-              PrettyMethod(h_m.Get()).c_str());
-  }
-}
-
-static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  for (;;) {
-    if (thread->ReadFlag(kCheckpointRequest)) {
-      thread->RunCheckpointFunction();
-    } else if (thread->ReadFlag(kSuspendRequest)) {
-      thread->FullSuspendCheck();
-    } else {
-      break;
-    }
-  }
-}
+static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, const char* shorty,
                                     jobject rcvr_jobj, jobject interface_art_method_jobj,
@@ -750,26 +222,6 @@
   return GetQuickToInterpreterBridge();
 }
 
-static inline const void* GetPortableResolutionTrampoline(ClassLinker* class_linker) {
-  return class_linker->GetPortableResolutionTrampoline();
-}
-
-static inline const void* GetQuickResolutionTrampoline(ClassLinker* class_linker) {
-  return class_linker->GetQuickResolutionTrampoline();
-}
-
-static inline const void* GetPortableImtConflictTrampoline(ClassLinker* class_linker) {
-  return class_linker->GetPortableImtConflictTrampoline();
-}
-
-static inline const void* GetQuickImtConflictTrampoline(ClassLinker* class_linker) {
-  return class_linker->GetQuickImtConflictTrampoline();
-}
-
-static inline const void* GetQuickToInterpreterBridgeTrampoline(ClassLinker* class_linker) {
-  return class_linker->GetQuickToInterpreterBridgeTrampoline();
-}
-
 extern "C" void art_portable_proxy_invoke_handler();
 static inline const void* GetPortableProxyInvokeHandler() {
   return reinterpret_cast<void*>(art_portable_proxy_invoke_handler);
@@ -786,21 +238,7 @@
 }
 
 template <typename INT_TYPE, typename FLOAT_TYPE>
-static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) {
-  const INT_TYPE kMaxInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::max());
-  const INT_TYPE kMinInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::min());
-  const FLOAT_TYPE kMaxIntAsFloat = static_cast<FLOAT_TYPE>(kMaxInt);
-  const FLOAT_TYPE kMinIntAsFloat = static_cast<FLOAT_TYPE>(kMinInt);
-  if (LIKELY(f > kMinIntAsFloat)) {
-     if (LIKELY(f < kMaxIntAsFloat)) {
-       return static_cast<INT_TYPE>(f);
-     } else {
-       return kMaxInt;
-     }
-  } else {
-    return (f != f) ? 0 : kMinInt;  // f != f implies NaN
-  }
-}
+static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f);
 
 }  // namespace art
 
diff --git a/runtime/entrypoints/math_entrypoints.cc b/runtime/entrypoints/math_entrypoints.cc
index b839b63..b0eaf1e 100644
--- a/runtime/entrypoints/math_entrypoints.cc
+++ b/runtime/entrypoints/math_entrypoints.cc
@@ -16,7 +16,7 @@
 
 #include "math_entrypoints.h"
 
-#include "entrypoint_utils.h"
+#include "entrypoint_utils-inl.h"
 
 namespace art {
 
diff --git a/runtime/entrypoints/portable/portable_alloc_entrypoints.cc b/runtime/entrypoints/portable/portable_alloc_entrypoints.cc
index 4c05e75..de95f7d 100644
--- a/runtime/entrypoints/portable/portable_alloc_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_alloc_entrypoints.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
 
diff --git a/runtime/entrypoints/portable/portable_cast_entrypoints.cc b/runtime/entrypoints/portable/portable_cast_entrypoints.cc
index a553a22..151b178 100644
--- a/runtime/entrypoints/portable/portable_cast_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_cast_entrypoints.cc
@@ -15,7 +15,7 @@
  */
 
 #include "common_throws.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/object-inl.h"
 
 namespace art {
diff --git a/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc b/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc
index b37ebcf..9364c46 100644
--- a/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
diff --git a/runtime/entrypoints/portable/portable_field_entrypoints.cc b/runtime/entrypoints/portable/portable_field_entrypoints.cc
index f48f1a9..371aca4 100644
--- a/runtime/entrypoints/portable/portable_field_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_field_entrypoints.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
diff --git a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
index 335a617..686954b 100644
--- a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
@@ -15,7 +15,7 @@
  */
 
 #include "dex_instruction.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
 
diff --git a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
index eb50ec3..6f9c083 100644
--- a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object-inl.h"
diff --git a/runtime/entrypoints/portable/portable_jni_entrypoints.cc b/runtime/entrypoints/portable/portable_jni_entrypoints.cc
index 3e7b30a..0d0f21b 100644
--- a/runtime/entrypoints/portable/portable_jni_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_jni_entrypoints.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
 #include "thread-inl.h"
diff --git a/runtime/entrypoints/portable/portable_lock_entrypoints.cc b/runtime/entrypoints/portable/portable_lock_entrypoints.cc
index 358ac23..fcd3e9d 100644
--- a/runtime/entrypoints/portable/portable_lock_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_lock_entrypoints.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/object-inl.h"
 
 namespace art {
diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
index 9e62e0e..23e1c36 100644
--- a/runtime/entrypoints/portable/portable_thread_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_method.h"
 #include "mirror/object-inl.h"
 #include "verifier/dex_gc_map.h"
diff --git a/runtime/entrypoints/portable/portable_throw_entrypoints.cc b/runtime/entrypoints/portable/portable_throw_entrypoints.cc
index 189e6b5..9e36a05 100644
--- a/runtime/entrypoints/portable/portable_throw_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_throw_entrypoints.cc
@@ -15,7 +15,7 @@
  */
 
 #include "dex_instruction.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
 
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index 2da016f..7ee869b 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -18,7 +18,7 @@
 #define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
 
 #include "dex_instruction-inl.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "interpreter/interpreter.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/object-inl.h"
@@ -431,7 +431,7 @@
     // Expect class to at least be initializing.
     DCHECK(called->GetDeclaringClass()->IsInitializing());
     // Don't want infinite recursion.
-    DCHECK(code != GetPortableResolutionTrampoline(linker));
+    DCHECK(code != linker->GetPortableResolutionTrampoline());
     // Set up entry into main method
     *called_addr = called;
   }
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index dde74de..1f2713a 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -17,7 +17,7 @@
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 
 #include "callee_save_frame.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object_array-inl.h"
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 53c9b97..704db05 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -15,7 +15,7 @@
  */
 
 #include "callee_save_frame.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
 #include "gc/accounting/card_table-inl.h"
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index 5cb0f36..cd1e247 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -16,7 +16,7 @@
 
 #include "callee_save_frame.h"
 #include "dex_file-inl.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_field-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index 2edcb78..9a22c15 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -38,7 +38,7 @@
   } else {
     result = instrumentation->GetQuickCodeFor(method);
   }
-  DCHECK(result != GetQuickToInterpreterBridgeTrampoline(Runtime::Current()->GetClassLinker()));
+  DCHECK(result != Runtime::Current()->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline());
   bool interpreter_entry = (result == GetQuickToInterpreterBridge());
   instrumentation->PushInstrumentationStackFrame(self, method->IsStatic() ? nullptr : this_object,
                                                  method, lr, interpreter_entry);
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 140b075..30e8609 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -15,7 +15,7 @@
  */
 
 #include "dex_file-inl.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object.h"
diff --git a/runtime/entrypoints/quick/quick_thread_entrypoints.cc b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
index 5c48fc7..118cd7f 100644
--- a/runtime/entrypoints/quick/quick_thread_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
@@ -15,7 +15,7 @@
  */
 
 #include "callee_save_frame.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "thread.h"
 #include "thread_list.h"
 
diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
index e6f294a..4dcb1c8 100644
--- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
@@ -16,7 +16,7 @@
 
 #include "callee_save_frame.h"
 #include "common_throws.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/object-inl.h"
 #include "object_utils.h"
 #include "thread.h"
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 2a66f2f..f7cb126 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -18,7 +18,7 @@
 #include "common_throws.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "instruction_set.h"
 #include "interpreter/interpreter.h"
diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h
index ad0a4f43..46b9363 100644
--- a/runtime/gc/accounting/card_table-inl.h
+++ b/runtime/gc/accounting/card_table-inl.h
@@ -50,8 +50,9 @@
 template <typename Visitor>
 inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, byte* scan_begin, byte* scan_end,
                               const Visitor& visitor, const byte minimum_age) const {
-  DCHECK(bitmap->HasAddress(scan_begin));
-  DCHECK(bitmap->HasAddress(scan_end - 1));  // scan_end is the byte after the last byte we scan.
+  DCHECK_GE(scan_begin, reinterpret_cast<byte*>(bitmap->HeapBegin()));
+  // scan_end is the byte after the last byte we scan.
+  DCHECK_LE(scan_end, reinterpret_cast<byte*>(bitmap->HeapLimit()));
   byte* card_cur = CardFromAddr(scan_begin);
   byte* card_end = CardFromAddr(scan_end);
   CheckCardValid(card_cur);
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index c66e80d..ad22a2e 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -68,9 +68,9 @@
              << ", capacity=" << std::dec << capacity_
              << ", max_capacity=" << std::dec << max_capacity_;
   for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
-    size_bracket_lock_names[i] =
+    size_bracket_lock_names_[i] =
         StringPrintf("an rosalloc size bracket %d lock", static_cast<int>(i));
-    size_bracket_locks_[i] = new Mutex(size_bracket_lock_names[i].c_str(), kRosAllocBracketLock);
+    size_bracket_locks_[i] = new Mutex(size_bracket_lock_names_[i].c_str(), kRosAllocBracketLock);
     current_runs_[i] = dedicated_full_run_;
   }
   DCHECK_EQ(footprint_, capacity_);
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 85a8225..c0ab151 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -440,7 +440,7 @@
   // The mutexes, one per size bracket.
   Mutex* size_bracket_locks_[kNumOfSizeBrackets];
   // Bracket lock names (since locks only have char* names).
-  std::string size_bracket_lock_names[kNumOfSizeBrackets];
+  std::string size_bracket_lock_names_[kNumOfSizeBrackets];
   // The types of page map entries.
   enum {
     kPageMapReleased = 0,     // Zero and released back to the OS.
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index 530a3c9..ef5d56e 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -40,6 +40,9 @@
   kCollectorTypeHeapTrim,
   // A (mostly) concurrent copying collector.
   kCollectorTypeCC,
+  // A homogeneous space compaction collector used in background transition
+  // when both foreground and background collector are CMS.
+  kCollectorTypeHomogeneousSpaceCompact,
 };
 std::ostream& operator<<(std::ostream& os, const CollectorType& collector_type);
 
diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc
index 9e73f14..f0e1512 100644
--- a/runtime/gc/gc_cause.cc
+++ b/runtime/gc/gc_cause.cc
@@ -31,6 +31,7 @@
     case kGcCauseForNativeAlloc: return "NativeAlloc";
     case kGcCauseCollectorTransition: return "CollectorTransition";
     case kGcCauseDisableMovingGc: return "DisableMovingGc";
+    case kGcCauseHomogeneousSpaceCompact: return "HomogeneousSpaceCompact";
     case kGcCauseTrim: return "HeapTrim";
     default:
       LOG(FATAL) << "Unreachable";
diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h
index 10e6667..1f2643a 100644
--- a/runtime/gc/gc_cause.h
+++ b/runtime/gc/gc_cause.h
@@ -39,6 +39,8 @@
   kGcCauseDisableMovingGc,
   // Not a real GC cause, used when we trim the heap.
   kGcCauseTrim,
+  // GC triggered for background transition when both foreground and background collector are CMS.
+  kGcCauseHomogeneousSpaceCompact,
 };
 
 const char* PrettyCause(GcCause cause);
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 58ba61b..419af30 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -41,11 +41,11 @@
                                                       const PreFenceVisitor& pre_fence_visitor) {
   if (kIsDebugBuild) {
     CheckPreconditionsForAllocObject(klass, byte_count);
+    // Since allocation can cause a GC which will need to SuspendAll, make sure all allocations are
+    // done in the runnable state where suspension is expected.
+    CHECK_EQ(self->GetState(), kRunnable);
+    self->AssertThreadSuspensionIsAllowable();
   }
-  // Since allocation can cause a GC which will need to SuspendAll, make sure all allocations are
-  // done in the runnable state where suspension is expected.
-  DCHECK_EQ(self->GetState(), kRunnable);
-  self->AssertThreadSuspensionIsAllowable();
   // Need to check that we arent the large object allocator since the large object allocation code
   // path this function. If we didn't check we would have an infinite loop.
   if (kCheckLargeObject && UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) {
@@ -54,49 +54,70 @@
   }
   mirror::Object* obj;
   AllocationTimer alloc_timer(this, &obj);
-  size_t bytes_allocated, usable_size;
-  obj = TryToAllocate<kInstrumented, false>(self, allocator, byte_count, &bytes_allocated,
-                                            &usable_size);
-  if (UNLIKELY(obj == nullptr)) {
-    bool is_current_allocator = allocator == GetCurrentAllocator();
-    obj = AllocateInternalWithGc(self, allocator, byte_count, &bytes_allocated, &usable_size,
-                                 &klass);
-    if (obj == nullptr) {
-      bool after_is_current_allocator = allocator == GetCurrentAllocator();
-      if (is_current_allocator && !after_is_current_allocator) {
-        // If the allocator changed, we need to restart the allocation.
-        return AllocObject<kInstrumented>(self, klass, byte_count, pre_fence_visitor);
+  size_t bytes_allocated;
+  size_t usable_size;
+  size_t new_num_bytes_allocated = 0;
+  if (allocator == kAllocatorTypeTLAB) {
+    byte_count = RoundUp(byte_count, space::BumpPointerSpace::kAlignment);
+  }
+  // If we have a thread local allocation we don't need to update bytes allocated.
+  if (allocator == kAllocatorTypeTLAB && byte_count <= self->TlabSize()) {
+    obj = self->AllocTlab(byte_count);
+    obj->SetClass(klass);
+    if (kUseBakerOrBrooksReadBarrier) {
+      if (kUseBrooksReadBarrier) {
+        obj->SetReadBarrierPointer(obj);
       }
-      return nullptr;
+      obj->AssertReadBarrierPointer();
     }
-  }
-  DCHECK_GT(bytes_allocated, 0u);
-  DCHECK_GT(usable_size, 0u);
-  obj->SetClass(klass);
-  if (kUseBakerOrBrooksReadBarrier) {
-    if (kUseBrooksReadBarrier) {
-      obj->SetReadBarrierPointer(obj);
+    bytes_allocated = byte_count;
+    pre_fence_visitor(obj, bytes_allocated);
+    QuasiAtomic::ThreadFenceForConstructor();
+  } else {
+    obj = TryToAllocate<kInstrumented, false>(self, allocator, byte_count, &bytes_allocated,
+                                              &usable_size);
+    if (UNLIKELY(obj == nullptr)) {
+      bool is_current_allocator = allocator == GetCurrentAllocator();
+      obj = AllocateInternalWithGc(self, allocator, byte_count, &bytes_allocated, &usable_size,
+                                   &klass);
+      if (obj == nullptr) {
+        bool after_is_current_allocator = allocator == GetCurrentAllocator();
+        if (is_current_allocator && !after_is_current_allocator) {
+          // If the allocator changed, we need to restart the allocation.
+          return AllocObject<kInstrumented>(self, klass, byte_count, pre_fence_visitor);
+        }
+        return nullptr;
+      }
     }
-    obj->AssertReadBarrierPointer();
+    DCHECK_GT(bytes_allocated, 0u);
+    DCHECK_GT(usable_size, 0u);
+    obj->SetClass(klass);
+    if (kUseBakerOrBrooksReadBarrier) {
+      if (kUseBrooksReadBarrier) {
+        obj->SetReadBarrierPointer(obj);
+      }
+      obj->AssertReadBarrierPointer();
+    }
+    if (collector::SemiSpace::kUseRememberedSet && UNLIKELY(allocator == kAllocatorTypeNonMoving)) {
+      // (Note this if statement will be constant folded away for the
+      // fast-path quick entry points.) Because SetClass() has no write
+      // barrier, if a non-moving space allocation, we need a write
+      // barrier as the class pointer may point to the bump pointer
+      // space (where the class pointer is an "old-to-young" reference,
+      // though rare) under the GSS collector with the remembered set
+      // enabled. We don't need this for kAllocatorTypeRosAlloc/DlMalloc
+      // cases because we don't directly allocate into the main alloc
+      // space (besides promotions) under the SS/GSS collector.
+      WriteBarrierField(obj, mirror::Object::ClassOffset(), klass);
+    }
+    pre_fence_visitor(obj, usable_size);
+    if (kIsDebugBuild && Runtime::Current()->IsStarted()) {
+      CHECK_LE(obj->SizeOf(), usable_size);
+    }
+    new_num_bytes_allocated =
+        static_cast<size_t>(num_bytes_allocated_.FetchAndAddSequentiallyConsistent(bytes_allocated))
+        + bytes_allocated;
   }
-  if (collector::SemiSpace::kUseRememberedSet && UNLIKELY(allocator == kAllocatorTypeNonMoving)) {
-    // (Note this if statement will be constant folded away for the
-    // fast-path quick entry points.) Because SetClass() has no write
-    // barrier, if a non-moving space allocation, we need a write
-    // barrier as the class pointer may point to the bump pointer
-    // space (where the class pointer is an "old-to-young" reference,
-    // though rare) under the GSS collector with the remembered set
-    // enabled. We don't need this for kAllocatorTypeRosAlloc/DlMalloc
-    // cases because we don't directly allocate into the main alloc
-    // space (besides promotions) under the SS/GSS collector.
-    WriteBarrierField(obj, mirror::Object::ClassOffset(), klass);
-  }
-  pre_fence_visitor(obj, usable_size);
-  if (kIsDebugBuild && Runtime::Current()->IsStarted()) {
-    CHECK_LE(obj->SizeOf(), usable_size);
-  }
-  const size_t new_num_bytes_allocated =
-      static_cast<size_t>(num_bytes_allocated_.FetchAndAddSequentiallyConsistent(bytes_allocated)) + bytes_allocated;
   // TODO: Deprecate.
   if (kInstrumented) {
     if (Runtime::Current()->HasStatsEnabled()) {
@@ -158,7 +179,8 @@
 inline mirror::Object* Heap::TryToAllocate(Thread* self, AllocatorType allocator_type,
                                            size_t alloc_size, size_t* bytes_allocated,
                                            size_t* usable_size) {
-  if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type, alloc_size))) {
+  if (allocator_type != kAllocatorTypeTLAB &&
+      UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type, alloc_size))) {
     return nullptr;
   }
   mirror::Object* ret;
@@ -206,18 +228,24 @@
       break;
     }
     case kAllocatorTypeTLAB: {
-      alloc_size = RoundUp(alloc_size, space::BumpPointerSpace::kAlignment);
+      DCHECK_ALIGNED(alloc_size, space::BumpPointerSpace::kAlignment);
       if (UNLIKELY(self->TlabSize() < alloc_size)) {
-        // Try allocating a new thread local buffer, if the allocaiton fails the space must be
-        // full so return nullptr.
-        if (!bump_pointer_space_->AllocNewTlab(self, alloc_size + kDefaultTLABSize)) {
+        const size_t new_tlab_size = alloc_size + kDefaultTLABSize;
+        if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type, new_tlab_size))) {
           return nullptr;
         }
+        // Try allocating a new thread local buffer, if the allocaiton fails the space must be
+        // full so return nullptr.
+        if (!bump_pointer_space_->AllocNewTlab(self, new_tlab_size)) {
+          return nullptr;
+        }
+        *bytes_allocated = new_tlab_size;
+      } else {
+        *bytes_allocated = 0;
       }
       // The allocation can't fail.
       ret = self->AllocTlab(alloc_size);
       DCHECK(ret != nullptr);
-      *bytes_allocated = alloc_size;
       *usable_size = alloc_size;
       break;
     }
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 19715e9..4ec9bc2 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -93,6 +93,10 @@
 static constexpr size_t kAllocationStackReserveSize = 1024;
 // Default mark stack size in bytes.
 static const size_t kDefaultMarkStackSize = 64 * KB;
+// Define space name.
+static const char* kDlMallocSpaceName[2] = {"main dlmalloc space", "main dlmalloc space 1"};
+static const char* kRosAllocSpaceName[2] = {"main rosalloc space", "main rosalloc space 1"};
+static const char* kMemMapSpaceName[2] = {"main space", "main space 1"};
 
 Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
            double target_utilization, double foreground_heap_growth_multiplier, size_t capacity,
@@ -103,7 +107,8 @@
            bool ignore_max_footprint, bool use_tlab,
            bool verify_pre_gc_heap, bool verify_pre_sweeping_heap, bool verify_post_gc_heap,
            bool verify_pre_gc_rosalloc, bool verify_pre_sweeping_rosalloc,
-           bool verify_post_gc_rosalloc)
+           bool verify_post_gc_rosalloc, bool use_homogeneous_space_compaction_for_oom,
+           uint64_t min_interval_homogeneous_space_compaction_by_oom)
     : non_moving_space_(nullptr),
       rosalloc_space_(nullptr),
       dlmalloc_space_(nullptr),
@@ -173,7 +178,11 @@
       verify_object_mode_(kVerifyObjectModeDisabled),
       disable_moving_gc_count_(0),
       running_on_valgrind_(Runtime::Current()->RunningOnValgrind()),
-      use_tlab_(use_tlab) {
+      use_tlab_(use_tlab),
+      main_space_backup_(nullptr),
+      min_interval_homogeneous_space_compaction_by_oom_(min_interval_homogeneous_space_compaction_by_oom),
+      last_time_homogeneous_space_compaction_by_oom_(NanoTime()),
+      use_homogeneous_space_compaction_for_oom_(use_homogeneous_space_compaction_for_oom) {
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     LOG(INFO) << "Heap() entering";
   }
@@ -205,30 +214,90 @@
     CHECK_GT(oat_file_end_addr, image_space->End());
     requested_alloc_space_begin = AlignUp(oat_file_end_addr, kPageSize);
   }
+
+  /*
+  requested_alloc_space_begin ->     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+                                     +-  nonmoving space (kNonMovingSpaceCapacity) +-
+                                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+                                     +-        main alloc space (capacity_)        +-
+                                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+                                     +-       main alloc space 1 (capacity_)       +-
+                                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+  */
+  bool create_backup_main_space =
+      background_collector_type == gc::kCollectorTypeHomogeneousSpaceCompact ||
+      use_homogeneous_space_compaction_for_oom;
   if (is_zygote) {
     // Reserve the address range before we create the non moving space to make sure bitmaps don't
     // take it.
     std::string error_str;
-    MemMap* mem_map = MemMap::MapAnonymous(
-        "main space", requested_alloc_space_begin + kNonMovingSpaceCapacity, capacity,
+    MemMap* main_space_map = MemMap::MapAnonymous(
+        kMemMapSpaceName[0], requested_alloc_space_begin + kNonMovingSpaceCapacity, capacity_,
         PROT_READ | PROT_WRITE, true, &error_str);
-    CHECK(mem_map != nullptr) << error_str;
+    CHECK(main_space_map != nullptr) << error_str;
+    MemMap* main_space_1_map = nullptr;
+    // Attempt to reserve an extra mem_map for homogeneous space compaction right after the main space map.
+    if (create_backup_main_space) {
+      main_space_1_map = MemMap::MapAnonymous(kMemMapSpaceName[1], main_space_map->End(), capacity_,
+                                               PROT_READ | PROT_WRITE, true, &error_str);
+      if (main_space_1_map == nullptr) {
+        LOG(WARNING) << "Failed to create map " <<  kMemMapSpaceName[1] << " with error "
+                     << error_str;
+      }
+    }
     // Non moving space is always dlmalloc since we currently don't have support for multiple
-    // rosalloc spaces.
+    // active rosalloc spaces.
     non_moving_space_ = space::DlMallocSpace::Create(
-        "zygote / non moving space", initial_size, kNonMovingSpaceCapacity, kNonMovingSpaceCapacity,
-        requested_alloc_space_begin, false);
+        "zygote / non moving space", initial_size, kNonMovingSpaceCapacity,
+        kNonMovingSpaceCapacity, requested_alloc_space_begin, false);
     non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
-    CreateMainMallocSpace(mem_map, initial_size, growth_limit, capacity);
+    CreateMainMallocSpace(main_space_map, initial_size, growth_limit_, capacity_);
+    if (main_space_1_map != nullptr) {
+      const char* name = kUseRosAlloc ? kRosAllocSpaceName[1] : kDlMallocSpaceName[1];
+      main_space_backup_ = CreateMallocSpaceFromMemMap(main_space_1_map, initial_size,
+                                                       growth_limit_, capacity_, name, true);
+    }
   } else {
     std::string error_str;
-    MemMap* mem_map = MemMap::MapAnonymous("main/non-moving space", requested_alloc_space_begin,
-                                           capacity, PROT_READ | PROT_WRITE, true, &error_str);
-    CHECK(mem_map != nullptr) << error_str;
+    byte* request_begin = requested_alloc_space_begin;
+    if (request_begin == nullptr) {
+      // Disable homogeneous space compaction since we don't have an image.
+      create_backup_main_space = false;
+    }
+    MemMap* main_space_1_map = nullptr;
+    if (create_backup_main_space) {
+      request_begin += kNonMovingSpaceCapacity;
+      // Attempt to reserve an extra mem_map for homogeneous space compaction right after the main space map.
+      main_space_1_map = MemMap::MapAnonymous(kMemMapSpaceName[1], request_begin + capacity_,
+                                               capacity_, PROT_READ | PROT_WRITE, true, &error_str);
+      if (main_space_1_map == nullptr) {
+        LOG(WARNING) << "Failed to create map " <<  kMemMapSpaceName[1] << " with error "
+                     << error_str;
+        request_begin = requested_alloc_space_begin;
+      }
+    }
+    MemMap* main_space_map = MemMap::MapAnonymous(kMemMapSpaceName[0], request_begin, capacity_,
+                                                  PROT_READ | PROT_WRITE, true, &error_str);
+    CHECK(main_space_map != nullptr) << error_str;
+    // Introduce a seperate non moving space.
+    if (main_space_1_map != nullptr) {
+      // Do this before creating the main malloc space to prevent bitmaps from being placed here.
+      non_moving_space_ = space::DlMallocSpace::Create(
+          "non moving space", kDefaultInitialSize, kNonMovingSpaceCapacity, kNonMovingSpaceCapacity,
+          requested_alloc_space_begin, false);
+      non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
+    }
     // Create the main free list space, which doubles as the non moving space. We can do this since
     // non zygote means that we won't have any background compaction.
-    CreateMainMallocSpace(mem_map, initial_size, growth_limit, capacity);
-    non_moving_space_ = main_space_;
+    CreateMainMallocSpace(main_space_map, initial_size, growth_limit_, capacity_);
+    if (main_space_1_map != nullptr) {
+      const char* name = kUseRosAlloc ? kRosAllocSpaceName[1] : kDlMallocSpaceName[1];
+      main_space_backup_ = CreateMallocSpaceFromMemMap(main_space_1_map, initial_size,
+                                                       growth_limit_, capacity_, name, true);
+      CHECK(main_space_backup_ != nullptr);
+    } else {
+      non_moving_space_ = main_space_;
+    }
   }
   CHECK(non_moving_space_ != nullptr);
 
@@ -240,7 +309,7 @@
       (IsMovingGc(foreground_collector_type_) || IsMovingGc(background_collector_type_))) {
     // TODO: Place bump-pointer spaces somewhere to minimize size of card table.
     // Divide by 2 for a temporary fix for reducing virtual memory usage.
-    const size_t bump_pointer_space_capacity = capacity / 2;
+    const size_t bump_pointer_space_capacity = capacity_ / 2;
     bump_pointer_space_ = space::BumpPointerSpace::Create("Bump pointer space",
                                                           bump_pointer_space_capacity, nullptr);
     CHECK(bump_pointer_space_ != nullptr) << "Failed to create bump pointer space";
@@ -253,13 +322,25 @@
   if (non_moving_space_ != main_space_) {
     AddSpace(non_moving_space_);
   }
+  if (main_space_backup_ != nullptr) {
+    AddSpace(main_space_backup_);
+  } else {
+    const char* disable_msg = "Disabling homogenous space compact due to no backup main space";
+    if (background_collector_type_ == gc::kCollectorTypeHomogeneousSpaceCompact) {
+      background_collector_type_ = collector_type_;
+      LOG(WARNING) << disable_msg;
+    } else if (use_homogeneous_space_compaction_for_oom_) {
+      LOG(WARNING) << disable_msg;
+    }
+    use_homogeneous_space_compaction_for_oom_ = false;
+  }
   if (main_space_ != nullptr) {
     AddSpace(main_space_);
   }
 
   // Allocate the large object space.
   if (kUseFreeListSpaceForLOS) {
-    large_object_space_ = space::FreeListSpace::Create("large object space", nullptr, capacity);
+    large_object_space_ = space::FreeListSpace::Create("large object space", nullptr, capacity_);
   } else {
     large_object_space_ = space::LargeObjectMapSpace::Create("large object space");
   }
@@ -328,7 +409,7 @@
   }
   if (kMovingCollector) {
     // TODO: Clean this up.
-    bool generational = foreground_collector_type_ == kCollectorTypeGSS;
+    const bool generational = foreground_collector_type_ == kCollectorTypeGSS;
     semi_space_collector_ = new collector::SemiSpace(this, generational,
                                                      generational ? "generational" : "");
     garbage_collectors_.push_back(semi_space_collector_);
@@ -339,9 +420,8 @@
   }
 
   if (GetImageSpace() != nullptr && main_space_ != nullptr) {
-    // Check that there's no gap between the image space and the main
-    // space so that the immune region won't break (eg. due to a large
-    // object allocated in the gap).
+    // Check that there's no gap between the image space and the main space so that the immune
+    // region won't break (eg. due to a large object allocated in the gap).
     bool no_gap = MemMap::CheckNoGaps(GetImageSpace()->GetMemMap(), main_space_->GetMemMap());
     if (!no_gap) {
       MemMap::DumpMaps(LOG(ERROR));
@@ -358,11 +438,36 @@
   }
 }
 
+space::MallocSpace* Heap::CreateMallocSpaceFromMemMap(MemMap* mem_map, size_t initial_size,
+                                                      size_t growth_limit, size_t capacity,
+                                                      const char* name, bool can_move_objects) {
+  space::MallocSpace* malloc_space = nullptr;
+  if (kUseRosAlloc) {
+    // Create rosalloc space.
+    malloc_space = space::RosAllocSpace::CreateFromMemMap(mem_map, name, kDefaultStartingSize,
+                                                          initial_size, growth_limit, capacity,
+                                                          low_memory_mode_, can_move_objects);
+  } else {
+    malloc_space = space::DlMallocSpace::CreateFromMemMap(mem_map, name, kDefaultStartingSize,
+                                                          initial_size, growth_limit, capacity,
+                                                          can_move_objects);
+  }
+  if (collector::SemiSpace::kUseRememberedSet) {
+    accounting::RememberedSet* rem_set  =
+        new accounting::RememberedSet(std::string(name) + " remembered set", this, malloc_space);
+    CHECK(rem_set != nullptr) << "Failed to create main space remembered set";
+    AddRememberedSet(rem_set);
+  }
+  CHECK(malloc_space != nullptr) << "Failed to create " << name;
+  malloc_space->SetFootprintLimit(malloc_space->Capacity());
+  return malloc_space;
+}
+
 void Heap::CreateMainMallocSpace(MemMap* mem_map, size_t initial_size, size_t growth_limit,
                                  size_t capacity) {
   // Is background compaction is enabled?
   bool can_move_objects = IsMovingGc(background_collector_type_) !=
-      IsMovingGc(foreground_collector_type_);
+      IsMovingGc(foreground_collector_type_) || use_homogeneous_space_compaction_for_oom_;
   // If we are the zygote and don't yet have a zygote space, it means that the zygote fork will
   // happen in the future. If this happens and we have kCompactZygote enabled we wish to compact
   // from the main space to the zygote space. If background compaction is enabled, always pass in
@@ -375,26 +480,10 @@
   if (collector::SemiSpace::kUseRememberedSet && main_space_ != nullptr) {
     RemoveRememberedSet(main_space_);
   }
-  if (kUseRosAlloc) {
-    rosalloc_space_ = space::RosAllocSpace::CreateFromMemMap(
-        mem_map, "main rosalloc space", kDefaultStartingSize, initial_size, growth_limit, capacity,
-        low_memory_mode_, can_move_objects);
-    main_space_ = rosalloc_space_;
-    CHECK(main_space_ != nullptr) << "Failed to create rosalloc space";
-  } else {
-    dlmalloc_space_ = space::DlMallocSpace::CreateFromMemMap(
-        mem_map, "main dlmalloc space", kDefaultStartingSize, initial_size, growth_limit, capacity,
-        can_move_objects);
-    main_space_ = dlmalloc_space_;
-    CHECK(main_space_ != nullptr) << "Failed to create dlmalloc space";
-  }
-  main_space_->SetFootprintLimit(main_space_->Capacity());
-  if (collector::SemiSpace::kUseRememberedSet) {
-    accounting::RememberedSet* main_space_rem_set =
-        new accounting::RememberedSet("Main space remembered set", this, main_space_);
-    CHECK(main_space_rem_set != nullptr) << "Failed to create main space remembered set";
-    AddRememberedSet(main_space_rem_set);
-  }
+  const char* name = kUseRosAlloc ? kRosAllocSpaceName[0] : kDlMallocSpaceName[0];
+  main_space_ = CreateMallocSpaceFromMemMap(mem_map, initial_size, growth_limit, capacity, name,
+                                            can_move_objects);
+  SetSpaceAsDefault(main_space_);
   VLOG(heap) << "Created main space " << main_space_;
 }
 
@@ -547,8 +636,11 @@
       RequestCollectorTransition(foreground_collector_type_, 0);
     } else {
       // Don't delay for debug builds since we may want to stress test the GC.
-      RequestCollectorTransition(background_collector_type_, kIsDebugBuild ? 0 :
-          kCollectorTransitionWait);
+      // If background_collector_type_ is kCollectorTypeHomogeneousSpaceCompact then we have
+      // special handling which does a homogenous space compaction once but then doesn't transition
+      // the collector.
+      RequestCollectorTransition(background_collector_type_,
+                                 kIsDebugBuild ? 0 : kCollectorTransitionWait);
     }
   }
 }
@@ -605,7 +697,7 @@
 }
 
 void Heap::AddSpace(space::Space* space) {
-  DCHECK(space != nullptr);
+  CHECK(space != nullptr);
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
   if (space->IsContinuousSpace()) {
     DCHECK(!space->IsDiscontinuousSpace());
@@ -811,7 +903,7 @@
   oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free
       << " free bytes";
   // If the allocation failed due to fragmentation, print out the largest continuous allocation.
-  if (allocator_type != kAllocatorTypeLOS && total_bytes_free >= byte_count) {
+  if (total_bytes_free >= byte_count) {
     space::MallocSpace* space = nullptr;
     if (allocator_type == kAllocatorTypeNonMoving) {
       space = non_moving_space_;
@@ -844,6 +936,15 @@
     ScopedThreadStateChange tsc(self, kSleeping);
     usleep(wait_time / 1000);  // Usleep takes microseconds.
   }
+  // Launch homogeneous space compaction if it is desired.
+  if (desired_collector_type == kCollectorTypeHomogeneousSpaceCompact) {
+    if (!CareAboutPauseTimes()) {
+      PerformHomogeneousSpaceCompact();
+    }
+    // No need to Trim(). Homogeneous space compaction may free more virtual and physical memory.
+    desired_collector_type = collector_type_;
+    return;
+  }
   // Transition the collector if the desired collector type is not the same as the current
   // collector type.
   TransitionCollector(desired_collector_type);
@@ -1092,6 +1193,17 @@
   }
 }
 
+space::RosAllocSpace* Heap::GetRosAllocSpace(gc::allocator::RosAlloc* rosalloc) const {
+  for (const auto& space : continuous_spaces_) {
+    if (space->AsContinuousSpace()->IsRosAllocSpace()) {
+      if (space->AsContinuousSpace()->AsRosAllocSpace()->GetRosAlloc() == rosalloc) {
+        return space->AsContinuousSpace()->AsRosAllocSpace();
+      }
+    }
+  }
+  return nullptr;
+}
+
 mirror::Object* Heap::AllocateInternalWithGc(Thread* self, AllocatorType allocator,
                                              size_t alloc_size, size_t* bytes_allocated,
                                              size_t* usable_size,
@@ -1173,6 +1285,44 @@
     return nullptr;
   }
   ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated, usable_size);
+  if (ptr == nullptr && use_homogeneous_space_compaction_for_oom_) {
+    const uint64_t current_time = NanoTime();
+    if ((allocator == kAllocatorTypeRosAlloc || allocator == kAllocatorTypeDlMalloc) &&
+        current_time - last_time_homogeneous_space_compaction_by_oom_ >
+        min_interval_homogeneous_space_compaction_by_oom_) {
+      last_time_homogeneous_space_compaction_by_oom_ = current_time;
+      HomogeneousSpaceCompactResult result = PerformHomogeneousSpaceCompact();
+      switch (result) {
+        case HomogeneousSpaceCompactResult::kSuccess:
+          // If the allocation succeeded, we delayed an oom.
+          ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated, usable_size);
+          if (ptr != nullptr) {
+            count_delayed_oom_++;
+          }
+          break;
+        case HomogeneousSpaceCompactResult::kErrorReject:
+          // Reject due to disabled moving GC.
+          break;
+        case HomogeneousSpaceCompactResult::kErrorVMShuttingDown:
+          // Throw OOM by default.
+          break;
+        default: {
+          LOG(FATAL) << "Unimplemented homogeneous space compaction result " << static_cast<size_t>(result);
+        }
+      }
+      // Always print that we ran homogeneous space compation since this can cause jank.
+      VLOG(heap) << "Ran heap homogeneous space compaction, "
+                << " requested defragmentation "
+                << count_requested_homogeneous_space_compaction_.LoadSequentiallyConsistent()
+                << " performed defragmentation "
+                << count_performed_homogeneous_space_compaction_.LoadSequentiallyConsistent()
+                << " ignored homogeneous space compaction "
+                << count_ignored_homogeneous_space_compaction_.LoadSequentiallyConsistent()
+                << " delayed count = "
+                << count_delayed_oom_.LoadSequentiallyConsistent();
+    }
+  }
+  // If the allocation hasn't succeeded by this point, throw an OOM error.
   if (ptr == nullptr) {
     ThrowOutOfMemoryError(self, alloc_size, allocator);
   }
@@ -1331,6 +1481,66 @@
   CollectGarbageInternal(gc_plan_.back(), kGcCauseExplicit, clear_soft_references);
 }
 
+HomogeneousSpaceCompactResult Heap::PerformHomogeneousSpaceCompact() {
+  Thread* self = Thread::Current();
+  // Inc requested homogeneous space compaction.
+  count_requested_homogeneous_space_compaction_++;
+  // Store performed homogeneous space compaction at a new request arrival.
+  ThreadList* tl = Runtime::Current()->GetThreadList();
+  ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
+  Locks::mutator_lock_->AssertNotHeld(self);
+  {
+    ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
+    MutexLock mu(self, *gc_complete_lock_);
+    // Ensure there is only one GC at a time.
+    WaitForGcToCompleteLocked(kGcCauseHomogeneousSpaceCompact, self);
+    // Homogeneous space compaction is a copying transition, can't run it if the moving GC disable count
+    // is non zero.
+    // If the collecotr type changed to something which doesn't benefit from homogeneous space compaction,
+    // exit.
+    if (disable_moving_gc_count_ != 0 || IsMovingGc(collector_type_)) {
+      return HomogeneousSpaceCompactResult::kErrorReject;
+    }
+    collector_type_running_ = kCollectorTypeHomogeneousSpaceCompact;
+  }
+  if (Runtime::Current()->IsShuttingDown(self)) {
+    // Don't allow heap transitions to happen if the runtime is shutting down since these can
+    // cause objects to get finalized.
+    FinishGC(self, collector::kGcTypeNone);
+    return HomogeneousSpaceCompactResult::kErrorVMShuttingDown;
+  }
+  // Suspend all threads.
+  tl->SuspendAll();
+  uint64_t start_time = NanoTime();
+  // Launch compaction.
+  space::MallocSpace* to_space = main_space_backup_;
+  space::MallocSpace* from_space = main_space_;
+  to_space->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
+  const uint64_t space_size_before_compaction = from_space->Size();
+  Compact(to_space, from_space, kGcCauseHomogeneousSpaceCompact);
+  // Leave as prot read so that we can still run ROSAlloc verification on this space.
+  from_space->GetMemMap()->Protect(PROT_READ);
+  const uint64_t space_size_after_compaction = to_space->Size();
+  std::swap(main_space_, main_space_backup_);
+  SetSpaceAsDefault(main_space_);  // Set as default to reset the proper dlmalloc space.
+  // Update performed homogeneous space compaction count.
+  count_performed_homogeneous_space_compaction_++;
+  // Print statics log and resume all threads.
+  uint64_t duration = NanoTime() - start_time;
+  LOG(INFO) << "Heap homogeneous space compaction took " << PrettyDuration(duration) << " size: "
+            << PrettySize(space_size_before_compaction) << " -> "
+            << PrettySize(space_size_after_compaction) << " compact-ratio: "
+            << std::fixed << static_cast<double>(space_size_after_compaction) /
+            static_cast<double>(space_size_before_compaction);
+  tl->ResumeAll();
+  // Finish GC.
+  reference_processor_.EnqueueClearedReferences(self);
+  GrowForUtilization(semi_space_collector_);
+  FinishGC(self, collector::kGcTypeFull);
+  return HomogeneousSpaceCompactResult::kSuccess;
+}
+
+
 void Heap::TransitionCollector(CollectorType collector_type) {
   if (collector_type == collector_type_) {
     return;
@@ -1385,7 +1595,7 @@
         // We are transitioning from non moving GC -> moving GC, since we copied from the bump
         // pointer space last transition it will be protected.
         bump_pointer_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
-        Compact(bump_pointer_space_, main_space_);
+        Compact(bump_pointer_space_, main_space_, kGcCauseCollectorTransition);
         // Remove the main space so that we don't try to trim it, this doens't work for debug
         // builds since RosAlloc attempts to read the magic number from a protected page.
         RemoveSpace(main_space_);
@@ -1399,7 +1609,7 @@
         // Compact to the main space from the bump pointer space, don't need to swap semispaces.
         AddSpace(main_space_);
         main_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
-        Compact(main_space_, bump_pointer_space_);
+        Compact(main_space_, bump_pointer_space_, kGcCauseCollectorTransition);
       }
       break;
     }
@@ -1725,14 +1935,15 @@
 }
 
 void Heap::Compact(space::ContinuousMemMapAllocSpace* target_space,
-                   space::ContinuousMemMapAllocSpace* source_space) {
+                   space::ContinuousMemMapAllocSpace* source_space,
+                   GcCause gc_cause) {
   CHECK(kMovingCollector);
   if (target_space != source_space) {
     // Don't swap spaces since this isn't a typical semi space collection.
     semi_space_collector_->SetSwapSemiSpaces(false);
     semi_space_collector_->SetFromSpace(source_space);
     semi_space_collector_->SetToSpace(target_space);
-    semi_space_collector_->Run(kGcCauseCollectorTransition, false);
+    semi_space_collector_->Run(gc_cause, false);
   } else {
     CHECK(target_space->IsBumpPointerSpace())
         << "In-place compaction is only supported for bump pointer spaces";
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 86dab21..b207953 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -72,6 +72,10 @@
   class SemiSpace;
 }  // namespace collector
 
+namespace allocator {
+  class RosAlloc;
+}  // namespace allocator
+
 namespace space {
   class AllocSpace;
   class BumpPointerSpace;
@@ -97,6 +101,15 @@
   }
 };
 
+enum HomogeneousSpaceCompactResult {
+  // Success.
+  kSuccess,
+  // Reject due to disabled moving GC.
+  kErrorReject,
+  // System is shutting down.
+  kErrorVMShuttingDown,
+};
+
 // If true, use rosalloc/RosAllocSpace instead of dlmalloc/DlMallocSpace
 static constexpr bool kUseRosAlloc = true;
 
@@ -151,7 +164,8 @@
                 bool ignore_max_footprint, bool use_tlab,
                 bool verify_pre_gc_heap, bool verify_pre_sweeping_heap, bool verify_post_gc_heap,
                 bool verify_pre_gc_rosalloc, bool verify_pre_sweeping_rosalloc,
-                bool verify_post_gc_rosalloc);
+                bool verify_post_gc_rosalloc, bool use_homogeneous_space_compaction,
+                uint64_t min_interval_homogeneous_space_compaction_by_oom);
 
   ~Heap();
 
@@ -499,6 +513,9 @@
     return rosalloc_space_;
   }
 
+  // Return the corresponding rosalloc space.
+  space::RosAllocSpace* GetRosAllocSpace(gc::allocator::RosAlloc* rosalloc) const;
+
   space::MallocSpace* GetNonMovingSpace() const {
     return non_moving_space_;
   }
@@ -568,12 +585,19 @@
   }
 
  private:
+  // Compact source space to target space.
   void Compact(space::ContinuousMemMapAllocSpace* target_space,
-               space::ContinuousMemMapAllocSpace* source_space)
+               space::ContinuousMemMapAllocSpace* source_space,
+               GcCause gc_cause)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void FinishGC(Thread* self, collector::GcType gc_type) LOCKS_EXCLUDED(gc_complete_lock_);
 
+  bool SupportHSpaceCompaction() const {
+    // Returns true if we can do hspace compaction.
+    return main_space_backup_ != nullptr;
+  }
+
   static ALWAYS_INLINE bool AllocatorHasAllocationStack(AllocatorType allocator_type) {
     return
         allocator_type != kAllocatorTypeBumpPointer &&
@@ -584,7 +608,8 @@
   }
   static bool IsMovingGc(CollectorType collector_type) {
     return collector_type == kCollectorTypeSS || collector_type == kCollectorTypeGSS ||
-        collector_type == kCollectorTypeCC || collector_type == kCollectorTypeMC;
+        collector_type == kCollectorTypeCC || collector_type == kCollectorTypeMC ||
+        collector_type == kCollectorTypeHomogeneousSpaceCompact;
   }
   bool ShouldAllocLargeObject(mirror::Class* c, size_t byte_count) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -682,10 +707,18 @@
   // Find a collector based on GC type.
   collector::GarbageCollector* FindCollectorByGcType(collector::GcType gc_type);
 
-  // Create the main free list space, typically either a RosAlloc space or DlMalloc space.
+  // Create a new alloc space and compact default alloc space to it.
+  HomogeneousSpaceCompactResult PerformHomogeneousSpaceCompact();
+
+  // Create the main free list malloc space, either a RosAlloc space or DlMalloc space.
   void CreateMainMallocSpace(MemMap* mem_map, size_t initial_size, size_t growth_limit,
                              size_t capacity);
 
+  // Create a malloc space based on a mem map. Does not set the space as default.
+  space::MallocSpace* CreateMallocSpaceFromMemMap(MemMap* mem_map, size_t initial_size,
+                                                  size_t growth_limit, size_t capacity,
+                                                  const char* name, bool can_move_objects);
+
   // Given the current contents of the alloc space, increase the allowed heap footprint to match
   // the target utilization ratio.  This should only be called immediately after a full garbage
   // collection.
@@ -972,6 +1005,30 @@
   const bool running_on_valgrind_;
   const bool use_tlab_;
 
+  // Pointer to the space which becomes the new main space when we do homogeneous space compaction.
+  space::MallocSpace* main_space_backup_;
+
+  // Minimal interval allowed between two homogeneous space compactions caused by OOM.
+  uint64_t min_interval_homogeneous_space_compaction_by_oom_;
+
+  // Times of the last homogeneous space compaction caused by OOM.
+  uint64_t last_time_homogeneous_space_compaction_by_oom_;
+
+  // Saved OOMs by homogeneous space compaction.
+  Atomic<size_t> count_delayed_oom_;
+
+  // Count for requested homogeneous space compaction.
+  Atomic<size_t> count_requested_homogeneous_space_compaction_;
+
+  // Count for ignored homogeneous space compaction.
+  Atomic<size_t> count_ignored_homogeneous_space_compaction_;
+
+  // Count for performed homogeneous space compaction.
+  Atomic<size_t> count_performed_homogeneous_space_compaction_;
+
+  // Whether or not we use homogeneous space compaction to avoid OOM errors.
+  bool use_homogeneous_space_compaction_for_oom_;
+
   friend class collector::GarbageCollector;
   friend class collector::MarkCompact;
   friend class collector::MarkSweep;
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index 5738d47..92c6f53 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -227,7 +227,7 @@
 // Callback from rosalloc when it needs to increase the footprint
 extern "C" void* art_heap_rosalloc_morecore(allocator::RosAlloc* rosalloc, intptr_t increment) {
   Heap* heap = Runtime::Current()->GetHeap();
-  RosAllocSpace* rosalloc_space = heap->GetRosAllocSpace();
+  RosAllocSpace* rosalloc_space = heap->GetRosAllocSpace(rosalloc);
   DCHECK(rosalloc_space != nullptr);
   DCHECK_EQ(rosalloc_space->GetRosAlloc(), rosalloc);
   return rosalloc_space->MoreCore(increment);
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 0e05b62..05320ce 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -93,16 +93,17 @@
     method->ClearIsPortableCompiled();
   }
   if (!method->IsResolutionMethod()) {
+    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
     if (quick_code == GetQuickToInterpreterBridge() ||
-        quick_code == GetQuickToInterpreterBridgeTrampoline(Runtime::Current()->GetClassLinker()) ||
-        (quick_code == GetQuickResolutionTrampoline(Runtime::Current()->GetClassLinker()) &&
+        quick_code == class_linker->GetQuickToInterpreterBridgeTrampoline() ||
+        (quick_code == class_linker->GetQuickResolutionTrampoline() &&
          Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly()
          && !method->IsNative() && !method->IsProxyMethod())) {
       if (kIsDebugBuild) {
         if (quick_code == GetQuickToInterpreterBridge()) {
           DCHECK(portable_code == GetPortableToInterpreterBridge());
-        } else if (quick_code == GetQuickResolutionTrampoline(Runtime::Current()->GetClassLinker())) {
-          DCHECK(portable_code == GetPortableResolutionTrampoline(Runtime::Current()->GetClassLinker()));
+        } else if (quick_code == class_linker->GetQuickResolutionTrampoline()) {
+          DCHECK(portable_code == class_linker->GetPortableResolutionTrampoline());
         }
       }
       DCHECK(!method->IsNative()) << PrettyMethod(method);
@@ -133,8 +134,8 @@
       new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
       new_quick_code = class_linker->GetQuickOatCodeFor(method);
     } else {
-      new_portable_code = GetPortableResolutionTrampoline(class_linker);
-      new_quick_code = GetQuickResolutionTrampoline(class_linker);
+      new_portable_code = class_linker->GetPortableResolutionTrampoline();
+      new_quick_code = class_linker->GetQuickResolutionTrampoline();
     }
   } else {  // !uninstall
     if ((interpreter_stubs_installed_ || forced_interpret_only_ || IsDeoptimized(method)) &&
@@ -152,11 +153,11 @@
         } else {
           new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
           new_quick_code = class_linker->GetQuickOatCodeFor(method);
-          DCHECK(new_quick_code != GetQuickToInterpreterBridgeTrampoline(class_linker));
+          DCHECK(new_quick_code != class_linker->GetQuickToInterpreterBridgeTrampoline());
         }
       } else {
-        new_portable_code = GetPortableResolutionTrampoline(class_linker);
-        new_quick_code = GetQuickResolutionTrampoline(class_linker);
+        new_portable_code = class_linker->GetPortableResolutionTrampoline();
+        new_quick_code = class_linker->GetQuickResolutionTrampoline();
       }
     }
   }
@@ -592,22 +593,25 @@
       new_portable_code = GetPortableToInterpreterBridge();
       new_quick_code = GetQuickToInterpreterBridge();
       new_have_portable_code = false;
-    } else if (quick_code == GetQuickResolutionTrampoline(Runtime::Current()->GetClassLinker()) ||
-        quick_code == GetQuickToInterpreterBridgeTrampoline(Runtime::Current()->GetClassLinker()) ||
-        quick_code == GetQuickToInterpreterBridge()) {
-      DCHECK((portable_code == GetPortableResolutionTrampoline(Runtime::Current()->GetClassLinker())) ||
-             (portable_code == GetPortableToInterpreterBridge()));
-      new_portable_code = portable_code;
-      new_quick_code = quick_code;
-      new_have_portable_code = have_portable_code;
-    } else if (entry_exit_stubs_installed_) {
-      new_quick_code = GetQuickInstrumentationEntryPoint();
-      new_portable_code = GetPortableToInterpreterBridge();
-      new_have_portable_code = false;
     } else {
-      new_portable_code = portable_code;
-      new_quick_code = quick_code;
-      new_have_portable_code = have_portable_code;
+      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+      if (quick_code == class_linker->GetQuickResolutionTrampoline() ||
+          quick_code == class_linker->GetQuickToInterpreterBridgeTrampoline() ||
+          quick_code == GetQuickToInterpreterBridge()) {
+        DCHECK((portable_code == class_linker->GetPortableResolutionTrampoline()) ||
+               (portable_code == GetPortableToInterpreterBridge()));
+        new_portable_code = portable_code;
+        new_quick_code = quick_code;
+        new_have_portable_code = have_portable_code;
+      } else if (entry_exit_stubs_installed_) {
+        new_quick_code = GetQuickInstrumentationEntryPoint();
+        new_portable_code = GetPortableToInterpreterBridge();
+        new_have_portable_code = false;
+      } else {
+        new_portable_code = portable_code;
+        new_quick_code = quick_code;
+        new_have_portable_code = have_portable_code;
+      }
     }
   }
   UpdateEntrypoints(method, new_quick_code, new_portable_code, new_have_portable_code);
@@ -661,8 +665,9 @@
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
     if (method->IsStatic() && !method->IsConstructor() &&
         !method->GetDeclaringClass()->IsInitialized()) {
-      UpdateEntrypoints(method, GetQuickResolutionTrampoline(class_linker),
-                        GetPortableResolutionTrampoline(class_linker), false);
+      // TODO: we're updating to entrypoints in the image here, we can avoid the trampoline.
+      UpdateEntrypoints(method, class_linker->GetQuickResolutionTrampoline(),
+                        class_linker->GetPortableResolutionTrampoline(), false);
     } else {
       bool have_portable_code = false;
       const void* quick_code = class_linker->GetQuickOatCodeFor(method);
@@ -742,8 +747,9 @@
   if (LIKELY(!instrumentation_stubs_installed_)) {
     const void* code = method->GetEntryPointFromQuickCompiledCode();
     DCHECK(code != nullptr);
-    if (LIKELY(code != GetQuickResolutionTrampoline(runtime->GetClassLinker())) &&
-        LIKELY(code != GetQuickToInterpreterBridgeTrampoline(runtime->GetClassLinker())) &&
+    ClassLinker* class_linker = runtime->GetClassLinker();
+    if (LIKELY(code != class_linker->GetQuickResolutionTrampoline()) &&
+        LIKELY(code != class_linker->GetQuickToInterpreterBridgeTrampoline()) &&
         LIKELY(code != GetQuickToInterpreterBridge())) {
       return code;
     }
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 2db62f8..e3068b3 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -95,11 +95,11 @@
     jint newValue = args[4];
     bool success;
     if (Runtime::Current()->IsActiveTransaction()) {
-      success = obj->CasFieldWeakSequentiallyConsistent32<true>(MemberOffset(offset),
-                                                                expectedValue, newValue);
+      success = obj->CasFieldStrongSequentiallyConsistent32<true>(MemberOffset(offset),
+                                                                  expectedValue, newValue);
     } else {
-      success = obj->CasFieldWeakSequentiallyConsistent32<false>(MemberOffset(offset),
-                                                                 expectedValue, newValue);
+      success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
+                                                                   expectedValue, newValue);
     }
     result->SetZ(success ? JNI_TRUE : JNI_FALSE);
   } else if (name == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 5277330..db42eb0 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -27,7 +27,7 @@
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
 #include "dex_instruction.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "handle_scope-inl.h"
 #include "nth_caller_visitor.h"
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 43bdf49..f3c8250 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -27,6 +27,11 @@
 namespace art {
 namespace mirror {
 
+inline uint32_t Array::ClassSize() {
+  uint32_t vtable_entries = Object::kVTableLength;
+  return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0);
+}
+
 template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline size_t Array::SizeOf() {
   // This is safe from overflow because the array was already allocated, so we know it's sane.
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 25a4535..6588b57 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -30,6 +30,9 @@
 
 class MANAGED Array : public Object {
  public:
+  // The size of a java.lang.Class representing an array.
+  static uint32_t ClassSize();
+
   // Allocates an array with the given properties, if fill_usable is true the array will be of at
   // least component_count size, however, if there's usable space at the end of the allocation the
   // array will fill it.
diff --git a/runtime/mirror/art_field-inl.h b/runtime/mirror/art_field-inl.h
index 686fded..90247ed 100644
--- a/runtime/mirror/art_field-inl.h
+++ b/runtime/mirror/art_field-inl.h
@@ -29,6 +29,11 @@
 namespace art {
 namespace mirror {
 
+inline uint32_t ArtField::ClassSize() {
+  uint32_t vtable_entries = Object::kVTableLength + 6;
+  return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0);
+}
+
 inline Class* ArtField::GetDeclaringClass() {
   Class* result = GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(ArtField, declaring_class_));
   DCHECK(result != NULL);
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index 502cec7..741c6eb 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -19,22 +19,33 @@
 
 #include <jni.h>
 
-#include "class.h"
 #include "modifiers.h"
 #include "object.h"
 #include "object_callbacks.h"
+#include "primitive.h"
 #include "read_barrier.h"
 
 namespace art {
 
 struct ArtFieldOffsets;
+class DexFile;
 class ScopedObjectAccessAlreadyRunnable;
 
 namespace mirror {
 
+class DexCache;
+
 // C++ mirror of java.lang.reflect.ArtField
-class MANAGED ArtField : public Object {
+class MANAGED ArtField FINAL : public Object {
  public:
+  // Size of java.lang.reflect.ArtField.class.
+  static uint32_t ClassSize();
+
+  // Size of an instance of java.lang.reflect.ArtField not including its value array.
+  static constexpr uint32_t InstanceSize() {
+    return sizeof(ArtField);
+  }
+
   static ArtField* FromReflectedField(const ScopedObjectAccessAlreadyRunnable& soa,
                                       jobject jlr_field)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -143,11 +154,17 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const char* GetTypeDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   Primitive::Type GetTypeAsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool IsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   size_t FieldSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   mirror::DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const DexFile* GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
@@ -169,11 +186,6 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(ArtField);
 };
 
-class MANAGED ArtFieldClass : public Class {
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ArtFieldClass);
-};
-
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 8fcacc2..a5b5df6 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -21,14 +21,29 @@
 
 #include "dex_file.h"
 #include "entrypoints/entrypoint_utils.h"
+#include "object-inl.h"
 #include "object_array.h"
+#include "object_utils.h"
 #include "oat.h"
 #include "quick/quick_method_frame_info.h"
+#include "read_barrier-inl.h"
 #include "runtime-inl.h"
 
 namespace art {
 namespace mirror {
 
+inline uint32_t ArtMethod::ClassSize() {
+  uint32_t vtable_entries = Object::kVTableLength + 8;
+  return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0);
+}
+
+template<ReadBarrierOption kReadBarrierOption>
+inline Class* ArtMethod::GetJavaLangReflectArtMethod() {
+  DCHECK(java_lang_reflect_ArtMethod_ != nullptr);
+  return ReadBarrier::BarrierForRoot<mirror::Class, kReadBarrierOption>(
+      &java_lang_reflect_ArtMethod_);
+}
+
 inline Class* ArtMethod::GetDeclaringClass() {
   Class* result = GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, declaring_class_));
   DCHECK(result != NULL) << this;
@@ -122,8 +137,8 @@
     return;
   }
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  if (code == GetQuickResolutionTrampoline(class_linker) ||
-      code == GetQuickToInterpreterBridgeTrampoline(class_linker)) {
+  if (code == class_linker->GetQuickResolutionTrampoline() ||
+      code == class_linker->GetQuickToInterpreterBridgeTrampoline()) {
     return;
   }
   DCHECK(IsWithinQuickCode(pc))
@@ -162,7 +177,7 @@
   // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
   // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
   // for non-native methods.
-  DCHECK(entry_point != GetQuickToInterpreterBridgeTrampoline(runtime->GetClassLinker()));
+  DCHECK(entry_point != runtime->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline());
   if (UNLIKELY(entry_point == GetQuickToInterpreterBridge()) ||
       UNLIKELY(entry_point == runtime->GetClassLinker()->GetQuickGenericJniTrampoline())) {
     return nullptr;
@@ -289,7 +304,7 @@
   // On failure, instead of nullptr we get the quick-generic-jni-trampoline for native method
   // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
   // for non-native methods. And we really shouldn't see a failure for non-native methods here.
-  DCHECK(entry_point != GetQuickToInterpreterBridgeTrampoline(runtime->GetClassLinker()));
+  DCHECK(entry_point != runtime->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline());
   CHECK(entry_point != GetQuickToInterpreterBridge());
 
   if (UNLIKELY(entry_point == runtime->GetClassLinker()->GetQuickGenericJniTrampoline())) {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 4821e29..1fa680d 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -355,14 +355,6 @@
   self->PopManagedStackFragment(fragment);
 }
 
-bool ArtMethod::IsRegistered() {
-  void* native_method =
-      GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_));
-  CHECK(native_method != nullptr);
-  void* jni_stub = GetJniDlsymLookupStub();
-  return native_method != jni_stub;
-}
-
 void ArtMethod::RegisterNative(Thread* self, const void* native_method, bool is_fast) {
   DCHECK(Thread::Current() == self);
   CHECK(IsNative()) << PrettyMethod(this);
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index a55c48b..081bee1 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -17,21 +17,19 @@
 #ifndef ART_RUNTIME_MIRROR_ART_METHOD_H_
 #define ART_RUNTIME_MIRROR_ART_METHOD_H_
 
-#include "class.h"
 #include "dex_file.h"
 #include "invoke_type.h"
 #include "modifiers.h"
 #include "object.h"
 #include "object_callbacks.h"
 #include "quick/quick_method_frame_info.h"
-#include "read_barrier.h"
+#include "read_barrier_option.h"
 
 namespace art {
 
 struct ArtMethodOffsets;
 struct ConstructorMethodOffsets;
 union JValue;
-struct MethodClassOffsets;
 class MethodHelper;
 class ScopedObjectAccessAlreadyRunnable;
 class StringPiece;
@@ -39,14 +37,20 @@
 
 namespace mirror {
 
-class StaticStorageBase;
-
 typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh,
     const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result);
 
-// C++ mirror of java.lang.reflect.Method and java.lang.reflect.Constructor
-class MANAGED ArtMethod : public Object {
+// C++ mirror of java.lang.reflect.ArtMethod.
+class MANAGED ArtMethod FINAL : public Object {
  public:
+  // Size of java.lang.reflect.ArtMethod.class.
+  static uint32_t ClassSize();
+
+  // Size of an instance of java.lang.reflect.ArtMethod not including its value array.
+  static constexpr uint32_t InstanceSize() {
+    return sizeof(ArtMethod);
+  }
+
   static ArtMethod* FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
                                         jobject jlr_method)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -357,8 +361,6 @@
     return kPointerSize;
   }
 
-  bool IsRegistered() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   void RegisterNative(Thread* self, const void* native_method, bool is_fast)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -411,11 +413,7 @@
   static void SetClass(Class* java_lang_reflect_ArtMethod);
 
   template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
-  static Class* GetJavaLangReflectArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(java_lang_reflect_ArtMethod_ != nullptr);
-    return ReadBarrier::BarrierForRoot<mirror::Class, kReadBarrierOption>(
-        &java_lang_reflect_ArtMethod_);
-  }
+  static Class* GetJavaLangReflectArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static void ResetClass();
 
@@ -423,27 +421,45 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   const DexFile* GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const char* GetShorty() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     uint32_t unused_length;
     return GetShorty(&unused_length);
   }
+
   const char* GetShorty(uint32_t* out_length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const Signature GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const DexFile::CodeItem* GetCodeItem() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool IsResolvedTypeIdx(uint16_t type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   int32_t GetLineNumFromDexPC(uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const DexFile::ProtoId& GetPrototype() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const DexFile::TypeList* GetParameterTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const char* GetDeclaringClassSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   uint16_t GetClassDefIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const DexFile::ClassDef& GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const char* GetReturnTypeDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   mirror::ClassLoader* GetClassLoader() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   mirror::DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   ArtMethod* GetInterfaceMethodIfProxy() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  protected:
@@ -505,11 +521,6 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(ArtMethod);
 };
 
-class MANAGED ArtMethodClass : public Class {
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ArtMethodClass);
-};
-
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 2daa6e4..349d4a3 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -19,8 +19,8 @@
 
 #include "class.h"
 
-#include "art_field.h"
-#include "art_method.h"
+#include "art_field-inl.h"
+#include "art_method-inl.h"
 #include "class_linker-inl.h"
 #include "class_loader.h"
 #include "common_throws.h"
@@ -29,6 +29,7 @@
 #include "gc/heap-inl.h"
 #include "iftable.h"
 #include "object_array-inl.h"
+#include "read_barrier-inl.h"
 #include "runtime.h"
 #include "string.h"
 
@@ -148,6 +149,23 @@
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable);
 }
 
+inline ArtMethod* Class::GetEmbeddedImTableEntry(uint32_t i) {
+  uint32_t offset = EmbeddedImTableOffset().Uint32Value() + i * sizeof(ImTableEntry);
+  return GetFieldObject<mirror::ArtMethod>(MemberOffset(offset));
+}
+
+inline void Class::SetEmbeddedImTableEntry(uint32_t i, ArtMethod* method) {
+  uint32_t offset = EmbeddedImTableOffset().Uint32Value() + i * sizeof(ImTableEntry);
+  SetFieldObject<false>(MemberOffset(offset), method);
+  CHECK(method == GetImTable()->Get(i));
+}
+
+inline void Class::SetEmbeddedVTableEntry(uint32_t i, ArtMethod* method) {
+  uint32_t offset = EmbeddedVTableOffset().Uint32Value() + i * sizeof(VTableEntry);
+  SetFieldObject<false>(MemberOffset(offset), method);
+  CHECK(method == GetVTableDuringLinking()->Get(i));
+}
+
 inline bool Class::Implements(Class* klass) {
   DCHECK(klass != NULL);
   DCHECK(klass->IsInterface()) << PrettyClass(this);
@@ -373,7 +391,8 @@
 
 inline void Class::SetSFields(ObjectArray<ArtField>* new_sfields)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(NULL == GetFieldObject<ObjectArray<ArtField>>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_)));
+  DCHECK((IsRetired() && new_sfields == nullptr) ||
+         (NULL == GetFieldObject<ObjectArray<ArtField>>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_))));
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields);
 }
 
@@ -435,9 +454,9 @@
 
 template<VerifyObjectFlags kVerifyFlags>
 inline uint32_t Class::GetAccessFlags() {
-  // Check class is loaded or this is java.lang.String that has a
+  // Check class is loaded/retired or this is java.lang.String that has a
   // circularity issue during loading the names of its members
-  DCHECK(IsLoaded<kVerifyFlags>() ||
+  DCHECK(IsIdxLoaded<kVerifyFlags>() || IsRetired<kVerifyFlags>() ||
          IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() ||
          this == String::GetJavaLangString() ||
          this == ArtField::GetJavaLangReflectArtField() ||
@@ -503,12 +522,63 @@
   return Alloc<true>(self, Runtime::Current()->GetHeap()->GetCurrentNonMovingAllocator());
 }
 
+inline uint32_t Class::ComputeClassSize(bool has_embedded_tables,
+                                        uint32_t num_vtable_entries,
+                                        uint32_t num_32bit_static_fields,
+                                        uint32_t num_64bit_static_fields,
+                                        uint32_t num_ref_static_fields) {
+  // Space used by java.lang.Class and its instance fields.
+  uint32_t size = sizeof(Class);
+  // Space used by embedded tables.
+  if (has_embedded_tables) {
+    uint32_t embedded_imt_size = kImtSize * sizeof(ImTableEntry);
+    uint32_t embedded_vtable_size = num_vtable_entries * sizeof(VTableEntry);
+    size += embedded_imt_size + embedded_vtable_size;
+  }
+  // Space used by reference statics.
+  size +=  num_ref_static_fields * sizeof(HeapReference<Object>);
+  // Possible pad for alignment.
+  if (((size & 7) != 0) && (num_64bit_static_fields > 0) && (num_32bit_static_fields == 0)) {
+    size += sizeof(uint32_t);
+  }
+  // Space used for primitive static fields.
+  size += (num_32bit_static_fields * sizeof(uint32_t)) +
+      (num_64bit_static_fields * sizeof(uint64_t));
+  return size;
+}
+
 template <bool kVisitClass, typename Visitor>
 inline void Class::VisitReferences(mirror::Class* klass, const Visitor& visitor) {
   // Visit the static fields first so that we don't overwrite the SFields / IFields instance
   // fields.
-  VisitStaticFieldsReferences<kVisitClass>(this, visitor);
   VisitInstanceFieldsReferences<kVisitClass>(klass, visitor);
+  if (!IsTemp()) {
+    // Temp classes don't ever populate imt/vtable or static fields and they are not even
+    // allocated with the right size for those.
+    VisitStaticFieldsReferences<kVisitClass>(this, visitor);
+    if (ShouldHaveEmbeddedImtAndVTable()) {
+      VisitEmbeddedImtAndVTable(visitor);
+    }
+  }
+}
+
+template<typename Visitor>
+inline void Class::VisitEmbeddedImtAndVTable(const Visitor& visitor) {
+  uint32_t pos = sizeof(mirror::Class);
+
+  size_t count = kImtSize;
+  for (size_t i = 0; i < count; ++i) {
+    MemberOffset offset = MemberOffset(pos);
+    visitor(this, offset, true);
+    pos += sizeof(ImTableEntry);
+  }
+
+  count = ((GetVTable() != NULL) ? GetVTable()->GetLength() : 0);
+  for (size_t i = 0; i < count; ++i) {
+    MemberOffset offset = MemberOffset(pos);
+    visitor(this, offset, true);
+    pos += sizeof(VTableEntry);
+  }
 }
 
 template<ReadBarrierOption kReadBarrierOption>
@@ -554,6 +624,36 @@
   }
 }
 
+inline ObjectArray<Class>* Class::GetInterfaces() {
+  CHECK(IsProxyClass());
+  // First static field.
+  DCHECK(GetSFields()->Get(0)->IsArtField());
+  DCHECK_STREQ(GetSFields()->Get(0)->GetName(), "interfaces");
+  MemberOffset field_offset = GetSFields()->Get(0)->GetOffset();
+  return GetFieldObject<ObjectArray<Class>>(field_offset);
+}
+
+inline ObjectArray<ObjectArray<Class>>* Class::GetThrows() {
+  CHECK(IsProxyClass());
+  // Second static field.
+  DCHECK(GetSFields()->Get(1)->IsArtField());
+  DCHECK_STREQ(GetSFields()->Get(1)->GetName(), "throws");
+  MemberOffset field_offset = GetSFields()->Get(1)->GetOffset();
+  return GetFieldObject<ObjectArray<ObjectArray<Class>>>(field_offset);
+}
+
+inline void Class::InitializeClassVisitor::operator()(
+    mirror::Object* obj, size_t usable_size) const {
+  DCHECK_LE(class_size_, usable_size);
+  // Avoid AsClass as object is not yet in live bitmap or allocation stack.
+  mirror::Class* klass = down_cast<mirror::Class*>(obj);
+  // DCHECK(klass->IsClass());
+  klass->SetClassSize(class_size_);
+  klass->SetPrimitiveType(Primitive::kPrimNot);  // Default to not being primitive.
+  klass->SetDexClassDefIndex(DexFile::kDexNoIndex16);  // Default to no valid class def index.
+  klass->SetDexTypeIndex(DexFile::kDexNoIndex16);  // Default to no valid type index.
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index c6472c6..371e984 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -63,7 +63,8 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   bool class_linker_initialized = class_linker != nullptr && class_linker->IsInitialized();
   if (LIKELY(class_linker_initialized)) {
-    if (UNLIKELY(new_status <= old_status && new_status != kStatusError)) {
+    if (UNLIKELY(new_status <= old_status && new_status != kStatusError &&
+                 new_status != kStatusRetired)) {
       LOG(FATAL) << "Unexpected change back of class status for " << PrettyClass(this) << " "
           << old_status << " -> " << new_status;
     }
@@ -113,11 +114,27 @@
   } else {
     SetField32Volatile<false>(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status);
   }
-  // Classes that are being resolved or initialized need to notify waiters that the class status
-  // changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass.
-  if ((old_status >= kStatusResolved || new_status >= kStatusResolved) &&
-      class_linker_initialized) {
-    NotifyAll(self);
+
+  if (!class_linker_initialized) {
+    // When the class linker is being initialized its single threaded and by definition there can be
+    // no waiters. During initialization classes may appear temporary but won't be retired as their
+    // size was statically computed.
+  } else {
+    // Classes that are being resolved or initialized need to notify waiters that the class status
+    // changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass.
+    if (IsTemp()) {
+      // Class is a temporary one, ensure that waiters for resolution get notified of retirement
+      // so that they can grab the new version of the class from the class linker's table.
+      CHECK_LT(new_status, kStatusResolved) << PrettyDescriptor(this);
+      if (new_status == kStatusRetired || new_status == kStatusError) {
+        NotifyAll(self);
+      }
+    } else {
+      CHECK_NE(new_status, kStatusRetired);
+      if (old_status >= kStatusResolved || new_status >= kStatusResolved) {
+        NotifyAll(self);
+      }
+    }
   }
 }
 
@@ -217,35 +234,39 @@
       os << StringPrintf("    %2zd: %s (cl=%p)\n", i, PrettyClass(interface).c_str(), cl);
     }
   }
-  // After this point, this may have moved due to GetDirectInterface.
-  os << "  vtable (" << h_this->NumVirtualMethods() << " entries, "
-     << (h_super.Get() != nullptr ? h_super->NumVirtualMethods() : 0) << " in super):\n";
-  for (size_t i = 0; i < NumVirtualMethods(); ++i) {
-    os << StringPrintf("    %2zd: %s\n", i,
-                       PrettyMethod(h_this->GetVirtualMethodDuringLinking(i)).c_str());
-  }
-  os << "  direct methods (" << h_this->NumDirectMethods() << " entries):\n";
-  for (size_t i = 0; i < h_this->NumDirectMethods(); ++i) {
-    os << StringPrintf("    %2zd: %s\n", i, PrettyMethod(h_this->GetDirectMethod(i)).c_str());
-  }
-  if (h_this->NumStaticFields() > 0) {
-    os << "  static fields (" << h_this->NumStaticFields() << " entries):\n";
-    if (h_this->IsResolved() || h_this->IsErroneous()) {
-      for (size_t i = 0; i < h_this->NumStaticFields(); ++i) {
-        os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetStaticField(i)).c_str());
-      }
-    } else {
-      os << "    <not yet available>";
+  if (!IsLoaded()) {
+    os << "  class not yet loaded";
+  } else {
+    // After this point, this may have moved due to GetDirectInterface.
+    os << "  vtable (" << h_this->NumVirtualMethods() << " entries, "
+        << (h_super.Get() != nullptr ? h_super->NumVirtualMethods() : 0) << " in super):\n";
+    for (size_t i = 0; i < NumVirtualMethods(); ++i) {
+      os << StringPrintf("    %2zd: %s\n", i,
+                         PrettyMethod(h_this->GetVirtualMethodDuringLinking(i)).c_str());
     }
-  }
-  if (h_this->NumInstanceFields() > 0) {
-    os << "  instance fields (" << h_this->NumInstanceFields() << " entries):\n";
-    if (h_this->IsResolved() || h_this->IsErroneous()) {
-      for (size_t i = 0; i < h_this->NumInstanceFields(); ++i) {
-        os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetInstanceField(i)).c_str());
+    os << "  direct methods (" << h_this->NumDirectMethods() << " entries):\n";
+    for (size_t i = 0; i < h_this->NumDirectMethods(); ++i) {
+      os << StringPrintf("    %2zd: %s\n", i, PrettyMethod(h_this->GetDirectMethod(i)).c_str());
+    }
+    if (h_this->NumStaticFields() > 0) {
+      os << "  static fields (" << h_this->NumStaticFields() << " entries):\n";
+      if (h_this->IsResolved() || h_this->IsErroneous()) {
+        for (size_t i = 0; i < h_this->NumStaticFields(); ++i) {
+          os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetStaticField(i)).c_str());
+        }
+      } else {
+        os << "    <not yet available>";
       }
-    } else {
-      os << "    <not yet available>";
+    }
+    if (h_this->NumInstanceFields() > 0) {
+      os << "  instance fields (" << h_this->NumInstanceFields() << " entries):\n";
+      if (h_this->IsResolved() || h_this->IsErroneous()) {
+        for (size_t i = 0; i < h_this->NumInstanceFields(); ++i) {
+          os << StringPrintf("    %2zd: %s\n", i, PrettyField(h_this->GetInstanceField(i)).c_str());
+        }
+      } else {
+        os << "    <not yet available>";
+      }
     }
   }
 }
@@ -721,9 +742,7 @@
   } else if (IsArrayClass()) {
     return 2;
   } else if (IsProxyClass()) {
-    mirror::SynthesizedProxyClass* proxy_class=
-        reinterpret_cast<mirror::SynthesizedProxyClass*>(this);
-    mirror::ObjectArray<mirror::Class>* interfaces = proxy_class->GetInterfaces();
+    mirror::ObjectArray<mirror::Class>* interfaces = GetInterfaces();
     return interfaces != nullptr ? interfaces->GetLength() : 0;
   } else {
     const DexFile::TypeList* interfaces = GetInterfaceTypeList();
@@ -753,9 +772,7 @@
       return class_linker->FindSystemClass(self, "Ljava/io/Serializable;");
     }
   } else if (klass->IsProxyClass()) {
-    mirror::SynthesizedProxyClass* proxy_class =
-        reinterpret_cast<mirror::SynthesizedProxyClass*>(klass.Get());
-    mirror::ObjectArray<mirror::Class>* interfaces = proxy_class->GetInterfaces();
+    mirror::ObjectArray<mirror::Class>* interfaces = klass.Get()->GetInterfaces();
     DCHECK(interfaces != nullptr);
     return interfaces->Get(idx);
   } else {
@@ -798,5 +815,49 @@
   return GetDexFile().GetInterfacesList(*class_def);
 }
 
+void Class::PopulateEmbeddedImtAndVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ObjectArray<ArtMethod>* table = GetImTable();
+  if (table != nullptr) {
+    for (uint32_t i = 0; i < kImtSize; i++) {
+      SetEmbeddedImTableEntry(i, table->Get(i));
+    }
+  }
+
+  table = GetVTableDuringLinking();
+  CHECK(table != nullptr);
+  for (int32_t i = 0; i < table->GetLength(); i++) {
+    SetEmbeddedVTableEntry(i, table->Get(i));
+  }
+}
+
+Class* Class::CopyOf(Thread* self, int32_t new_length) {
+  DCHECK_GE(new_length, static_cast<int32_t>(sizeof(Class)));
+  // We may get copied by a compacting GC.
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> h_this(hs.NewHandle(this));
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  InitializeClassVisitor visitor(new_length);
+
+  mirror::Object* new_class =
+      kMovingClasses ? heap->AllocObject<true>(self, java_lang_Class_, new_length, visitor)
+                     : heap->AllocNonMovableObject<true>(self, java_lang_Class_, new_length, visitor);
+  if (UNLIKELY(new_class == nullptr)) {
+    CHECK(self->IsExceptionPending());  // Expect an OOME.
+    return NULL;
+  }
+
+  mirror::Class* new_class_obj = new_class->AsClass();
+  memcpy(new_class_obj, h_this.Get(), sizeof(Class));
+
+  new_class_obj->SetStatus(kStatusResolving, self);
+  new_class_obj->PopulateEmbeddedImtAndVTable();
+  // Correct some fields.
+  new_class_obj->SetLockWord(LockWord(), false);
+  new_class_obj->SetClassSize(new_length);
+
+  Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(new_class_obj);
+  return new_class_obj;
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 7ac53ea..0f42044 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -22,6 +22,7 @@
 #include "invoke_type.h"
 #include "modifiers.h"
 #include "object.h"
+#include "object_array.h"
 #include "object_callbacks.h"
 #include "primitive.h"
 #include "read_barrier.h"
@@ -62,7 +63,6 @@
 
 namespace art {
 
-struct ClassClassOffsets;
 struct ClassOffsets;
 class Signature;
 class StringPiece;
@@ -70,13 +70,29 @@
 namespace mirror {
 
 class ArtField;
+class ArtMethod;
 class ClassLoader;
 class DexCache;
 class IfTable;
 
 // C++ mirror of java.lang.Class
-class MANAGED Class : public Object {
+class MANAGED Class FINAL : public Object {
  public:
+  // Interface method table size. Increasing this value reduces the chance of two interface methods
+  // colliding in the interface method table but increases the size of classes that implement
+  // (non-marker) interfaces.
+  static constexpr size_t kImtSize = 64;
+
+  // imtable entry embedded in class object.
+  struct MANAGED ImTableEntry {
+    HeapReference<ArtMethod> method;
+  };
+
+  // vtable entry embedded in class object.
+  struct MANAGED VTableEntry {
+    HeapReference<ArtMethod> method;
+  };
+
   // Class Status
   //
   // kStatusNotReady: If a Class cannot be found in the class table by
@@ -95,6 +111,11 @@
   // using ResolveClass to initialize the super_class_ and ensuring the
   // interfaces are resolved.
   //
+  // kStatusResolving: Class is just cloned with the right size from
+  // temporary class that's acting as a placeholder for linking. The old
+  // class will be retired. New class is set to this status first before
+  // moving on to being resolved.
+  //
   // kStatusResolved: Still holding the lock on Class, the ClassLinker
   // shows linking is complete and fields of the Class populated by making
   // it kStatusResolved. Java allows circularities of the form where a super
@@ -109,18 +130,20 @@
   //
   // TODO: Explain the other states
   enum Status {
+    kStatusRetired = -2,
     kStatusError = -1,
     kStatusNotReady = 0,
     kStatusIdx = 1,  // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_.
     kStatusLoaded = 2,  // DEX idx values resolved.
-    kStatusResolved = 3,  // Part of linking.
-    kStatusVerifying = 4,  // In the process of being verified.
-    kStatusRetryVerificationAtRuntime = 5,  // Compile time verification failed, retry at runtime.
-    kStatusVerifyingAtRuntime = 6,  // Retrying verification at runtime.
-    kStatusVerified = 7,  // Logically part of linking; done pre-init.
-    kStatusInitializing = 8,  // Class init in progress.
-    kStatusInitialized = 9,  // Ready to go.
-    kStatusMax = 10,
+    kStatusResolving = 3,  // Just cloned from temporary class object.
+    kStatusResolved = 4,  // Part of linking.
+    kStatusVerifying = 5,  // In the process of being verified.
+    kStatusRetryVerificationAtRuntime = 6,  // Compile time verification failed, retry at runtime.
+    kStatusVerifyingAtRuntime = 7,  // Retrying verification at runtime.
+    kStatusVerified = 8,  // Logically part of linking; done pre-init.
+    kStatusInitializing = 9,  // Class init in progress.
+    kStatusInitialized = 10,  // Ready to go.
+    kStatusMax = 11,
   };
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -136,6 +159,12 @@
     return OFFSET_OF_OBJECT_MEMBER(Class, status_);
   }
 
+  // Returns true if the class has been retired.
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  bool IsRetired() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return GetStatus<kVerifyFlags>() == kStatusRetired;
+  }
+
   // Returns true if the class has failed to link.
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsErroneous() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -274,6 +303,13 @@
     }
   }
 
+  // Returns true if this class is the placeholder and should retire and
+  // be replaced with a class with the right size for embedded imt/vtable.
+  bool IsTemp() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    Status s = GetStatus();
+    return s < Status::kStatusResolving && ShouldHaveEmbeddedImtAndVTable();
+  }
+
   String* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);  // Returns the cached name.
   void SetName(String* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);  // Sets the cached name.
   // Computes the name, then sets the cached value.
@@ -451,6 +487,25 @@
   void SetClassSize(uint32_t new_class_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Compute how many bytes would be used a class with the given elements.
+  static uint32_t ComputeClassSize(bool has_embedded_tables,
+                                   uint32_t num_vtable_entries,
+                                   uint32_t num_32bit_static_fields,
+                                   uint32_t num_64bit_static_fields,
+                                   uint32_t num_ref_static_fields);
+
+  // The size of java.lang.Class.class.
+  static uint32_t ClassClassSize() {
+    // The number of vtable entries in java.lang.Class.
+    uint32_t vtable_entries = Object::kVTableLength + 64;
+    return ComputeClassSize(true, vtable_entries, 0, 1, 0);
+  }
+
+  // The size of a java.lang.Class representing a primitive such as int.class.
+  static uint32_t PrimitiveClassSize() {
+    return ComputeClassSize(false, 0, 0, 0, 0);
+  }
+
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   uint32_t GetObjectSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -623,8 +678,6 @@
     return OFFSET_OF_OBJECT_MEMBER(Class, vtable_);
   }
 
-  ObjectArray<ArtMethod>* GetImTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   void SetImTable(ObjectArray<ArtMethod>* new_imtable)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -632,6 +685,26 @@
     return OFFSET_OF_OBJECT_MEMBER(Class, imtable_);
   }
 
+  static MemberOffset EmbeddedImTableOffset() {
+    return MemberOffset(sizeof(Class));
+  }
+
+  static MemberOffset EmbeddedVTableOffset() {
+    return MemberOffset(sizeof(Class) + kImtSize * sizeof(mirror::Class::ImTableEntry));
+  }
+
+  bool ShouldHaveEmbeddedImtAndVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return IsInstantiable();
+  }
+
+  ArtMethod* GetEmbeddedImTableEntry(uint32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  void SetEmbeddedImTableEntry(uint32_t i, ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  void SetEmbeddedVTableEntry(uint32_t i, ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  void PopulateEmbeddedImtAndVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Given a method implemented by this class but potentially from a super class, return the
   // specific implementation method for this class.
   ArtMethod* FindVirtualMethodForVirtual(ArtMethod* method)
@@ -739,11 +812,6 @@
   void SetReferenceInstanceOffsets(uint32_t new_reference_offsets)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Beginning of static field data
-  static MemberOffset FieldsOffset() {
-    return OFFSET_OF_OBJECT_MEMBER(Class, fields_);
-  }
-
   // Returns the number of static fields containing reference types.
   uint32_t NumReferenceStaticFields() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(IsResolved() || IsErroneous());
@@ -751,7 +819,7 @@
   }
 
   uint32_t NumReferenceStaticFieldsDuringLinking() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(IsLoaded() || IsErroneous());
+    DCHECK(IsLoaded() || IsErroneous() || IsRetired());
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_));
   }
 
@@ -865,25 +933,65 @@
 
   template <bool kVisitClass, typename Visitor>
   void VisitReferences(mirror::Class* klass, const Visitor& visitor)
-      NO_THREAD_SAFETY_ANALYSIS;
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Visit references within the embedded tables of the class.
+  // TODO: remove NO_THREAD_SAFETY_ANALYSIS when annotalysis handles visitors better.
+  template<typename Visitor>
+  void VisitEmbeddedImtAndVTable(const Visitor& visitor) NO_THREAD_SAFETY_ANALYSIS;
 
   std::string GetDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool DescriptorEquals(const char* match) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   std::string GetArrayDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const DexFile::ClassDef* GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   uint32_t NumDirectInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   uint16_t GetDirectInterfaceTypeIdx(uint32_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   static mirror::Class* GetDirectInterface(Thread* self, Handle<mirror::Class> klass, uint32_t idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const char* GetSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   std::string GetLocation() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const DexFile& GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const DexFile::TypeList* GetInterfaceTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Asserts we are initialized or initializing in the given thread.
   void AssertInitializedOrInitializingInThread(Thread* self)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  Class* CopyOf(Thread* self, int32_t new_length)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // For proxy class only.
+  ObjectArray<Class>* GetInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // For proxy class only.
+  ObjectArray<ObjectArray<Class>>* GetThrows() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore
+  // fence.
+  class InitializeClassVisitor {
+   public:
+    explicit InitializeClassVisitor(uint32_t class_size) : class_size_(class_size) {
+    }
+
+    void operator()(mirror::Object* obj, size_t usable_size) const
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+   private:
+    const uint32_t class_size_;
+
+    DISALLOW_COPY_AND_ASSIGN(InitializeClassVisitor);
+  };
+
  private:
   void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -902,6 +1010,8 @@
 
   void CheckObjectAlloc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  ObjectArray<ArtMethod>* GetImTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // defining class loader, or NULL for the "bootstrap" system loader
   HeapReference<ClassLoader> class_loader_;
 
@@ -1012,7 +1122,12 @@
   // values are kept in a table in gDvm.
   // InitiatingLoaderList initiating_loader_list_;
 
-  // Location of first static field.
+  // The following data exist in real class objects.
+  // Embedded Imtable, for class object that's not an interface, fixed size.
+  ImTableEntry embedded_imtable_[0];
+  // Embedded Vtable, for class object that's not an interface, variable size.
+  VTableEntry embedded_vtable_[0];
+  // Static fields, variable size.
   uint32_t fields_[0];
 
   // java.lang.Class
@@ -1024,14 +1139,6 @@
 
 std::ostream& operator<<(std::ostream& os, const Class::Status& rhs);
 
-class MANAGED ClassClass : public Class {
- private:
-  int32_t pad_;
-  int64_t serialVersionUID_;
-  friend struct art::ClassClassOffsets;  // for verifying offset information
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass);
-};
-
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h
index 74dae38..f3594e4 100644
--- a/runtime/mirror/class_loader.h
+++ b/runtime/mirror/class_loader.h
@@ -27,6 +27,12 @@
 
 // C++ mirror of java.lang.ClassLoader
 class MANAGED ClassLoader : public Object {
+ public:
+  // Size of an instance of java.lang.ClassLoader.
+  static constexpr uint32_t InstanceSize() {
+    return sizeof(ClassLoader);
+  }
+
  private:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   HeapReference<Object> packages_;
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 7e40f64..08cff99 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -24,6 +24,11 @@
 namespace art {
 namespace mirror {
 
+inline uint32_t DexCache::ClassSize() {
+  uint32_t vtable_entries = Object::kVTableLength + 1;
+  return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0);
+}
+
 inline ArtMethod* DexCache::GetResolvedMethod(uint32_t method_idx)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ArtMethod* method = GetResolvedMethods()->Get(method_idx);
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 65a5026..bfd603a 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -18,10 +18,8 @@
 #define ART_RUNTIME_MIRROR_DEX_CACHE_H_
 
 #include "art_method.h"
-#include "class.h"
 #include "object.h"
 #include "object_array.h"
-#include "string.h"
 
 namespace art {
 
@@ -33,15 +31,21 @@
 namespace mirror {
 
 class ArtField;
+class ArtMethod;
 class Class;
+class String;
 
-class MANAGED DexCacheClass : public Class {
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(DexCacheClass);
-};
-
-class MANAGED DexCache : public Object {
+// C++ mirror of java.lang.DexCache.
+class MANAGED DexCache FINAL : public Object {
  public:
+  // Size of java.lang.DexCache.class.
+  static uint32_t ClassSize();
+
+  // Size of an instance of java.lang.DexCache not including referenced values.
+  static constexpr uint32_t InstanceSize() {
+    return sizeof(DexCache);
+  }
+
   void Init(const DexFile* dex_file,
             String* location,
             ObjectArray<String>* strings,
diff --git a/runtime/mirror/iftable.h b/runtime/mirror/iftable.h
index ad312ed..5feb602 100644
--- a/runtime/mirror/iftable.h
+++ b/runtime/mirror/iftable.h
@@ -23,7 +23,7 @@
 namespace art {
 namespace mirror {
 
-class MANAGED IfTable : public ObjectArray<Object> {
+class MANAGED IfTable FINAL : public ObjectArray<Object> {
  public:
   Class* GetInterface(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     Class* interface = Get((i * kMax) + kInterface)->AsClass();
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 089ef57..3d45683 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -35,6 +35,11 @@
 namespace art {
 namespace mirror {
 
+inline uint32_t Object::ClassSize() {
+  uint32_t vtable_entries = kVTableLength;
+  return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0);
+}
+
 template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline Class* Object::GetClass() {
   return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(
@@ -75,6 +80,12 @@
       OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
 }
 
+inline bool Object::CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val) {
+  // Force use of non-transactional mode and do not check.
+  return CasFieldWeakRelaxed32<false, false>(
+      OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue());
+}
+
 inline uint32_t Object::GetLockOwnerThreadId() {
   return Monitor::GetLockOwnerThreadId(this);
 }
@@ -443,6 +454,8 @@
   SetField32<kTransactionActive, kCheckTransaction, kVerifyFlags, true>(field_offset, new_value);
 }
 
+// TODO: Pass memory_order_ and strong/weak as arguments to avoid code duplication?
+
 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
 inline bool Object::CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset,
                                                          int32_t old_value, int32_t new_value) {
@@ -461,6 +474,42 @@
   return atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_value, new_value);
 }
 
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldWeakRelaxed32(MemberOffset field_offset,
+                                          int32_t old_value, int32_t new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
+
+  return atomic_addr->CompareExchangeWeakRelaxed(old_value, new_value);
+}
+
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset,
+                                                           int32_t old_value, int32_t new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr);
+
+  return atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_value, new_value);
+}
+
 template<VerifyObjectFlags kVerifyFlags, bool kIsVolatile>
 inline int64_t Object::GetField64(MemberOffset field_offset) {
   if (kVerifyFlags & kVerifyThis) {
@@ -526,6 +575,23 @@
   return atomic_addr->CompareExchangeWeakSequentiallyConsistent(old_value, new_value);
 }
 
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldStrongSequentiallyConsistent64(MemberOffset field_offset,
+                                                           int64_t old_value, int64_t new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteField64(this, field_offset, old_value, true);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  Atomic<int64_t>* atomic_addr = reinterpret_cast<Atomic<int64_t>*>(raw_addr);
+  return atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_value, new_value);
+}
+
 template<class T, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption,
          bool kIsVolatile>
 inline T* Object::GetFieldObject(MemberOffset field_offset) {
@@ -644,6 +710,38 @@
   return success;
 }
 
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline bool Object::CasFieldStrongSequentiallyConsistentObject(MemberOffset field_offset,
+                                                             Object* old_value, Object* new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  if (kVerifyFlags & kVerifyWrites) {
+    VerifyObject(new_value);
+  }
+  if (kVerifyFlags & kVerifyReads) {
+    VerifyObject(old_value);
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true);
+  }
+  HeapReference<Object> old_ref(HeapReference<Object>::FromMirrorPtr(old_value));
+  HeapReference<Object> new_ref(HeapReference<Object>::FromMirrorPtr(new_value));
+  byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
+  Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
+
+  bool success = atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_ref.reference_,
+                                                                          new_ref.reference_);
+
+  if (success) {
+    Runtime::Current()->GetHeap()->WriteBarrierField(this, field_offset, new_value);
+  }
+  return success;
+}
+
 template<bool kVisitClass, bool kIsStatic, typename Visitor>
 inline void Object::VisitFieldsReferences(uint32_t ref_offsets, const Visitor& visitor) {
   if (LIKELY(ref_offsets != CLASS_WALK_SUPER)) {
@@ -687,6 +785,7 @@
 
 template<bool kVisitClass, typename Visitor>
 inline void Object::VisitStaticFieldsReferences(mirror::Class* klass, const Visitor& visitor) {
+  DCHECK(!klass->IsTemp());
   klass->VisitFieldsReferences<kVisitClass, true>(
       klass->GetReferenceStaticOffsets<kVerifyNone>(), visitor);
 }
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index e58091f..5f88d54 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -156,7 +156,7 @@
         // loop iteration.
         LockWord hash_word(LockWord::FromHashCode(GenerateIdentityHashCode()));
         DCHECK_EQ(hash_word.GetState(), LockWord::kHashCode);
-        if (const_cast<Object*>(this)->CasLockWordWeakSequentiallyConsistent(lw, hash_word)) {
+        if (const_cast<Object*>(this)->CasLockWordWeakRelaxed(lw, hash_word)) {
           return hash_word.GetHashCode();
         }
         break;
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index d29011a..4fae470 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -63,13 +63,24 @@
 // C++ mirror of java.lang.Object
 class MANAGED LOCKABLE Object {
  public:
+  // The number of vtable entries in java.lang.Object.
+  static constexpr size_t kVTableLength = 11;
+
+  // The size of the java.lang.Class representing a java.lang.Object.
+  static uint32_t ClassSize();
+
+  // Size of an instance of java.lang.Object.
+  static constexpr uint32_t InstanceSize() {
+    return sizeof(Object);
+  }
+
   static MemberOffset ClassOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Object, klass_);
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
-  Class* GetClass() ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE Class* GetClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   void SetClass(Class* new_klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -99,19 +110,14 @@
     return OFFSET_OF_OBJECT_MEMBER(Object, monitor_);
   }
 
-  // As volatile can be false if the mutators are suspended. This is an optimization since it
+  // As_volatile can be false if the mutators are suspended. This is an optimization since it
   // avoids the barriers.
   LockWord GetLockWord(bool as_volatile) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void SetLockWord(LockWord new_val, bool as_volatile) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  // All Cas operations defined here have C++11 memory_order_seq_cst ordering
-  // semantics: Preceding memory operations become visible to other threads
-  // before the CAS, and subsequent operations become visible after the CAS.
-  // The Cas operations defined here do not fail spuriously, i.e. they
-  // have C++11 "strong" semantics.
-  // TODO: In most, possibly all, cases, these assumptions are too strong.
-  // Confirm and weaken the implementation.
   bool CasLockWordWeakSequentiallyConsistent(LockWord old_val, LockWord new_val)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   uint32_t GetLockOwnerThreadId();
 
   mirror::Object* MonitorEnter(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -202,27 +208,27 @@
   // Accessor for Java type fields.
   template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
       ReadBarrierOption kReadBarrierOption = kWithReadBarrier, bool kIsVolatile = false>
-  T* GetFieldObject(MemberOffset field_offset) ALWAYS_INLINE
+  ALWAYS_INLINE T* GetFieldObject(MemberOffset field_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
       ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
-  T* GetFieldObjectVolatile(MemberOffset field_offset) ALWAYS_INLINE
+  ALWAYS_INLINE T* GetFieldObjectVolatile(MemberOffset field_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
-  void SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, Object* new_value)
-      ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE void SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, Object* new_value)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
-  void SetFieldObject(MemberOffset field_offset, Object* new_value) ALWAYS_INLINE
+  ALWAYS_INLINE void SetFieldObject(MemberOffset field_offset, Object* new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetFieldObjectVolatile(MemberOffset field_offset, Object* new_value) ALWAYS_INLINE
+  ALWAYS_INLINE void SetFieldObjectVolatile(MemberOffset field_offset, Object* new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
@@ -231,49 +237,67 @@
                                                 Object* new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  bool CasFieldStrongSequentiallyConsistentObject(MemberOffset field_offset, Object* old_value,
+                                                  Object* new_value)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   HeapReference<Object>* GetFieldObjectReferenceAddr(MemberOffset field_offset);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
-  int32_t GetField32(MemberOffset field_offset) ALWAYS_INLINE
+  ALWAYS_INLINE int32_t GetField32(MemberOffset field_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  int32_t GetField32Volatile(MemberOffset field_offset) ALWAYS_INLINE
+  ALWAYS_INLINE int32_t GetField32Volatile(MemberOffset field_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
-  void SetField32(MemberOffset field_offset, int32_t new_value) ALWAYS_INLINE
+  ALWAYS_INLINE void SetField32(MemberOffset field_offset, int32_t new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetField32Volatile(MemberOffset field_offset, int32_t new_value) ALWAYS_INLINE
+  ALWAYS_INLINE void SetField32Volatile(MemberOffset field_offset, int32_t new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  bool CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset, int32_t old_value,
-                                            int32_t new_value) ALWAYS_INLINE
+  ALWAYS_INLINE bool CasFieldWeakSequentiallyConsistent32(MemberOffset field_offset,
+                                                          int32_t old_value, int32_t new_value)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  bool CasFieldWeakRelaxed32(MemberOffset field_offset, int32_t old_value,
+                             int32_t new_value) ALWAYS_INLINE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  bool CasFieldStrongSequentiallyConsistent32(MemberOffset field_offset, int32_t old_value,
+                                              int32_t new_value) ALWAYS_INLINE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
-  int64_t GetField64(MemberOffset field_offset) ALWAYS_INLINE
+  ALWAYS_INLINE int64_t GetField64(MemberOffset field_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  int64_t GetField64Volatile(MemberOffset field_offset) ALWAYS_INLINE
+  ALWAYS_INLINE int64_t GetField64Volatile(MemberOffset field_offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
-  void SetField64(MemberOffset field_offset, int64_t new_value) ALWAYS_INLINE
+  ALWAYS_INLINE void SetField64(MemberOffset field_offset, int64_t new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetField64Volatile(MemberOffset field_offset, int64_t new_value) ALWAYS_INLINE
+  ALWAYS_INLINE void SetField64Volatile(MemberOffset field_offset, int64_t new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
@@ -283,6 +307,12 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  bool CasFieldStrongSequentiallyConsistent64(MemberOffset field_offset, int64_t old_value,
+                                              int64_t new_value)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  template<bool kTransactionActive, bool kCheckTransaction = true,
       VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename T>
   void SetFieldPtr(MemberOffset field_offset, T new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index 54d1240..7012b19 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -23,8 +23,13 @@
 namespace mirror {
 
 template<class T>
-class MANAGED ObjectArray : public Array {
+class MANAGED ObjectArray: public Array {
  public:
+  // The size of Object[].class.
+  static uint32_t ClassSize() {
+    return Array::ClassSize();
+  }
+
   static ObjectArray<T>* Alloc(Thread* self, Class* object_array_class, int32_t length,
                                gc::AllocatorType allocator_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index f85fb27..7e1de5d 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -28,7 +28,7 @@
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "dex_file.h"
-#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
 #include "iftable-inl.h"
diff --git a/runtime/mirror/proxy.h b/runtime/mirror/proxy.h
index 6e4947e..db511d6 100644
--- a/runtime/mirror/proxy.h
+++ b/runtime/mirror/proxy.h
@@ -25,28 +25,8 @@
 
 namespace mirror {
 
-// All proxy objects have a class which is a synthesized proxy class. The synthesized proxy class
-// has the static fields used to implement reflection on proxy objects.
-class MANAGED SynthesizedProxyClass : public Class {
- public:
-  ObjectArray<Class>* GetInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldObject<ObjectArray<Class>>(OFFSET_OF_OBJECT_MEMBER(SynthesizedProxyClass,
-                                                                       interfaces_));
-  }
-
-  ObjectArray<ObjectArray<Class>>* GetThrows()  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldObject<ObjectArray<ObjectArray<Class>>>(OFFSET_OF_OBJECT_MEMBER(SynthesizedProxyClass,
-                                                                                     throws_));
-  }
-
- private:
-  HeapReference<ObjectArray<Class>> interfaces_;
-  HeapReference<ObjectArray<ObjectArray<Class>>> throws_;
-  DISALLOW_IMPLICIT_CONSTRUCTORS(SynthesizedProxyClass);
-};
-
 // C++ mirror of java.lang.reflect.Proxy.
-class MANAGED Proxy : public Object {
+class MANAGED Proxy FINAL : public Object {
  private:
   HeapReference<Object> h_;
 
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index abecbc5..52b0927 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -29,7 +29,7 @@
 namespace mirror {
 
 // C++ mirror of java.lang.StackTraceElement
-class MANAGED StackTraceElement : public Object {
+class MANAGED StackTraceElement FINAL : public Object {
  public:
   String* GetDeclaringClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_));
diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h
index 315f7b1..6736497 100644
--- a/runtime/mirror/string-inl.h
+++ b/runtime/mirror/string-inl.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_MIRROR_STRING_INL_H_
 
 #include "array.h"
+#include "class.h"
 #include "intern_table.h"
 #include "runtime.h"
 #include "string.h"
@@ -26,6 +27,11 @@
 namespace art {
 namespace mirror {
 
+inline uint32_t String::ClassSize() {
+  uint32_t vtable_entries = Object::kVTableLength + 51;
+  return Class::ComputeClassSize(true, vtable_entries, 1, 1, 2);
+}
+
 inline CharArray* String::GetCharArray() {
   return GetFieldObject<CharArray>(ValueOffset());
 }
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index b8acede..8ab4db9 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -19,22 +19,28 @@
 
 #include <gtest/gtest.h>
 
-#include "class.h"
 #include "object_callbacks.h"
 #include "read_barrier.h"
 
 namespace art {
 
 template<class T> class Handle;
-struct StringClassOffsets;
 struct StringOffsets;
 class StringPiece;
 
 namespace mirror {
 
 // C++ mirror of java.lang.String
-class MANAGED String : public Object {
+class MANAGED String FINAL : public Object {
  public:
+  // Size of java.lang.String.class.
+  static uint32_t ClassSize();
+
+  // Size of an instance of java.lang.String not including its value array.
+  static constexpr uint32_t InstanceSize() {
+    return sizeof(String);
+  }
+
   static MemberOffset CountOffset() {
     return OFFSET_OF_OBJECT_MEMBER(String, count_);
   }
@@ -160,16 +166,6 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(String);
 };
 
-class MANAGED StringClass : public Class {
- private:
-  HeapReference<CharArray> ASCII_;
-  HeapReference<Object> CASE_INSENSITIVE_ORDER_;
-  uint32_t REPLACEMENT_CHAR_;
-  int64_t serialVersionUID_;
-  friend struct art::StringClassOffsets;  // for verifying offset information
-  DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass);
-};
-
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index e619dda..cede1a0 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -21,7 +21,6 @@
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
-#include "mirror/proxy.h"
 #include "object_utils.h"
 #include "scoped_thread_state_change.h"
 #include "scoped_fast_native_object_access.h"
@@ -91,8 +90,7 @@
 
 static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) {
   ScopedFastNativeObjectAccess soa(env);
-  mirror::SynthesizedProxyClass* c =
-      down_cast<mirror::SynthesizedProxyClass*>(DecodeClass(soa, javaThis));
+  mirror::Class* c = DecodeClass(soa, javaThis);
   return soa.AddLocalReference<jobjectArray>(c->GetInterfaces()->Clone(soa.Self()));
 }
 
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index 22e81e4..ac602ac 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -21,7 +21,6 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
-#include "mirror/proxy.h"
 #include "object_utils.h"
 #include "reflection.h"
 #include "scoped_fast_native_object_access.h"
@@ -39,8 +38,7 @@
   ScopedFastNativeObjectAccess soa(env);
   mirror::ArtMethod* proxy_method = mirror::ArtMethod::FromReflectedMethod(soa, javaMethod);
   CHECK(proxy_method->GetDeclaringClass()->IsProxyClass());
-  mirror::SynthesizedProxyClass* proxy_class =
-      down_cast<mirror::SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
+  mirror::Class* proxy_class = proxy_method->GetDeclaringClass();
   int throws_index = -1;
   size_t num_virt_methods = proxy_class->NumVirtualMethods();
   for (size_t i = 0; i < num_virt_methods; i++) {
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 7cc4cac..65dece0 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -28,8 +28,8 @@
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
   // JNI must use non transactional mode.
-  bool success = obj->CasFieldWeakSequentiallyConsistent32<false>(MemberOffset(offset),
-                                                                  expectedValue, newValue);
+  bool success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
+                                                                    expectedValue, newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
@@ -38,8 +38,8 @@
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
   // JNI must use non transactional mode.
-  bool success = obj->CasFieldWeakSequentiallyConsistent64<false>(MemberOffset(offset),
-                                                                  expectedValue, newValue);
+  bool success = obj->CasFieldStrongSequentiallyConsistent64<false>(MemberOffset(offset),
+                                                                    expectedValue, newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
@@ -50,8 +50,8 @@
   mirror::Object* expectedValue = soa.Decode<mirror::Object*>(javaExpectedValue);
   mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
   // JNI must use non transactional mode.
-  bool success = obj->CasFieldWeakSequentiallyConsistentObject<false>(MemberOffset(offset),
-                                                                      expectedValue, newValue);
+  bool success = obj->CasFieldStrongSequentiallyConsistentObject<false>(MemberOffset(offset),
+                                                                        expectedValue, newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 70253af..44f4466 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -24,7 +24,7 @@
 #include "dex_file.h"
 #include "invoke_type.h"
 #include "mem_map.h"
-#include "mirror/art_method.h"
+#include "mirror/class.h"
 #include "oat.h"
 #include "os.h"
 
diff --git a/runtime/object_callbacks.h b/runtime/object_callbacks.h
index d8c1c40..0e6f4d8 100644
--- a/runtime/object_callbacks.h
+++ b/runtime/object_callbacks.h
@@ -26,10 +26,10 @@
 
 namespace art {
 namespace mirror {
-class Class;
-class Object;
-template<class MirrorType> class HeapReference;
-class Reference;
+  class Class;
+  class Object;
+  template<class MirrorType> class HeapReference;
+  class Reference;
 }  // namespace mirror
 class StackVisitor;
 
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index 28ce8f3..4379b4a 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -25,7 +25,6 @@
 #include "mirror/class.h"
 #include "mirror/dex_cache.h"
 #include "mirror/iftable.h"
-#include "mirror/proxy.h"
 #include "mirror/string.h"
 
 #include "runtime.h"
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index e1e133f..a016cc5 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -197,13 +197,18 @@
 #else
 #error "ART default GC type must be set"
 #endif
+  // If we are using homogeneous space compaction then default background compaction to off since
+  // homogeneous space compactions when we transition to not jank perceptible.
+  use_homogeneous_space_compaction_for_oom_ = false;
   // If background_collector_type_ is kCollectorTypeNone, it defaults to the collector_type_ after
-  // parsing options.
+  // parsing options. If you set this to kCollectorTypeHSpaceCompact then we will do an hspace
+  // compaction when we transition to background instead of a normal collector transition.
   background_collector_type_ = gc::kCollectorTypeSS;
   stack_size_ = 0;  // 0 means default.
   max_spins_before_thin_lock_inflation_ = Monitor::kDefaultMaxSpinsBeforeThinLockInflation;
   low_memory_mode_ = false;
   use_tlab_ = false;
+  min_interval_homogeneous_space_compaction_by_oom_ = MsToNs(100 * 1000);  // 100s.
   verify_pre_gc_heap_ = false;
   // Pre sweeping is the one that usually fails if the GC corrupted the heap.
   verify_pre_sweeping_heap_ = kIsDebugBuild;
@@ -416,6 +421,10 @@
       low_memory_mode_ = true;
     } else if (option == "-XX:UseTLAB") {
       use_tlab_ = true;
+    } else if (option == "-XX:EnableHSpaceCompactForOOM") {
+      use_homogeneous_space_compaction_for_oom_ = true;
+    } else if (option == "-XX:DisableHSpaceCompactForOOM") {
+      use_homogeneous_space_compaction_for_oom_ = false;
     } else if (StartsWith(option, "-D")) {
       properties_.push_back(option.substr(strlen("-D")));
     } else if (StartsWith(option, "-Xjnitrace:")) {
@@ -439,12 +448,17 @@
       if (!ParseStringAfterChar(option, '=', &substring)) {
         return false;
       }
-      gc::CollectorType collector_type = ParseCollectorType(substring);
-      if (collector_type != gc::kCollectorTypeNone) {
-        background_collector_type_ = collector_type;
+      // Special handling for HSpaceCompact since this is only valid as a background GC type.
+      if (substring == "HSpaceCompact") {
+        background_collector_type_ = gc::kCollectorTypeHomogeneousSpaceCompact;
       } else {
-        Usage("Unknown -XX:BackgroundGC option %s\n", substring.c_str());
-        return false;
+        gc::CollectorType collector_type = ParseCollectorType(substring);
+        if (collector_type != gc::kCollectorTypeNone) {
+          background_collector_type_ = collector_type;
+        } else {
+          Usage("Unknown -XX:BackgroundGC option %s\n", substring.c_str());
+          return false;
+        }
       }
     } else if (option == "-XX:+DisableExplicitGC") {
       is_explicit_gc_disabled_ = true;
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index d0f3c12..4c74be6 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -88,6 +88,12 @@
   static constexpr uint32_t kExplicitSuspendCheck = 2;
   static constexpr uint32_t kExplicitStackOverflowCheck = 4;
   uint32_t explicit_checks_;
+  // Whether or not we use homogeneous space compaction to avoid OOM errors. If enabled,
+  // the heap will attempt to create an extra space which enables compacting from a malloc space to
+  // another malloc space when we are about to throw OOM.
+  bool use_homogeneous_space_compaction_for_oom_;
+  // Minimal interval allowed between two homogeneous space compactions caused by OOM.
+  uint64_t min_interval_homogeneous_space_compaction_by_oom_;
 
  private:
   ParsedOptions() {}
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 1034923..49f6fe0 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -20,6 +20,9 @@
 #include "entrypoints/entrypoint_utils.h"
 #include "handle_scope-inl.h"
 #include "mirror/art_method-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
+#include "mirror/throwable.h"
 #include "verifier/method_verifier.h"
 
 namespace art {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index efa205e..94d6cdf 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -638,7 +638,9 @@
                        options->verify_post_gc_heap_,
                        options->verify_pre_gc_rosalloc_,
                        options->verify_pre_sweeping_rosalloc_,
-                       options->verify_post_gc_rosalloc_);
+                       options->verify_post_gc_rosalloc_,
+                       options->use_homogeneous_space_compaction_for_oom_,
+                       options->min_interval_homogeneous_space_compaction_by_oom_);
 
   dump_gc_performance_on_shutdown_ = options->dump_gc_performance_on_shutdown_;
 
@@ -1013,8 +1015,8 @@
     method->SetEntryPointFromPortableCompiledCode(nullptr);
     method->SetEntryPointFromQuickCompiledCode(nullptr);
   } else {
-    method->SetEntryPointFromPortableCompiledCode(GetPortableImtConflictTrampoline(class_linker));
-    method->SetEntryPointFromQuickCompiledCode(GetQuickImtConflictTrampoline(class_linker));
+    method->SetEntryPointFromPortableCompiledCode(class_linker->GetPortableImtConflictTrampoline());
+    method->SetEntryPointFromQuickCompiledCode(class_linker->GetQuickImtConflictTrampoline());
   }
   return method.Get();
 }
@@ -1033,8 +1035,8 @@
     method->SetEntryPointFromPortableCompiledCode(nullptr);
     method->SetEntryPointFromQuickCompiledCode(nullptr);
   } else {
-    method->SetEntryPointFromPortableCompiledCode(GetPortableResolutionTrampoline(class_linker));
-    method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionTrampoline(class_linker));
+    method->SetEntryPointFromPortableCompiledCode(class_linker->GetPortableResolutionTrampoline());
+    method->SetEntryPointFromQuickCompiledCode(class_linker->GetQuickResolutionTrampoline());
   }
   return method.Get();
 }
diff --git a/runtime/thread.h b/runtime/thread.h
index 4312741..bf125f9 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -47,7 +47,7 @@
 
 namespace gc {
 namespace collector {
-class SemiSpace;
+  class SemiSpace;
 }  // namespace collector
 }  // namespace gc
 
@@ -61,7 +61,6 @@
   template<class T> class PrimitiveArray;
   typedef PrimitiveArray<int32_t> IntArray;
   class StackTraceElement;
-  class StaticStorageBase;
   class Throwable;
 }  // namespace mirror
 class BaseMutex;
@@ -781,7 +780,7 @@
   void RevokeThreadLocalAllocationStack();
 
   size_t GetThreadLocalBytesAllocated() const {
-    return tlsPtr_.thread_local_pos - tlsPtr_.thread_local_start;
+    return tlsPtr_.thread_local_end - tlsPtr_.thread_local_start;
   }
 
   size_t GetThreadLocalObjectsAllocated() const {
@@ -900,7 +899,7 @@
   // first if possible.
   /***********************************************************************************************/
 
-  struct PACKED(4)  tls_32bit_sized_values {
+  struct PACKED(4) tls_32bit_sized_values {
     // We have no control over the size of 'bool', but want our boolean fields
     // to be 4-byte quantities.
     typedef uint32_t bool32_t;
diff --git a/runtime/utils.h b/runtime/utils.h
index 448c591..b47de81 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -167,6 +167,10 @@
 
 // For rounding integers.
 template<typename T>
+static constexpr T RoundDown(T x, typename TypeIdentity<T>::type n)
+    __attribute__((warn_unused_result));
+
+template<typename T>
 static constexpr T RoundDown(T x, typename TypeIdentity<T>::type n) {
   return
       DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0))
@@ -174,17 +178,27 @@
 }
 
 template<typename T>
+static constexpr T RoundUp(T x, typename TypeIdentity<T>::type n)
+    __attribute__((warn_unused_result));
+
+template<typename T>
 static constexpr T RoundUp(T x, typename TypeIdentity<T>::type n) {
   return RoundDown(x + n - 1, n);
 }
 
 // For aligning pointers.
 template<typename T>
+static inline T* AlignDown(T* x, uintptr_t n) __attribute__((warn_unused_result));
+
+template<typename T>
 static inline T* AlignDown(T* x, uintptr_t n) {
   return reinterpret_cast<T*>(RoundDown(reinterpret_cast<uintptr_t>(x), n));
 }
 
 template<typename T>
+static inline T* AlignUp(T* x, uintptr_t n) __attribute__((warn_unused_result));
+
+template<typename T>
 static inline T* AlignUp(T* x, uintptr_t n) {
   return reinterpret_cast<T*>(RoundUp(reinterpret_cast<uintptr_t>(x), n));
 }
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index 9ac04d7..f70faf5 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -19,7 +19,7 @@
 #include <stdio.h>
 #include <memory>
 
-#include "class_linker.h"
+#include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "dex_file.h"
 
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index f412034..739dbf8 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -61,9 +61,6 @@
     test_Memory_pokeShort();
     test_Memory_pokeInt();
     test_Memory_pokeLong();
-    test_AtomicBoolean_compareAndSet();
-    test_AtomicInteger_compareAndSet();
-    test_AtomicLong_compareAndSet();
   }
 
   /*
@@ -96,60 +93,6 @@
     Assert.assertNotNull(Thread.currentThread());
   }
 
-  /**
-   * Will test inlining CAS, by inclusion of AtomicBoolean in core.oat.
-   */
-  public static void test_AtomicBoolean_compareAndSet() {
-    java.util.concurrent.atomic.AtomicBoolean ab = new java.util.concurrent.atomic.AtomicBoolean();
-    Assert.assertEquals(ab.compareAndSet(false, false), true);
-    Assert.assertEquals(ab.compareAndSet(true, false), false);
-    Assert.assertEquals(ab.compareAndSet(true, true), false);
-    Assert.assertEquals(ab.compareAndSet(false, true), true);
-    Assert.assertEquals(ab.compareAndSet(false, true), false);
-    Assert.assertEquals(ab.compareAndSet(false, false), false);
-    Assert.assertEquals(ab.compareAndSet(true, true), true);
-    Assert.assertEquals(ab.compareAndSet(true, false), true);
-    Assert.assertEquals(ab.compareAndSet(true, false), false);
-    Assert.assertEquals(ab.compareAndSet(true, true), false);
-    Assert.assertEquals(ab.compareAndSet(false, false), true);
-  }
-
-  /**
-   * Will test inlining CAS, by inclusion of AtomicInteger in core.oat.
-   */
-  public static void test_AtomicInteger_compareAndSet() {
-    java.util.concurrent.atomic.AtomicInteger ab = new java.util.concurrent.atomic.AtomicInteger();
-    Assert.assertEquals(ab.compareAndSet(0, 0), true);
-    Assert.assertEquals(ab.compareAndSet(0x12345678, 0), false);
-    Assert.assertEquals(ab.compareAndSet(0x12345678, 0x12345678), false);
-    Assert.assertEquals(ab.compareAndSet(0, 0x12345678), true);
-    Assert.assertEquals(ab.compareAndSet(0, 0x12345678), false);
-    Assert.assertEquals(ab.compareAndSet(0, 0), false);
-    Assert.assertEquals(ab.compareAndSet(0x12345678, 0x12345678), true);
-    Assert.assertEquals(ab.compareAndSet(0x12345678, 0), true);
-    Assert.assertEquals(ab.compareAndSet(0x12345678, 0), false);
-    Assert.assertEquals(ab.compareAndSet(0x12345678, 0x12345678), false);
-    Assert.assertEquals(ab.compareAndSet(0, 0), true);
-  }
-
-  /**
-   * Will test inlining CAS, by inclusion of AtomicLong in core.oat.
-   */
-  public static void test_AtomicLong_compareAndSet() {
-    java.util.concurrent.atomic.AtomicLong ab = new java.util.concurrent.atomic.AtomicLong();
-    Assert.assertEquals(ab.compareAndSet(0l, 0l), true);
-    Assert.assertEquals(ab.compareAndSet(0x1234567890l, 0l), false);
-    Assert.assertEquals(ab.compareAndSet(0x1234567890l, 0x1234567890l), false);
-    Assert.assertEquals(ab.compareAndSet(0l, 0x1234567890l), true);
-    Assert.assertEquals(ab.compareAndSet(0l, 0x1234567890l), false);
-    Assert.assertEquals(ab.compareAndSet(0l, 0l), false);
-    Assert.assertEquals(ab.compareAndSet(0x1234567890l, 0x1234567890l), true);
-    Assert.assertEquals(ab.compareAndSet(0x1234567890l, 0l), true);
-    Assert.assertEquals(ab.compareAndSet(0x1234567890l, 0l), false);
-    Assert.assertEquals(ab.compareAndSet(0x1234567890l, 0x1234567890l), false);
-    Assert.assertEquals(ab.compareAndSet(0l, 0l), true);
-  }
-
   public static void test_String_length() {
     String str0 = "";
     String str1 = "x";
@@ -580,6 +523,7 @@
 
   static Object runtime;
   static Method address_of;
+  static Method new_non_movable_array;
   static Method peek_byte;
   static Method peek_short;
   static Method peek_int;
@@ -594,6 +538,7 @@
     Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime");
     runtime = get_runtime.invoke(null);
     address_of = vm_runtime.getDeclaredMethod("addressOf", Object.class);
+    new_non_movable_array = vm_runtime.getDeclaredMethod("newNonMovableArray", Class.class, Integer.TYPE);
 
     Class<?> io_memory = Class.forName("libcore.io.Memory");
     peek_byte = io_memory.getDeclaredMethod("peekByte", Long.TYPE);
@@ -607,7 +552,7 @@
   }
 
   public static void test_Memory_peekByte() throws Exception {
-    byte[] b = new byte [2];
+    byte[] b = (byte[])new_non_movable_array.invoke(runtime, Byte.TYPE, 2);
     b[0] = 0x12;
     b[1] = 0x11;
     long address = (long)address_of.invoke(runtime, b);
@@ -616,7 +561,7 @@
   }
 
   public static void test_Memory_peekShort() throws Exception {
-    byte[] b = new byte [3];
+    byte[] b = (byte[])new_non_movable_array.invoke(runtime, Byte.TYPE, 3);
     b[0] = 0x13;
     b[1] = 0x12;
     b[2] = 0x11;
@@ -626,7 +571,7 @@
   }
 
   public static void test_Memory_peekInt() throws Exception {
-    byte[] b = new byte [5];
+    byte[] b = (byte[])new_non_movable_array.invoke(runtime, Byte.TYPE, 5);
     b[0] = 0x15;
     b[1] = 0x14;
     b[2] = 0x13;
@@ -638,7 +583,7 @@
   }
 
   public static void test_Memory_peekLong() throws Exception {
-    byte[] b = new byte [9];
+    byte[] b = (byte[])new_non_movable_array.invoke(runtime, Byte.TYPE, 9);
     b[0] = 0x19;
     b[1] = 0x18;
     b[2] = 0x17;
@@ -655,7 +600,7 @@
 
   public static void test_Memory_pokeByte() throws Exception {
     byte[] r = {0x11, 0x12};
-    byte[] b = new byte [2];
+    byte[] b = (byte[])new_non_movable_array.invoke(runtime, Byte.TYPE, 2);
     long address = (long)address_of.invoke(runtime, b);
     poke_byte.invoke(null, address, (byte)0x11);
     poke_byte.invoke(null, address + 1, (byte)0x12);
@@ -665,7 +610,7 @@
   public static void test_Memory_pokeShort() throws Exception {
     byte[] ra = {0x12, 0x11, 0x13};
     byte[] ru = {0x12, 0x22, 0x21};
-    byte[] b = new byte [3];
+    byte[] b = (byte[])new_non_movable_array.invoke(runtime, Byte.TYPE, 3);
     long address = (long)address_of.invoke(runtime, b);
 
     // Aligned write
@@ -681,7 +626,7 @@
   public static void test_Memory_pokeInt() throws Exception {
     byte[] ra = {0x14, 0x13, 0x12, 0x11, 0x15};
     byte[] ru = {0x14, 0x24, 0x23, 0x22, 0x21};
-    byte[] b = new byte [5];
+    byte[] b = (byte[])new_non_movable_array.invoke(runtime, Byte.TYPE, 5);
     long address = (long)address_of.invoke(runtime, b);
 
     b[4] = 0x15;
@@ -695,7 +640,7 @@
   public static void test_Memory_pokeLong() throws Exception {
     byte[] ra = {0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x19};
     byte[] ru = {0x18, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21};
-    byte[] b = new byte [9];
+    byte[] b = (byte[])new_non_movable_array.invoke(runtime, Byte.TYPE, 9);
     long address = (long)address_of.invoke(runtime, b);
 
     b[8] = 0x19;