Merge "Add extra handling for loading intern tables"
diff --git a/Android.mk b/Android.mk
index e27c3db..b9f6170 100644
--- a/Android.mk
+++ b/Android.mk
@@ -98,6 +98,8 @@
 include $(art_path)/build/Android.gtest.mk
 include $(art_path)/test/Android.run-test.mk
 
+TEST_ART_TARGET_SYNC_DEPS += $(ART_TEST_TARGET_GTEST_DEPENDENCIES) $(ART_TEST_TARGET_RUN_TEST_DEPENDENCIES)
+
 # Make sure /system is writable on the device.
 TEST_ART_ADB_ROOT_AND_REMOUNT := \
     ($(ADB) root && \
@@ -484,7 +486,7 @@
 build-art-host-tests:   build-art-host $(TEST_ART_RUN_TEST_DEPENDENCIES) $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES) $(ART_TEST_HOST_GTEST_DEPENDENCIES) | $(TEST_ART_RUN_TEST_ORDERONLY_DEPENDENCIES)
 
 .PHONY: build-art-target-tests
-build-art-target-tests:   build-art-target $(TEST_ART_RUN_TEST_DEPENDENCIES) $(TEST_ART_TARGET_SYNC_DEPS) | $(TEST_ART_RUN_TEST_ORDERONLY_DEPENDENCIES)
+build-art-target-tests:   build-art-target $(TEST_ART_RUN_TEST_DEPENDENCIES) $(ART_TEST_TARGET_RUN_TEST_DEPENDENCIES) $(ART_TEST_TARGET_GTEST_DEPENDENCIES) | $(TEST_ART_RUN_TEST_ORDERONLY_DEPENDENCIES)
 
 ########################################################################
 # targets to switch back and forth from libdvm to libart
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index ad94148..c716d92 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -164,8 +164,8 @@
                         art::WellKnownClasses::java_lang_Thread_init,
                         thr_group.get(),
                         thr_name.get(),
-                        /*Priority*/ 0,
-                        /*Daemon*/ true);
+                        /*Priority=*/ 0,
+                        /*Daemon=*/ true);
 }
 
 struct CallbackData {
@@ -289,7 +289,7 @@
 
   // If the agent isn't loaded we might need to tell ddms code the connection is closed.
   if (!agent_loaded_ && notified_ddm_active_) {
-    NotifyDdms(/*active*/false);
+    NotifyDdms(/*active=*/false);
   }
 }
 
@@ -605,7 +605,7 @@
         if (memcmp(kListenStartMessage, buf, sizeof(kListenStartMessage)) == 0) {
           agent_listening_ = true;
           if (adb_connection_socket_ != -1) {
-            SendAgentFds(/*require_handshake*/ !performed_handshake_);
+            SendAgentFds(/*require_handshake=*/ !performed_handshake_);
           }
         } else if (memcmp(kListenEndMessage, buf, sizeof(kListenEndMessage)) == 0) {
           agent_listening_ = false;
@@ -647,7 +647,7 @@
           VLOG(jdwp) << "Sending fds as soon as we received them.";
           // The agent was already loaded so this must be after a disconnection. Therefore have the
           // transport perform the handshake.
-          SendAgentFds(/*require_handshake*/ true);
+          SendAgentFds(/*require_handshake=*/ true);
         }
       } else if (FlagsSet(control_sock_poll.revents, POLLRDHUP)) {
         // The other end of the adb connection just dropped it.
@@ -663,7 +663,7 @@
         } else if (agent_listening_ && !sent_agent_fds_) {
           VLOG(jdwp) << "Sending agent fds again on data.";
           // Agent was already loaded so it can deal with the handshake.
-          SendAgentFds(/*require_handshake*/ true);
+          SendAgentFds(/*require_handshake=*/ true);
         }
       } else if (FlagsSet(adb_socket_poll.revents, POLLRDHUP)) {
         DCHECK(!agent_has_socket_);
@@ -763,7 +763,7 @@
   }
 
   if (!notified_ddm_active_) {
-    NotifyDdms(/*active*/ true);
+    NotifyDdms(/*active=*/ true);
   }
   uint32_t reply_type;
   std::vector<uint8_t> reply;
@@ -826,9 +826,9 @@
 void AdbConnectionState::AttachJdwpAgent(art::Thread* self) {
   art::Runtime* runtime = art::Runtime::Current();
   self->AssertNoPendingException();
-  runtime->AttachAgent(/* JNIEnv */ nullptr,
+  runtime->AttachAgent(/* env= */ nullptr,
                        MakeAgentArg(),
-                       /* classloader */ nullptr);
+                       /* class_loader= */ nullptr);
   if (self->IsExceptionPending()) {
     LOG(ERROR) << "Failed to load agent " << agent_name_;
     art::ScopedObjectAccess soa(self);
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 316ce64..d024e77 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -93,6 +93,6 @@
 endif
 
 ADB_EXECUTABLE := $(HOST_OUT_EXECUTABLES)/adb
-ADB := $(ADB_EXECUTABLE)
+ADB ?= $(ADB_EXECUTABLE)
 
 endif # ART_ANDROID_COMMON_MK
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index c6fdf27..4badc5a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -404,6 +404,7 @@
 ART_TEST_TARGET_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST_RULES :=
 ART_TEST_HOST_GTEST_DEPENDENCIES :=
+ART_TEST_TARGET_GTEST_DEPENDENCIES :=
 
 ART_GTEST_TARGET_ANDROID_ROOT := '/system'
 ifneq ($(ART_TEST_ANDROID_ROOT),)
@@ -432,7 +433,7 @@
 
   # Add the test dependencies to test-art-target-sync, which will be a prerequisite for the test
   # to ensure files are pushed to the device.
-  TEST_ART_TARGET_SYNC_DEPS += \
+  gtest_deps := \
     $$(ART_GTEST_$(1)_TARGET_DEPS) \
     $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_TARGET_GTEST_$(file)_DEX)) \
     $$(gtest_exe) \
@@ -442,6 +443,8 @@
     $$(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar \
     $$(TARGET_OUT_JAVA_LIBRARIES)/core-simple-testdex.jar
 
+  ART_TEST_TARGET_GTEST_DEPENDENCIES += $$(gtest_deps)
+
 $$(gtest_rule): PRIVATE_TARGET_EXE := $$(gtest_target_exe)
 $$(gtest_rule): PRIVATE_MAYBE_CHROOT_COMMAND := $$(maybe_chroot_command)
 
@@ -473,6 +476,7 @@
   maybe_chroot_command :=
   maybe_art_test_chroot :=
   gtest_target_exe :=
+  gtest_deps :=
   gtest_exe :=
   gtest_rule :=
 endef  # define-art-gtest-rule-target
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index c4ae593..e2adac1 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -39,7 +39,6 @@
 # Use dex2oat debug version for better error reporting
 # $(1): compiler - optimizing, interpreter or interp-ac (interpreter-access-checks).
 # $(2): 2ND_ or undefined, 2ND_ for 32-bit host builds.
-# $(3): multi-image.
 # NB depending on HOST_CORE_DEX_LOCATIONS so we are sure to have the dex files in frameworks for
 # run-test --no-image
 define create-core-oat-host-rules
@@ -66,25 +65,14 @@
     $$(error found $(1) expected interpreter, interp-ac, or optimizing)
   endif
 
-  # If $(3) is true, generate a multi-image.
-  ifeq ($(3),true)
-    core_multi_infix := -multi
-    core_multi_param := --multi-image --no-inline-from=core-oj-hostdex.jar
-    core_multi_group := _multi
-  else
-    core_multi_infix :=
-    core_multi_param :=
-    core_multi_group :=
-  endif
-
-  core_image_name := $($(2)HOST_CORE_IMG_OUT_BASE)$$(core_infix)$$(core_multi_infix)$(CORE_IMG_SUFFIX)
-  core_oat_name := $($(2)HOST_CORE_OAT_OUT_BASE)$$(core_infix)$$(core_multi_infix)$(CORE_OAT_SUFFIX)
+  core_image_name := $($(2)HOST_CORE_IMG_OUT_BASE)$$(core_infix)$(CORE_IMG_SUFFIX)
+  core_oat_name := $($(2)HOST_CORE_OAT_OUT_BASE)$$(core_infix)$(CORE_OAT_SUFFIX)
 
   # Using the bitness suffix makes it easier to add as a dependency for the run-test mk.
   ifeq ($(2),)
-    HOST_CORE_IMAGE_$(1)$$(core_multi_group)_64 := $$(core_image_name)
+    HOST_CORE_IMAGE_$(1)_64 := $$(core_image_name)
   else
-    HOST_CORE_IMAGE_$(1)$$(core_multi_group)_32 := $$(core_image_name)
+    HOST_CORE_IMAGE_$(1)_32 := $$(core_image_name)
   endif
   HOST_CORE_IMG_OUTS += $$(core_image_name)
   HOST_CORE_OAT_OUTS += $$(core_oat_name)
@@ -92,7 +80,6 @@
 $$(core_image_name): PRIVATE_CORE_COMPILE_OPTIONS := $$(core_compile_options)
 $$(core_image_name): PRIVATE_CORE_IMG_NAME := $$(core_image_name)
 $$(core_image_name): PRIVATE_CORE_OAT_NAME := $$(core_oat_name)
-$$(core_image_name): PRIVATE_CORE_MULTI_PARAM := $$(core_multi_param)
 $$(core_image_name): $$(HOST_CORE_DEX_LOCATIONS) $$(core_dex2oat_dependency)
 	@echo "host dex2oat: $$@"
 	@mkdir -p $$(dir $$@)
@@ -104,9 +91,10 @@
 	  --base=$$(LIBART_IMG_HOST_BASE_ADDRESS) --instruction-set=$$($(2)ART_HOST_ARCH) \
 	  $$(LOCAL_$(2)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES_OPTION) \
 	  --host --android-root=$$(HOST_OUT) \
-	  --generate-debug-info --generate-build-id --compile-pic \
+	  --generate-debug-info --generate-build-id \
 	  --runtime-arg -XX:SlowDebug=true \
-	  $$(PRIVATE_CORE_MULTI_PARAM) $$(PRIVATE_CORE_COMPILE_OPTIONS)
+	  --no-inline-from=core-oj-hostdex.jar \
+	  $$(PRIVATE_CORE_COMPILE_OPTIONS)
 
 $$(core_oat_name): $$(core_image_name)
 
@@ -119,21 +107,17 @@
 endef  # create-core-oat-host-rules
 
 # $(1): compiler - optimizing, interpreter or interp-ac (interpreter-access-checks).
-# $(2): multi-image.
 define create-core-oat-host-rule-combination
-  $(call create-core-oat-host-rules,$(1),,$(2))
+  $(call create-core-oat-host-rules,$(1),)
 
   ifneq ($(HOST_PREFER_32_BIT),true)
-    $(call create-core-oat-host-rules,$(1),2ND_,$(2))
+    $(call create-core-oat-host-rules,$(1),2ND_)
   endif
 endef
 
-$(eval $(call create-core-oat-host-rule-combination,optimizing,false))
-$(eval $(call create-core-oat-host-rule-combination,interpreter,false))
-$(eval $(call create-core-oat-host-rule-combination,interp-ac,false))
-$(eval $(call create-core-oat-host-rule-combination,optimizing,true))
-$(eval $(call create-core-oat-host-rule-combination,interpreter,true))
-$(eval $(call create-core-oat-host-rule-combination,interp-ac,true))
+$(eval $(call create-core-oat-host-rule-combination,optimizing))
+$(eval $(call create-core-oat-host-rule-combination,interpreter))
+$(eval $(call create-core-oat-host-rule-combination,interp-ac))
 
 .PHONY: test-art-host-dex2oat-host
 test-art-host-dex2oat-host: $(HOST_CORE_IMG_OUTS)
@@ -197,7 +181,7 @@
 	  --instruction-set-variant=$$($(2)DEX2OAT_TARGET_CPU_VARIANT) \
 	  --instruction-set-features=$$($(2)DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) \
 	  --android-root=$$(PRODUCT_OUT)/system \
-	  --generate-debug-info --generate-build-id --compile-pic \
+	  --generate-debug-info --generate-build-id \
 	  --runtime-arg -XX:SlowDebug=true \
 	  $$(PRIVATE_CORE_COMPILE_OPTIONS) || (rm $$(PRIVATE_CORE_OAT_NAME); exit 1)
 
diff --git a/compiler/driver/compiler_options_map-inl.h b/compiler/driver/compiler_options_map-inl.h
index 9914d81..d4a582f 100644
--- a/compiler/driver/compiler_options_map-inl.h
+++ b/compiler/driver/compiler_options_map-inl.h
@@ -43,9 +43,6 @@
     }
     options->SetCompilerFilter(compiler_filter);
   }
-  if (map.Exists(Base::PIC)) {
-    options->compile_pic_ = true;
-  }
   map.AssignIfExists(Base::HugeMethodMaxThreshold, &options->huge_method_threshold_);
   map.AssignIfExists(Base::LargeMethodMaxThreshold, &options->large_method_threshold_);
   map.AssignIfExists(Base::SmallMethodMaxThreshold, &options->small_method_threshold_);
@@ -109,9 +106,6 @@
           .template WithType<std::string>()
           .IntoKey(Map::CompilerFilter)
 
-      .Define("--compile-pic")
-          .IntoKey(Map::PIC)
-
       .Define("--huge-method-max=_")
           .template WithType<unsigned int>()
           .IntoKey(Map::HugeMethodMaxThreshold)
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 25eadcd..0a28f65 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -4350,7 +4350,7 @@
     // Add ADD with its PC-relative type patch.
     vixl::aarch64::Label* add_label = NewBootImageIntrinsicPatch(boot_image_reference, adrp_label);
     EmitAddPlaceholder(add_label, reg.X(), reg.X());
-  } else if (Runtime::Current()->IsAotCompiler()) {
+  } else if (GetCompilerOptions().GetCompilePic()) {
     // Add ADRP with its PC-relative .data.bimg.rel.ro patch.
     vixl::aarch64::Label* adrp_label = NewBootImageRelRoPatch(boot_image_reference);
     EmitAdrpPlaceholder(adrp_label, reg.X());
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 130ccf3..8bd4af5 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -8914,7 +8914,7 @@
     CodeGeneratorARMVIXL::PcRelativePatchInfo* labels =
         NewBootImageIntrinsicPatch(boot_image_reference);
     EmitMovwMovtPlaceholder(labels, reg);
-  } else if (Runtime::Current()->IsAotCompiler()) {
+  } else if (GetCompilerOptions().GetCompilePic()) {
     CodeGeneratorARMVIXL::PcRelativePatchInfo* labels =
         NewBootImageRelRoPatch(boot_image_reference);
     EmitMovwMovtPlaceholder(labels, reg);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 1cf5515..1f0e200 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1766,7 +1766,7 @@
     PcRelativePatchInfo* info_low = NewBootImageIntrinsicPatch(boot_image_reference, info_high);
     EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, /* base */ ZERO);
     __ Addiu(reg, TMP, /* placeholder */ 0x5678, &info_low->label);
-  } else if (Runtime::Current()->IsAotCompiler()) {
+  } else if (GetCompilerOptions().GetCompilePic()) {
     PcRelativePatchInfo* info_high = NewBootImageRelRoPatch(boot_image_reference);
     PcRelativePatchInfo* info_low = NewBootImageRelRoPatch(boot_image_reference, info_high);
     EmitPcRelativeAddressPlaceholderHigh(info_high, reg, /* base */ ZERO);
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 27534b0..0005d8f 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -1680,7 +1680,7 @@
     PcRelativePatchInfo* info_low = NewBootImageIntrinsicPatch(boot_image_reference, info_high);
     EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
     __ Daddiu(reg, AT, /* placeholder */ 0x5678);
-  } else if (Runtime::Current()->IsAotCompiler()) {
+  } else if (GetCompilerOptions().GetCompilePic()) {
     PcRelativePatchInfo* info_high = NewBootImageRelRoPatch(boot_image_reference);
     PcRelativePatchInfo* info_low = NewBootImageRelRoPatch(boot_image_reference, info_high);
     EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 39cbe5e..ca1e93b 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4988,7 +4988,7 @@
         invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex()).AsRegister<Register>();
     __ leal(reg, Address(method_address_reg, CodeGeneratorX86::kDummy32BitOffset));
     RecordBootImageIntrinsicPatch(method_address, boot_image_reference);
-  } else if (Runtime::Current()->IsAotCompiler()) {
+  } else if (GetCompilerOptions().GetCompilePic()) {
     DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
     HX86ComputeBaseMethodAddress* method_address =
         invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress();
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index e458dff..e6643fb 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1125,7 +1125,7 @@
   if (GetCompilerOptions().IsBootImage()) {
     __ leal(reg, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
     RecordBootImageIntrinsicPatch(boot_image_reference);
-  } else if (Runtime::Current()->IsAotCompiler()) {
+  } else if (GetCompilerOptions().GetCompilePic()) {
     __ movl(reg, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
     RecordBootImageRelRoPatch(boot_image_reference);
   } else {
diff --git a/compiler/optimizing/pc_relative_fixups_x86.cc b/compiler/optimizing/pc_relative_fixups_x86.cc
index 4b07d5b..4ff293c 100644
--- a/compiler/optimizing/pc_relative_fixups_x86.cc
+++ b/compiler/optimizing/pc_relative_fixups_x86.cc
@@ -17,7 +17,6 @@
 #include "pc_relative_fixups_x86.h"
 #include "code_generator_x86.h"
 #include "intrinsics_x86.h"
-#include "runtime.h"
 
 namespace art {
 namespace x86 {
@@ -239,7 +238,7 @@
       case Intrinsics::kIntegerValueOf:
         // This intrinsic can be call free if it loads the address of the boot image object.
         // If we're compiling PIC, we need the address base for loading from .data.bimg.rel.ro.
-        if (Runtime::Current()->UseJitCompilation()) {
+        if (!codegen_->GetCompilerOptions().GetCompilePic()) {
           break;
         }
         FALLTHROUGH_INTENDED;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 690802b..71cdfd2 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -296,9 +296,6 @@
   UsageError("      Example: --instruction-set-features=div");
   UsageError("      Default: default");
   UsageError("");
-  UsageError("  --compile-pic: Force indirect use of code, methods, and classes");
-  UsageError("      Default: disabled for apps (ignored for boot image which is always PIC)");
-  UsageError("");
   UsageError("  --compiler-backend=(Quick|Optimizing): select compiler backend");
   UsageError("      set.");
   UsageError("      Example: --compiler-backend=Optimizing");
@@ -419,8 +416,7 @@
   UsageError("  --app-image-file=<file-name>: specify a file name for app image.");
   UsageError("      Example: --app-image-file=/data/dalvik-cache/system@app@Calculator.apk.art");
   UsageError("");
-  UsageError("  --multi-image: specify that separate oat and image files be generated for each "
-             "input dex file.");
+  UsageError("  --multi-image: obsolete, ignored");
   UsageError("");
   UsageError("  --force-determinism: force the compiler to emit a deterministic output.");
   UsageError("");
@@ -637,7 +633,6 @@
       image_storage_mode_(ImageHeader::kStorageModeUncompressed),
       passes_to_run_filename_(nullptr),
       dirty_image_objects_filename_(nullptr),
-      multi_image_(false),
       is_host_(false),
       elf_writers_(),
       oat_writers_(),
@@ -727,10 +722,8 @@
   }
 
   void ProcessOptions(ParserOptions* parser_options) {
+    compiler_options_->compile_pic_ = true;  // All AOT compilation is PIC.
     compiler_options_->boot_image_ = !image_filenames_.empty();
-    if (compiler_options_->boot_image_) {
-      compiler_options_->compile_pic_ = true;
-    }
     compiler_options_->app_image_ = app_image_fd_ != -1 || !app_image_file_name_.empty();
 
     if (IsBootImage() && image_filenames_.size() == 1) {
@@ -919,20 +912,6 @@
         break;
     }
 
-    if (!IsBootImage() && multi_image_) {
-      Usage("--multi-image can only be used when creating boot images");
-    }
-    if (IsBootImage() && multi_image_ && image_filenames_.size() > 1) {
-      Usage("--multi-image cannot be used with multiple image names");
-    }
-
-    // For now, if we're on the host and compile the boot image, *always* use multiple image files.
-    if (!kIsTargetBuild && IsBootImage()) {
-      if (image_filenames_.size() == 1) {
-        multi_image_ = true;
-      }
-    }
-
     // Done with usage checks, enable watchdog if requested
     if (parser_options->watch_dog_enabled) {
       int64_t timeout = parser_options->watch_dog_timeout_in_ms > 0
@@ -978,7 +957,7 @@
     std::string base_oat = oat_filenames_[0];
     size_t last_oat_slash = base_oat.rfind('/');
     if (last_oat_slash == std::string::npos) {
-      Usage("--multi-image used with unusable oat filename %s", base_oat.c_str());
+      Usage("Unusable boot image oat filename %s", base_oat.c_str());
     }
     // We also need to honor path components that were encoded through '@'. Otherwise the loading
     // code won't be able to find the images.
@@ -990,7 +969,7 @@
     std::string base_img = image_filenames_[0];
     size_t last_img_slash = base_img.rfind('/');
     if (last_img_slash == std::string::npos) {
-      Usage("--multi-image used with unusable image filename %s", base_img.c_str());
+      Usage("Unusable boot image filename %s", base_img.c_str());
     }
     // We also need to honor path components that were encoded through '@'. Otherwise the loading
     // code won't be able to find the images.
@@ -1015,7 +994,7 @@
       base_symbol_oat = oat_unstripped_[0];
       size_t last_symbol_oat_slash = base_symbol_oat.rfind('/');
       if (last_symbol_oat_slash == std::string::npos) {
-        Usage("--multi-image used with unusable symbol filename %s", base_symbol_oat.c_str());
+        Usage("Unusable boot image symbol filename %s", base_symbol_oat.c_str());
       }
       base_symbol_oat = base_symbol_oat.substr(0, last_symbol_oat_slash + 1);
     }
@@ -1199,7 +1178,6 @@
 
     AssignTrueIfExists(args, M::Host, &is_host_);
     AssignTrueIfExists(args, M::AvoidStoringInvocation, &avoid_storing_invocation_);
-    AssignTrueIfExists(args, M::MultiImage, &multi_image_);
     AssignIfExists(args, M::CopyDexFiles, &copy_dex_files_);
 
     if (args.Exists(M::ForceDeterminism)) {
@@ -1263,7 +1241,7 @@
     PruneNonExistentDexFiles();
 
     // Expand oat and image filenames for multi image.
-    if (IsBootImage() && multi_image_) {
+    if (IsBootImage() && image_filenames_.size() == 1) {
       ExpandOatAndImageFilenames();
     }
 
@@ -1987,7 +1965,6 @@
 
       image_writer_.reset(new linker::ImageWriter(*compiler_options_,
                                                   image_base_,
-                                                  compiler_options_->GetCompilePic(),
                                                   IsAppImage(),
                                                   image_storage_mode_,
                                                   oat_filenames_,
@@ -2610,32 +2587,9 @@
     for (size_t i = 0, size = oat_filenames_.size(); i != size; ++i) {
       oat_data_begins.push_back(image_writer_->GetOatDataBegin(i));
     }
-    // Destroy ImageWriter before doing FixupElf.
+    // Destroy ImageWriter.
     image_writer_.reset();
 
-    for (size_t i = 0, size = oat_filenames_.size(); i != size; ++i) {
-      const char* oat_filename = oat_filenames_[i];
-      // Do not fix up the ELF file if we are --compile-pic or compiling the app image
-      if (!compiler_options_->GetCompilePic() && IsBootImage()) {
-        std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename));
-        if (oat_file.get() == nullptr) {
-          PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
-          return false;
-        }
-
-        if (!linker::ElfWriter::Fixup(oat_file.get(), oat_data_begins[i])) {
-          oat_file->Erase();
-          LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath();
-          return false;
-        }
-
-        if (oat_file->FlushCloseOrErase()) {
-          PLOG(ERROR) << "Failed to flush and close fixed ELF file " << oat_file->GetPath();
-          return false;
-        }
-      }
-    }
-
     return true;
   }
 
@@ -2809,7 +2763,6 @@
   const char* dirty_image_objects_filename_;
   std::unique_ptr<HashSet<std::string>> dirty_image_objects_;
   std::unique_ptr<std::vector<std::string>> passes_to_run_;
-  bool multi_image_;
   bool is_host_;
   std::string android_root_;
   std::string no_inline_from_string_;
diff --git a/dex2oat/linker/image_test.cc b/dex2oat/linker/image_test.cc
index 96c48b8..b628c9e 100644
--- a/dex2oat/linker/image_test.cc
+++ b/dex2oat/linker/image_test.cc
@@ -79,8 +79,6 @@
                              /*boot_oat_begin*/0U,
                              /*boot_oat_size_*/0U,
                              sizeof(void*),
-                             /*compile_pic*/false,
-                             /*is_pic*/false,
                              ImageHeader::kDefaultStorageMode,
                              /*data_size*/0u);
     ASSERT_TRUE(image_header.IsValid());
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 2b6786d..443ee52 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -214,7 +214,6 @@
   // TODO: compile_pic should be a test argument.
   std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_options_,
                                                       kRequestedImageBase,
-                                                      /*compile_pic*/false,
                                                       /*compile_app_image*/false,
                                                       storage_mode,
                                                       oat_filename_vector,
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 20053a7..6410c7a 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -2409,8 +2409,6 @@
       boot_oat_begin,
       boot_oat_end - boot_oat_begin,
       static_cast<uint32_t>(target_ptr_size_),
-      compile_pic_,
-      /*is_pic*/compile_app_image_,
       image_storage_mode_,
       /*data_size*/0u);
 
@@ -3340,7 +3338,6 @@
 ImageWriter::ImageWriter(
     const CompilerOptions& compiler_options,
     uintptr_t image_begin,
-    bool compile_pic,
     bool compile_app_image,
     ImageHeader::StorageMode image_storage_mode,
     const std::vector<const char*>& oat_filenames,
@@ -3349,7 +3346,6 @@
     : compiler_options_(compiler_options),
       global_image_begin_(reinterpret_cast<uint8_t*>(image_begin)),
       image_objects_offset_begin_(0),
-      compile_pic_(compile_pic),
       compile_app_image_(compile_app_image),
       target_ptr_size_(InstructionSetPointerSize(compiler_options.GetInstructionSet())),
       image_infos_(oat_filenames.size()),
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 142f77b..93e4be5 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -77,7 +77,6 @@
  public:
   ImageWriter(const CompilerOptions& compiler_options,
               uintptr_t image_begin,
-              bool compile_pic,
               bool compile_app_image,
               ImageHeader::StorageMode image_storage_mode,
               const std::vector<const char*>& oat_filenames,
@@ -758,7 +757,6 @@
   std::unordered_map<mirror::Object*, uint32_t> oat_index_map_;
 
   // Boolean flags.
-  const bool compile_pic_;
   const bool compile_app_image_;
 
   // Size of pointers on the target architecture.
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index 00fb0af..a04cfb6 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 CompactDexWriter::CompactDexWriter(DexLayout* dex_layout)
-    : DexWriter(dex_layout, /*compute_offsets*/ true) {
+    : DexWriter(dex_layout, /*compute_offsets=*/ true) {
   CHECK(GetCompactDexLevel() != CompactDexLevel::kCompactDexLevelNone);
 }
 
@@ -36,7 +36,7 @@
 
 CompactDexWriter::Container::Container(bool dedupe_code_items)
     : code_item_dedupe_(dedupe_code_items, &data_section_),
-      data_item_dedupe_(/*dedupe*/ true, &data_section_) {}
+      data_item_dedupe_(/*enabled=*/ true, &data_section_) {}
 
 uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) {
   const uint32_t start_offset = stream->Tell();
@@ -211,7 +211,7 @@
 
 CompactDexWriter::Deduper::Deduper(bool enabled, DexContainer::Section* section)
     : enabled_(enabled),
-      dedupe_map_(/*bucket_count*/ 32,
+      dedupe_map_(/*__n=*/ 32,
                   HashedMemoryRange::HashEqual(section),
                   HashedMemoryRange::HashEqual(section)) {}
 
@@ -406,16 +406,16 @@
   // Based on: https://source.android.com/devices/tech/dalvik/dex-format
   // Since the offsets may not be calculated already, the writing must be done in the correct order.
   const uint32_t string_ids_offset = main_stream->Tell();
-  WriteStringIds(main_stream, /*reserve_only*/ true);
+  WriteStringIds(main_stream, /*reserve_only=*/ true);
   WriteTypeIds(main_stream);
   const uint32_t proto_ids_offset = main_stream->Tell();
-  WriteProtoIds(main_stream, /*reserve_only*/ true);
+  WriteProtoIds(main_stream, /*reserve_only=*/ true);
   WriteFieldIds(main_stream);
   WriteMethodIds(main_stream);
   const uint32_t class_defs_offset = main_stream->Tell();
-  WriteClassDefs(main_stream, /*reserve_only*/ true);
+  WriteClassDefs(main_stream, /*reserve_only=*/ true);
   const uint32_t call_site_ids_offset = main_stream->Tell();
-  WriteCallSiteIds(main_stream, /*reserve_only*/ true);
+  WriteCallSiteIds(main_stream, /*reserve_only=*/ true);
   WriteMethodHandles(main_stream);
 
   if (compute_offsets_) {
@@ -426,7 +426,7 @@
 
   // Write code item first to minimize the space required for encoded methods.
   // For cdex, the code items don't depend on the debug info.
-  WriteCodeItems(data_stream, /*reserve_only*/ false);
+  WriteCodeItems(data_stream, /*reserve_only=*/ false);
 
   // Sort the debug infos by method index order, this reduces size by ~0.1% by reducing the size of
   // the debug info offset table.
@@ -445,19 +445,19 @@
   // Write delayed id sections that depend on data sections.
   {
     Stream::ScopedSeek seek(main_stream, string_ids_offset);
-    WriteStringIds(main_stream, /*reserve_only*/ false);
+    WriteStringIds(main_stream, /*reserve_only=*/ false);
   }
   {
     Stream::ScopedSeek seek(main_stream, proto_ids_offset);
-    WriteProtoIds(main_stream, /*reserve_only*/ false);
+    WriteProtoIds(main_stream, /*reserve_only=*/ false);
   }
   {
     Stream::ScopedSeek seek(main_stream, class_defs_offset);
-    WriteClassDefs(main_stream, /*reserve_only*/ false);
+    WriteClassDefs(main_stream, /*reserve_only=*/ false);
   }
   {
     Stream::ScopedSeek seek(main_stream, call_site_ids_offset);
-    WriteCallSiteIds(main_stream, /*reserve_only*/ false);
+    WriteCallSiteIds(main_stream, /*reserve_only=*/ false);
   }
 
   // Write the map list.
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index a4c5cda..365171b 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -790,16 +790,16 @@
   // Based on: https://source.android.com/devices/tech/dalvik/dex-format
   // Since the offsets may not be calculated already, the writing must be done in the correct order.
   const uint32_t string_ids_offset = stream->Tell();
-  WriteStringIds(stream, /*reserve_only*/ true);
+  WriteStringIds(stream, /*reserve_only=*/ true);
   WriteTypeIds(stream);
   const uint32_t proto_ids_offset = stream->Tell();
-  WriteProtoIds(stream, /*reserve_only*/ true);
+  WriteProtoIds(stream, /*reserve_only=*/ true);
   WriteFieldIds(stream);
   WriteMethodIds(stream);
   const uint32_t class_defs_offset = stream->Tell();
-  WriteClassDefs(stream, /*reserve_only*/ true);
+  WriteClassDefs(stream, /*reserve_only=*/ true);
   const uint32_t call_site_ids_offset = stream->Tell();
-  WriteCallSiteIds(stream, /*reserve_only*/ true);
+  WriteCallSiteIds(stream, /*reserve_only=*/ true);
   WriteMethodHandles(stream);
 
   uint32_t data_offset_ = 0u;
@@ -812,13 +812,13 @@
   // Write code item first to minimize the space required for encoded methods.
   // Reserve code item space since we need the debug offsets to actually write them.
   const uint32_t code_items_offset = stream->Tell();
-  WriteCodeItems(stream, /*reserve_only*/ true);
+  WriteCodeItems(stream, /*reserve_only=*/ true);
   // Write debug info section.
   WriteDebugInfoItems(stream);
   {
     // Actually write code items since debug info offsets are calculated now.
     Stream::ScopedSeek seek(stream, code_items_offset);
-    WriteCodeItems(stream, /*reserve_only*/ false);
+    WriteCodeItems(stream, /*reserve_only=*/ false);
   }
 
   WriteEncodedArrays(stream);
@@ -833,19 +833,19 @@
   // Write delayed id sections that depend on data sections.
   {
     Stream::ScopedSeek seek(stream, string_ids_offset);
-    WriteStringIds(stream, /*reserve_only*/ false);
+    WriteStringIds(stream, /*reserve_only=*/ false);
   }
   {
     Stream::ScopedSeek seek(stream, proto_ids_offset);
-    WriteProtoIds(stream, /*reserve_only*/ false);
+    WriteProtoIds(stream, /*reserve_only=*/ false);
   }
   {
     Stream::ScopedSeek seek(stream, class_defs_offset);
-    WriteClassDefs(stream, /*reserve_only*/ false);
+    WriteClassDefs(stream, /*reserve_only=*/ false);
   }
   {
     Stream::ScopedSeek seek(stream, call_site_ids_offset);
-    WriteCallSiteIds(stream, /*reserve_only*/ false);
+    WriteCallSiteIds(stream, /*reserve_only=*/ false);
   }
 
   // Write the map list.
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 493a8a2..7a849f2 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -294,7 +294,7 @@
   {
     Options options;
     std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file,
-                                                                /*eagerly_assign_offsets*/ true,
+                                                                /*eagerly_assign_offsets=*/ true,
                                                                 options));
     sections = dex_ir::GetSortedDexFileSections(header.get(),
                                                 dex_ir::SortDirection::kSortDescending);
@@ -321,9 +321,9 @@
   // Extract all the dex files from the vdex file.
   std::string error_msg;
   std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
-                                                false /*writeable*/,
-                                                false /*low_4gb*/,
-                                                false /*unquicken */,
+                                                /*writable=*/ false,
+                                                /*low_4gb=*/ false,
+                                                /*unquicken= */ false,
                                                 &error_msg /*out*/));
   if (vdex == nullptr) {
     std::cerr << "Could not open vdex file "
diff --git a/dexlayout/dexdiag_test.cc b/dexlayout/dexdiag_test.cc
index f936ff9..d3bfd14 100644
--- a/dexlayout/dexdiag_test.cc
+++ b/dexlayout/dexdiag_test.cc
@@ -68,14 +68,14 @@
     EXPECT_TRUE(!oat_location.empty());
     std::cout << "==" << oat_location << std::endl;
     std::string error_msg;
-    std::unique_ptr<OatFile> oat(OatFile::Open(/* zip_fd */ -1,
+    std::unique_ptr<OatFile> oat(OatFile::Open(/* zip_fd= */ -1,
                                                oat_location.c_str(),
                                                oat_location.c_str(),
-                                               /* requested_base */ nullptr,
-                                               /* executable */ false,
-                                               /* low_4gb */ false,
-                                               /* abs_dex_location */ nullptr,
-                                               /* reservation */ nullptr,
+                                               /* requested_base= */ nullptr,
+                                               /* executable= */ false,
+                                               /* low_4gb= */ false,
+                                               /* abs_dex_location= */ nullptr,
+                                               /* reservation= */ nullptr,
                                                &error_msg));
     EXPECT_TRUE(oat != nullptr) << error_msg;
     return oat;
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 1b8412d..db6945f 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1914,10 +1914,10 @@
               data_section->Begin(),
               data_section->Size(),
               location,
-              /* checksum */ 0,
-              /*oat_dex_file*/ nullptr,
+              /* location_checksum= */ 0,
+              /*oat_dex_file=*/ nullptr,
               verify,
-              /*verify_checksum*/ false,
+              /*verify_checksum=*/ false,
               error_msg));
       CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << *error_msg;
 
@@ -1928,11 +1928,11 @@
       // Regenerate output IR to catch any bugs that might happen during writing.
       std::unique_ptr<dex_ir::Header> output_header(
           dex_ir::DexIrBuilder(*output_dex_file,
-                               /*eagerly_assign_offsets*/ true,
+                               /*eagerly_assign_offsets=*/ true,
                                GetOptions()));
       std::unique_ptr<dex_ir::Header> orig_header(
           dex_ir::DexIrBuilder(*dex_file,
-                               /*eagerly_assign_offsets*/ true,
+                               /*eagerly_assign_offsets=*/ true,
                                GetOptions()));
       CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), error_msg)) << *error_msg;
     }
@@ -1955,7 +1955,7 @@
   const ArtDexFileLoader dex_file_loader;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
   if (!dex_file_loader.Open(
-        file_name, file_name, /* verify */ true, verify_checksum, &error_msg, &dex_files)) {
+        file_name, file_name, /* verify= */ true, verify_checksum, &error_msg, &dex_files)) {
     // Display returned error message to user. Note that this error behavior
     // differs from the error messages shown by the original Dalvik dexdump.
     LOG(ERROR) << error_msg;
@@ -1972,7 +1972,7 @@
       if (!ProcessDexFile(file_name,
                           dex_files[i].get(),
                           i,
-                          /*dex_container*/ nullptr,
+                          /*dex_container=*/ nullptr,
                           &error_msg)) {
         LOG(WARNING) << "Failed to run dex file " << i << " in " << file_name << " : " << error_msg;
       }
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 78a8dd6..d212e71 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -203,7 +203,7 @@
   }
 
   // Create DexLayout instance.
-  DexLayout dex_layout(options, profile_info.get(), out_file, /*header*/ nullptr);
+  DexLayout dex_layout(options, profile_info.get(), out_file, /*header=*/ nullptr);
 
   // Process all files supplied on command line.
   int result = 0;
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 187c687..54157d9 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -298,7 +298,7 @@
     for (const std::string& dex_file : GetLibCoreDexFileNames()) {
       std::vector<std::string> dexlayout_args =
           { "-w", tmp_dir, "-o", tmp_name, dex_file };
-      if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
+      if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) {
         return false;
       }
       std::string dex_file_name = "classes.dex";
@@ -333,8 +333,8 @@
     const ArtDexFileLoader dex_file_loader;
     bool result = dex_file_loader.Open(input_dex.c_str(),
                                        input_dex,
-                                       /*verify*/ true,
-                                       /*verify_checksum*/ false,
+                                       /*verify=*/ true,
+                                       /*verify_checksum=*/ false,
                                        &error_msg,
                                        &dex_files);
 
@@ -359,7 +359,7 @@
         pfi.AddMethodIndex(static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags),
                            dex_location,
                            dex_file->GetLocationChecksum(),
-                           /*dex_method_idx*/i,
+                           /*method_idx=*/i,
                            dex_file->NumMethodIds());
       }
       DexCacheResolvedClasses cur_classes(dex_location,
@@ -447,7 +447,7 @@
     // -v makes sure that the layout did not corrupt the dex file.
     std::vector<std::string> dexlayout_args =
         { "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
-    if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
+    if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) {
       return false;
     }
 
@@ -459,7 +459,7 @@
     // -i since the checksum won't match from the first layout.
     std::vector<std::string> second_dexlayout_args =
         { "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
-    if (!DexLayoutExec(second_dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
+    if (!DexLayoutExec(second_dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) {
       return false;
     }
 
@@ -493,7 +493,7 @@
     std::string output_dex = tmp_dir + "classes.dex.new";
 
     std::vector<std::string> dexlayout_args = { "-w", tmp_dir, "-o", "/dev/null", input_dex };
-    if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option*/ false)) {
+    if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) {
       return false;
     }
 
@@ -615,7 +615,7 @@
       { "-a", "-i", "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kDexFileDuplicateOffset,
-                            nullptr /* profile_file */,
+                            /* profile_file= */ nullptr,
                             dexlayout_args));
 }
 
@@ -624,7 +624,7 @@
   std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kNullSetRefListElementInputDex,
-                            nullptr /* profile_file */,
+                            /* profile_file= */ nullptr,
                             dexlayout_args));
 }
 
@@ -666,7 +666,7 @@
   std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kUnknownTypeDebugInfoInputDex,
-                            nullptr /* profile_file */,
+                            /* profile_file= */ nullptr,
                             dexlayout_args));
 }
 
@@ -675,7 +675,7 @@
   std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kDuplicateCodeItemInputDex,
-                            nullptr /* profile_file */,
+                            /* profile_file= */ nullptr,
                             dexlayout_args));
 }
 
@@ -734,7 +734,7 @@
       };
   // -v makes sure that the layout did not corrupt the dex file.
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
-                            /*dex_filename*/ nullptr,
+                            /*dex_filename=*/ nullptr,
                             &profile_file,
                             dexlayout_args));
   ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new"));
@@ -772,7 +772,7 @@
       };
   // -v makes sure that the layout did not corrupt the dex file.
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
-                            /*dex_filename*/ nullptr,
+                            /*dex_filename=*/ nullptr,
                             &profile_file,
                             dexlayout_args));
   ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new"));
@@ -785,8 +785,8 @@
   const std::string input_jar = GetTestDexFileName("ManyMethods");
   CHECK(dex_file_loader.Open(input_jar.c_str(),
                              input_jar.c_str(),
-                             /*verify*/ true,
-                             /*verify_checksum*/ true,
+                             /*verify=*/ true,
+                             /*verify_checksum=*/ true,
                              &error_msg,
                              &dex_files)) << error_msg;
   ASSERT_EQ(dex_files.size(), 1u);
@@ -800,14 +800,14 @@
     // Filter out all the classes other than the one below based on class descriptor.
     options.class_filter_.insert("LManyMethods$Strings;");
     DexLayout dexlayout(options,
-                        /*info*/ nullptr,
-                        /*out_file*/ nullptr,
-                        /*header*/ nullptr);
+                        /*info=*/ nullptr,
+                        /*out_file=*/ nullptr,
+                        /*header=*/ nullptr);
     std::unique_ptr<DexContainer> out;
     bool result = dexlayout.ProcessDexFile(
         dex_file->GetLocation().c_str(),
         dex_file.get(),
-        /*dex_file_index*/ 0,
+        /*dex_file_index=*/ 0,
         &out,
         &error_msg);
     ASSERT_TRUE(result) << "Failed to run dexlayout " << error_msg;
@@ -818,10 +818,10 @@
             out->GetDataSection()->Begin(),
             out->GetDataSection()->Size(),
             dex_file->GetLocation().c_str(),
-            /* checksum */ 0,
-            /*oat_dex_file*/ nullptr,
-            /* verify */ true,
-            /*verify_checksum*/ false,
+            /* location_checksum= */ 0,
+            /*oat_dex_file=*/ nullptr,
+            /* verify= */ true,
+            /*verify_checksum=*/ false,
             &error_msg));
     ASSERT_TRUE(output_dex_file != nullptr);
 
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 067daa7..adb6a54 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -172,7 +172,7 @@
   if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
                                content.size(),
                                fileName,
-                               /*verify*/ true,
+                               /*verify=*/ true,
                                kVerifyChecksum,
                                &error_code,
                                &error_msg,
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 10bb673..21cdcf1 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -251,8 +251,8 @@
     std::unique_ptr<OatFileAssistant> oat_file_assistant;
     oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(),
                                                             isa_,
-                                                            false /*load_executable*/,
-                                                            false /*only_load_system_executable*/,
+                                                            /*load_executable=*/ false,
+                                                            /*only_load_system_executable=*/ false,
                                                             vdex_fd_,
                                                             oat_fd_,
                                                             zip_fd_);
diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc
index 93ebf2b..b9116f0 100644
--- a/dexoptanalyzer/dexoptanalyzer_test.cc
+++ b/dexoptanalyzer/dexoptanalyzer_test.cc
@@ -73,7 +73,7 @@
               bool downgrade = false) {
     int dexoptanalyzerResult = Analyze(dex_file, compiler_filter, assume_profile_changed);
     dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult);
-    OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable*/ false);
+    OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable=*/ false);
     int assistantResult = oat_file_assistant.GetDexOptNeeded(
         compiler_filter, assume_profile_changed, downgrade);
     EXPECT_EQ(assistantResult, dexoptanalyzerResult);
@@ -175,7 +175,7 @@
   Copy(GetDexSrc1(), dex_location);
   GenerateOatForTest(dex_location.c_str(),
                      CompilerFilter::kSpeed,
-                     /*with_alternate_image*/true);
+                     /*with_alternate_image=*/true);
 
   Verify(dex_location, CompilerFilter::kExtract);
   Verify(dex_location, CompilerFilter::kQuicken);
@@ -192,7 +192,7 @@
   Copy(GetDexSrc1(), dex_location);
   GenerateOatForTest(dex_location.c_str(),
                      CompilerFilter::kExtract,
-                     /*with_alternate_image*/true);
+                     /*with_alternate_image=*/true);
 
   Verify(dex_location, CompilerFilter::kExtract);
   Verify(dex_location, CompilerFilter::kQuicken);
@@ -208,6 +208,7 @@
 
   Verify(dex_location, CompilerFilter::kExtract);
   Verify(dex_location, CompilerFilter::kSpeed);
+  Verify(dex_location, CompilerFilter::kEverything);
 }
 
 // Case: We have a stripped DEX file and a PIC ODEX file, but no OAT file.
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index 2ed41c8..262e815 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -41,9 +41,9 @@
   } else if (instruction_set == InstructionSet::kArm64) {
     return new arm64::DisassemblerArm64(options);
   } else if (instruction_set == InstructionSet::kMips) {
-    return new mips::DisassemblerMips(options, /* is_o32_abi */ true);
+    return new mips::DisassemblerMips(options, /* is_o32_abi= */ true);
   } else if (instruction_set == InstructionSet::kMips64) {
-    return new mips::DisassemblerMips(options, /* is_o32_abi */ false);
+    return new mips::DisassemblerMips(options, /* is_o32_abi= */ false);
   } else if (instruction_set == InstructionSet::kX86) {
     return new x86::DisassemblerX86(options, false);
   } else if (instruction_set == InstructionSet::kX86_64) {
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index 245a15b..a1edd00 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -1007,7 +1007,7 @@
                      begin_image_ptr,
                      RegionCommon<T>::remote_contents_,
                      base_ptr,
-                     /*log_dirty_objects*/true);
+                     /*log_dirty_objects=*/true);
     // Print shared dirty after since it's less important.
     if (RegionCommon<T>::GetZygoteDirtyEntryCount() != 0) {
       // We only reach this point if both pids were specified.  Furthermore,
@@ -1019,7 +1019,7 @@
                        begin_image_ptr,
                        RegionCommon<T>::zygote_contents_,
                        begin_image_ptr,
-                       /*log_dirty_objects*/false);
+                       /*log_dirty_objects=*/false);
     }
     RegionSpecializedBase<T>::DumpDirtyObjects();
     RegionSpecializedBase<T>::DumpDirtyEntries();
diff --git a/libartbase/base/memory_tool.h b/libartbase/base/memory_tool.h
index d381f01..1a6a9bb 100644
--- a/libartbase/base/memory_tool.h
+++ b/libartbase/base/memory_tool.h
@@ -44,7 +44,7 @@
 
 extern "C" void __asan_handle_no_return();
 
-# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address, noinline))
 # define MEMORY_TOOL_HANDLE_NO_RETURN __asan_handle_no_return()
 constexpr bool kRunningOnMemoryTool = true;
 constexpr bool kMemoryToolDetectsLeaks = true;
diff --git a/libartbase/base/unix_file/fd_file.h b/libartbase/base/unix_file/fd_file.h
index 54a16a2..f5aa2a5 100644
--- a/libartbase/base/unix_file/fd_file.h
+++ b/libartbase/base/unix_file/fd_file.h
@@ -37,13 +37,13 @@
   FdFile() = default;
   // Creates an FdFile using the given file descriptor.
   // Takes ownership of the file descriptor.
-  FdFile(int fd, bool checkUsage);
-  FdFile(int fd, const std::string& path, bool checkUsage);
-  FdFile(int fd, const std::string& path, bool checkUsage, bool read_only_mode);
+  FdFile(int fd, bool check_usage);
+  FdFile(int fd, const std::string& path, bool check_usage);
+  FdFile(int fd, const std::string& path, bool check_usage, bool read_only_mode);
 
-  FdFile(const std::string& path, int flags, bool checkUsage)
-      : FdFile(path, flags, 0640, checkUsage) {}
-  FdFile(const std::string& path, int flags, mode_t mode, bool checkUsage);
+  FdFile(const std::string& path, int flags, bool check_usage)
+      : FdFile(path, flags, 0640, check_usage) {}
+  FdFile(const std::string& path, int flags, mode_t mode, bool check_usage);
 
   // Move constructor.
   FdFile(FdFile&& other) noexcept;
diff --git a/libdexfile/dex/type_reference.h b/libdexfile/dex/type_reference.h
index 9e7b880..3207e32 100644
--- a/libdexfile/dex/type_reference.h
+++ b/libdexfile/dex/type_reference.h
@@ -31,8 +31,8 @@
 // A type is located by its DexFile and the string_ids_ table index into that DexFile.
 class TypeReference : public DexFileReference {
  public:
-  TypeReference(const DexFile* file, dex::TypeIndex index)
-      : DexFileReference(file, index.index_) {}
+  TypeReference(const DexFile* dex_file, dex::TypeIndex index)
+      : DexFileReference(dex_file, index.index_) {}
 
   dex::TypeIndex TypeIndex() const {
     return dex::TypeIndex(index);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index d30ec31..feb05d6 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -224,7 +224,7 @@
     debug::WriteDebugInfo(builder_.get(),
                           debug_info,
                           dwarf::DW_DEBUG_FRAME_FORMAT,
-                          true /* write_oat_patches */);
+                          /* write_oat_patches= */ true);
 
     builder_->End();
 
@@ -401,7 +401,7 @@
                                              options_.absolute_addresses_,
                                              oat_file.Begin(),
                                              oat_file.End(),
-                                             true /* can_read_literals_ */,
+                                             /* can_read_literals_= */ true,
                                              Is64BitInstructionSet(instruction_set_)
                                                  ? &Thread::DumpThreadOffset<PointerSize::k64>
                                                  : &Thread::DumpThreadOffset<PointerSize::k32>))) {
@@ -640,7 +640,7 @@
           Options options;
           options.compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone;
           options.update_checksum_ = true;
-          DexLayout dex_layout(options, /*info*/ nullptr, /*out_file*/ nullptr, /*header*/ nullptr);
+          DexLayout dex_layout(options, /*info=*/ nullptr, /*out_file=*/ nullptr, /*header=*/ nullptr);
           std::unique_ptr<art::DexContainer> dex_container;
           bool result = dex_layout.ProcessDexFile(vdex_dex_file->GetLocation().c_str(),
                                                   vdex_dex_file.get(),
@@ -661,9 +661,9 @@
               main_section->Size(),
               vdex_dex_file->GetLocation(),
               vdex_file->GetLocationChecksum(i),
-              nullptr /*oat_dex_file*/,
-              false /*verify*/,
-              true /*verify_checksum*/,
+              /*oat_dex_file=*/ nullptr,
+              /*verify=*/ false,
+              /*verify_checksum=*/ true,
               &error_msg));
           if (dex == nullptr) {
             os << "Failed to load DexFile from layout container: " + error_msg;
@@ -676,12 +676,12 @@
             break;
           }
 
-          if (!ExportDexFile(os, *oat_dex_file, dex.get(), true /*used_dexlayout*/)) {
+          if (!ExportDexFile(os, *oat_dex_file, dex.get(), /*used_dexlayout=*/ true)) {
             success = false;
             break;
           }
         } else {
-          if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get(), false /*used_dexlayout*/)) {
+          if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get(), /*used_dexlayout=*/ false)) {
             success = false;
             break;
           }
@@ -764,8 +764,8 @@
         PROT_READ | PROT_WRITE,
         MAP_PRIVATE,
         file->Fd(),
-        /* start offset */ 0,
-        /* low_4gb */ false,
+        /* start offset= */ 0,
+        /* low_4gb= */ false,
         vdex_filename.c_str(),
         error_msg);
     if (!mmap.IsValid()) {
@@ -786,7 +786,7 @@
     }
 
     vdex_file->Unquicken(MakeNonOwningPointerVector(tmp_dex_files),
-                         /* decompile_return_instruction */ true);
+                         /* decompile_return_instruction= */ true);
 
     *dex_files = std::move(tmp_dex_files);
     return vdex_file;
@@ -1514,7 +1514,7 @@
       }
       return verifier::MethodVerifier::VerifyMethodAndDump(
           soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
-          class_def, code_item, method, method_access_flags, /* api_level */ 0);
+          class_def, code_item, method, method_access_flags, /* api_level= */ 0);
     }
 
     return nullptr;
@@ -1795,8 +1795,6 @@
 
     os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
 
-    os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
-
     {
       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots().Ptr()) << "\n";
       static_assert(arraysize(image_roots_descriptions_) ==
@@ -1862,14 +1860,14 @@
       oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location);
     }
     if (oat_file == nullptr) {
-      oat_file = OatFile::Open(/* zip_fd */ -1,
+      oat_file = OatFile::Open(/* zip_fd= */ -1,
                                oat_location,
                                oat_location,
-                               /* requested_base */ nullptr,
-                               /* executable */ false,
-                               /* low_4gb */ false,
-                               /* abs_dex_location */ nullptr,
-                               /* reservation */ nullptr,
+                               /* requested_base= */ nullptr,
+                               /* executable= */ false,
+                               /* low_4gb= */ false,
+                               /* abs_dex_location= */ nullptr,
+                               /* reservation= */ nullptr,
                                &error_msg);
     }
     if (oat_file == nullptr) {
@@ -2760,14 +2758,14 @@
     // We need to map the oat file in the low 4gb or else the fixup wont be able to fit oat file
     // pointers into 32 bit pointer sized ArtMethods.
     std::string error_msg;
-    std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
+    std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd= */ -1,
                                                     options->app_oat_,
                                                     options->app_oat_,
-                                                    /* requested_base */ nullptr,
-                                                    /* executable */ false,
-                                                    /* low_4gb */ true,
-                                                    /* abs_dex_location */ nullptr,
-                                                    /* reservation */ nullptr,
+                                                    /* requested_base= */ nullptr,
+                                                    /* executable= */ false,
+                                                    /* low_4gb= */ true,
+                                                    /* abs_dex_location= */ nullptr,
+                                                    /* reservation= */ nullptr,
                                                     &error_msg));
     if (oat_file == nullptr) {
       LOG(ERROR) << "Failed to open oat file " << options->app_oat_ << " with error " << error_msg;
@@ -2884,14 +2882,14 @@
                  << "oatdump might fail if the oat file does not contain the dex code.";
   }
   std::string error_msg;
-  std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd= */ -1,
                                                   oat_filename,
                                                   oat_filename,
-                                                  /* requested_base */ nullptr,
-                                                  /* executable */ false,
-                                                  /* low_4gb */ false,
+                                                  /* requested_base= */ nullptr,
+                                                  /* executable= */ false,
+                                                  /* low_4gb= */ false,
                                                   dex_filename,
-                                                  /* reservation */ nullptr,
+                                                  /* reservation= */ nullptr,
                                                   &error_msg));
   if (oat_file == nullptr) {
     LOG(ERROR) << "Failed to open oat file from '" << oat_filename << "': " << error_msg;
@@ -2910,14 +2908,14 @@
                         std::string& output_name,
                         bool no_bits) {
   std::string error_msg;
-  std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd= */ -1,
                                                   oat_filename,
                                                   oat_filename,
-                                                  /* requested_base */ nullptr,
-                                                  /* executable */ false,
-                                                  /* low_4gb */ false,
+                                                  /* requested_base= */ nullptr,
+                                                  /* executable= */ false,
+                                                  /* low_4gb= */ false,
                                                   dex_filename,
-                                                  /* reservation */ nullptr,
+                                                  /* reservation= */ nullptr,
                                                   &error_msg));
   if (oat_file == nullptr) {
     LOG(ERROR) << "Failed to open oat file from '" << oat_filename << "': " << error_msg;
@@ -2958,14 +2956,14 @@
 
     if (oat_filename != nullptr) {
       std::string error_msg;
-      std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
+      std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd= */ -1,
                                                       oat_filename,
                                                       oat_filename,
-                                                      /* requested_base */ nullptr,
-                                                      /* executable */ false,
-                                                      /*low_4gb*/false,
+                                                      /* requested_base= */ nullptr,
+                                                      /* executable= */ false,
+                                                      /*low_4gb=*/false,
                                                       dex_filename,
-                                                      /* reservation */ nullptr,
+                                                      /* reservation= */ nullptr,
                                                       &error_msg));
       if (oat_file == nullptr) {
         LOG(ERROR) << "Failed to open oat file from '" << oat_filename << "': " << error_msg;
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index bcba182..e6936f6 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -93,8 +93,8 @@
   ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
   const std::string dex_location = tmp_dir_+ "/core-oj-hostdex.jar_export.dex";
   const std::string dexdump2 = GetExecutableFilePath("dexdump2",
-                                                     /*is_debug*/false,
-                                                     /*is_static*/false);
+                                                     /*is_debug=*/false,
+                                                     /*is_static=*/false);
   std::string output;
   auto post_fork_fn = []() { return true; };
   ForkAndExecResult res = ForkAndExec({dexdump2, "-d", dex_location}, post_fork_fn, &output);
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index 3213bbe..48f326a 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -313,10 +313,10 @@
     return StackUtil::GetFrameCount(env, thread, count_ptr);
   }
 
-  static jvmtiError PopFrame(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+  static jvmtiError PopFrame(jvmtiEnv* env, jthread thread) {
     ENSURE_VALID_ENV(env);
     ENSURE_HAS_CAP(env, can_pop_frame);
-    return ERR(NOT_IMPLEMENTED);
+    return StackUtil::PopFrame(env, thread);
   }
 
   static jvmtiError GetFrameLocation(jvmtiEnv* env,
diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h
index 82f3866..1218e3b 100644
--- a/openjdkjvmti/art_jvmti.h
+++ b/openjdkjvmti/art_jvmti.h
@@ -249,7 +249,7 @@
     .can_get_owned_monitor_info                      = 1,
     .can_get_current_contended_monitor               = 1,
     .can_get_monitor_info                            = 1,
-    .can_pop_frame                                   = 0,
+    .can_pop_frame                                   = 1,
     .can_redefine_classes                            = 1,
     .can_signal_thread                               = 1,
     .can_get_source_file_name                        = 1,
@@ -291,6 +291,7 @@
 //   can_retransform_classes:
 //   can_redefine_any_class:
 //   can_redefine_classes:
+//   can_pop_frame:
 //     We need to ensure that inlined code is either not present or can always be deoptimized. This
 //     is not guaranteed for non-debuggable processes since we might have inlined bootclasspath code
 //     on a threads stack.
@@ -303,7 +304,7 @@
     .can_get_owned_monitor_info                      = 0,
     .can_get_current_contended_monitor               = 0,
     .can_get_monitor_info                            = 0,
-    .can_pop_frame                                   = 0,
+    .can_pop_frame                                   = 1,
     .can_redefine_classes                            = 1,
     .can_signal_thread                               = 0,
     .can_get_source_file_name                        = 0,
diff --git a/openjdkjvmti/events-inl.h b/openjdkjvmti/events-inl.h
index e98517f..ca66556 100644
--- a/openjdkjvmti/events-inl.h
+++ b/openjdkjvmti/events-inl.h
@@ -26,7 +26,9 @@
 #include "jni/jni_internal.h"
 #include "nativehelper/scoped_local_ref.h"
 #include "scoped_thread_state_change-inl.h"
+#include "stack.h"
 #include "ti_breakpoint.h"
+#include "ti_thread.h"
 
 #include "art_jvmti.h"
 
@@ -359,6 +361,7 @@
   // have to deal with use-after-free or the frames being reallocated later.
   art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
   return env->notify_frames.erase(frame) != 0 &&
+      !frame->GetForcePopFrame() &&
       ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
 }
 
@@ -418,6 +421,67 @@
   ExecuteCallback<ArtJvmtiEvent::kFramePop>(event, jnienv, jni_thread, jmethod, is_exception);
 }
 
+struct ScopedDisablePopFrame {
+ public:
+  explicit ScopedDisablePopFrame(art::Thread* thread) : thread_(thread) {
+    art::Locks::mutator_lock_->AssertSharedHeld(thread_);
+    art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
+    JvmtiGlobalTLSData* data = ThreadUtil::GetOrCreateGlobalTLSData(thread_);
+    current_top_frame_ = art::StackVisitor::ComputeNumFrames(
+        thread_, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+    old_disable_frame_pop_depth_ = data->disable_pop_frame_depth;
+    data->disable_pop_frame_depth = current_top_frame_;
+    DCHECK(old_disable_frame_pop_depth_ == JvmtiGlobalTLSData::kNoDisallowedPopFrame ||
+           current_top_frame_ > old_disable_frame_pop_depth_)
+        << "old: " << old_disable_frame_pop_depth_ << " current: " << current_top_frame_;
+  }
+
+  ~ScopedDisablePopFrame() {
+    art::Locks::mutator_lock_->AssertSharedHeld(thread_);
+    art::MutexLock mu(thread_, *art::Locks::thread_list_lock_);
+    JvmtiGlobalTLSData* data = ThreadUtil::GetGlobalTLSData(thread_);
+    DCHECK_EQ(data->disable_pop_frame_depth, current_top_frame_);
+    data->disable_pop_frame_depth = old_disable_frame_pop_depth_;
+  }
+
+ private:
+  art::Thread* thread_;
+  size_t current_top_frame_;
+  size_t old_disable_frame_pop_depth_;
+};
+// We want to prevent the use of PopFrame when reporting either of these events.
+template <ArtJvmtiEvent kEvent>
+inline void EventHandler::DispatchClassLoadOrPrepareEvent(art::Thread* thread,
+                                                          JNIEnv* jnienv,
+                                                          jthread jni_thread,
+                                                          jclass klass) const {
+  ScopedDisablePopFrame sdpf(thread);
+  art::ScopedThreadStateChange stsc(thread, art::ThreadState::kNative);
+  std::vector<impl::EventHandlerFunc<kEvent>> events = CollectEvents<kEvent>(thread,
+                                                                             jnienv,
+                                                                             jni_thread,
+                                                                             klass);
+
+  for (auto event : events) {
+    ExecuteCallback<kEvent>(event, jnienv, jni_thread, klass);
+  }
+}
+
+template <>
+inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassLoad>(art::Thread* thread,
+                                                                   JNIEnv* jnienv,
+                                                                   jthread jni_thread,
+                                                                   jclass klass) const {
+  DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassLoad>(thread, jnienv, jni_thread, klass);
+}
+template <>
+inline void EventHandler::DispatchEvent<ArtJvmtiEvent::kClassPrepare>(art::Thread* thread,
+                                                                      JNIEnv* jnienv,
+                                                                      jthread jni_thread,
+                                                                      jclass klass) const {
+  DispatchClassLoadOrPrepareEvent<ArtJvmtiEvent::kClassPrepare>(thread, jnienv, jni_thread, klass);
+}
+
 // Need to give a custom specialization for NativeMethodBind since it has to deal with an out
 // variable.
 template <>
@@ -553,6 +617,7 @@
                               : ArtJvmtiEvent::kClassFileLoadHookRetransformable;
   return (added && caps.can_access_local_variables == 1) ||
       caps.can_generate_breakpoint_events == 1 ||
+      caps.can_pop_frame == 1 ||
       (caps.can_retransform_classes == 1 &&
        IsEventEnabledAnywhere(event) &&
        env->event_masks.IsEnabledAnywhere(event));
@@ -573,6 +638,11 @@
     if (caps.can_generate_breakpoint_events == 1) {
       HandleBreakpointEventsChanged(added);
     }
+    if (caps.can_pop_frame == 1 && added) {
+      // TODO We should keep track of how many of these have been enabled and remove it if there are
+      // no more possible users. This isn't expected to be too common.
+      art::Runtime::Current()->SetNonStandardExitsEnabled();
+    }
   }
 }
 
diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h
index bf12cb1..9f91a08 100644
--- a/openjdkjvmti/events.h
+++ b/openjdkjvmti/events.h
@@ -301,6 +301,13 @@
                                                            unsigned char** new_class_data) const
       REQUIRES(!envs_lock_);
 
+  template <ArtJvmtiEvent kEvent>
+  ALWAYS_INLINE inline void DispatchClassLoadOrPrepareEvent(art::Thread* thread,
+                                                            JNIEnv* jnienv,
+                                                            jthread jni_thread,
+                                                            jclass klass) const
+      REQUIRES(!envs_lock_);
+
   void HandleEventType(ArtJvmtiEvent event, bool enable);
   void HandleLocalAccessCapabilityAdded();
   void HandleBreakpointEventsChanged(bool enable);
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index 220ad22..5a98755 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -112,6 +112,23 @@
   size_t stop;
 };
 
+art::ShadowFrame* FindFrameAtDepthVisitor::GetOrCreateShadowFrame(bool* created_frame) {
+  art::ShadowFrame* cur = GetCurrentShadowFrame();
+  if (cur == nullptr) {
+    *created_frame = true;
+    art::ArtMethod* method = GetMethod();
+    const uint16_t num_regs = method->DexInstructionData().RegistersSize();
+    cur = GetThread()->FindOrCreateDebuggerShadowFrame(GetFrameId(),
+                                                       num_regs,
+                                                       method,
+                                                       GetDexPc());
+    DCHECK(cur != nullptr);
+  } else {
+    *created_frame = false;
+  }
+  return cur;
+}
+
 template <typename FrameFn>
 GetStackTraceVisitor<FrameFn> MakeStackTraceVisitor(art::Thread* thread_in,
                                                     size_t start,
@@ -1065,16 +1082,7 @@
     // From here we are sure to succeed.
     bool needs_instrument = false;
     // Get/create a shadow frame
-    art::ShadowFrame* shadow_frame = visitor.GetCurrentShadowFrame();
-    if (shadow_frame == nullptr) {
-      needs_instrument = true;
-      const size_t frame_id = visitor.GetFrameId();
-      const uint16_t num_regs = method->DexInstructionData().RegistersSize();
-      shadow_frame = target->FindOrCreateDebuggerShadowFrame(frame_id,
-                                                             num_regs,
-                                                             method,
-                                                             visitor.GetDexPc());
-    }
+    art::ShadowFrame* shadow_frame = visitor.GetOrCreateShadowFrame(&needs_instrument);
     {
       art::WriterMutexLock lk(self, tienv->event_info_mutex_);
       // Mark shadow frame as needs_notify_pop_
@@ -1089,4 +1097,88 @@
   } while (true);
 }
 
+jvmtiError StackUtil::PopFrame(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread thread) {
+  art::Thread* self = art::Thread::Current();
+  art::Thread* target;
+  do {
+    ThreadUtil::SuspendCheck(self);
+    art::MutexLock ucsl_mu(self, *art::Locks::user_code_suspension_lock_);
+    // Make sure we won't be suspended in the middle of holding the thread_suspend_count_lock_ by a
+    // user-code suspension. We retry and do another SuspendCheck to clear this.
+    if (ThreadUtil::WouldSuspendForUserCodeLocked(self)) {
+      continue;
+    }
+    // From now on we know we cannot get suspended by user-code.
+    // NB This does a SuspendCheck (during thread state change) so we need to make sure we don't
+    // have the 'suspend_lock' locked here.
+    art::ScopedObjectAccess soa(self);
+    art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_);
+    jvmtiError err = ERR(INTERNAL);
+    if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) {
+      return err;
+    }
+    {
+      art::MutexLock tscl_mu(self, *art::Locks::thread_suspend_count_lock_);
+      if (target == self || target->GetUserCodeSuspendCount() == 0) {
+        // We cannot be the current thread for this function.
+        return ERR(THREAD_NOT_SUSPENDED);
+      }
+    }
+    JvmtiGlobalTLSData* tls_data = ThreadUtil::GetGlobalTLSData(target);
+    constexpr art::StackVisitor::StackWalkKind kWalkKind =
+        art::StackVisitor::StackWalkKind::kIncludeInlinedFrames;
+    if (tls_data != nullptr &&
+        tls_data->disable_pop_frame_depth != JvmtiGlobalTLSData::kNoDisallowedPopFrame &&
+        tls_data->disable_pop_frame_depth == art::StackVisitor::ComputeNumFrames(target,
+                                                                                 kWalkKind)) {
+      LOG(WARNING) << "Disallowing frame pop due to in-progress class-load/prepare. Frame at depth "
+                   << tls_data->disable_pop_frame_depth << " was marked as un-poppable by the "
+                   << "jvmti plugin. See b/117615146 for more information.";
+      return ERR(OPAQUE_FRAME);
+    }
+    // We hold the user_code_suspension_lock_ so the target thread is staying suspended until we are
+    // done.
+    std::unique_ptr<art::Context> context(art::Context::Create());
+    FindFrameAtDepthVisitor final_frame(target, context.get(), 0);
+    FindFrameAtDepthVisitor penultimate_frame(target, context.get(), 1);
+    final_frame.WalkStack();
+    penultimate_frame.WalkStack();
+
+    if (!final_frame.FoundFrame() || !penultimate_frame.FoundFrame()) {
+      // Cannot do it if there is only one frame!
+      return ERR(NO_MORE_FRAMES);
+    }
+
+    art::ArtMethod* called_method = final_frame.GetMethod();
+    art::ArtMethod* calling_method = penultimate_frame.GetMethod();
+    if (calling_method->IsNative() || called_method->IsNative()) {
+      return ERR(OPAQUE_FRAME);
+    }
+    // From here we are sure to succeed.
+
+    // Get/create a shadow frame
+    bool created_final_frame = false;
+    bool created_penultimate_frame = false;
+    art::ShadowFrame* called_shadow_frame =
+        final_frame.GetOrCreateShadowFrame(&created_final_frame);
+    art::ShadowFrame* calling_shadow_frame =
+        penultimate_frame.GetOrCreateShadowFrame(&created_penultimate_frame);
+
+    CHECK_NE(called_shadow_frame, calling_shadow_frame)
+        << "Frames at different depths not different!";
+
+    // Tell the shadow-frame to return immediately and skip all exit events.
+    called_shadow_frame->SetForcePopFrame(true);
+    calling_shadow_frame->SetForceRetryInstruction(true);
+
+    // Make sure can we will go to the interpreter and use the shadow frames. The early return for
+    // the final frame will force everything to the interpreter so we only need to instrument if it
+    // was not present.
+    if (created_final_frame) {
+      DeoptManager::Get()->DeoptimizeThread(target);
+    }
+    return OK;
+  } while (true);
+}
+
 }  // namespace openjdkjvmti
diff --git a/openjdkjvmti/ti_stack.h b/openjdkjvmti/ti_stack.h
index b41fa4b..55c4269 100644
--- a/openjdkjvmti/ti_stack.h
+++ b/openjdkjvmti/ti_stack.h
@@ -81,6 +81,8 @@
                                         jobject** owned_monitors_ptr);
 
   static jvmtiError NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth);
+
+  static jvmtiError PopFrame(jvmtiEnv* env, jthread thread);
 };
 
 struct FindFrameAtDepthVisitor : art::StackVisitor {
@@ -110,6 +112,9 @@
     }
   }
 
+  art::ShadowFrame* GetOrCreateShadowFrame(/*out*/bool* created_frame)
+      REQUIRES_SHARED(art::Locks::mutator_lock_);
+
  private:
   bool found_frame_;
   size_t cnt_;
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index b54c77d..a0e5b5c 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -623,18 +623,10 @@
   return ERR(NONE);
 }
 
-// The struct that we store in the art::Thread::custom_tls_ that maps the jvmtiEnvs to the data
-// stored with that thread. This is needed since different jvmtiEnvs are not supposed to share TLS
-// data but we only have a single slot in Thread objects to store data.
-struct JvmtiGlobalTLSData : public art::TLSData {
-  std::unordered_map<jvmtiEnv*, const void*> data GUARDED_BY(art::Locks::thread_list_lock_);
-};
-
 static void RemoveTLSData(art::Thread* target, void* ctx) REQUIRES(art::Locks::thread_list_lock_) {
   jvmtiEnv* env = reinterpret_cast<jvmtiEnv*>(ctx);
   art::Locks::thread_list_lock_->AssertHeld(art::Thread::Current());
-  JvmtiGlobalTLSData* global_tls =
-      reinterpret_cast<JvmtiGlobalTLSData*>(target->GetCustomTLS(kJvmtiTlsKey));
+  JvmtiGlobalTLSData* global_tls = ThreadUtil::GetGlobalTLSData(target);
   if (global_tls != nullptr) {
     global_tls->data.erase(env);
   }
@@ -657,19 +649,27 @@
     return err;
   }
 
-  JvmtiGlobalTLSData* global_tls =
-      reinterpret_cast<JvmtiGlobalTLSData*>(target->GetCustomTLS(kJvmtiTlsKey));
-  if (global_tls == nullptr) {
-    // Synchronized using thread_list_lock_ to prevent racing sets.
-    target->SetCustomTLS(kJvmtiTlsKey, new JvmtiGlobalTLSData);
-    global_tls = reinterpret_cast<JvmtiGlobalTLSData*>(target->GetCustomTLS(kJvmtiTlsKey));
-  }
+  JvmtiGlobalTLSData* global_tls = GetOrCreateGlobalTLSData(target);
 
   global_tls->data[env] = data;
 
   return ERR(NONE);
 }
 
+JvmtiGlobalTLSData* ThreadUtil::GetOrCreateGlobalTLSData(art::Thread* thread) {
+  JvmtiGlobalTLSData* data = GetGlobalTLSData(thread);
+  if (data != nullptr) {
+    return data;
+  } else {
+    thread->SetCustomTLS(kJvmtiTlsKey, new JvmtiGlobalTLSData);
+    return GetGlobalTLSData(thread);
+  }
+}
+
+JvmtiGlobalTLSData* ThreadUtil::GetGlobalTLSData(art::Thread* thread) {
+  return reinterpret_cast<JvmtiGlobalTLSData*>(thread->GetCustomTLS(kJvmtiTlsKey));
+}
+
 jvmtiError ThreadUtil::GetThreadLocalStorage(jvmtiEnv* env,
                                              jthread thread,
                                              void** data_ptr) {
@@ -686,8 +686,7 @@
     return err;
   }
 
-  JvmtiGlobalTLSData* global_tls =
-      reinterpret_cast<JvmtiGlobalTLSData*>(target->GetCustomTLS(kJvmtiTlsKey));
+  JvmtiGlobalTLSData* global_tls = GetGlobalTLSData(target);
   if (global_tls == nullptr) {
     *data_ptr = nullptr;
     return OK;
diff --git a/openjdkjvmti/ti_thread.h b/openjdkjvmti/ti_thread.h
index c6b6af1..39f1f07 100644
--- a/openjdkjvmti/ti_thread.h
+++ b/openjdkjvmti/ti_thread.h
@@ -32,11 +32,14 @@
 #ifndef ART_OPENJDKJVMTI_TI_THREAD_H_
 #define ART_OPENJDKJVMTI_TI_THREAD_H_
 
+#include <unordered_map>
+
 #include "jni.h"
 #include "jvmti.h"
 
 #include "base/macros.h"
 #include "base/mutex.h"
+#include "thread.h"
 
 namespace art {
 class ArtField;
@@ -49,6 +52,18 @@
 
 class EventHandler;
 
+// The struct that we store in the art::Thread::custom_tls_ that maps the jvmtiEnvs to the data
+// stored with that thread. This is needed since different jvmtiEnvs are not supposed to share TLS
+// data but we only have a single slot in Thread objects to store data.
+struct JvmtiGlobalTLSData : public art::TLSData {
+  std::unordered_map<jvmtiEnv*, const void*> data GUARDED_BY(art::Locks::thread_list_lock_);
+
+  // The depth of the last frame where popping using PopFrame it is not allowed. It is set to
+  // kNoDisallowedPopFrame if all frames can be popped. See b/117615146 for more information.
+  static constexpr size_t kNoDisallowedPopFrame = -1;
+  size_t disable_pop_frame_depth = kNoDisallowedPopFrame;
+};
+
 class ThreadUtil {
  public:
   static void Register(EventHandler* event_handler);
@@ -134,6 +149,11 @@
     REQUIRES(!art::Locks::user_code_suspension_lock_,
              !art::Locks::thread_suspend_count_lock_);
 
+  static JvmtiGlobalTLSData* GetGlobalTLSData(art::Thread* thread)
+      REQUIRES(art::Locks::thread_list_lock_);
+  static JvmtiGlobalTLSData* GetOrCreateGlobalTLSData(art::Thread* thread)
+      REQUIRES(art::Locks::thread_list_lock_);
+
  private:
   // We need to make sure only one thread tries to suspend threads at a time so we can get the
   // 'suspend-only-once' behavior the spec requires. Internally, ART considers suspension to be a
diff --git a/profman/boot_image_profile.cc b/profman/boot_image_profile.cc
index 6715680..4d8eef9 100644
--- a/profman/boot_image_profile.cc
+++ b/profman/boot_image_profile.cc
@@ -38,7 +38,7 @@
     // Avoid merging classes since we may want to only add classes that fit a certain criteria.
     // If we merged the classes, every single class in each profile would be in the out_profile,
     // but we want to only included classes that are in at least a few profiles.
-    out_profile->MergeWith(*profile, /*merge_classes*/ false);
+    out_profile->MergeWith(*profile, /*merge_classes=*/ false);
   }
 
   // Image classes that were added because they are commonly used.
@@ -96,7 +96,7 @@
               is_clean = false;
             }
           },
-          /*instance_fields*/ VoidFunctor(),
+          /*instance_field_visitor=*/ VoidFunctor(),
           method_visitor,
           method_visitor);
 
diff --git a/profman/profile_assistant.cc b/profman/profile_assistant.cc
index b509fb4..4dc5262 100644
--- a/profman/profile_assistant.cc
+++ b/profman/profile_assistant.cc
@@ -37,7 +37,7 @@
 
   ProfileCompilationInfo info;
   // Load the reference profile.
-  if (!info.Load(reference_profile_file->Fd(), /*merge_classes*/ true, filter_fn)) {
+  if (!info.Load(reference_profile_file->Fd(), /*merge_classes=*/ true, filter_fn)) {
     LOG(WARNING) << "Could not load reference profile file";
     return kErrorBadProfiles;
   }
@@ -49,7 +49,7 @@
   // Merge all current profiles.
   for (size_t i = 0; i < profile_files.size(); i++) {
     ProfileCompilationInfo cur_info;
-    if (!cur_info.Load(profile_files[i]->Fd(), /*merge_classes*/ true, filter_fn)) {
+    if (!cur_info.Load(profile_files[i]->Fd(), /*merge_classes=*/ true, filter_fn)) {
       LOG(WARNING) << "Could not load profile file at index " << i;
       return kErrorBadProfiles;
     }
@@ -92,7 +92,7 @@
   // Will block until all the locks are acquired.
   bool Init(const std::vector<std::string>& filenames, /* out */ std::string* error) {
     for (size_t i = 0; i < filenames.size(); i++) {
-      flocks_[i] = LockedFile::Open(filenames[i].c_str(), O_RDWR, /* block */ true, error);
+      flocks_[i] = LockedFile::Open(filenames[i].c_str(), O_RDWR, /* block= */ true, error);
       if (flocks_[i].get() == nullptr) {
         *error += " (index=" + std::to_string(i) + ")";
         return false;
@@ -106,7 +106,7 @@
     for (size_t i = 0; i < fds.size(); i++) {
       DCHECK_GE(fds[i], 0);
       flocks_[i] = LockedFile::DupOf(fds[i], "profile-file",
-                                     true /* read_only_mode */, error);
+                                     /* read_only_mode= */ true, error);
       if (flocks_[i].get() == nullptr) {
         *error += " (index=" + std::to_string(i) + ")";
         return false;
@@ -138,7 +138,7 @@
   // cleared after processing.
   ScopedFlock reference_profile_file = LockedFile::DupOf(reference_profile_file_fd,
                                                          "reference-profile",
-                                                         false /* read_only_mode */,
+                                                         /* read_only_mode= */ false,
                                                          &error);
   if (reference_profile_file.get() == nullptr) {
     LOG(WARNING) << "Could not lock reference profiled files: " << error;
@@ -163,7 +163,7 @@
   }
 
   ScopedFlock locked_reference_profile_file = LockedFile::Open(
-      reference_profile_file.c_str(), O_RDWR, /* block */ true, &error);
+      reference_profile_file.c_str(), O_RDWR, /* block= */ true, &error);
   if (locked_reference_profile_file.get() == nullptr) {
     LOG(WARNING) << "Could not lock reference profile files: " << error;
     return kErrorCannotLock;
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index f9707d3..31dfbc0 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -720,7 +720,7 @@
   ASSERT_TRUE(info.Load(GetFd(profile_file)));
   // Verify that the profile has matching methods.
   ScopedObjectAccess soa(Thread::Current());
-  ObjPtr<mirror::Class> klass = GetClass(soa, /* class_loader */ nullptr, "Ljava/lang/Math;");
+  ObjPtr<mirror::Class> klass = GetClass(soa, /* class_loader= */ nullptr, "Ljava/lang/Math;");
   ASSERT_TRUE(klass != nullptr);
   size_t method_count = 0;
   for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
@@ -932,8 +932,8 @@
     AssertInlineCaches(inline_monomorphic,
                        expected_monomorphic,
                        info,
-                       /*megamorphic*/false,
-                       /*missing_types*/false);
+                       /*is_megamorphic=*/false,
+                       /*is_missing_types=*/false);
   }
 
   {
@@ -949,8 +949,8 @@
     AssertInlineCaches(inline_polymorhic,
                        expected_polymorphic,
                        info,
-                       /*megamorphic*/false,
-                       /*missing_types*/false);
+                       /*is_megamorphic=*/false,
+                       /*is_missing_types=*/false);
   }
 
   {
@@ -963,8 +963,8 @@
     AssertInlineCaches(inline_megamorphic,
                        expected_megamorphic,
                        info,
-                       /*megamorphic*/true,
-                       /*missing_types*/false);
+                       /*is_megamorphic=*/true,
+                       /*is_missing_types=*/false);
   }
 
   {
@@ -977,8 +977,8 @@
     AssertInlineCaches(inline_missing_types,
                        expected_missing_Types,
                        info,
-                       /*megamorphic*/false,
-                       /*missing_types*/true);
+                       /*is_megamorphic=*/false,
+                       /*is_missing_types=*/true);
   }
 
   {
@@ -1005,7 +1005,7 @@
   const uint16_t kNumberOfMethodsToEnableCompilation = 100;
   ProfileCompilationInfo info1;
   SetupProfile("p1", 1, kNumberOfMethodsToEnableCompilation, 0, profile1, &info1,
-      /*start_method_index*/0, /*reverse_dex_write_order*/false);
+      /*start_method_index=*/0, /*reverse_dex_write_order=*/false);
 
   // The reference profile info will contain the methods with indices 50-150.
   // When setting up the profile reverse the order in which the dex files
@@ -1014,7 +1014,7 @@
   const uint16_t kNumberOfMethodsAlreadyCompiled = 100;
   ProfileCompilationInfo reference_info;
   SetupProfile("p1", 1, kNumberOfMethodsAlreadyCompiled, 0, reference_profile,
-      &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order*/true);
+      &reference_info, kNumberOfMethodsToEnableCompilation / 2, /*reverse_dex_write_order=*/true);
 
   // We should advise compilation.
   ASSERT_EQ(ProfileAssistant::kCompile,
@@ -1233,9 +1233,9 @@
   ProfileCompilationInfo info2_filter;
   ProfileCompilationInfo expected;
 
-  info2_filter.Load(profile1.GetFd(), /*merge_classes*/ true, filter_fn);
-  info2_filter.Load(profile2.GetFd(), /*merge_classes*/ true, filter_fn);
-  expected.Load(reference_profile.GetFd(), /*merge_classes*/ true, filter_fn);
+  info2_filter.Load(profile1.GetFd(), /*merge_classes=*/ true, filter_fn);
+  info2_filter.Load(profile2.GetFd(), /*merge_classes=*/ true, filter_fn);
+  expected.Load(reference_profile.GetFd(), /*merge_classes=*/ true, filter_fn);
 
   ASSERT_TRUE(expected.MergeWith(info1_filter));
   ASSERT_TRUE(expected.MergeWith(info2_filter));
@@ -1260,13 +1260,13 @@
                "fake-location2",
                d2.GetLocationChecksum(),
                num_methods_to_add,
-               /*num_classes*/ 0,
+               /*number_of_classes=*/ 0,
                profile1,
                &info1,
-               /*start_method_index*/ 0,
-               /*reverse_dex_write_order*/ false,
-               /*number_of_methods1*/ d1.NumMethodIds(),
-               /*number_of_methods2*/ d2.NumMethodIds());
+               /*start_method_index=*/ 0,
+               /*reverse_dex_write_order=*/ false,
+               /*number_of_methods1=*/ d1.NumMethodIds(),
+               /*number_of_methods2=*/ d2.NumMethodIds());
 
   // Run profman and pass the dex file with --apk-fd.
   android::base::unique_fd apk_fd(
diff --git a/profman/profman.cc b/profman/profman.cc
index 2b5bf48..d989c8c 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -427,7 +427,7 @@
       if (use_apk_fd_list) {
         if (dex_file_loader.OpenZip(apks_fd_[i],
                                     dex_locations_[i],
-                                    /* verify */ false,
+                                    /* verify= */ false,
                                     kVerifyChecksum,
                                     &error_msg,
                                     &dex_files_for_location)) {
@@ -438,7 +438,7 @@
       } else {
         if (dex_file_loader.Open(apk_files_[i].c_str(),
                                  dex_locations_[i],
-                                 /* verify */ false,
+                                 /* verify= */ false,
                                  kVerifyChecksum,
                                  &error_msg,
                                  &dex_files_for_location)) {
@@ -574,7 +574,7 @@
     if (!FdIsValid(dump_output_to_fd_)) {
       std::cout << dump;
     } else {
-      unix_file::FdFile out_fd(dump_output_to_fd_, false /*check_usage*/);
+      unix_file::FdFile out_fd(dump_output_to_fd_, /*check_usage=*/ false);
       if (!out_fd.WriteFully(dump.c_str(), dump.length())) {
         return -1;
       }
@@ -700,7 +700,7 @@
     if (!FdIsValid(dump_output_to_fd_)) {
       std::cout << dump;
     } else {
-      unix_file::FdFile out_fd(dump_output_to_fd_, false /*check_usage*/);
+      unix_file::FdFile out_fd(dump_output_to_fd_, /*check_usage=*/ false);
       if (!out_fd.WriteFully(dump.c_str(), dump.length())) {
         return -1;
       }
@@ -924,7 +924,7 @@
       flags |= ProfileCompilationInfo::MethodHotness::kFlagPostStartup;
     }
 
-    TypeReference class_ref(/* dex_file */ nullptr, dex::TypeIndex());
+    TypeReference class_ref(/* dex_file= */ nullptr, dex::TypeIndex());
     if (!FindClass(dex_files, klass, &class_ref)) {
       LOG(WARNING) << "Could not find class: " << klass;
       return false;
@@ -993,7 +993,7 @@
         return false;
       }
       std::vector<TypeReference> classes(inline_cache_elems.size(),
-                                         TypeReference(/* dex_file */ nullptr, dex::TypeIndex()));
+                                         TypeReference(/* dex_file= */ nullptr, dex::TypeIndex()));
       size_t class_it = 0;
       for (const std::string& ic_class : inline_cache_elems) {
         if (!FindClass(dex_files, ic_class, &(classes[class_it++]))) {
@@ -1213,7 +1213,7 @@
     // Do not clear if invalid. The input might be an archive.
     bool load_ok = use_fds
         ? profile.Load(profile_files_fd_[0])
-        : profile.Load(profile_files_[0], /*clear_if_invalid*/ false);
+        : profile.Load(profile_files_[0], /*clear_if_invalid=*/ false);
     if (load_ok) {
       // Open the dex files to look up classes and methods.
       std::vector<std::unique_ptr<const DexFile>> dex_files;
@@ -1223,7 +1223,7 @@
       }
       bool result = use_fds
           ? profile.Save(reference_profile_file_fd_)
-          : profile.Save(reference_profile_file_, /*bytes_written*/ nullptr);
+          : profile.Save(reference_profile_file_, /*bytes_written=*/ nullptr);
       return result ? 0 : kErrorFailedToSaveProfile;
     } else {
       return kErrorFailedToLoadProfile;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index f4b8697..33ad987 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -240,9 +240,6 @@
         "entrypoints/quick/quick_trampoline_entrypoints.cc",
     ],
 
-    // b/77976998, clang lld does not recognize the --keep-unique flag.
-    use_clang_lld: false,
-
     arch: {
         arm: {
             srcs: [
@@ -642,6 +639,7 @@
     ],
     header_libs: [
         "art_cmdlineparser_headers", // For parsed_options_test.
+        "cpp-define-generator-definitions",
     ],
     include_dirs: [
         "external/zlib",
diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc
index d4dbbf9..dcc3aff 100644
--- a/runtime/arch/arch_test.cc
+++ b/runtime/arch/arch_test.cc
@@ -17,30 +17,16 @@
 #include <stdint.h>
 
 #include "art_method-inl.h"
+#include "asm_defines.h"
 #include "base/callee_save_type.h"
 #include "entrypoints/quick/callee_save_frame.h"
 #include "common_runtime_test.h"
 #include "quick/quick_method_frame_info.h"
 
-// asm_support.h declares tests next to the #defines. We use asm_support_check.h to (safely)
-// generate CheckAsmSupportOffsetsAndSizes using gtest's EXPECT for the tests. We also use the
-// RETURN_TYPE, HEADER and FOOTER defines from asm_support_check.h to try to ensure that any
-// tests are actually generated.
-
-// Let CheckAsmSupportOffsetsAndSizes return a size_t (the count).
-#define ASM_SUPPORT_CHECK_RETURN_TYPE size_t
-
-// Declare the counter that will be updated per test.
-#define ASM_SUPPORT_CHECK_HEADER size_t count = 0;
-
-// Use EXPECT_EQ for tests, and increment the counter.
-#define ADD_TEST_EQ(x, y) EXPECT_EQ(x, y); count++;
-
-// Return the counter at the end of CheckAsmSupportOffsetsAndSizes.
-#define ASM_SUPPORT_CHECK_FOOTER return count;
-
-// Generate CheckAsmSupportOffsetsAndSizes().
-#include "asm_support_check.h"
+// Static asserts to check the values of generated #defines for assembly.
+#define ASM_DEFINE(NAME, EXPR) static_assert((NAME) == (EXPR), "Unexpected value of " #NAME);
+#include "asm_defines.def"
+#undef ASM_DEFINE
 
 namespace art {
 
@@ -60,11 +46,6 @@
   }
 };
 
-TEST_F(ArchTest, CheckCommonOffsetsAndSizes) {
-  size_t test_count = CheckAsmSupportOffsetsAndSizes();
-  EXPECT_GT(test_count, 0u);
-}
-
 // Grab architecture specific constants.
 namespace arm {
 #include "arch/arm/asm_support_arm.h"
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc
index d0f61c9..7796ca7 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64.cc
@@ -16,6 +16,11 @@
 
 #include "instruction_set_features_arm64.h"
 
+#if defined(ART_TARGET_ANDROID) && defined(__aarch64__)
+#include <asm/hwcap.h>
+#include <sys/auxv.h>
+#endif
+
 #include <fstream>
 #include <sstream>
 
@@ -31,6 +36,10 @@
 
 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant(
     const std::string& variant, std::string* error_msg) {
+  // The CPU variant string is passed to ART through --instruction-set-variant option.
+  // During build, such setting is from TARGET_CPU_VARIANT in device BoardConfig.mk, for example:
+  //   TARGET_CPU_VARIANT := cortex-a75
+
   // Look for variants that need a fix for a53 erratum 835769.
   static const char* arm64_variants_with_a53_835769_bug[] = {
       // Pessimistically assume all generic CPUs are cortex-a53.
@@ -39,14 +48,70 @@
       "cortex-a53",
       "cortex-a53.a57",
       "cortex-a53.a72",
-      // Pessimistically assume all "big" cortex CPUs are paired with a cortex-a53.
+      // Pessimistically assume following "big" cortex CPUs are paired with a cortex-a53.
       "cortex-a57",
       "cortex-a72",
       "cortex-a73",
   };
+
+  static const char* arm64_variants_with_crc[] = {
+      "default",
+      "generic",
+      "kryo",
+      "exynos-m1",
+      "exynos-m2",
+      "exynos-m3",
+      "cortex-a35",
+      "cortex-a53",
+      "cortex-a53.a57",
+      "cortex-a53.a72",
+      "cortex-a57",
+      "cortex-a72",
+      "cortex-a73",
+      "cortex-a55",
+      "cortex-a75",
+      "cortex-a76",
+  };
+
+  static const char* arm64_variants_with_lse[] = {
+      "cortex-a55",
+      "cortex-a75",
+      "cortex-a76",
+  };
+
+  static const char* arm64_variants_with_fp16[] = {
+      "cortex-a55",
+      "cortex-a75",
+      "cortex-a76",
+  };
+
+  static const char* arm64_variants_with_dotprod[] = {
+      "cortex-a55",
+      "cortex-a75",
+      "cortex-a76",
+  };
+
   bool needs_a53_835769_fix = FindVariantInArray(arm64_variants_with_a53_835769_bug,
                                                  arraysize(arm64_variants_with_a53_835769_bug),
                                                  variant);
+  // The variants that need a fix for 843419 are the same that need a fix for 835769.
+  bool needs_a53_843419_fix = needs_a53_835769_fix;
+
+  bool has_crc = FindVariantInArray(arm64_variants_with_crc,
+                                    arraysize(arm64_variants_with_crc),
+                                    variant);
+
+  bool has_lse = FindVariantInArray(arm64_variants_with_lse,
+                                    arraysize(arm64_variants_with_lse),
+                                    variant);
+
+  bool has_fp16 = FindVariantInArray(arm64_variants_with_fp16,
+                                     arraysize(arm64_variants_with_fp16),
+                                     variant);
+
+  bool has_dotprod = FindVariantInArray(arm64_variants_with_dotprod,
+                                        arraysize(arm64_variants_with_dotprod),
+                                        variant);
 
   if (!needs_a53_835769_fix) {
     // Check to see if this is an expected variant.
@@ -54,6 +119,7 @@
         "cortex-a35",
         "cortex-a55",
         "cortex-a75",
+        "cortex-a76",
         "exynos-m1",
         "exynos-m2",
         "exynos-m3",
@@ -68,31 +134,91 @@
     }
   }
 
-  // The variants that need a fix for 843419 are the same that need a fix for 835769.
-  bool needs_a53_843419_fix = needs_a53_835769_fix;
-
-  return Arm64FeaturesUniquePtr(
-      new Arm64InstructionSetFeatures(needs_a53_835769_fix, needs_a53_843419_fix));
+  return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(needs_a53_835769_fix,
+                                                                needs_a53_843419_fix,
+                                                                has_crc,
+                                                                has_lse,
+                                                                has_fp16,
+                                                                has_dotprod));
 }
 
 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
   bool is_a53 = (bitmap & kA53Bitfield) != 0;
-  return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53, is_a53));
+  bool has_crc = (bitmap & kCRCBitField) != 0;
+  bool has_lse = (bitmap & kLSEBitField) != 0;
+  bool has_fp16 = (bitmap & kFP16BitField) != 0;
+  bool has_dotprod = (bitmap & kDotProdBitField) != 0;
+  return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53,
+                                                                is_a53,
+                                                                has_crc,
+                                                                has_lse,
+                                                                has_fp16,
+                                                                has_dotprod));
 }
 
 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromCppDefines() {
-  const bool is_a53 = true;  // Pessimistically assume all ARM64s are A53s.
-  return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53, is_a53));
+  // For more details about ARM feature macros, refer to
+  // Arm C Language Extensions Documentation (ACLE).
+  // https://developer.arm.com/docs/101028/latest
+  bool needs_a53_835769_fix = false;
+  bool needs_a53_843419_fix = needs_a53_835769_fix;
+  bool has_crc = false;
+  bool has_lse = false;
+  bool has_fp16 = false;
+  bool has_dotprod = false;
+
+#if defined (__ARM_FEATURE_CRC32)
+  has_crc = true;
+#endif
+
+#if defined (__ARM_ARCH_8_1A__) || defined (__ARM_ARCH_8_2A__)
+  // There is no specific ACLE macro defined for ARMv8.1 LSE features.
+  has_lse = true;
+#endif
+
+#if defined (__ARM_FEATURE_FP16_SCALAR_ARITHMETIC) || defined (__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
+  has_fp16 = true;
+#endif
+
+#if defined (__ARM_FEATURE_DOTPROD)
+  has_dotprod = true;
+#endif
+
+  return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(needs_a53_835769_fix,
+                                                                needs_a53_843419_fix,
+                                                                has_crc,
+                                                                has_lse,
+                                                                has_fp16,
+                                                                has_dotprod));
 }
 
 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromCpuInfo() {
-  const bool is_a53 = true;  // Conservative default.
-  return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53, is_a53));
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
 }
 
 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromHwcap() {
-  const bool is_a53 = true;  // Pessimistically assume all ARM64s are A53s.
-  return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(is_a53, is_a53));
+  bool needs_a53_835769_fix = false;  // No HWCAP for this.
+  bool needs_a53_843419_fix = false;  // No HWCAP for this.
+  bool has_crc = false;
+  bool has_lse = false;
+  bool has_fp16 = false;
+  bool has_dotprod = false;
+
+#if defined(ART_TARGET_ANDROID) && defined(__aarch64__)
+  uint64_t hwcaps = getauxval(AT_HWCAP);
+  has_crc = hwcaps & HWCAP_CRC32 ? true : false;
+  has_lse = hwcaps & HWCAP_ATOMICS ? true : false;
+  has_fp16 = hwcaps & HWCAP_FPHP ? true : false;
+  has_dotprod = hwcaps & HWCAP_ASIMDDP ? true : false;
+#endif
+
+  return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures(needs_a53_835769_fix,
+                                                                needs_a53_843419_fix,
+                                                                has_crc,
+                                                                has_lse,
+                                                                has_fp16,
+                                                                has_dotprod));
 }
 
 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromAssembly() {
@@ -106,11 +232,33 @@
   }
   const Arm64InstructionSetFeatures* other_as_arm64 = other->AsArm64InstructionSetFeatures();
   return fix_cortex_a53_835769_ == other_as_arm64->fix_cortex_a53_835769_ &&
-      fix_cortex_a53_843419_ == other_as_arm64->fix_cortex_a53_843419_;
+      fix_cortex_a53_843419_ == other_as_arm64->fix_cortex_a53_843419_ &&
+      has_crc_ == other_as_arm64->has_crc_ &&
+      has_lse_ == other_as_arm64->has_lse_ &&
+      has_fp16_ == other_as_arm64->has_fp16_ &&
+      has_dotprod_ == other_as_arm64->has_dotprod_;
+}
+
+bool Arm64InstructionSetFeatures::HasAtLeast(const InstructionSetFeatures* other) const {
+  if (InstructionSet::kArm64 != other->GetInstructionSet()) {
+    return false;
+  }
+  // Currently 'default' feature is cortex-a53 with fixes 835769 and 843419.
+  // Newer CPUs are not required to have such features,
+  // so these two a53 fix features are not tested for HasAtLeast.
+  const Arm64InstructionSetFeatures* other_as_arm64 = other->AsArm64InstructionSetFeatures();
+  return (has_crc_ || !other_as_arm64->has_crc_)
+      && (has_lse_ || !other_as_arm64->has_lse_)
+      && (has_fp16_ || !other_as_arm64->has_fp16_)
+      && (has_dotprod_ || !other_as_arm64->has_dotprod_);
 }
 
 uint32_t Arm64InstructionSetFeatures::AsBitmap() const {
-  return (fix_cortex_a53_835769_ ? kA53Bitfield : 0);
+  return (fix_cortex_a53_835769_ ? kA53Bitfield : 0)
+      | (has_crc_ ? kCRCBitField : 0)
+      | (has_lse_ ? kLSEBitField: 0)
+      | (has_fp16_ ? kFP16BitField: 0)
+      | (has_dotprod_ ? kDotProdBitField : 0);
 }
 
 std::string Arm64InstructionSetFeatures::GetFeatureString() const {
@@ -120,26 +268,100 @@
   } else {
     result += "-a53";
   }
+  if (has_crc_) {
+    result += ",crc";
+  } else {
+    result += ",-crc";
+  }
+  if (has_lse_) {
+    result += ",lse";
+  } else {
+    result += ",-lse";
+  }
+  if (has_fp16_) {
+    result += ",fp16";
+  } else {
+    result += ",-fp16";
+  }
+  if (has_dotprod_) {
+    result += ",dotprod";
+  } else {
+    result += ",-dotprod";
+  }
   return result;
 }
 
 std::unique_ptr<const InstructionSetFeatures>
 Arm64InstructionSetFeatures::AddFeaturesFromSplitString(
     const std::vector<std::string>& features, std::string* error_msg) const {
+  // This 'features' string is from '--instruction-set-features=' option in ART.
+  // These ARMv8.x feature strings align with those introduced in other compilers:
+  // https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
+  // User can also use armv8.x-a to select group of features:
+  //   armv8.1-a is equivalent to crc,lse
+  //   armv8.2-a is equivalent to crc,lse,fp16
+  //   armv8.3-a is equivalent to crc,lse,fp16
+  //   armv8.4-a is equivalent to crc,lse,fp16,dotprod
+  // For detailed optional & mandatory features support in armv8.x-a,
+  // please refer to section 'A1.7 ARMv8 architecture extensions' in
+  // ARM Architecture Reference Manual ARMv8 document:
+  // https://developer.arm.com/products/architecture/cpu-architecture/a-profile/docs/ddi0487/latest/
+  // arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile/
   bool is_a53 = fix_cortex_a53_835769_;
+  bool has_crc = has_crc_;
+  bool has_lse = has_lse_;
+  bool has_fp16 = has_fp16_;
+  bool has_dotprod = has_dotprod_;
   for (auto i = features.begin(); i != features.end(); i++) {
     std::string feature = android::base::Trim(*i);
     if (feature == "a53") {
       is_a53 = true;
     } else if (feature == "-a53") {
       is_a53 = false;
+    } else if (feature == "crc") {
+      has_crc = true;
+    } else if (feature == "-crc") {
+      has_crc = false;
+    } else if (feature == "lse") {
+      has_lse = true;
+    } else if (feature == "-lse") {
+      has_lse = false;
+    } else if (feature == "fp16") {
+      has_fp16 = true;
+    } else if (feature == "-fp16") {
+      has_fp16 = false;
+    } else if (feature == "dotprod") {
+      has_dotprod = true;
+    } else if (feature == "-dotprod") {
+      has_dotprod = false;
+    } else if (feature == "armv8.1-a") {
+      has_crc = true;
+      has_lse = true;
+    } else if (feature == "armv8.2-a") {
+      has_crc = true;
+      has_lse = true;
+      has_fp16 = true;
+    } else if (feature == "armv8.3-a") {
+      has_crc = true;
+      has_lse = true;
+      has_fp16 = true;
+    } else if (feature == "armv8.4-a") {
+      has_crc = true;
+      has_lse = true;
+      has_fp16 = true;
+      has_dotprod = true;
     } else {
       *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
       return nullptr;
     }
   }
   return std::unique_ptr<const InstructionSetFeatures>(
-      new Arm64InstructionSetFeatures(is_a53, is_a53));
+      new Arm64InstructionSetFeatures(is_a53,  // erratum 835769
+                                      is_a53,  // erratum 843419
+                                      has_crc,
+                                      has_lse,
+                                      has_fp16,
+                                      has_dotprod));
 }
 
 }  // namespace art
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.h b/runtime/arch/arm64/instruction_set_features_arm64.h
index 163a2d8..4ec8fa2 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64.h
+++ b/runtime/arch/arm64/instruction_set_features_arm64.h
@@ -49,6 +49,11 @@
 
   bool Equals(const InstructionSetFeatures* other) const override;
 
+  // Note that newer CPUs do not have a53 erratum 835769 and 843419,
+  // so the two a53 fix features (fix_cortex_a53_835769 and fix_cortex_a53_843419)
+  // are not tested for HasAtLeast.
+  bool HasAtLeast(const InstructionSetFeatures* other) const override;
+
   InstructionSet GetInstructionSet() const override {
     return InstructionSet::kArm64;
   }
@@ -68,6 +73,23 @@
       return fix_cortex_a53_843419_;
   }
 
+  bool HasCRC() const {
+    return has_crc_;
+  }
+
+  bool HasLSE() const {
+    return has_lse_;
+  }
+
+  bool HasFP16() const {
+    return has_fp16_;
+  }
+
+  // Are Dot Product instructions (UDOT/SDOT) available?
+  bool HasDotProd() const {
+    return has_dotprod_;
+  }
+
   virtual ~Arm64InstructionSetFeatures() {}
 
  protected:
@@ -77,19 +99,36 @@
                                  std::string* error_msg) const override;
 
  private:
-  Arm64InstructionSetFeatures(bool needs_a53_835769_fix, bool needs_a53_843419_fix)
+  Arm64InstructionSetFeatures(bool needs_a53_835769_fix,
+                              bool needs_a53_843419_fix,
+                              bool has_crc,
+                              bool has_lse,
+                              bool has_fp16,
+                              bool has_dotprod)
       : InstructionSetFeatures(),
         fix_cortex_a53_835769_(needs_a53_835769_fix),
-        fix_cortex_a53_843419_(needs_a53_843419_fix) {
+        fix_cortex_a53_843419_(needs_a53_843419_fix),
+        has_crc_(has_crc),
+        has_lse_(has_lse),
+        has_fp16_(has_fp16),
+        has_dotprod_(has_dotprod) {
   }
 
   // Bitmap positions for encoding features as a bitmap.
   enum {
     kA53Bitfield = 1 << 0,
+    kCRCBitField = 1 << 1,
+    kLSEBitField = 1 << 2,
+    kFP16BitField = 1 << 3,
+    kDotProdBitField = 1 << 4,
   };
 
   const bool fix_cortex_a53_835769_;
   const bool fix_cortex_a53_843419_;
+  const bool has_crc_;      // optional in ARMv8.0, mandatory in ARMv8.1.
+  const bool has_lse_;      // ARMv8.1 Large System Extensions.
+  const bool has_fp16_;     // ARMv8.2 FP16 extensions.
+  const bool has_dotprod_;  // optional in ARMv8.2, mandatory in ARMv8.4.
 
   DISALLOW_COPY_AND_ASSIGN(Arm64InstructionSetFeatures);
 };
diff --git a/runtime/arch/arm64/instruction_set_features_arm64_test.cc b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
index b946f4f..99d6b0d 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64_test.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
@@ -28,32 +28,37 @@
   ASSERT_TRUE(arm64_features.get() != nullptr) << error_msg;
   EXPECT_EQ(arm64_features->GetInstructionSet(), InstructionSet::kArm64);
   EXPECT_TRUE(arm64_features->Equals(arm64_features.get()));
-  EXPECT_STREQ("a53", arm64_features->GetFeatureString().c_str());
-  EXPECT_EQ(arm64_features->AsBitmap(), 1U);
+  EXPECT_STREQ("a53,crc,-lse,-fp16,-dotprod", arm64_features->GetFeatureString().c_str());
+  EXPECT_EQ(arm64_features->AsBitmap(), 3U);
 
   std::unique_ptr<const InstructionSetFeatures> cortex_a57_features(
       InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a57", &error_msg));
   ASSERT_TRUE(cortex_a57_features.get() != nullptr) << error_msg;
   EXPECT_EQ(cortex_a57_features->GetInstructionSet(), InstructionSet::kArm64);
   EXPECT_TRUE(cortex_a57_features->Equals(cortex_a57_features.get()));
-  EXPECT_STREQ("a53", cortex_a57_features->GetFeatureString().c_str());
-  EXPECT_EQ(cortex_a57_features->AsBitmap(), 1U);
+  EXPECT_TRUE(cortex_a57_features->HasAtLeast(arm64_features.get()));
+  EXPECT_STREQ("a53,crc,-lse,-fp16,-dotprod", cortex_a57_features->GetFeatureString().c_str());
+  EXPECT_EQ(cortex_a57_features->AsBitmap(), 3U);
 
   std::unique_ptr<const InstructionSetFeatures> cortex_a73_features(
       InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a73", &error_msg));
   ASSERT_TRUE(cortex_a73_features.get() != nullptr) << error_msg;
   EXPECT_EQ(cortex_a73_features->GetInstructionSet(), InstructionSet::kArm64);
   EXPECT_TRUE(cortex_a73_features->Equals(cortex_a73_features.get()));
-  EXPECT_STREQ("a53", cortex_a73_features->GetFeatureString().c_str());
-  EXPECT_EQ(cortex_a73_features->AsBitmap(), 1U);
+  EXPECT_TRUE(cortex_a73_features->AsArm64InstructionSetFeatures()->HasCRC());
+  EXPECT_FALSE(cortex_a73_features->AsArm64InstructionSetFeatures()->HasLSE());
+  EXPECT_FALSE(cortex_a73_features->AsArm64InstructionSetFeatures()->HasFP16());
+  EXPECT_FALSE(cortex_a73_features->AsArm64InstructionSetFeatures()->HasDotProd());
+  EXPECT_STREQ("a53,crc,-lse,-fp16,-dotprod", cortex_a73_features->GetFeatureString().c_str());
+  EXPECT_EQ(cortex_a73_features->AsBitmap(), 3U);
 
   std::unique_ptr<const InstructionSetFeatures> cortex_a35_features(
       InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a35", &error_msg));
   ASSERT_TRUE(cortex_a35_features.get() != nullptr) << error_msg;
   EXPECT_EQ(cortex_a35_features->GetInstructionSet(), InstructionSet::kArm64);
   EXPECT_TRUE(cortex_a35_features->Equals(cortex_a35_features.get()));
-  EXPECT_STREQ("-a53", cortex_a35_features->GetFeatureString().c_str());
-  EXPECT_EQ(cortex_a35_features->AsBitmap(), 0U);
+  EXPECT_STREQ("-a53,crc,-lse,-fp16,-dotprod", cortex_a35_features->GetFeatureString().c_str());
+  EXPECT_EQ(cortex_a35_features->AsBitmap(), 2U);
 
   std::unique_ptr<const InstructionSetFeatures> kryo_features(
       InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "kryo", &error_msg));
@@ -62,28 +67,107 @@
   EXPECT_TRUE(kryo_features->Equals(kryo_features.get()));
   EXPECT_TRUE(kryo_features->Equals(cortex_a35_features.get()));
   EXPECT_FALSE(kryo_features->Equals(cortex_a57_features.get()));
-  EXPECT_STREQ("-a53", kryo_features->GetFeatureString().c_str());
-  EXPECT_EQ(kryo_features->AsBitmap(), 0U);
+  EXPECT_STREQ("-a53,crc,-lse,-fp16,-dotprod", kryo_features->GetFeatureString().c_str());
+  EXPECT_EQ(kryo_features->AsBitmap(), 2U);
 
   std::unique_ptr<const InstructionSetFeatures> cortex_a55_features(
       InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a55", &error_msg));
   ASSERT_TRUE(cortex_a55_features.get() != nullptr) << error_msg;
   EXPECT_EQ(cortex_a55_features->GetInstructionSet(), InstructionSet::kArm64);
   EXPECT_TRUE(cortex_a55_features->Equals(cortex_a55_features.get()));
-  EXPECT_TRUE(cortex_a55_features->Equals(cortex_a35_features.get()));
+  EXPECT_FALSE(cortex_a55_features->Equals(cortex_a35_features.get()));
   EXPECT_FALSE(cortex_a55_features->Equals(cortex_a57_features.get()));
-  EXPECT_STREQ("-a53", cortex_a55_features->GetFeatureString().c_str());
-  EXPECT_EQ(cortex_a55_features->AsBitmap(), 0U);
+  EXPECT_TRUE(cortex_a35_features->HasAtLeast(arm64_features.get()));
+  EXPECT_STREQ("-a53,crc,lse,fp16,dotprod", cortex_a55_features->GetFeatureString().c_str());
+  EXPECT_EQ(cortex_a55_features->AsBitmap(), 30U);
 
   std::unique_ptr<const InstructionSetFeatures> cortex_a75_features(
       InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a75", &error_msg));
   ASSERT_TRUE(cortex_a75_features.get() != nullptr) << error_msg;
   EXPECT_EQ(cortex_a75_features->GetInstructionSet(), InstructionSet::kArm64);
   EXPECT_TRUE(cortex_a75_features->Equals(cortex_a75_features.get()));
-  EXPECT_TRUE(cortex_a75_features->Equals(cortex_a35_features.get()));
+  EXPECT_FALSE(cortex_a75_features->Equals(cortex_a35_features.get()));
   EXPECT_FALSE(cortex_a75_features->Equals(cortex_a57_features.get()));
-  EXPECT_STREQ("-a53", cortex_a75_features->GetFeatureString().c_str());
-  EXPECT_EQ(cortex_a75_features->AsBitmap(), 0U);
+  EXPECT_TRUE(cortex_a75_features->HasAtLeast(arm64_features.get()));
+  EXPECT_TRUE(cortex_a75_features->HasAtLeast(cortex_a55_features.get()));
+  EXPECT_FALSE(cortex_a35_features->HasAtLeast(cortex_a75_features.get()));
+  EXPECT_FALSE(cortex_a75_features->AsArm64InstructionSetFeatures()->NeedFixCortexA53_835769());
+  EXPECT_FALSE(cortex_a75_features->AsArm64InstructionSetFeatures()->NeedFixCortexA53_843419());
+  EXPECT_TRUE(cortex_a75_features->AsArm64InstructionSetFeatures()->HasCRC());
+  EXPECT_TRUE(cortex_a75_features->AsArm64InstructionSetFeatures()->HasLSE());
+  EXPECT_TRUE(cortex_a75_features->AsArm64InstructionSetFeatures()->HasFP16());
+  EXPECT_TRUE(cortex_a75_features->AsArm64InstructionSetFeatures()->HasDotProd());
+  EXPECT_STREQ("-a53,crc,lse,fp16,dotprod", cortex_a75_features->GetFeatureString().c_str());
+  EXPECT_EQ(cortex_a75_features->AsBitmap(), 30U);
+
+  std::unique_ptr<const InstructionSetFeatures> cortex_a76_features(
+      InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "cortex-a76", &error_msg));
+  ASSERT_TRUE(cortex_a76_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(cortex_a76_features->GetInstructionSet(), InstructionSet::kArm64);
+  EXPECT_TRUE(cortex_a76_features->Equals(cortex_a76_features.get()));
+  EXPECT_FALSE(cortex_a76_features->Equals(cortex_a35_features.get()));
+  EXPECT_FALSE(cortex_a76_features->Equals(cortex_a57_features.get()));
+  EXPECT_TRUE(cortex_a76_features->Equals(cortex_a75_features.get()));
+  EXPECT_TRUE(cortex_a76_features->HasAtLeast(arm64_features.get()));
+  EXPECT_TRUE(cortex_a76_features->HasAtLeast(cortex_a55_features.get()));
+  EXPECT_FALSE(cortex_a35_features->HasAtLeast(cortex_a76_features.get()));
+  EXPECT_FALSE(cortex_a76_features->AsArm64InstructionSetFeatures()->NeedFixCortexA53_835769());
+  EXPECT_FALSE(cortex_a76_features->AsArm64InstructionSetFeatures()->NeedFixCortexA53_843419());
+  EXPECT_TRUE(cortex_a76_features->AsArm64InstructionSetFeatures()->HasCRC());
+  EXPECT_TRUE(cortex_a76_features->AsArm64InstructionSetFeatures()->HasLSE());
+  EXPECT_TRUE(cortex_a76_features->AsArm64InstructionSetFeatures()->HasFP16());
+  EXPECT_TRUE(cortex_a76_features->AsArm64InstructionSetFeatures()->HasDotProd());
+  EXPECT_STREQ("-a53,crc,lse,fp16,dotprod", cortex_a76_features->GetFeatureString().c_str());
+  EXPECT_EQ(cortex_a76_features->AsBitmap(), 30U);
+}
+
+TEST(Arm64InstructionSetFeaturesTest, Arm64AddFeaturesFromString) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> base_features(
+      InstructionSetFeatures::FromVariant(InstructionSet::kArm64, "generic", &error_msg));
+  ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
+
+  // Build features for a Cortex-A76 processor (with ARMv8.2 and Dot Product exentions support).
+  std::unique_ptr<const InstructionSetFeatures> a76_features(
+      base_features->AddFeaturesFromString("-a53,armv8.2-a,dotprod", &error_msg));
+  ASSERT_TRUE(a76_features.get() != nullptr) << error_msg;
+  ASSERT_EQ(a76_features->GetInstructionSet(), InstructionSet::kArm64);
+  EXPECT_TRUE(a76_features->Equals(a76_features.get()));
+  EXPECT_FALSE(a76_features->AsArm64InstructionSetFeatures()->NeedFixCortexA53_835769());
+  EXPECT_FALSE(a76_features->AsArm64InstructionSetFeatures()->NeedFixCortexA53_843419());
+  EXPECT_TRUE(a76_features->AsArm64InstructionSetFeatures()->HasCRC());
+  EXPECT_TRUE(a76_features->AsArm64InstructionSetFeatures()->HasLSE());
+  EXPECT_TRUE(a76_features->AsArm64InstructionSetFeatures()->HasFP16());
+  EXPECT_TRUE(a76_features->AsArm64InstructionSetFeatures()->HasDotProd());
+  EXPECT_STREQ("-a53,crc,lse,fp16,dotprod", a76_features->GetFeatureString().c_str());
+  EXPECT_EQ(a76_features->AsBitmap(), 30U);
+
+  // Build features for a default ARM64 processor.
+  std::unique_ptr<const InstructionSetFeatures> generic_features(
+      base_features->AddFeaturesFromString("default", &error_msg));
+  ASSERT_TRUE(generic_features.get() != nullptr) << error_msg;
+  ASSERT_EQ(generic_features->GetInstructionSet(), InstructionSet::kArm64);
+  EXPECT_TRUE(generic_features->Equals(generic_features.get()));
+  EXPECT_FALSE(generic_features->AsArm64InstructionSetFeatures()->HasLSE());
+  EXPECT_FALSE(generic_features->AsArm64InstructionSetFeatures()->HasFP16());
+  EXPECT_FALSE(generic_features->AsArm64InstructionSetFeatures()->HasDotProd());
+  EXPECT_STREQ("a53,crc,-lse,-fp16,-dotprod", generic_features->GetFeatureString().c_str());
+  EXPECT_EQ(generic_features->AsBitmap(), 3U);
+
+  // Build features for a ARM64 processor that supports up to ARMv8.2.
+  std::unique_ptr<const InstructionSetFeatures> armv8_2a_cpu_features(
+      base_features->AddFeaturesFromString("-a53,armv8.2-a", &error_msg));
+  ASSERT_TRUE(armv8_2a_cpu_features.get() != nullptr) << error_msg;
+  ASSERT_EQ(armv8_2a_cpu_features->GetInstructionSet(), InstructionSet::kArm64);
+  EXPECT_TRUE(armv8_2a_cpu_features->Equals(armv8_2a_cpu_features.get()));
+  EXPECT_FALSE(armv8_2a_cpu_features->AsArm64InstructionSetFeatures()->NeedFixCortexA53_835769());
+  EXPECT_FALSE(armv8_2a_cpu_features->AsArm64InstructionSetFeatures()->NeedFixCortexA53_843419());
+  EXPECT_TRUE(armv8_2a_cpu_features->AsArm64InstructionSetFeatures()->HasCRC());
+  EXPECT_TRUE(armv8_2a_cpu_features->AsArm64InstructionSetFeatures()->HasLSE());
+  EXPECT_TRUE(armv8_2a_cpu_features->AsArm64InstructionSetFeatures()->HasFP16());
+  EXPECT_FALSE(armv8_2a_cpu_features->AsArm64InstructionSetFeatures()->HasDotProd());
+  EXPECT_STREQ("-a53,crc,lse,fp16,-dotprod", armv8_2a_cpu_features->GetFeatureString().c_str());
+  EXPECT_EQ(armv8_2a_cpu_features->AsBitmap(), 14U);
 }
 
 }  // namespace art
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 5247a0e..eac9856 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -20,216 +20,7 @@
 #include "heap_poisoning.h"
 #include "read_barrier_config.h"
 
-// To generate tests related to the constants in this header, either define ADD_TEST_EQ before
-// including, or use asm_support_check.h.
-#ifndef ADD_TEST_EQ  // Allow #include-r to replace with their own.
-#define DEFINED_ADD_TEST_EQ 1
-#define ADD_TEST_EQ(x, y)
-#endif
-
-// Rounds the value n up to the nearest multiple of sz. sz must be a multiple of two.
-#define ALIGN_UP(n, sz) (((n) + (sz - 1)) & ~((sz) - 1))
-
-#if defined(__LP64__)
-#define POINTER_SIZE_SHIFT 3
-#define POINTER_SIZE art::PointerSize::k64
-#else
-#define POINTER_SIZE_SHIFT 2
-#define POINTER_SIZE art::PointerSize::k32
-#endif
-ADD_TEST_EQ(static_cast<size_t>(1U << POINTER_SIZE_SHIFT),
-            static_cast<size_t>(__SIZEOF_POINTER__))
-
-// Import platform-independent constant defines from our autogenerated list.
-// Export new defines (for assembly use) by editing cpp-define-generator def files.
-#define DEFINE_CHECK_EQ ADD_TEST_EQ
-#include "asm_support_gen.h"
-#undef DEFINE_CHECK_EQ
-
-// Offset of field Thread::tlsPtr_.exception.
-#define THREAD_EXCEPTION_OFFSET (THREAD_CARD_TABLE_OFFSET + __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_EXCEPTION_OFFSET,
-            art::Thread::ExceptionOffset<POINTER_SIZE>().Int32Value())
-
-// Offset of field Thread::tlsPtr_.managed_stack.top_quick_frame_.
-#define THREAD_TOP_QUICK_FRAME_OFFSET (THREAD_CARD_TABLE_OFFSET + (3 * __SIZEOF_POINTER__))
-ADD_TEST_EQ(THREAD_TOP_QUICK_FRAME_OFFSET,
-            art::Thread::TopOfManagedStackOffset<POINTER_SIZE>().Int32Value())
-
-// Offset of field Thread::tlsPtr_.self.
-#define THREAD_SELF_OFFSET (THREAD_CARD_TABLE_OFFSET + (9 * __SIZEOF_POINTER__))
-ADD_TEST_EQ(THREAD_SELF_OFFSET,
-            art::Thread::SelfOffset<POINTER_SIZE>().Int32Value())
-
-// Offset of field Thread::tlsPtr_.thread_local_pos.
-#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 34 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_LOCAL_POS_OFFSET,
-            art::Thread::ThreadLocalPosOffset<POINTER_SIZE>().Int32Value())
-// Offset of field Thread::tlsPtr_.thread_local_end.
-#define THREAD_LOCAL_END_OFFSET (THREAD_LOCAL_POS_OFFSET + __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_LOCAL_END_OFFSET,
-            art::Thread::ThreadLocalEndOffset<POINTER_SIZE>().Int32Value())
-// Offset of field Thread::tlsPtr_.thread_local_objects.
-#define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_LOCAL_END_OFFSET + 2 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
-            art::Thread::ThreadLocalObjectsOffset<POINTER_SIZE>().Int32Value())
-
-// Offset of field Thread::tlsPtr_.mterp_current_ibase.
-#define THREAD_CURRENT_IBASE_OFFSET \
-    (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__ + (1 + 166) * __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_CURRENT_IBASE_OFFSET,
-            art::Thread::MterpCurrentIBaseOffset<POINTER_SIZE>().Int32Value())
-// Offset of field Thread::tlsPtr_.mterp_default_ibase.
-#define THREAD_DEFAULT_IBASE_OFFSET (THREAD_CURRENT_IBASE_OFFSET + __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_DEFAULT_IBASE_OFFSET,
-            art::Thread::MterpDefaultIBaseOffset<POINTER_SIZE>().Int32Value())
-// Offset of field Thread::tlsPtr_.mterp_alt_ibase.
-#define THREAD_ALT_IBASE_OFFSET (THREAD_DEFAULT_IBASE_OFFSET + __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_ALT_IBASE_OFFSET,
-            art::Thread::MterpAltIBaseOffset<POINTER_SIZE>().Int32Value())
-// Offset of field Thread::tlsPtr_.rosalloc_runs.
-#define THREAD_ROSALLOC_RUNS_OFFSET (THREAD_ALT_IBASE_OFFSET + __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_ROSALLOC_RUNS_OFFSET,
-            art::Thread::RosAllocRunsOffset<POINTER_SIZE>().Int32Value())
-// Offset of field Thread::tlsPtr_.thread_local_alloc_stack_top.
-#define THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET (THREAD_ROSALLOC_RUNS_OFFSET + 16 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET,
-            art::Thread::ThreadLocalAllocStackTopOffset<POINTER_SIZE>().Int32Value())
-// Offset of field Thread::tlsPtr_.thread_local_alloc_stack_end.
-#define THREAD_LOCAL_ALLOC_STACK_END_OFFSET (THREAD_ROSALLOC_RUNS_OFFSET + 17 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_LOCAL_ALLOC_STACK_END_OFFSET,
-            art::Thread::ThreadLocalAllocStackEndOffset<POINTER_SIZE>().Int32Value())
-// Offset of field Thread::interpreter_cache_. This is aligned on a 16 byte boundary so we need to
-// round up depending on the size of tlsPtr_.
-#define THREAD_INTERPRETER_CACHE_OFFSET \
-  (ALIGN_UP((THREAD_CARD_TABLE_OFFSET + 301 * __SIZEOF_POINTER__), 16))
-ADD_TEST_EQ(THREAD_INTERPRETER_CACHE_OFFSET,
-            art::Thread::InterpreterCacheOffset<POINTER_SIZE>().Int32Value())
-
-// Offsets within ShadowFrame.
-#define SHADOWFRAME_LINK_OFFSET 0
-ADD_TEST_EQ(SHADOWFRAME_LINK_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::LinkOffset()))
-#define SHADOWFRAME_METHOD_OFFSET (SHADOWFRAME_LINK_OFFSET + 1 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(SHADOWFRAME_METHOD_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::MethodOffset()))
-#define SHADOWFRAME_RESULT_REGISTER_OFFSET (SHADOWFRAME_LINK_OFFSET + 2 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(SHADOWFRAME_RESULT_REGISTER_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::ResultRegisterOffset()))
-#define SHADOWFRAME_DEX_PC_PTR_OFFSET (SHADOWFRAME_LINK_OFFSET + 3 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(SHADOWFRAME_DEX_PC_PTR_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::DexPCPtrOffset()))
-#define SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET (SHADOWFRAME_LINK_OFFSET + 4 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::DexInstructionsOffset()))
-#define SHADOWFRAME_LOCK_COUNT_DATA_OFFSET (SHADOWFRAME_LINK_OFFSET + 5 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(SHADOWFRAME_LOCK_COUNT_DATA_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::LockCountDataOffset()))
-#define SHADOWFRAME_NUMBER_OF_VREGS_OFFSET (SHADOWFRAME_LINK_OFFSET + 6 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::NumberOfVRegsOffset()))
-#define SHADOWFRAME_DEX_PC_OFFSET (SHADOWFRAME_NUMBER_OF_VREGS_OFFSET + 4)
-ADD_TEST_EQ(SHADOWFRAME_DEX_PC_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::DexPCOffset()))
-#define SHADOWFRAME_CACHED_HOTNESS_COUNTDOWN_OFFSET (SHADOWFRAME_NUMBER_OF_VREGS_OFFSET + 8)
-ADD_TEST_EQ(SHADOWFRAME_CACHED_HOTNESS_COUNTDOWN_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::CachedHotnessCountdownOffset()))
-#define SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET (SHADOWFRAME_NUMBER_OF_VREGS_OFFSET + 10)
-ADD_TEST_EQ(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::HotnessCountdownOffset()))
-#define SHADOWFRAME_VREGS_OFFSET (SHADOWFRAME_NUMBER_OF_VREGS_OFFSET + 16)
-ADD_TEST_EQ(SHADOWFRAME_VREGS_OFFSET,
-            static_cast<int32_t>(art::ShadowFrame::VRegsOffset()))
-
-#if defined(USE_BROOKS_READ_BARRIER)
-#define MIRROR_OBJECT_HEADER_SIZE 16
-#else
-#define MIRROR_OBJECT_HEADER_SIZE 8
-#endif
-ADD_TEST_EQ(size_t(MIRROR_OBJECT_HEADER_SIZE), sizeof(art::mirror::Object))
-
-// Offsets within java.lang.Class.
-#define MIRROR_CLASS_COMPONENT_TYPE_OFFSET (4 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_CLASS_COMPONENT_TYPE_OFFSET,
-            art::mirror::Class::ComponentTypeOffset().Int32Value())
-#define MIRROR_CLASS_IF_TABLE_OFFSET (16 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_CLASS_IF_TABLE_OFFSET,
-            art::mirror::Class::IfTableOffset().Int32Value())
-#define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (56 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET,
-            art::mirror::Class::AccessFlagsOffset().Int32Value())
-#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (88 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET,
-            art::mirror::Class::ObjectSizeOffset().Int32Value())
-#define MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET (92 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET,
-            art::mirror::Class::ObjectSizeAllocFastPathOffset().Int32Value())
-#define MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET (96 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET,
-            art::mirror::Class::PrimitiveTypeOffset().Int32Value())
-#define MIRROR_CLASS_STATUS_OFFSET (104 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_CLASS_STATUS_OFFSET,
-            art::mirror::Class::StatusOffset().Int32Value())
-
-#define PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT 16
-ADD_TEST_EQ(PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT,
-            static_cast<int>(art::mirror::Class::kPrimitiveTypeSizeShiftShift))
-
-// Array offsets.
-#define MIRROR_ARRAY_LENGTH_OFFSET      MIRROR_OBJECT_HEADER_SIZE
-ADD_TEST_EQ(MIRROR_ARRAY_LENGTH_OFFSET, art::mirror::Array::LengthOffset().Int32Value())
-
-#define MIRROR_CHAR_ARRAY_DATA_OFFSET   (4 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_CHAR_ARRAY_DATA_OFFSET,
-            art::mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value())
-
-#define MIRROR_BOOLEAN_ARRAY_DATA_OFFSET MIRROR_CHAR_ARRAY_DATA_OFFSET
-ADD_TEST_EQ(MIRROR_BOOLEAN_ARRAY_DATA_OFFSET,
-            art::mirror::Array::DataOffset(sizeof(uint8_t)).Int32Value())
-
-#define MIRROR_BYTE_ARRAY_DATA_OFFSET MIRROR_CHAR_ARRAY_DATA_OFFSET
-ADD_TEST_EQ(MIRROR_BYTE_ARRAY_DATA_OFFSET,
-            art::mirror::Array::DataOffset(sizeof(int8_t)).Int32Value())
-
-#define MIRROR_SHORT_ARRAY_DATA_OFFSET MIRROR_CHAR_ARRAY_DATA_OFFSET
-ADD_TEST_EQ(MIRROR_SHORT_ARRAY_DATA_OFFSET,
-            art::mirror::Array::DataOffset(sizeof(int16_t)).Int32Value())
-
-#define MIRROR_INT_ARRAY_DATA_OFFSET MIRROR_CHAR_ARRAY_DATA_OFFSET
-ADD_TEST_EQ(MIRROR_INT_ARRAY_DATA_OFFSET,
-            art::mirror::Array::DataOffset(sizeof(int32_t)).Int32Value())
-
-#define MIRROR_WIDE_ARRAY_DATA_OFFSET (8 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_WIDE_ARRAY_DATA_OFFSET,
-            art::mirror::Array::DataOffset(sizeof(uint64_t)).Int32Value())
-
-#define MIRROR_OBJECT_ARRAY_DATA_OFFSET (4 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_OBJECT_ARRAY_DATA_OFFSET,
-    art::mirror::Array::DataOffset(
-        sizeof(art::mirror::HeapReference<art::mirror::Object>)).Int32Value())
-
-#define MIRROR_OBJECT_ARRAY_COMPONENT_SIZE 4
-ADD_TEST_EQ(static_cast<size_t>(MIRROR_OBJECT_ARRAY_COMPONENT_SIZE),
-            sizeof(art::mirror::HeapReference<art::mirror::Object>))
-
-#define MIRROR_LONG_ARRAY_DATA_OFFSET (8 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_LONG_ARRAY_DATA_OFFSET,
-            art::mirror::Array::DataOffset(sizeof(uint64_t)).Int32Value())
-
-// Offsets within java.lang.String.
-#define MIRROR_STRING_COUNT_OFFSET  MIRROR_OBJECT_HEADER_SIZE
-ADD_TEST_EQ(MIRROR_STRING_COUNT_OFFSET, art::mirror::String::CountOffset().Int32Value())
-
-#define MIRROR_STRING_VALUE_OFFSET (8 + MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(MIRROR_STRING_VALUE_OFFSET, art::mirror::String::ValueOffset().Int32Value())
-
-// String compression feature.
-#define STRING_COMPRESSION_FEATURE 1
-ADD_TEST_EQ(STRING_COMPRESSION_FEATURE, art::mirror::kUseStringCompression);
-
-#ifdef DEFINED_ADD_TEST_EQ
-#undef ADD_TEST_EQ
-#undef DEFINED_ADD_TEST_EQ
-#endif
+// Automatically generated header based on the asm_defines.def file.
+#include "asm_defines.h"
 
 #endif  // ART_RUNTIME_ASM_SUPPORT_H_
diff --git a/runtime/asm_support_check.h b/runtime/asm_support_check.h
deleted file mode 100644
index 3163506..0000000
--- a/runtime/asm_support_check.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_ASM_SUPPORT_CHECK_H_
-#define ART_RUNTIME_ASM_SUPPORT_CHECK_H_
-
-#include "art_method.h"
-#include "base/bit_utils.h"
-#include "base/callee_save_type.h"
-#include "gc/accounting/card_table.h"
-#include "gc/allocator/rosalloc.h"
-#include "gc/heap.h"
-#include "jit/jit.h"
-#include "lock_word.h"
-#include "mirror/class.h"
-#include "mirror/dex_cache.h"
-#include "mirror/string.h"
-#include "runtime.h"
-#include "stack.h"
-#include "thread.h"
-#include "utils/dex_cache_arrays_layout.h"
-
-#ifndef ADD_TEST_EQ
-#define ADD_TEST_EQ(x, y) CHECK_EQ(x, y);
-#endif
-
-#ifndef ASM_SUPPORT_CHECK_RETURN_TYPE
-#define ASM_SUPPORT_CHECK_RETURN_TYPE void
-#endif
-
-// Prepare for re-include of asm_support.h.
-#ifdef ART_RUNTIME_ASM_SUPPORT_H_
-#undef ART_RUNTIME_ASM_SUPPORT_H_
-#endif
-
-namespace art {
-
-static inline ASM_SUPPORT_CHECK_RETURN_TYPE CheckAsmSupportOffsetsAndSizes() {
-#ifdef ASM_SUPPORT_CHECK_HEADER
-  ASM_SUPPORT_CHECK_HEADER
-#endif
-
-#include "asm_support.h"
-
-#ifdef ASM_SUPPORT_CHECK_FOOTER
-  ASM_SUPPORT_CHECK_FOOTER
-#endif
-}
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_ASM_SUPPORT_CHECK_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5820ef0..7549c04 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -8935,7 +8935,7 @@
         self,
         kDexFileIndexStart + 1));
     DCHECK(h_long_array != nullptr);
-    h_long_array->Set(kDexFileIndexStart, reinterpret_cast<intptr_t>(dex_file));
+    h_long_array->Set(kDexFileIndexStart, reinterpret_cast64<int64_t>(dex_file));
 
     // Note that this creates a finalizable dalvik.system.DexFile object and a corresponding
     // FinalizerReference which will never get cleaned up without a started runtime.
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 832f1d7..4da0091 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -19,6 +19,7 @@
 #include <android-base/parseint.h>
 
 #include "art_field-inl.h"
+#include "base/casts.h"
 #include "base/dchecked_vector.h"
 #include "base/stl_util.h"
 #include "class_linker.h"
@@ -474,8 +475,8 @@
   int32_t long_array_size = long_array->GetLength();
   // Index 0 from the long array stores the oat file. The dex files start at index 1.
   for (int32_t j = 1; j < long_array_size; ++j) {
-    const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
-        long_array->GetWithoutChecks(j)));
+    const DexFile* cp_dex_file =
+        reinterpret_cast64<const DexFile*>(long_array->GetWithoutChecks(j));
     if (cp_dex_file != nullptr && cp_dex_file->NumClassDefs() > 0) {
       // TODO(calin): It's unclear why the dex files with no classes are skipped here and when
       // cp_dex_file can be null.
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
index c29043e..15ab5f0 100644
--- a/runtime/common_dex_operations.h
+++ b/runtime/common_dex_operations.h
@@ -27,6 +27,7 @@
 #include "dex/primitive.h"
 #include "handle_scope-inl.h"
 #include "instrumentation.h"
+#include "interpreter/interpreter.h"
 #include "interpreter/shadow_frame.h"
 #include "interpreter/unstarted_runtime.h"
 #include "jvalue-inl.h"
@@ -172,6 +173,14 @@
     if (UNLIKELY(self->IsExceptionPending())) {
       return false;
     }
+    if (shadow_frame.GetForcePopFrame()) {
+      // We need to check this here since we expect that the FieldWriteEvent happens before the
+      // actual field write. If one pops the stack we should not modify the field.  The next
+      // instruction will force a pop. Return true.
+      DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
+      DCHECK(interpreter::PrevFrameWillRetry(self, shadow_frame));
+      return true;
+    }
   }
 
   switch (field_type) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index fccfce4..84631c3 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -753,6 +753,7 @@
   const char* shorty = non_proxy_method->GetShorty(&shorty_len);
 
   JValue result;
+  bool force_frame_pop = false;
 
   if (UNLIKELY(deopt_frame != nullptr)) {
     HandleDeoptimization(&result, method, deopt_frame, &fragment);
@@ -788,6 +789,7 @@
     }
 
     result = interpreter::EnterInterpreterFromEntryPoint(self, accessor, shadow_frame);
+    force_frame_pop = shadow_frame->GetForcePopFrame();
   }
 
   // Pop transition.
@@ -804,12 +806,20 @@
       LOG(WARNING) << "Got a deoptimization request on un-deoptimizable method "
                    << caller->PrettyMethod();
     } else {
+      VLOG(deopt) << "Forcing deoptimization on return from method " << method->PrettyMethod()
+                  << " to " << caller->PrettyMethod()
+                  << (force_frame_pop ? " for frame-pop" : "");
+      DCHECK(!force_frame_pop || result.GetJ() == 0) << "Force frame pop should have no result.";
+      if (force_frame_pop && self->GetException() != nullptr) {
+        LOG(WARNING) << "Suppressing exception for instruction-retry: "
+                     << self->GetException()->Dump();
+      }
       // Push the context of the deoptimization stack so we can restore the return value and the
       // exception before executing the deoptimized frames.
       self->PushDeoptimizationContext(
           result,
           shorty[0] == 'L' || shorty[0] == '[',  /* class or array */
-          self->GetException(),
+          force_frame_pop ? nullptr : self->GetException(),
           false /* from_code */,
           DeoptimizationMethodType::kDefault);
 
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index ae9acd6d..46cc79c 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -573,8 +573,10 @@
     if (ref != nullptr) {
       if (!collector_->immune_spaces_.ContainsObject(ref.Ptr())) {
         // Not immune, must be a zygote large object.
-        CHECK(Runtime::Current()->GetHeap()->GetLargeObjectsSpace()->IsZygoteLargeObject(
-            Thread::Current(), ref.Ptr()))
+        space::LargeObjectSpace* large_object_space =
+            Runtime::Current()->GetHeap()->GetLargeObjectsSpace();
+        CHECK(large_object_space->Contains(ref.Ptr()) &&
+              large_object_space->IsZygoteLargeObject(Thread::Current(), ref.Ptr()))
             << "Non gray object references non immune, non zygote large object "<< ref << " "
             << mirror::Object::PrettyTypeOf(ref) << " in holder " << holder << " "
             << mirror::Object::PrettyTypeOf(holder) << " offset=" << offset.Uint32Value();
@@ -2960,7 +2962,13 @@
       // Since the mark bitmap is still filled in from last GC, we can not use that or else the
       // mutator may see references to the from space. Instead, use the Baker pointer itself as
       // the mark bit.
-      if (ref->AtomicSetReadBarrierState(ReadBarrier::NonGrayState(), ReadBarrier::GrayState())) {
+      //
+      // We need to avoid marking objects that are on allocation stack as that will lead to a
+      // situation (after this GC cycle is finished) where some object(s) are on both allocation
+      // stack and live bitmap. This leads to visiting the same object(s) twice during a heapdump
+      // (b/117426281).
+      if (!IsOnAllocStack(ref) &&
+          ref->AtomicSetReadBarrierState(ReadBarrier::NonGrayState(), ReadBarrier::GrayState())) {
         // TODO: We don't actually need to scan this object later, we just need to clear the gray
         // bit.
         // Also make sure the object is marked.
@@ -2969,6 +2977,8 @@
         } else {
           mark_bitmap->AtomicTestAndSet(ref);
         }
+        // We don't need to mark newly allocated objects (those in allocation stack) as they can
+        // only point to to-space objects. Also, they are considered live till the next GC cycle.
         PushOntoMarkStack(self, ref);
       }
       return ref;
diff --git a/runtime/gc/collector/immune_spaces_test.cc b/runtime/gc/collector/immune_spaces_test.cc
index 7bd87bd..3f85c71 100644
--- a/runtime/gc/collector/immune_spaces_test.cc
+++ b/runtime/gc/collector/immune_spaces_test.cc
@@ -125,8 +125,6 @@
         /*boot_oat_begin*/0u,
         /*boot_oat_size*/0u,
         /*pointer_size*/sizeof(void*),
-        /*compile_pic*/false,
-        /*is_pic*/false,
         ImageHeader::kStorageModeUncompressed,
         /*storage_size*/0u);
     return new DummyImageSpace(std::move(map),
diff --git a/runtime/image.cc b/runtime/image.cc
index bdf045b..a4351d0 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '3', '\0' };  // Image relocations.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '4', '\0' };  // Remove PIC flags.
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
@@ -42,8 +42,6 @@
                          uint32_t boot_oat_begin,
                          uint32_t boot_oat_size,
                          uint32_t pointer_size,
-                         bool compile_pic,
-                         bool is_pic,
                          StorageMode storage_mode,
                          size_t data_size)
   : image_begin_(image_begin),
@@ -60,8 +58,6 @@
     patch_delta_(0),
     image_roots_(image_roots),
     pointer_size_(pointer_size),
-    compile_pic_(compile_pic),
-    is_pic_(is_pic),
     storage_mode_(storage_mode),
     data_size_(data_size) {
   CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize));
diff --git a/runtime/image.h b/runtime/image.h
index 73c1b8f..bd8bc28 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -108,8 +108,6 @@
         patch_delta_(0),
         image_roots_(0U),
         pointer_size_(0U),
-        compile_pic_(0),
-        is_pic_(0),
         storage_mode_(kDefaultStorageMode),
         data_size_(0) {}
 
@@ -127,8 +125,6 @@
               uint32_t boot_oat_begin,
               uint32_t boot_oat_size,
               uint32_t pointer_size,
-              bool compile_pic,
-              bool is_pic,
               StorageMode storage_mode,
               size_t data_size);
 
@@ -318,14 +314,6 @@
   void RelocateImageMethods(int64_t delta);
   void RelocateImageObjects(int64_t delta);
 
-  bool CompilePic() const {
-    return compile_pic_ != 0;
-  }
-
-  bool IsPic() const {
-    return is_pic_ != 0;
-  }
-
   uint32_t GetBootImageBegin() const {
     return boot_image_begin_;
   }
@@ -442,14 +430,6 @@
   // Pointer size, this affects the size of the ArtMethods.
   uint32_t pointer_size_;
 
-  // Boolean (0 or 1) to denote if the image was compiled with --compile-pic option
-  const uint32_t compile_pic_;
-
-  // Boolean (0 or 1) to denote if the image can be mapped at a random address, this only refers to
-  // the .art file. Currently, app oat files do not depend on their app image. There are no pointers
-  // from the app oat code to the app image.
-  const uint32_t is_pic_;
-
   // Image section sizes/offsets correspond to the uncompressed form.
   ImageSection sections_[kSectionCount];
 
diff --git a/runtime/imt_conflict_table.h b/runtime/imt_conflict_table.h
index 3586864..02b3be4 100644
--- a/runtime/imt_conflict_table.h
+++ b/runtime/imt_conflict_table.h
@@ -187,17 +187,17 @@
 
   ArtMethod* GetMethod(size_t index, PointerSize pointer_size) const {
     if (pointer_size == PointerSize::k64) {
-      return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data64_[index]));
+      return reinterpret_cast64<ArtMethod*>(data64_[index]);
     } else {
-      return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data32_[index]));
+      return reinterpret_cast32<ArtMethod*>(data32_[index]);
     }
   }
 
   void SetMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
     if (pointer_size == PointerSize::k64) {
-      data64_[index] = dchecked_integral_cast<uint64_t>(reinterpret_cast<uintptr_t>(method));
+      data64_[index] = reinterpret_cast64<uint64_t>(method);
     } else {
-      data32_[index] = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(method));
+      data32_[index] = reinterpret_cast32<uint32_t>(method);
     }
   }
 
diff --git a/runtime/imtable.h b/runtime/imtable.h
index aa0a504..3c52fb8 100644
--- a/runtime/imtable.h
+++ b/runtime/imtable.h
@@ -21,6 +21,7 @@
 #error IMT_SIZE not defined
 #endif
 
+#include "base/casts.h"
 #include "base/enums.h"
 #include "base/macros.h"
 #include "base/mutex.h"
@@ -46,10 +47,10 @@
     uint8_t* ptr = AddressOfElement(index, pointer_size);
     if (pointer_size == PointerSize::k32) {
       uint32_t value = *reinterpret_cast<uint32_t*>(ptr);
-      return reinterpret_cast<ArtMethod*>(value);
+      return reinterpret_cast32<ArtMethod*>(value);
     } else {
       uint64_t value = *reinterpret_cast<uint64_t*>(ptr);
-      return reinterpret_cast<ArtMethod*>(value);
+      return reinterpret_cast64<ArtMethod*>(value);
     }
   }
 
@@ -57,11 +58,9 @@
     DCHECK_LT(index, kSize);
     uint8_t* ptr = AddressOfElement(index, pointer_size);
     if (pointer_size == PointerSize::k32) {
-      uintptr_t value = reinterpret_cast<uintptr_t>(method);
-      DCHECK_EQ(static_cast<uint32_t>(value), value);  // Check that we dont lose any non 0 bits.
-      *reinterpret_cast<uint32_t*>(ptr) = static_cast<uint32_t>(value);
+      *reinterpret_cast<uint32_t*>(ptr) = reinterpret_cast32<uint32_t>(method);
     } else {
-      *reinterpret_cast<uint64_t*>(ptr) = reinterpret_cast<uint64_t>(method);
+      *reinterpret_cast<uint64_t*>(ptr) = reinterpret_cast64<uint64_t>(method);
     }
   }
 
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index df66061..2ae95dc 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -261,6 +261,12 @@
                                         shadow_frame.GetThisObject(accessor.InsSize()),
                                         method,
                                         0);
+      if (UNLIKELY(shadow_frame.GetForcePopFrame())) {
+        // The caller will retry this invoke. Just return immediately without any value.
+        DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
+        DCHECK(PrevFrameWillRetry(self, shadow_frame));
+        return JValue();
+      }
       if (UNLIKELY(self->IsExceptionPending())) {
         instrumentation->MethodUnwindEvent(self,
                                            shadow_frame.GetThisObject(accessor.InsSize()),
@@ -494,8 +500,8 @@
   JValue value;
   // Set value to last known result in case the shadow frame chain is empty.
   value.SetJ(ret_val->GetJ());
-  // Are we executing the first shadow frame?
-  bool first = true;
+  // How many frames we have executed.
+  size_t frame_cnt = 0;
   while (shadow_frame != nullptr) {
     // We do not want to recover lock state for lock counting when deoptimizing. Currently,
     // the compiler should not have compiled a method that failed structured-locking checks.
@@ -510,24 +516,30 @@
       // the instrumentation. To prevent from reporting it a second time, we simply pass a
       // null Instrumentation*.
       const instrumentation::Instrumentation* const instrumentation =
-          first ? nullptr : Runtime::Current()->GetInstrumentation();
+          frame_cnt == 0 ? nullptr : Runtime::Current()->GetInstrumentation();
       new_dex_pc = MoveToExceptionHandler(
           self, *shadow_frame, instrumentation) ? shadow_frame->GetDexPC() : dex::kDexNoIndex;
     } else if (!from_code) {
       // Deoptimization is not called from code directly.
       const Instruction* instr = &accessor.InstructionAt(dex_pc);
-      if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc) {
-        DCHECK(first);
+      if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc ||
+          shadow_frame->GetForceRetryInstruction()) {
+        DCHECK(frame_cnt == 0 || (frame_cnt == 1 && shadow_frame->GetForceRetryInstruction()))
+            << "frame_cnt: " << frame_cnt
+            << " force-retry: " << shadow_frame->GetForceRetryInstruction();
         // Need to re-execute the dex instruction.
         // (1) An invocation might be split into class initialization and invoke.
         //     In this case, the invoke should not be skipped.
         // (2) A suspend check should also execute the dex instruction at the
         //     corresponding dex pc.
+        // If the ForceRetryInstruction bit is set this must be the second frame (the first being
+        // the one that is being popped).
         DCHECK_EQ(new_dex_pc, dex_pc);
+        shadow_frame->SetForceRetryInstruction(false);
       } else if (instr->Opcode() == Instruction::MONITOR_ENTER ||
                  instr->Opcode() == Instruction::MONITOR_EXIT) {
         DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault);
-        DCHECK(first);
+        DCHECK_EQ(frame_cnt, 0u);
         // Non-idempotent dex instruction should not be re-executed.
         // On the other hand, if a MONITOR_ENTER is at the dex_pc of a suspend
         // check, that MONITOR_ENTER should be executed. That case is handled
@@ -553,7 +565,7 @@
         DCHECK_EQ(new_dex_pc, dex_pc);
       } else {
         DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault);
-        DCHECK(first);
+        DCHECK_EQ(frame_cnt, 0u);
         // By default, we re-execute the dex instruction since if they are not
         // an invoke, so that we don't have to decode the dex instruction to move
         // result into the right vreg. All slow paths have been audited to be
@@ -566,7 +578,7 @@
     } else {
       // Nothing to do, the dex_pc is the one at which the code requested
       // the deoptimization.
-      DCHECK(first);
+      DCHECK_EQ(frame_cnt, 0u);
       DCHECK_EQ(new_dex_pc, dex_pc);
     }
     if (new_dex_pc != dex::kDexNoIndex) {
@@ -585,7 +597,7 @@
     // and should advance dex pc past the invoke instruction.
     from_code = false;
     deopt_method_type = DeoptimizationMethodType::kDefault;
-    first = false;
+    frame_cnt++;
   }
   ret_val->SetJ(value.GetJ());
 }
@@ -657,5 +669,18 @@
   InitMterpTls(self);
 }
 
+bool PrevFrameWillRetry(Thread* self, const ShadowFrame& frame) {
+  ShadowFrame* prev_frame = frame.GetLink();
+  if (prev_frame == nullptr) {
+    NthCallerVisitor vis(self, 1, false);
+    vis.WalkStack();
+    prev_frame = vis.GetCurrentShadowFrame();
+    if (prev_frame == nullptr) {
+      prev_frame = self->FindDebuggerShadowFrame(vis.GetFrameId());
+    }
+  }
+  return prev_frame != nullptr && prev_frame->GetForceRetryInstruction();
+}
+
 }  // namespace interpreter
 }  // namespace art
diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h
index 0d43b90..d7e69a6 100644
--- a/runtime/interpreter/interpreter.h
+++ b/runtime/interpreter/interpreter.h
@@ -69,6 +69,12 @@
 
 void InitInterpreterTls(Thread* self);
 
+// Returns true if the previous frame has the ForceRetryInstruction bit set. This is required for
+// ForPopFrame to work correctly since that will cause the java function return with null/0 which
+// might not be expected by the code being run.
+bool PrevFrameWillRetry(Thread* self, const ShadowFrame& frame)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
 }  // namespace interpreter
 
 }  // namespace art
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 6577726..b170232 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -18,6 +18,7 @@
 
 #include <cmath>
 
+#include "base/casts.h"
 #include "base/enums.h"
 #include "class_root.h"
 #include "debugger.h"
@@ -371,6 +372,12 @@
     if (UNLIKELY(self->IsExceptionPending())) {
       return false;
     }
+    if (UNLIKELY(shadow_frame.GetForcePopFrame())) {
+      // Don't actually set the field. The next instruction will force us to pop.
+      DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
+      DCHECK(PrevFrameWillRetry(self, shadow_frame));
+      return true;
+    }
   }
   // Note: iput-x-quick instructions are only for non-volatile fields.
   switch (field_type) {
@@ -440,6 +447,11 @@
       self->IsExceptionThrownByCurrentMethod(exception.Get())) {
     // See b/65049545 for why we don't need to check to see if the exception has changed.
     instrumentation->ExceptionThrownEvent(self, exception.Get());
+    if (shadow_frame.GetForcePopFrame()) {
+      // We will check in the caller for GetForcePopFrame again. We need to bail out early to
+      // prevent an ExceptionHandledEvent from also being sent before popping.
+      return true;
+    }
   }
   bool clear_exception = false;
   uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(
@@ -584,10 +596,10 @@
   for (uint32_t i = 0, e = shadow_frame->NumberOfVRegs(); i < e; ++i) {
     if (shadow_frame->GetVRegReference(i) == existing) {
       DCHECK_EQ(shadow_frame->GetVRegReference(i),
-                reinterpret_cast<mirror::Object*>(static_cast<uint32_t>(shadow_frame->GetVReg(i))));
+                reinterpret_cast32<mirror::Object*>(shadow_frame->GetVReg(i)));
       shadow_frame->SetVRegReference(i, result.GetL());
       DCHECK_EQ(shadow_frame->GetVRegReference(i),
-                reinterpret_cast<mirror::Object*>(static_cast<uint32_t>(shadow_frame->GetVReg(i))));
+                reinterpret_cast32<mirror::Object*>(shadow_frame->GetVReg(i)));
     }
   }
 }
@@ -1445,7 +1457,7 @@
   // If both register locations contains the same value, the register probably holds a reference.
   // Note: As an optimization, non-moving collectors leave a stale reference value
   // in the references array even after the original vreg was overwritten to a non-reference.
-  if (src_value == reinterpret_cast<uintptr_t>(o.Ptr())) {
+  if (src_value == reinterpret_cast32<uint32_t>(o.Ptr())) {
     new_shadow_frame->SetVRegReference(dest_reg, o);
   } else {
     new_shadow_frame->SetVReg(dest_reg, src_value);
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 04935cf..cb64ff4 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -24,16 +24,39 @@
 #include "interpreter_common.h"
 #include "jit/jit.h"
 #include "jvalue-inl.h"
+#include "nth_caller_visitor.h"
 #include "safe_math.h"
 #include "shadow_frame-inl.h"
+#include "thread.h"
 
 namespace art {
 namespace interpreter {
 
+#define CHECK_FORCE_RETURN()                                                        \
+  do {                                                                              \
+    if (UNLIKELY(shadow_frame.GetForcePopFrame())) {                                \
+      DCHECK(PrevFrameWillRetry(self, shadow_frame))                                \
+          << "Pop frame forced without previous frame ready to retry instruction!"; \
+      DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());                     \
+      if (UNLIKELY(NeedsMethodExitEvent(instrumentation))) {                        \
+        SendMethodExitEvents(self,                                                  \
+                             instrumentation,                                       \
+                             shadow_frame,                                          \
+                             shadow_frame.GetThisObject(accessor.InsSize()),        \
+                             shadow_frame.GetMethod(),                              \
+                             inst->GetDexPc(insns),                                 \
+                             JValue());                                             \
+      }                                                                             \
+      ctx->result = JValue(); /* Handled in caller. */                              \
+      return;                                                                       \
+    }                                                                               \
+  } while (false)
+
 #define HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instr)                                    \
   do {                                                                                          \
     DCHECK(self->IsExceptionPending());                                                         \
     self->AllowThreadSuspension();                                                              \
+    CHECK_FORCE_RETURN();                                                                       \
     if (!MoveToExceptionHandler(self, shadow_frame, instr)) {                                   \
       /* Structured locking is to be enforced for abnormal termination, too. */                 \
       DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame);                        \
@@ -44,6 +67,7 @@
       ctx->result = JValue(); /* Handled in caller. */                                          \
       return;                                                                                   \
     } else {                                                                                    \
+      CHECK_FORCE_RETURN();                                                                     \
       int32_t displacement =                                                                    \
           static_cast<int32_t>(shadow_frame.GetDexPC()) - static_cast<int32_t>(dex_pc);         \
       inst = inst->RelativeAt(displacement);                                                    \
@@ -52,8 +76,39 @@
 
 #define HANDLE_PENDING_EXCEPTION() HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(instrumentation)
 
+#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, _next_function) \
+  do {                                                                                          \
+    if (UNLIKELY(shadow_frame.GetForceRetryInstruction())) {                                    \
+      /* Don't need to do anything except clear the flag and exception. We leave the */         \
+      /* instruction the same so it will be re-executed on the next go-around.       */         \
+      DCHECK(inst->IsInvoke());                                                                 \
+      shadow_frame.SetForceRetryInstruction(false);                                             \
+      if (UNLIKELY(_is_exception_pending)) {                                                    \
+        DCHECK(self->IsExceptionPending());                                                     \
+        if (kIsDebugBuild) {                                                                    \
+          LOG(WARNING) << "Suppressing exception for instruction-retry: "                       \
+                       << self->GetException()->Dump();                                         \
+        }                                                                                       \
+        self->ClearException();                                                                 \
+      }                                                                                         \
+    } else if (UNLIKELY(_is_exception_pending)) {                                               \
+      /* Should have succeeded. */                                                              \
+      DCHECK(!shadow_frame.GetForceRetryInstruction());                                         \
+      HANDLE_PENDING_EXCEPTION();                                                               \
+    } else {                                                                                    \
+      inst = inst->_next_function();                                                            \
+    }                                                                                           \
+  } while (false)
+
+#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(_is_exception_pending) \
+  POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_4xx)
+#define POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(_is_exception_pending) \
+  POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL(_is_exception_pending, Next_3xx)
+
 #define POSSIBLY_HANDLE_PENDING_EXCEPTION(_is_exception_pending, _next_function)  \
   do {                                                                            \
+    /* Should only be on invoke instructions. */                                  \
+    DCHECK(!shadow_frame.GetForceRetryInstruction());                             \
     if (UNLIKELY(_is_exception_pending)) {                                        \
       HANDLE_PENDING_EXCEPTION();                                                 \
     } else {                                                                      \
@@ -67,17 +122,22 @@
   }
 
 // Code to run before each dex instruction.
-#define PREAMBLE_SAVE(save_ref)                                                                      \
+#define PREAMBLE_SAVE(save_ref)                                                                 \
   {                                                                                             \
-    if (UNLIKELY(instrumentation->HasDexPcListeners()) &&                                       \
-        UNLIKELY(!DoDexPcMoveEvent(self,                                                        \
-                                   accessor,                                                    \
-                                   shadow_frame,                                                \
-                                   dex_pc,                                                      \
-                                   instrumentation,                                             \
-                                   save_ref))) {                                                \
-      HANDLE_PENDING_EXCEPTION();                                                               \
-      break;                                                                                    \
+    /* We need to put this before & after the instrumentation to avoid having to put in a */    \
+    /* post-script macro.                                                                 */    \
+    CHECK_FORCE_RETURN();                                                                       \
+    if (UNLIKELY(instrumentation->HasDexPcListeners())) {                                       \
+      if (UNLIKELY(!DoDexPcMoveEvent(self,                                                      \
+                                     accessor,                                                  \
+                                     shadow_frame,                                              \
+                                     dex_pc,                                                    \
+                                     instrumentation,                                           \
+                                     save_ref))) {                                              \
+        HANDLE_PENDING_EXCEPTION();                                                             \
+        break;                                                                                  \
+      }                                                                                         \
+      CHECK_FORCE_RETURN();                                                                     \
     }                                                                                           \
   }                                                                                             \
   do {} while (false)
@@ -181,7 +241,8 @@
                                            const JValue& result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   bool had_event = false;
-  if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+  // We don't send method-exit if it's a pop-frame. We still send frame_popped though.
+  if (UNLIKELY(instrumentation->HasMethodExitListeners() && !frame.GetForcePopFrame())) {
     had_event = true;
     instrumentation->MethodExitEvent(self, thiz.Ptr(), method, dex_pc, result);
   }
@@ -221,6 +282,9 @@
   uint16_t inst_data;
   jit::Jit* jit = Runtime::Current()->GetJit();
 
+  DCHECK(!shadow_frame.GetForceRetryInstruction())
+      << "Entered interpreter from invoke without retry instruction being handled!";
+
   do {
     dex_pc = inst->GetDexPc(insns);
     shadow_frame.SetDexPC(dex_pc);
@@ -1607,84 +1671,84 @@
         PREAMBLE();
         bool success = DoInvoke<kVirtual, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_VIRTUAL_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kVirtual, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_SUPER: {
         PREAMBLE();
         bool success = DoInvoke<kSuper, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_SUPER_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kSuper, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_DIRECT: {
         PREAMBLE();
         bool success = DoInvoke<kDirect, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_DIRECT_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kDirect, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_INTERFACE: {
         PREAMBLE();
         bool success = DoInvoke<kInterface, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_INTERFACE_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kInterface, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_STATIC: {
         PREAMBLE();
         bool success = DoInvoke<kStatic, false, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_STATIC_RANGE: {
         PREAMBLE();
         bool success = DoInvoke<kStatic, true, do_access_check>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_VIRTUAL_QUICK: {
         PREAMBLE();
         bool success = DoInvokeVirtualQuick<false>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
         PREAMBLE();
         bool success = DoInvokeVirtualQuick<true>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_POLYMORPHIC: {
@@ -1692,7 +1756,7 @@
         DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
         bool success = DoInvokePolymorphic<false /* is_range */>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_4xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
         break;
       }
       case Instruction::INVOKE_POLYMORPHIC_RANGE: {
@@ -1700,7 +1764,7 @@
         DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
         bool success = DoInvokePolymorphic<true /* is_range */>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_4xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
         break;
       }
       case Instruction::INVOKE_CUSTOM: {
@@ -1708,7 +1772,7 @@
         DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
         bool success = DoInvokeCustom<false /* is_range */>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::INVOKE_CUSTOM_RANGE: {
@@ -1716,7 +1780,7 @@
         DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
         bool success = DoInvokeCustom<true /* is_range */>(
             self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
         break;
       }
       case Instruction::NEG_INT:
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index fbc96f7..c385fb9 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -152,6 +152,11 @@
   const instrumentation::Instrumentation* const instrumentation = runtime->GetInstrumentation();
   return instrumentation->NonJitProfilingActive() ||
       Dbg::IsDebuggerActive() ||
+      // mterp only knows how to deal with the normal exits. It cannot handle any of the
+      // non-standard force-returns.
+      // TODO We really only need to switch interpreters if a PopFrame has actually happened. We
+      // should check this here.
+      UNLIKELY(runtime->AreNonStandardExitsEnabled()) ||
       // An async exception has been thrown. We need to go to the switch interpreter. MTerp doesn't
       // know how to deal with these so we could end up never dealing with it if we are in an
       // infinite loop. Since this can be called in a tight loop and getting the current thread
diff --git a/runtime/interpreter/shadow_frame.h b/runtime/interpreter/shadow_frame.h
index 91371d1..c0920a8 100644
--- a/runtime/interpreter/shadow_frame.h
+++ b/runtime/interpreter/shadow_frame.h
@@ -49,6 +49,17 @@
 //  - interpreter - separate VRegs and reference arrays. References are in the reference array.
 //  - JNI - just VRegs, but where every VReg holds a reference.
 class ShadowFrame {
+ private:
+  // Used to keep track of extra state the shadowframe has.
+  enum class FrameFlags : uint32_t {
+    // We have been requested to notify when this frame gets popped.
+    kNotifyFramePop = 1 << 0,
+    // We have been asked to pop this frame off the stack as soon as possible.
+    kForcePopFrame  = 1 << 1,
+    // We have been asked to re-execute the last instruction.
+    kForceRetryInst = 1 << 2,
+  };
+
  public:
   // Compute size of ShadowFrame in bytes assuming it has a reference array.
   static size_t ComputeSize(uint32_t num_vregs) {
@@ -179,12 +190,8 @@
   mirror::Object* GetVRegReference(size_t i) const REQUIRES_SHARED(Locks::mutator_lock_) {
     DCHECK_LT(i, NumberOfVRegs());
     mirror::Object* ref;
-    if (HasReferenceArray()) {
-      ref = References()[i].AsMirrorPtr();
-    } else {
-      const uint32_t* vreg_ptr = &vregs_[i];
-      ref = reinterpret_cast<const StackReference<mirror::Object>*>(vreg_ptr)->AsMirrorPtr();
-    }
+    DCHECK(HasReferenceArray());
+    ref = References()[i].AsMirrorPtr();
     ReadBarrier::MaybeAssertToSpaceInvariant(ref);
     if (kVerifyFlags & kVerifyReads) {
       VerifyObject(ref);
@@ -345,11 +352,27 @@
   }
 
   bool NeedsNotifyPop() const {
-    return needs_notify_pop_;
+    return GetFrameFlag(FrameFlags::kNotifyFramePop);
   }
 
   void SetNotifyPop(bool notify) {
-    needs_notify_pop_ = notify;
+    UpdateFrameFlag(notify, FrameFlags::kNotifyFramePop);
+  }
+
+  bool GetForcePopFrame() const {
+    return GetFrameFlag(FrameFlags::kForcePopFrame);
+  }
+
+  void SetForcePopFrame(bool enable) {
+    UpdateFrameFlag(enable, FrameFlags::kForcePopFrame);
+  }
+
+  bool GetForceRetryInstruction() const {
+    return GetFrameFlag(FrameFlags::kForceRetryInst);
+  }
+
+  void SetForceRetryInstruction(bool enable) {
+    UpdateFrameFlag(enable, FrameFlags::kForceRetryInst);
   }
 
  private:
@@ -364,7 +387,7 @@
         dex_pc_(dex_pc),
         cached_hotness_countdown_(0),
         hotness_countdown_(0),
-        needs_notify_pop_(0) {
+        frame_flags_(0) {
     // TODO(iam): Remove this parameter, it's an an artifact of portable removal
     DCHECK(has_reference_array);
     if (has_reference_array) {
@@ -374,6 +397,18 @@
     }
   }
 
+  void UpdateFrameFlag(bool enable, FrameFlags flag) {
+    if (enable) {
+      frame_flags_ |= static_cast<uint32_t>(flag);
+    } else {
+      frame_flags_ &= ~static_cast<uint32_t>(flag);
+    }
+  }
+
+  bool GetFrameFlag(FrameFlags flag) const {
+    return (frame_flags_ & static_cast<uint32_t>(flag)) != 0;
+  }
+
   const StackReference<mirror::Object>* References() const {
     DCHECK(HasReferenceArray());
     const uint32_t* vreg_end = &vregs_[NumberOfVRegs()];
@@ -397,9 +432,11 @@
   uint32_t dex_pc_;
   int16_t cached_hotness_countdown_;
   int16_t hotness_countdown_;
-  // TODO Might be worth it to try to bit-pack this into some other field to reduce stack usage.
-  // NB alignment requires that this field takes 4 bytes. Only 1 bit is actually ever used.
-  bool needs_notify_pop_;
+
+  // This is a set of ShadowFrame::FrameFlags which denote special states this frame is in.
+  // NB alignment requires that this field takes 4 bytes no matter its size. Only 3 bits are
+  // currently used.
+  uint32_t frame_flags_;
 
   // This is a two-part array:
   //  - [0..number_of_vregs) holds the raw virtual registers, and each element here is always 4
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 4cd3782..38ecc5a 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -638,7 +638,7 @@
   }
 
   uint32_t args[1];
-  args[0] = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h_array.Get()));
+  args[0] = reinterpret_cast32<uint32_t>(h_array.Get());
   EnterInterpreterFromInvoke(self, constructor, h_obj.Get(), args, nullptr);
 
   if (self->IsExceptionPending()) {
@@ -1691,14 +1691,21 @@
 }
 
 void UnstartedRuntime::UnstartedJNIVMRuntimeNewUnpaddedArray(
-    Thread* self, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED,
-    uint32_t* args, JValue* result) {
+    Thread* self,
+    ArtMethod* method ATTRIBUTE_UNUSED,
+    mirror::Object* receiver ATTRIBUTE_UNUSED,
+    uint32_t* args,
+    JValue* result) {
   int32_t length = args[1];
   DCHECK_GE(length, 0);
-  ObjPtr<mirror::Class> element_class = reinterpret_cast<mirror::Object*>(args[0])->AsClass();
+  ObjPtr<mirror::Object> element_class = reinterpret_cast32<mirror::Object*>(args[0])->AsClass();
+  if (element_class == nullptr) {
+    AbortTransactionOrFail(self, "VMRuntime.newUnpaddedArray with null element_class.");
+    return;
+  }
   Runtime* runtime = Runtime::Current();
   ObjPtr<mirror::Class> array_class =
-      runtime->GetClassLinker()->FindArrayClass(self, element_class);
+      runtime->GetClassLinker()->FindArrayClass(self, element_class->AsClass());
   DCHECK(array_class != nullptr);
   gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
   result->SetL(mirror::Array::Alloc<true, true>(self,
@@ -1789,14 +1796,17 @@
   receiver->NotifyAll(self);
 }
 
-void UnstartedRuntime::UnstartedJNIStringCompareTo(
-    Thread* self, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver, uint32_t* args,
-    JValue* result) {
-  mirror::String* rhs = reinterpret_cast<mirror::Object*>(args[0])->AsString();
+void UnstartedRuntime::UnstartedJNIStringCompareTo(Thread* self,
+                                                   ArtMethod* method ATTRIBUTE_UNUSED,
+                                                   mirror::Object* receiver,
+                                                   uint32_t* args,
+                                                   JValue* result) {
+  ObjPtr<mirror::Object> rhs = reinterpret_cast32<mirror::Object*>(args[0]);
   if (rhs == nullptr) {
-    AbortTransactionOrFail(self, "String.compareTo with null object");
+    AbortTransactionOrFail(self, "String.compareTo with null object.");
+    return;
   }
-  result->SetI(receiver->AsString()->CompareTo(rhs));
+  result->SetI(receiver->AsString()->CompareTo(rhs->AsString()));
 }
 
 void UnstartedRuntime::UnstartedJNIStringIntern(
@@ -1854,9 +1864,16 @@
 }
 
 void UnstartedRuntime::UnstartedJNIUnsafeCompareAndSwapInt(
-    Thread* self ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED,
-    mirror::Object* receiver ATTRIBUTE_UNUSED, uint32_t* args, JValue* result) {
-  mirror::Object* obj = reinterpret_cast<mirror::Object*>(args[0]);
+    Thread* self,
+    ArtMethod* method ATTRIBUTE_UNUSED,
+    mirror::Object* receiver ATTRIBUTE_UNUSED,
+    uint32_t* args,
+    JValue* result) {
+  ObjPtr<mirror::Object> obj = reinterpret_cast32<mirror::Object*>(args[0]);
+  if (obj == nullptr) {
+    AbortTransactionOrFail(self, "Unsafe.compareAndSwapInt with null object.");
+    return;
+  }
   jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
   jint expectedValue = args[3];
   jint newValue = args[4];
@@ -1877,12 +1894,14 @@
   result->SetZ(success ? JNI_TRUE : JNI_FALSE);
 }
 
-void UnstartedRuntime::UnstartedJNIUnsafeGetIntVolatile(
-    Thread* self, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED,
-    uint32_t* args, JValue* result) {
-  mirror::Object* obj = reinterpret_cast<mirror::Object*>(args[0]);
+void UnstartedRuntime::UnstartedJNIUnsafeGetIntVolatile(Thread* self,
+                                                        ArtMethod* method ATTRIBUTE_UNUSED,
+                                                        mirror::Object* receiver ATTRIBUTE_UNUSED,
+                                                        uint32_t* args,
+                                                        JValue* result) {
+  ObjPtr<mirror::Object> obj = reinterpret_cast32<mirror::Object*>(args[0]);
   if (obj == nullptr) {
-    AbortTransactionOrFail(self, "Cannot access null object, retry at runtime.");
+    AbortTransactionOrFail(self, "Unsafe.compareAndSwapIntVolatile with null object.");
     return;
   }
 
@@ -1890,12 +1909,18 @@
   result->SetI(obj->GetField32Volatile(MemberOffset(offset)));
 }
 
-void UnstartedRuntime::UnstartedJNIUnsafePutObject(
-    Thread* self ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED,
-    mirror::Object* receiver ATTRIBUTE_UNUSED, uint32_t* args, JValue* result ATTRIBUTE_UNUSED) {
-  mirror::Object* obj = reinterpret_cast<mirror::Object*>(args[0]);
+void UnstartedRuntime::UnstartedJNIUnsafePutObject(Thread* self,
+                                                   ArtMethod* method ATTRIBUTE_UNUSED,
+                                                   mirror::Object* receiver ATTRIBUTE_UNUSED,
+                                                   uint32_t* args,
+                                                   JValue* result ATTRIBUTE_UNUSED) {
+  ObjPtr<mirror::Object> obj = reinterpret_cast32<mirror::Object*>(args[0]);
+  if (obj == nullptr) {
+    AbortTransactionOrFail(self, "Unsafe.putObject with null object.");
+    return;
+  }
   jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
-  mirror::Object* newValue = reinterpret_cast<mirror::Object*>(args[3]);
+  ObjPtr<mirror::Object> newValue = reinterpret_cast32<mirror::Object*>(args[3]);
   if (Runtime::Current()->IsActiveTransaction()) {
     obj->SetFieldObject<true>(MemberOffset(offset), newValue);
   } else {
@@ -1904,18 +1929,32 @@
 }
 
 void UnstartedRuntime::UnstartedJNIUnsafeGetArrayBaseOffsetForComponentType(
-    Thread* self ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED,
-    mirror::Object* receiver ATTRIBUTE_UNUSED, uint32_t* args, JValue* result) {
-  ObjPtr<mirror::Class> component = reinterpret_cast<mirror::Object*>(args[0])->AsClass();
-  Primitive::Type primitive_type = component->GetPrimitiveType();
+    Thread* self,
+    ArtMethod* method ATTRIBUTE_UNUSED,
+    mirror::Object* receiver ATTRIBUTE_UNUSED,
+    uint32_t* args,
+    JValue* result) {
+  ObjPtr<mirror::Object> component = reinterpret_cast32<mirror::Object*>(args[0]);
+  if (component == nullptr) {
+    AbortTransactionOrFail(self, "Unsafe.getArrayBaseOffsetForComponentType with null component.");
+    return;
+  }
+  Primitive::Type primitive_type = component->AsClass()->GetPrimitiveType();
   result->SetI(mirror::Array::DataOffset(Primitive::ComponentSize(primitive_type)).Int32Value());
 }
 
 void UnstartedRuntime::UnstartedJNIUnsafeGetArrayIndexScaleForComponentType(
-    Thread* self ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED,
-    mirror::Object* receiver ATTRIBUTE_UNUSED, uint32_t* args, JValue* result) {
-  ObjPtr<mirror::Class> component = reinterpret_cast<mirror::Object*>(args[0])->AsClass();
-  Primitive::Type primitive_type = component->GetPrimitiveType();
+    Thread* self,
+    ArtMethod* method ATTRIBUTE_UNUSED,
+    mirror::Object* receiver ATTRIBUTE_UNUSED,
+    uint32_t* args,
+    JValue* result) {
+  ObjPtr<mirror::Object> component = reinterpret_cast32<mirror::Object*>(args[0]);
+  if (component == nullptr) {
+    AbortTransactionOrFail(self, "Unsafe.getArrayIndexScaleForComponentType with null component.");
+    return;
+  }
+  Primitive::Type primitive_type = component->AsClass()->GetPrimitiveType();
   result->SetI(Primitive::ComponentSize(primitive_type));
 }
 
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index ba99a07..4391910 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -18,6 +18,7 @@
 
 #include "array-inl.h"
 #include "art_field-inl.h"
+#include "base/casts.h"
 #include "class-inl.h"
 #include "class_linker.h"
 #include "class_root.h"
@@ -1680,8 +1681,7 @@
 }
 
 ArtField* FieldVarHandle::GetField() {
-  uintptr_t opaque_field = static_cast<uintptr_t>(GetField64(ArtFieldOffset()));
-  return reinterpret_cast<ArtField*>(opaque_field);
+  return reinterpret_cast64<ArtField*>(GetField64(ArtFieldOffset()));
 }
 
 bool FieldVarHandle::Access(AccessMode access_mode,
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 0d1fe44..36f9b1a 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -20,6 +20,7 @@
 
 #include "android-base/stringprintf.h"
 
+#include "base/casts.h"
 #include "base/file_utils.h"
 #include "base/logging.h"
 #include "base/os.h"
@@ -74,10 +75,10 @@
     return false;
   }
 
-  oat_file = reinterpret_cast<const OatFile*>(static_cast<uintptr_t>(long_data[kOatFileIndex]));
+  oat_file = reinterpret_cast64<const OatFile*>(long_data[kOatFileIndex]);
   dex_files.reserve(array_size - 1);
   for (jsize i = kDexFileIndexStart; i < array_size; ++i) {
-    dex_files.push_back(reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(long_data[i])));
+    dex_files.push_back(reinterpret_cast64<const DexFile*>(long_data[i]));
   }
 
   env->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array), long_data, JNI_ABORT);
@@ -99,9 +100,9 @@
     return nullptr;
   }
 
-  long_data[kOatFileIndex] = reinterpret_cast<uintptr_t>(oat_file);
+  long_data[kOatFileIndex] = reinterpret_cast64<jlong>(oat_file);
   for (size_t i = 0; i < vec.size(); ++i) {
-    long_data[kDexFileIndexStart + i] = reinterpret_cast<uintptr_t>(vec[i].get());
+    long_data[kDexFileIndexStart + i] = reinterpret_cast64<jlong>(vec[i].get());
   }
 
   env->ReleaseLongArrayElements(long_array, long_data, 0);
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index b18a048..861d1db 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -682,6 +682,11 @@
   Runtime::Current()->SetProcessPackageName(package_name.c_str());
 }
 
+static jboolean VMRuntime_hasBootImageSpaces(JNIEnv* env ATTRIBUTE_UNUSED,
+                                             jclass klass ATTRIBUTE_UNUSED) {
+  return Runtime::Current()->GetHeap()->HasBootImageSpace() ? JNI_TRUE : JNI_FALSE;
+}
+
 static JNINativeMethod gMethods[] = {
   FAST_NATIVE_METHOD(VMRuntime, addressOf, "(Ljava/lang/Object;)J"),
   NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
@@ -690,6 +695,7 @@
   NATIVE_METHOD(VMRuntime, clearGrowthLimit, "()V"),
   NATIVE_METHOD(VMRuntime, concurrentGC, "()V"),
   NATIVE_METHOD(VMRuntime, disableJitCompilation, "()V"),
+  FAST_NATIVE_METHOD(VMRuntime, hasBootImageSpaces, "()Z"),  // Could be CRITICAL.
   NATIVE_METHOD(VMRuntime, hasUsedHiddenApi, "()Z"),
   NATIVE_METHOD(VMRuntime, setHiddenApiExemptions, "([Ljava/lang/String;)V"),
   NATIVE_METHOD(VMRuntime, setHiddenApiAccessLogSamplingRate, "(I)V"),
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index e882e73..36a6b7f 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -402,6 +402,8 @@
   bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
     exception_handler_->SetHandlerFrameDepth(GetFrameDepth());
     ArtMethod* method = GetMethod();
+    VLOG(deopt) << "Deoptimizing stack: depth: " << GetFrameDepth()
+                << " at method " << ArtMethod::PrettyMethod(method);
     if (method == nullptr || single_frame_done_) {
       FinishStackWalk();
       return false;  // End stack walk.
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index 374591e..bde0d11 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -22,6 +22,7 @@
 #include "arch/instruction_set.h"
 #include "art_method.h"
 #include "base/callee_save_type.h"
+#include "base/casts.h"
 #include "entrypoints/quick/callee_save_frame.h"
 #include "gc_root-inl.h"
 #include "obj_ptr-inl.h"
@@ -82,7 +83,7 @@
 
 inline ArtMethod* Runtime::GetCalleeSaveMethodUnchecked(CalleeSaveType type)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  return reinterpret_cast<ArtMethod*>(callee_save_methods_[static_cast<size_t>(type)]);
+  return reinterpret_cast64<ArtMethod*>(callee_save_methods_[static_cast<size_t>(type)]);
 }
 
 }  // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7787a93..b3a2bdd 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -49,7 +49,6 @@
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "asm_support.h"
-#include "asm_support_check.h"
 #include "base/aborting.h"
 #include "base/arena_allocator.h"
 #include "base/atomic.h"
@@ -257,6 +256,7 @@
       is_native_bridge_loaded_(false),
       is_native_debuggable_(false),
       async_exceptions_thrown_(false),
+      non_standard_exits_enabled_(false),
       is_java_debuggable_(false),
       zygote_max_failed_boots_(0),
       experimental_flags_(ExperimentalFlags::kNone),
@@ -277,7 +277,6 @@
   static_assert(Runtime::kCalleeSaveSize ==
                     static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType), "Unexpected size");
 
-  CheckAsmSupportOffsetsAndSizes();
   std::fill(callee_save_methods_, callee_save_methods_ + arraysize(callee_save_methods_), 0u);
   interpreter::CheckInterpreterAsmConstants();
   callbacks_.reset(new RuntimeCallbacks());
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 478ff50..398a48d 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -654,6 +654,14 @@
     is_native_debuggable_ = value;
   }
 
+  bool AreNonStandardExitsEnabled() const {
+    return non_standard_exits_enabled_;
+  }
+
+  void SetNonStandardExitsEnabled() {
+    non_standard_exits_enabled_ = true;
+  }
+
   bool AreAsyncExceptionsThrown() const {
     return async_exceptions_thrown_;
   }
@@ -986,6 +994,10 @@
   // MterpShouldSwitchInterpreters function.
   bool async_exceptions_thrown_;
 
+  // Whether anything is going to be using the shadow-frame APIs to force a function to return
+  // early. Doing this requires that (1) we be debuggable and (2) that mterp is exited.
+  bool non_standard_exits_enabled_;
+
   // Whether Java code needs to be debuggable.
   bool is_java_debuggable_;
 
diff --git a/runtime/stack.cc b/runtime/stack.cc
index eb9c661..25939d2 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -139,9 +139,9 @@
     } else {
       uint16_t reg = accessor.RegistersSize() - accessor.InsSize();
       uint32_t value = 0;
-      bool success = GetVReg(m, reg, kReferenceVReg, &value);
-      // We currently always guarantee the `this` object is live throughout the method.
-      CHECK(success) << "Failed to read the this object in " << ArtMethod::PrettyMethod(m);
+      if (!GetVReg(m, reg, kReferenceVReg, &value)) {
+        return nullptr;
+      }
       return reinterpret_cast<mirror::Object*>(value);
     }
   }
@@ -223,20 +223,39 @@
   switch (location_kind) {
     case DexRegisterLocation::Kind::kInStack: {
       const int32_t offset = dex_register_map[vreg].GetStackOffsetInBytes();
+      BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map);
+      if (kind == kReferenceVReg && !stack_mask.LoadBit(offset / kFrameSlotSize)) {
+        return false;
+      }
       const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset;
       *val = *reinterpret_cast<const uint32_t*>(addr);
       return true;
     }
-    case DexRegisterLocation::Kind::kInRegister:
+    case DexRegisterLocation::Kind::kInRegister: {
+      uint32_t register_mask = code_info.GetRegisterMaskOf(stack_map);
+      uint32_t reg = dex_register_map[vreg].GetMachineRegister();
+      if (kind == kReferenceVReg && !(register_mask & (1 << reg))) {
+        return false;
+      }
+      return GetRegisterIfAccessible(reg, kind, val);
+    }
     case DexRegisterLocation::Kind::kInRegisterHigh:
     case DexRegisterLocation::Kind::kInFpuRegister:
     case DexRegisterLocation::Kind::kInFpuRegisterHigh: {
+      if (kind == kReferenceVReg) {
+        return false;
+      }
       uint32_t reg = dex_register_map[vreg].GetMachineRegister();
       return GetRegisterIfAccessible(reg, kind, val);
     }
-    case DexRegisterLocation::Kind::kConstant:
-      *val = dex_register_map[vreg].GetConstant();
+    case DexRegisterLocation::Kind::kConstant: {
+      uint32_t result = dex_register_map[vreg].GetConstant();
+      if (kind == kReferenceVReg && result != 0) {
+        return false;
+      }
+      *val = result;
       return true;
+    }
     case DexRegisterLocation::Kind::kNone:
       return false;
     default:
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 0092b97..68c8229 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -45,6 +45,7 @@
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/bit_utils.h"
+#include "base/casts.h"
 #include "base/file_utils.h"
 #include "base/memory_tool.h"
 #include "base/mutex.h"
@@ -500,7 +501,7 @@
 Thread* Thread::FromManagedThread(const ScopedObjectAccessAlreadyRunnable& soa,
                                   ObjPtr<mirror::Object> thread_peer) {
   ArtField* f = jni::DecodeArtField(WellKnownClasses::java_lang_Thread_nativePeer);
-  Thread* result = reinterpret_cast<Thread*>(static_cast<uintptr_t>(f->GetLong(thread_peer)));
+  Thread* result = reinterpret_cast64<Thread*>(f->GetLong(thread_peer));
   // Sanity check that if we have a result it is either suspended or we hold the thread_list_lock_
   // to stop it from going away.
   if (kIsDebugBuild) {
@@ -907,7 +908,7 @@
     }
     self->GetJniEnv()->SetLongField(thread_peer,
                                     WellKnownClasses::java_lang_Thread_nativePeer,
-                                    reinterpret_cast<jlong>(self));
+                                    reinterpret_cast64<jlong>(self));
     return true;
   };
   return Attach(thread_name, as_daemon, set_peer_action);
@@ -949,8 +950,9 @@
 
   Thread* self = this;
   DCHECK_EQ(self, Thread::Current());
-  env->SetLongField(peer.get(), WellKnownClasses::java_lang_Thread_nativePeer,
-                    reinterpret_cast<jlong>(self));
+  env->SetLongField(peer.get(),
+                    WellKnownClasses::java_lang_Thread_nativePeer,
+                    reinterpret_cast64<jlong>(self));
 
   ScopedObjectAccess soa(self);
   StackHandleScope<1> hs(self);
@@ -3368,11 +3370,34 @@
     HandleWrapperObjPtr<mirror::Throwable> h_exception(hs.NewHandleWrapper(&exception));
     instrumentation->ExceptionThrownEvent(this, exception.Ptr());
   }
-  // Does instrumentation need to deoptimize the stack?
-  // Note: we do this *after* reporting the exception to instrumentation in case it
-  // now requires deoptimization. It may happen if a debugger is attached and requests
-  // new events (single-step, breakpoint, ...) when the exception is reported.
-  if (Dbg::IsForcedInterpreterNeededForException(this)) {
+  // Does instrumentation need to deoptimize the stack or otherwise go to interpreter for something?
+  // Note: we do this *after* reporting the exception to instrumentation in case it now requires
+  // deoptimization. It may happen if a debugger is attached and requests new events (single-step,
+  // breakpoint, ...) when the exception is reported.
+  ShadowFrame* cf;
+  bool force_frame_pop = false;
+  {
+    NthCallerVisitor visitor(this, 0, false);
+    visitor.WalkStack();
+    cf = visitor.GetCurrentShadowFrame();
+    if (cf == nullptr) {
+      cf = FindDebuggerShadowFrame(visitor.GetFrameId());
+    }
+    force_frame_pop = cf != nullptr && cf->GetForcePopFrame();
+    if (kIsDebugBuild && force_frame_pop) {
+      NthCallerVisitor penultimate_visitor(this, 1, false);
+      penultimate_visitor.WalkStack();
+      ShadowFrame* penultimate_frame = penultimate_visitor.GetCurrentShadowFrame();
+      if (penultimate_frame == nullptr) {
+        penultimate_frame = FindDebuggerShadowFrame(penultimate_visitor.GetFrameId());
+      }
+      DCHECK(penultimate_frame != nullptr &&
+             penultimate_frame->GetForceRetryInstruction())
+          << "Force pop frame without retry instruction found. penultimate frame is null: "
+          << (penultimate_frame == nullptr ? "true" : "false");
+    }
+  }
+  if (Dbg::IsForcedInterpreterNeededForException(this) || force_frame_pop) {
     NthCallerVisitor visitor(this, 0, false);
     visitor.WalkStack();
     if (Runtime::Current()->IsAsyncDeoptimizeable(visitor.caller_pc)) {
@@ -3380,10 +3405,16 @@
       const DeoptimizationMethodType method_type = DeoptimizationMethodType::kDefault;
       // Save the exception into the deoptimization context so it can be restored
       // before entering the interpreter.
+      if (force_frame_pop) {
+        VLOG(deopt) << "Deopting " << cf->GetMethod()->PrettyMethod() << " for frame-pop";
+        DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
+        // Get rid of the exception since we are doing a framepop instead.
+        ClearException();
+      }
       PushDeoptimizationContext(
           JValue(),
           false /* is_reference */,
-          exception,
+          (force_frame_pop ? nullptr : exception),
           false /* from_code */,
           method_type);
       artDeoptimize(this);
@@ -3567,8 +3598,8 @@
     if (!m->IsNative() && !m->IsRuntimeMethod() && (!m->IsProxyMethod() || m->IsConstructor())) {
       const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
       DCHECK(method_header->IsOptimized());
-      StackReference<mirror::Object>* vreg_base = reinterpret_cast<StackReference<mirror::Object>*>(
-          reinterpret_cast<uintptr_t>(cur_quick_frame));
+      StackReference<mirror::Object>* vreg_base =
+          reinterpret_cast<StackReference<mirror::Object>*>(cur_quick_frame);
       uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc());
       CodeInfo code_info(method_header, kPrecise
           ? CodeInfo::DecodeFlags::AllTables  // We will need dex register maps.
diff --git a/test/1953-pop-frame/check b/test/1953-pop-frame/check
new file mode 100755
index 0000000..d552272
--- /dev/null
+++ b/test/1953-pop-frame/check
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The RI has restrictions and bugs around some PopFrame behavior that ART lacks.
+# See b/116003018. Some configurations cannot handle the class load events in
+# quite the right way so they are disabled there too.
+./default-check "$@" || \
+  (patch -p0 expected.txt < class-loading-expected.patch >/dev/null && ./default-check "$@")
diff --git a/test/1953-pop-frame/class-loading-expected.patch b/test/1953-pop-frame/class-loading-expected.patch
new file mode 100644
index 0000000..2edef15
--- /dev/null
+++ b/test/1953-pop-frame/class-loading-expected.patch
@@ -0,0 +1,21 @@
+74a75,94
+> Test stopped during a ClassLoad event.
+> Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0
+> Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+> 	art.Test1953.popFrame(Native Method)
+> 	art.Test1953.runTestOn(Test1953.java)
+> 	art.Test1953.runTestOn(Test1953.java)
+> 	art.Test1953.runTests(Test1953.java)
+> 	<Additional frames hidden>
+> TC0.foo == 1
+> result is ClassLoadObject { cnt: 1, curClass: 1} base-call count: 1
+> Test stopped during a ClassPrepare event.
+> Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0
+> Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+> 	art.Test1953.popFrame(Native Method)
+> 	art.Test1953.runTestOn(Test1953.java)
+> 	art.Test1953.runTestOn(Test1953.java)
+> 	art.Test1953.runTests(Test1953.java)
+> 	<Additional frames hidden>
+> TC1.foo == 2
+> result is ClassLoadObject { cnt: 1, curClass: 2} base-call count: 1
diff --git a/test/1953-pop-frame/expected.txt b/test/1953-pop-frame/expected.txt
new file mode 100644
index 0000000..906703d
--- /dev/null
+++ b/test/1953-pop-frame/expected.txt
@@ -0,0 +1,98 @@
+Test stopped using breakpoint
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped using breakpoint with declared synchronized function
+Single call with PopFrame on SynchronizedFunctionTestObject { cnt: 0 } base-call-count: 0
+result is SynchronizedFunctionTestObject { cnt: 2 } base-call count: 1
+Test stopped using breakpoint with synchronized block
+Single call with PopFrame on SynchronizedTestObject { cnt: 0 } base-call-count: 0
+result is SynchronizedTestObject { cnt: 2 } base-call count: 1
+Test stopped on single step
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped on field access
+Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0
+result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1
+Test stopped on field modification
+Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0
+result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1
+Test stopped during Method Exit of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Enter of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Exit of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped during Method Enter of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Exit due to exception thrown in same function
+Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: false } base-call-count: 0
+result is ExceptionOnceObject { cnt: 2, throwInSub: false } base-call count: 1
+Test stopped during Method Exit due to exception thrown in subroutine
+Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: true } base-call-count: 0
+result is ExceptionOnceObject { cnt: 2, throwInSub: true } base-call count: 1
+Test stopped during notifyFramePop without exception on pop of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped during notifyFramePop without exception on pop of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during notifyFramePop with exception on pop of calledFunction
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError thrown and caught!
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during notifyFramePop with exception on pop of doThrow
+Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionCatchTestObject$TestError caught in called function.
+result is ExceptionCatchTestObject { cnt: 1 } base-call count: 1
+Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in called function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError caught in same function.
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in subroutine)
+Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionCatchTestObject$TestError caught in called function.
+result is ExceptionCatchTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in calling function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError thrown and caught!
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in called function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError caught in same function.
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in parent of calling function)
+Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowFarTestObject$TestError thrown and caught!
+result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in called function)
+Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowFarTestObject$TestError caught in same function.
+result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1
+Test stopped during random Suspend.
+Single call with PopFrame on SuspendSuddenlyObject { cnt: 0 } base-call-count: 0
+result is SuspendSuddenlyObject { cnt: 2 } base-call count: 1
+Test redefining frame being popped.
+Single call with PopFrame on RedefineTestObject { states: [] current: ORIGINAL } base-call-count: 0
+result is RedefineTestObject { states: [ORIGINAL, REDEFINED] current: REDEFINED } base-call count: 1
+Test stopped during a native method fails
+Single call with PopFrame on NativeCalledObject { cnt: 0 } base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+result is NativeCalledObject { cnt: 1 } base-call count: 1
+Test stopped in a method called by native fails
+Single call with PopFrame on NativeCallerObject { cnt: 0 } base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+result is NativeCallerObject { cnt: 1 } base-call count: 1
diff --git a/test/1953-pop-frame/info.txt b/test/1953-pop-frame/info.txt
new file mode 100644
index 0000000..b5eb546
--- /dev/null
+++ b/test/1953-pop-frame/info.txt
@@ -0,0 +1,7 @@
+Test basic JVMTI breakpoint functionality.
+
+This test places a breakpoint on the first instruction of a number of functions
+that are entered in every way possible for the given class of method.
+
+It also tests that breakpoints don't interfere with each other by having
+multiple breakpoints be set at once.
diff --git a/test/1953-pop-frame/pop_frame.cc b/test/1953-pop-frame/pop_frame.cc
new file mode 100644
index 0000000..1c2d2a1
--- /dev/null
+++ b/test/1953-pop-frame/pop_frame.cc
@@ -0,0 +1,998 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#include <cstdio>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+#include "jni.h"
+#include "jvmti.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
+
+// Test infrastructure
+#include "jni_binder.h"
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
+#include "ti_macros.h"
+
+namespace art {
+namespace Test1953PopFrame {
+
+struct TestData {
+  jlocation target_loc;
+  jmethodID target_method;
+  jclass target_klass;
+  jfieldID target_field;
+  jrawMonitorID notify_monitor;
+  jint frame_pop_offset;
+  jmethodID frame_pop_setup_method;
+  std::vector<std::string> interesting_classes;
+  bool hit_location;
+
+  TestData(jvmtiEnv* jvmti,
+           JNIEnv* env,
+           jlocation loc,
+           jobject meth,
+           jclass klass,
+           jobject field,
+           jobject setup_meth,
+           jint pop_offset,
+           const std::vector<std::string>&& interesting)
+      : target_loc(loc),
+        target_method(meth != nullptr ? env->FromReflectedMethod(meth) : nullptr),
+        target_klass(reinterpret_cast<jclass>(env->NewGlobalRef(klass))),
+        target_field(field != nullptr ? env->FromReflectedField(field) : nullptr),
+        frame_pop_offset(pop_offset),
+        frame_pop_setup_method(setup_meth != nullptr ? env->FromReflectedMethod(setup_meth)
+                                                     : nullptr),
+        interesting_classes(interesting),
+        hit_location(false) {
+    JvmtiErrorToException(env, jvmti, jvmti->CreateRawMonitor("SuspendStopMonitor",
+                                                              &notify_monitor));
+  }
+
+  void PerformSuspend(jvmtiEnv* jvmti, JNIEnv* env) {
+    // Wake up the waiting thread.
+    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorEnter(notify_monitor));
+    hit_location = true;
+    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorNotifyAll(notify_monitor));
+    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorExit(notify_monitor));
+    // Suspend ourself
+    jvmti->SuspendThread(nullptr);
+  }
+};
+
+void JNICALL cbSingleStep(jvmtiEnv* jvmti,
+                          JNIEnv* env,
+                          jthread thr,
+                          jmethodID meth,
+                          jlocation loc) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (meth != data->target_method || loc != data->target_loc) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbExceptionCatch(jvmtiEnv *jvmti,
+                              JNIEnv* env,
+                              jthread thr,
+                              jmethodID method,
+                              jlocation location ATTRIBUTE_UNUSED,
+                              jobject exception ATTRIBUTE_UNUSED) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (method != data->target_method) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbException(jvmtiEnv *jvmti,
+                         JNIEnv* env,
+                         jthread thr,
+                         jmethodID method,
+                         jlocation location ATTRIBUTE_UNUSED,
+                         jobject exception ATTRIBUTE_UNUSED,
+                         jmethodID catch_method ATTRIBUTE_UNUSED,
+                         jlocation catch_location ATTRIBUTE_UNUSED) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (method != data->target_method) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbMethodEntry(jvmtiEnv *jvmti,
+                           JNIEnv* env,
+                           jthread thr,
+                           jmethodID method) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (method != data->target_method) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbMethodExit(jvmtiEnv *jvmti,
+                          JNIEnv* env,
+                          jthread thr,
+                          jmethodID method,
+                          jboolean was_popped_by_exception ATTRIBUTE_UNUSED,
+                          jvalue return_value ATTRIBUTE_UNUSED) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (method != data->target_method) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbFieldModification(jvmtiEnv* jvmti,
+                                 JNIEnv* env,
+                                 jthread thr,
+                                 jmethodID method ATTRIBUTE_UNUSED,
+                                 jlocation location ATTRIBUTE_UNUSED,
+                                 jclass field_klass ATTRIBUTE_UNUSED,
+                                 jobject object ATTRIBUTE_UNUSED,
+                                 jfieldID field,
+                                 char signature_type ATTRIBUTE_UNUSED,
+                                 jvalue new_value ATTRIBUTE_UNUSED) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (field != data->target_field) {
+    // TODO What to do here.
+    LOG(FATAL) << "Strange, shouldn't get here!";
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbFieldAccess(jvmtiEnv* jvmti,
+                           JNIEnv* env,
+                           jthread thr,
+                           jmethodID method ATTRIBUTE_UNUSED,
+                           jlocation location ATTRIBUTE_UNUSED,
+                           jclass field_klass,
+                           jobject object ATTRIBUTE_UNUSED,
+                           jfieldID field) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (field != data->target_field || !env->IsSameObject(field_klass, data->target_klass)) {
+    // TODO What to do here.
+    LOG(FATAL) << "Strange, shouldn't get here!";
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbBreakpointHit(jvmtiEnv* jvmti,
+                             JNIEnv* env,
+                             jthread thr,
+                             jmethodID method,
+                             jlocation loc) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (data->frame_pop_setup_method == method) {
+    CHECK(loc == 0) << "We should have stopped at location 0";
+    if (JvmtiErrorToException(env,
+                              jvmti,
+                              jvmti->NotifyFramePop(thr, data->frame_pop_offset))) {
+      return;
+    }
+    return;
+  }
+  if (method != data->target_method || loc != data->target_loc) {
+    // TODO What to do here.
+    LOG(FATAL) << "Strange, shouldn't get here!";
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbFramePop(jvmtiEnv* jvmti,
+                        JNIEnv* env,
+                        jthread thr,
+                        jmethodID method ATTRIBUTE_UNUSED,
+                        jboolean was_popped_by_exception ATTRIBUTE_UNUSED) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbClassLoadOrPrepare(jvmtiEnv* jvmti,
+                                  JNIEnv* env,
+                                  jthread thr,
+                                  jclass klass) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  char* name;
+  if (JvmtiErrorToException(env, jvmti, jvmti->GetClassSignature(klass, &name, nullptr))) {
+    return;
+  }
+  std::string name_str(name);
+  if (JvmtiErrorToException(env,
+                            jvmti,
+                            jvmti->Deallocate(reinterpret_cast<unsigned char*>(name)))) {
+    return;
+  }
+  if (std::find(data->interesting_classes.cbegin(),
+                data->interesting_classes.cend(),
+                name_str) != data->interesting_classes.cend()) {
+    data->PerformSuspend(jvmti, env);
+  }
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_setupTest(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
+  jvmtiCapabilities caps;
+  memset(&caps, 0, sizeof(caps));
+  // Most of these will already be there but might as well be complete.
+  caps.can_pop_frame                          = 1;
+  caps.can_generate_single_step_events        = 1;
+  caps.can_generate_breakpoint_events         = 1;
+  caps.can_suspend                            = 1;
+  caps.can_generate_method_entry_events       = 1;
+  caps.can_generate_method_exit_events        = 1;
+  caps.can_generate_monitor_events            = 1;
+  caps.can_generate_exception_events          = 1;
+  caps.can_generate_frame_pop_events          = 1;
+  caps.can_generate_field_access_events       = 1;
+  caps.can_generate_field_modification_events = 1;
+  caps.can_redefine_classes                   = 1;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
+    return;
+  }
+  jvmtiEventCallbacks cb;
+  memset(&cb, 0, sizeof(cb));
+  // TODO Add the rest of these.
+  cb.Breakpoint        = cbBreakpointHit;
+  cb.SingleStep        = cbSingleStep;
+  cb.FieldAccess       = cbFieldAccess;
+  cb.FieldModification = cbFieldModification;
+  cb.MethodEntry       = cbMethodEntry;
+  cb.MethodExit        = cbMethodExit;
+  cb.Exception         = cbException;
+  cb.ExceptionCatch    = cbExceptionCatch;
+  cb.FramePop          = cbFramePop;
+  cb.ClassLoad         = cbClassLoadOrPrepare;
+  cb.ClassPrepare      = cbClassLoadOrPrepare;
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)));
+}
+
+static bool DeleteTestData(JNIEnv* env, jthread thr, TestData* data) {
+  env->DeleteGlobalRef(data->target_klass);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
+    return false;
+  }
+  return JvmtiErrorToException(env,
+                               jvmti_env,
+                               jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data)));
+}
+
+static TestData* SetupTestData(JNIEnv* env,
+                               jobject meth,
+                               jlocation loc,
+                               jclass target_klass,
+                               jobject field,
+                               jobject setup_meth,
+                               jint pop_offset,
+                               const std::vector<std::string>&& interesting_names) {
+  void* data_ptr;
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->Allocate(sizeof(TestData),
+                                                reinterpret_cast<uint8_t**>(&data_ptr)))) {
+    return nullptr;
+  }
+  data = new (data_ptr) TestData(jvmti_env,
+                                 env,
+                                 loc,
+                                 meth,
+                                 target_klass,
+                                 field,
+                                 setup_meth,
+                                 pop_offset,
+                                 std::move(interesting_names));
+  if (env->ExceptionCheck()) {
+    env->DeleteGlobalRef(data->target_klass);
+    jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data));
+    return nullptr;
+  }
+  return data;
+}
+
+static TestData* SetupTestData(JNIEnv* env,
+                               jobject meth,
+                               jlocation loc,
+                               jclass target_klass,
+                               jobject field,
+                               jobject setup_meth,
+                               jint pop_offset) {
+  std::vector<std::string> empty;
+  return SetupTestData(
+      env, meth, loc, target_klass, field, setup_meth, pop_offset, std::move(empty));
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_setupSuspendClassEvent(JNIEnv* env,
+                                                      jclass klass ATTRIBUTE_UNUSED,
+                                                      jint event_num,
+                                                      jobjectArray interesting_names,
+                                                      jthread thr) {
+  CHECK(event_num == JVMTI_EVENT_CLASS_LOAD || event_num == JVMTI_EVENT_CLASS_PREPARE);
+  std::vector<std::string> names;
+  jint cnt = env->GetArrayLength(interesting_names);
+  for (jint i = 0; i < cnt; i++) {
+    env->PushLocalFrame(1);
+    jstring name_obj = reinterpret_cast<jstring>(env->GetObjectArrayElement(interesting_names, i));
+    const char* name_chr = env->GetStringUTFChars(name_obj, nullptr);
+    names.push_back(std::string(name_chr));
+    env->ReleaseStringUTFChars(name_obj, name_chr);
+    env->PopLocalFrame(nullptr);
+  }
+  TestData* data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0, std::move(names));
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  JvmtiErrorToException(env,
+                        jvmti_env,
+                        jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                            static_cast<jvmtiEvent>(event_num),
+                                                            thr));
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_clearSuspendClassEvent(JNIEnv* env,
+                                                      jclass klass ATTRIBUTE_UNUSED,
+                                                      jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_CLASS_LOAD,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_CLASS_PREPARE,
+                                                                thr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_setupSuspendSingleStepAt(JNIEnv* env,
+                                                        jclass klass ATTRIBUTE_UNUSED,
+                                                        jobject meth,
+                                                        jlocation loc,
+                                                        jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                            JVMTI_EVENT_SINGLE_STEP,
+                                                                            thr));
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_clearSuspendSingleStepFor(JNIEnv* env,
+                                                         jclass klass ATTRIBUTE_UNUSED,
+                                                         jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_SINGLE_STEP,
+                                                                thr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_setupSuspendPopFrameEvent(JNIEnv* env,
+                                                         jclass klass ATTRIBUTE_UNUSED,
+                                                         jint offset,
+                                                         jobject breakpoint_func,
+                                                         jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, breakpoint_func, offset);
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_FRAME_POP,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_BREAKPOINT,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetBreakpoint(data->frame_pop_setup_method, 0))) {
+    return;
+  }
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_clearSuspendPopFrameEvent(JNIEnv* env,
+                                                         jclass klass ATTRIBUTE_UNUSED,
+                                                         jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_FRAME_POP,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_BREAKPOINT,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->ClearBreakpoint(data->frame_pop_setup_method, 0))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_setupSuspendBreakpointFor(JNIEnv* env,
+                                                         jclass klass ATTRIBUTE_UNUSED,
+                                                         jobject meth,
+                                                         jlocation loc,
+                                                         jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_BREAKPOINT,
+                                                                thr))) {
+    return;
+  }
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetBreakpoint(data->target_method,
+                                                                 data->target_loc));
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_clearSuspendBreakpointFor(JNIEnv* env,
+                                                         jclass klass ATTRIBUTE_UNUSED,
+                                                         jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_BREAKPOINT,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->ClearBreakpoint(data->target_method,
+                                                       data->target_loc))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_setupSuspendExceptionEvent(JNIEnv* env,
+                                                          jclass klass ATTRIBUTE_UNUSED,
+                                                          jobject method,
+                                                          jboolean is_catch,
+                                                          jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(
+                                thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  JvmtiErrorToException(env,
+                        jvmti_env,
+                        jvmti_env->SetEventNotificationMode(
+                            JVMTI_ENABLE,
+                            is_catch ? JVMTI_EVENT_EXCEPTION_CATCH : JVMTI_EVENT_EXCEPTION,
+                            thr));
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_clearSuspendExceptionEvent(JNIEnv* env,
+                                                          jclass klass ATTRIBUTE_UNUSED,
+                                                          jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_EXCEPTION_CATCH,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_EXCEPTION,
+                                                                thr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_setupSuspendMethodEvent(JNIEnv* env,
+                                                       jclass klass ATTRIBUTE_UNUSED,
+                                                       jobject method,
+                                                       jboolean enter,
+                                                       jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(
+                                thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  JvmtiErrorToException(env,
+                        jvmti_env,
+                        jvmti_env->SetEventNotificationMode(
+                            JVMTI_ENABLE,
+                            enter ? JVMTI_EVENT_METHOD_ENTRY : JVMTI_EVENT_METHOD_EXIT,
+                            thr));
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_clearSuspendMethodEvent(JNIEnv* env,
+                                                       jclass klass ATTRIBUTE_UNUSED,
+                                                       jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_METHOD_EXIT,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_METHOD_ENTRY,
+                                                                thr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_setupFieldSuspendFor(JNIEnv* env,
+                                                    jclass klass ATTRIBUTE_UNUSED,
+                                                    jclass target_klass,
+                                                    jobject field,
+                                                    jboolean access,
+                                                    jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(
+                                thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, nullptr, 0, target_klass, field, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(
+                                JVMTI_ENABLE,
+                                access ? JVMTI_EVENT_FIELD_ACCESS : JVMTI_EVENT_FIELD_MODIFICATION,
+                                thr))) {
+    return;
+  }
+  if (access) {
+    JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldAccessWatch(data->target_klass,
+                                                                         data->target_field));
+  } else {
+    JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldModificationWatch(data->target_klass,
+                                                                               data->target_field));
+  }
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_clearFieldSuspendFor(JNIEnv* env,
+                                                    jclass klass ATTRIBUTE_UNUSED,
+                                                    jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_FIELD_ACCESS,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_FIELD_MODIFICATION,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->ClearFieldModificationWatch(
+                                data->target_klass, data->target_field)) &&
+      JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->ClearFieldAccessWatch(
+                                data->target_klass, data->target_field))) {
+    return;
+  } else {
+    env->ExceptionClear();
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_setupWaitForNativeCall(JNIEnv* env,
+                                                      jclass klass ATTRIBUTE_UNUSED,
+                                                      jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(
+                                thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_clearWaitForNativeCall(JNIEnv* env,
+                                                      jclass klass ATTRIBUTE_UNUSED,
+                                                      jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_waitForSuspendHit(JNIEnv* env,
+                                                 jclass klass ATTRIBUTE_UNUSED,
+                                                 jthread thr) {
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(thr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(data->notify_monitor))) {
+    return;
+  }
+  while (!data->hit_location) {
+    if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorWait(data->notify_monitor, -1))) {
+      return;
+    }
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(data->notify_monitor))) {
+    return;
+  }
+  jint state = 0;
+  while (!JvmtiErrorToException(env, jvmti_env, jvmti_env->GetThreadState(thr, &state)) &&
+         (state & JVMTI_THREAD_STATE_SUSPENDED) == 0) { }
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_popFrame(JNIEnv* env,
+                                        jclass klass ATTRIBUTE_UNUSED,
+                                        jthread thr) {
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->PopFrame(thr));
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_00024NativeCalledObject_calledFunction(
+    JNIEnv* env, jobject thiz) {
+  env->PushLocalFrame(1);
+  jclass klass = env->GetObjectClass(thiz);
+  jfieldID cnt = env->GetFieldID(klass, "cnt", "I");
+  env->SetIntField(thiz, cnt, env->GetIntField(thiz, cnt) + 1);
+  env->PopLocalFrame(nullptr);
+  TestData *data;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->GetThreadLocalStorage(/* thread */ nullptr,
+                                                             reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  data->PerformSuspend(jvmti_env, env);
+}
+
+extern "C" JNIEXPORT
+void JNICALL Java_art_Test1953_00024NativeCallerObject_run(
+    JNIEnv* env, jobject thiz) {
+  env->PushLocalFrame(1);
+  jclass klass = env->GetObjectClass(thiz);
+  jfieldID baseCnt = env->GetFieldID(klass, "baseCnt", "I");
+  env->SetIntField(thiz, baseCnt, env->GetIntField(thiz, baseCnt) + 1);
+  jmethodID called = env->GetMethodID(klass, "calledFunction", "()V");
+  env->CallVoidMethod(thiz, called);
+  env->PopLocalFrame(nullptr);
+}
+
+extern "C" JNIEXPORT
+jboolean JNICALL Java_art_Test1953_isClassLoaded(JNIEnv* env, jclass, jstring name) {
+  ScopedUtfChars chr(env, name);
+  if (env->ExceptionCheck()) {
+    return false;
+  }
+  jint cnt = 0;
+  jclass* klasses = nullptr;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLoadedClasses(&cnt, &klasses))) {
+    return false;
+  }
+  bool res = false;
+  for (jint i = 0; !res && i < cnt; i++) {
+    char* sig;
+    if (JvmtiErrorToException(env,
+                              jvmti_env,
+                              jvmti_env->GetClassSignature(klasses[i], &sig, nullptr))) {
+      return false;
+    }
+    res = (strcmp(sig, chr.c_str()) == 0);
+    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig));
+  }
+  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
+  return res;
+}
+
+}  // namespace Test1953PopFrame
+}  // namespace art
+
diff --git a/test/1953-pop-frame/run b/test/1953-pop-frame/run
new file mode 100755
index 0000000..d16d4e6
--- /dev/null
+++ b/test/1953-pop-frame/run
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# On RI we need to turn class-load tests off since those events are buggy around
+# pop-frame (see b/116003018).
+ARGS=""
+if [[ "$TEST_RUNTIME" == "jvm" ]]; then
+  ARGS="--args DISABLE_CLASS_LOAD_TESTS"
+fi
+
+./default-run "$@" --jvmti $ARGS
diff --git a/tools/cpp-define-generator/constant_card_table.def b/test/1953-pop-frame/src/Main.java
similarity index 70%
rename from tools/cpp-define-generator/constant_card_table.def
rename to test/1953-pop-frame/src/Main.java
index ae3e8f3..156076e 100644
--- a/tools/cpp-define-generator/constant_card_table.def
+++ b/test/1953-pop-frame/src/Main.java
@@ -14,12 +14,10 @@
  * limitations under the License.
  */
 
-// Export heap values.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "gc/accounting/card_table.h"
-#endif
-
-// Size of references to the heap on the stack.
-DEFINE_EXPR(CARD_TABLE_CARD_SHIFT, size_t, art::gc::accounting::CardTable::kCardShift)
-
+import java.util.Arrays;
+import java.util.List;
+public class Main {
+  public static void main(String[] args) throws Exception {
+    art.Test1953.run(!Arrays.asList(args).contains("DISABLE_CLASS_LOAD_TESTS"));
+  }
+}
diff --git a/test/1953-pop-frame/src/art/Breakpoint.java b/test/1953-pop-frame/src/art/Breakpoint.java
new file mode 100644
index 0000000..bbb89f7
--- /dev/null
+++ b/test/1953-pop-frame/src/art/Breakpoint.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Executable;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Objects;
+
+public class Breakpoint {
+  public static class Manager {
+    public static class BP {
+      public final Executable method;
+      public final long location;
+
+      public BP(Executable method) {
+        this(method, getStartLocation(method));
+      }
+
+      public BP(Executable method, long location) {
+        this.method = method;
+        this.location = location;
+      }
+
+      @Override
+      public boolean equals(Object other) {
+        return (other instanceof BP) &&
+            method.equals(((BP)other).method) &&
+            location == ((BP)other).location;
+      }
+
+      @Override
+      public String toString() {
+        return method.toString() + " @ " + getLine();
+      }
+
+      @Override
+      public int hashCode() {
+        return Objects.hash(method, location);
+      }
+
+      public int getLine() {
+        try {
+          LineNumber[] lines = getLineNumberTable(method);
+          int best = -1;
+          for (LineNumber l : lines) {
+            if (l.location > location) {
+              break;
+            } else {
+              best = l.line;
+            }
+          }
+          return best;
+        } catch (Exception e) {
+          return -1;
+        }
+      }
+    }
+
+    private Set<BP> breaks = new HashSet<>();
+
+    public void setBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.add(b)) {
+          Breakpoint.setBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void setBreakpoint(Executable method, long location) {
+      setBreakpoints(new BP(method, location));
+    }
+
+    public void clearBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.remove(b)) {
+          Breakpoint.clearBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void clearBreakpoint(Executable method, long location) {
+      clearBreakpoints(new BP(method, location));
+    }
+
+    public void clearAllBreakpoints() {
+      clearBreakpoints(breaks.toArray(new BP[0]));
+    }
+  }
+
+  public static void startBreakpointWatch(Class<?> methodClass,
+                                          Executable breakpointReached,
+                                          Thread thr) {
+    startBreakpointWatch(methodClass, breakpointReached, false, thr);
+  }
+
+  /**
+   * Enables the trapping of breakpoint events.
+   *
+   * If allowRecursive == true then breakpoints will be sent even if one is currently being handled.
+   */
+  public static native void startBreakpointWatch(Class<?> methodClass,
+                                                 Executable breakpointReached,
+                                                 boolean allowRecursive,
+                                                 Thread thr);
+  public static native void stopBreakpointWatch(Thread thr);
+
+  public static final class LineNumber implements Comparable<LineNumber> {
+    public final long location;
+    public final int line;
+
+    private LineNumber(long loc, int line) {
+      this.location = loc;
+      this.line = line;
+    }
+
+    public boolean equals(Object other) {
+      return other instanceof LineNumber && ((LineNumber)other).line == line &&
+          ((LineNumber)other).location == location;
+    }
+
+    public int compareTo(LineNumber other) {
+      int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line));
+      if (v != 0) {
+        return v;
+      } else {
+        return Long.valueOf(location).compareTo(Long.valueOf(other.location));
+      }
+    }
+  }
+
+  public static native void setBreakpoint(Executable m, long loc);
+  public static void setBreakpoint(Executable m, LineNumber l) {
+    setBreakpoint(m, l.location);
+  }
+
+  public static native void clearBreakpoint(Executable m, long loc);
+  public static void clearBreakpoint(Executable m, LineNumber l) {
+    clearBreakpoint(m, l.location);
+  }
+
+  private static native Object[] getLineNumberTableNative(Executable m);
+  public static LineNumber[] getLineNumberTable(Executable m) {
+    Object[] nativeTable = getLineNumberTableNative(m);
+    long[] location = (long[])(nativeTable[0]);
+    int[] lines = (int[])(nativeTable[1]);
+    if (lines.length != location.length) {
+      throw new Error("Lines and locations have different lengths!");
+    }
+    LineNumber[] out = new LineNumber[lines.length];
+    for (int i = 0; i < lines.length; i++) {
+      out[i] = new LineNumber(location[i], lines[i]);
+    }
+    return out;
+  }
+
+  public static native long getStartLocation(Executable m);
+
+  public static int locationToLine(Executable m, long location) {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      int best = -1;
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.location > location) {
+          break;
+        } else {
+          best = l.line;
+        }
+      }
+      return best;
+    } catch (Exception e) {
+      return -1;
+    }
+  }
+
+  public static long lineToLocation(Executable m, int line) throws Exception {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.line == line) {
+          return l.location;
+        }
+      }
+      throw new Exception("Unable to find line " + line + " in " + m);
+    } catch (Exception e) {
+      throw new Exception("Unable to get line number info for " + m, e);
+    }
+  }
+}
+
diff --git a/test/1953-pop-frame/src/art/Redefinition.java b/test/1953-pop-frame/src/art/Redefinition.java
new file mode 100644
index 0000000..56d2938
--- /dev/null
+++ b/test/1953-pop-frame/src/art/Redefinition.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+  public static final class CommonClassDefinition {
+    public final Class<?> target;
+    public final byte[] class_file_bytes;
+    public final byte[] dex_file_bytes;
+
+    public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+      this.target = target;
+      this.class_file_bytes = class_file_bytes;
+      this.dex_file_bytes = dex_file_bytes;
+    }
+  }
+
+  // A set of possible test configurations. Test should set this if they need to.
+  // This must be kept in sync with the defines in ti-agent/common_helper.cc
+  public static enum Config {
+    COMMON_REDEFINE(0),
+    COMMON_RETRANSFORM(1),
+    COMMON_TRANSFORM(2);
+
+    private final int val;
+    private Config(int val) {
+      this.val = val;
+    }
+  }
+
+  public static void setTestConfiguration(Config type) {
+    nativeSetTestConfiguration(type.val);
+  }
+
+  private static native void nativeSetTestConfiguration(int type);
+
+  // Transforms the class
+  public static native void doCommonClassRedefinition(Class<?> target,
+                                                      byte[] classfile,
+                                                      byte[] dexfile);
+
+  public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+    ArrayList<Class<?>> classes = new ArrayList<>();
+    ArrayList<byte[]> class_files = new ArrayList<>();
+    ArrayList<byte[]> dex_files = new ArrayList<>();
+
+    for (CommonClassDefinition d : defs) {
+      classes.add(d.target);
+      class_files.add(d.class_file_bytes);
+      dex_files.add(d.dex_file_bytes);
+    }
+    doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+                                   class_files.toArray(new byte[0][]),
+                                   dex_files.toArray(new byte[0][]));
+  }
+
+  public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+    for (CommonClassDefinition d : defs) {
+      addCommonTransformationResult(d.target.getCanonicalName(),
+                                    d.class_file_bytes,
+                                    d.dex_file_bytes);
+    }
+  }
+
+  public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+                                                           byte[][] classfiles,
+                                                           byte[][] dexfiles);
+  public static native void doCommonClassRetransformation(Class<?>... target);
+  public static native void setPopRetransformations(boolean pop);
+  public static native void popTransformationFor(String name);
+  public static native void enableCommonRetransformation(boolean enable);
+  public static native void addCommonTransformationResult(String target_name,
+                                                          byte[] class_bytes,
+                                                          byte[] dex_bytes);
+}
diff --git a/test/1953-pop-frame/src/art/StackTrace.java b/test/1953-pop-frame/src/art/StackTrace.java
new file mode 100644
index 0000000..2ea2f20
--- /dev/null
+++ b/test/1953-pop-frame/src/art/StackTrace.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Executable;
+
+public class StackTrace {
+  public static class StackFrameData {
+    public final Thread thr;
+    public final Executable method;
+    public final long current_location;
+    public final int depth;
+
+    public StackFrameData(Thread thr, Executable e, long loc, int depth) {
+      this.thr = thr;
+      this.method = e;
+      this.current_location = loc;
+      this.depth = depth;
+    }
+    @Override
+    public String toString() {
+      return String.format(
+          "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }",
+          this.thr,
+          this.method,
+          this.current_location,
+          this.depth);
+    }
+  }
+
+  public static native int GetStackDepth(Thread thr);
+
+  private static native StackFrameData[] nativeGetStackTrace(Thread thr);
+
+  public static StackFrameData[] GetStackTrace(Thread thr) {
+    // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not
+    // suspended. The spec says that not being suspended is fine but since we want this to be
+    // consistent we will suspend for the RI.
+    boolean suspend_thread =
+        !System.getProperty("java.vm.name").equals("Dalvik") &&
+        !thr.equals(Thread.currentThread()) &&
+        !Suspension.isSuspended(thr);
+    if (suspend_thread) {
+      Suspension.suspend(thr);
+    }
+    StackFrameData[] out = nativeGetStackTrace(thr);
+    if (suspend_thread) {
+      Suspension.resume(thr);
+    }
+    return out;
+  }
+}
+
diff --git a/tools/cpp-define-generator/constant_card_table.def b/test/1953-pop-frame/src/art/Suspension.java
similarity index 61%
copy from tools/cpp-define-generator/constant_card_table.def
copy to test/1953-pop-frame/src/art/Suspension.java
index ae3e8f3..16e62cc 100644
--- a/tools/cpp-define-generator/constant_card_table.def
+++ b/test/1953-pop-frame/src/art/Suspension.java
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
-// Export heap values.
+package art;
 
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "gc/accounting/card_table.h"
-#endif
+public class Suspension {
+  // Suspends a thread using jvmti.
+  public native static void suspend(Thread thr);
 
-// Size of references to the heap on the stack.
-DEFINE_EXPR(CARD_TABLE_CARD_SHIFT, size_t, art::gc::accounting::CardTable::kCardShift)
+  // Resumes a thread using jvmti.
+  public native static void resume(Thread thr);
 
+  public native static boolean isSuspended(Thread thr);
+
+  public native static int[] suspendList(Thread... threads);
+  public native static int[] resumeList(Thread... threads);
+}
diff --git a/test/1953-pop-frame/src/art/Test1953.java b/test/1953-pop-frame/src/art/Test1953.java
new file mode 100644
index 0000000..adec776
--- /dev/null
+++ b/test/1953-pop-frame/src/art/Test1953.java
@@ -0,0 +1,976 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Base64;
+import java.util.EnumSet;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
+
+public class Test1953 {
+  public final boolean canRunClassLoadTests;
+  public static void doNothing() {}
+
+  public interface TestRunnable extends Runnable {
+    public int getBaseCallCount();
+    public Method getCalledMethod() throws Exception;
+    public default Method getCallingMethod() throws Exception {
+      return this.getClass().getMethod("run");
+    };
+  }
+
+  public static interface TestSuspender {
+    public void setup(Thread thr);
+    public void waitForSuspend(Thread thr);
+    public void cleanup(Thread thr);
+  }
+
+  public static interface ThreadRunnable { public void run(Thread thr); }
+  public static TestSuspender makeSuspend(final ThreadRunnable setup, final ThreadRunnable clean) {
+    return new TestSuspender() {
+      public void setup(Thread thr) { setup.run(thr); }
+      public void waitForSuspend(Thread thr) { Test1953.waitForSuspendHit(thr); }
+      public void cleanup(Thread thr) { clean.run(thr); }
+    };
+  }
+
+  public void runTestOn(TestRunnable testObj, ThreadRunnable su, ThreadRunnable cl) throws
+      Exception {
+    runTestOn(testObj, makeSuspend(su, cl));
+  }
+
+  private static void SafePrintStackTrace(StackTraceElement st[]) {
+    for (StackTraceElement e : st) {
+      System.out.println("\t" + e.getClassName() + "." + e.getMethodName() + "(" +
+          (e.isNativeMethod() ? "Native Method" : e.getFileName()) + ")");
+      if (e.getClassName().equals("art.Test1953") && e.getMethodName().equals("runTests")) {
+        System.out.println("\t<Additional frames hidden>");
+        break;
+      }
+    }
+  }
+
+  public void runTestOn(TestRunnable testObj, TestSuspender su) throws Exception {
+    System.out.println("Single call with PopFrame on " + testObj + " base-call-count: " +
+        testObj.getBaseCallCount());
+    final CountDownLatch continue_latch = new CountDownLatch(1);
+    final CountDownLatch startup_latch = new CountDownLatch(1);
+    Runnable await = () -> {
+      try {
+        startup_latch.countDown();
+        continue_latch.await();
+      } catch (Exception e) {
+        throw new Error("Failed to await latch", e);
+      }
+    };
+    Thread thr = new Thread(() -> { await.run(); testObj.run(); });
+    thr.start();
+
+    // Wait until the other thread is started.
+    startup_latch.await();
+
+    // Do any final setup.
+    preTest.accept(testObj);
+
+    // Setup suspension method on the thread.
+    su.setup(thr);
+
+    // Let the other thread go.
+    continue_latch.countDown();
+
+    // Wait for the other thread to hit the breakpoint/watchpoint/whatever and suspend itself
+    // (without re-entering java)
+    su.waitForSuspend(thr);
+
+    // Cleanup the breakpoint/watchpoint/etc.
+    su.cleanup(thr);
+
+    try {
+      // Pop the frame.
+      popFrame(thr);
+    } catch (Exception e) {
+      System.out.println("Failed to pop frame due to " + e);
+      SafePrintStackTrace(e.getStackTrace());
+    }
+
+    // Start the other thread going again.
+    Suspension.resume(thr);
+
+    // Wait for the other thread to finish.
+    thr.join();
+
+    // See how many times calledFunction was called.
+    System.out.println("result is " + testObj + " base-call count: " + testObj.getBaseCallCount());
+  }
+
+  public static abstract class AbstractTestObject implements TestRunnable {
+    public int callerCnt;
+
+    public AbstractTestObject() {
+      callerCnt = 0;
+    }
+
+    public int getBaseCallCount() {
+      return callerCnt;
+    }
+
+    public void run() {
+      callerCnt++;
+      // This function should be re-executed by the popFrame.
+      calledFunction();
+    }
+
+    public Method getCalledMethod() throws Exception {
+      return this.getClass().getMethod("calledFunction");
+    }
+
+    public abstract void calledFunction();
+  }
+
+  public static class RedefineTestObject extends AbstractTestObject implements Runnable {
+    public static enum RedefineState { ORIGINAL, REDEFINED, };
+    /* public static class RedefineTestObject extends AbstractTestObject implements Runnable {
+     *   public static final byte[] CLASS_BYTES;
+     *   public static final byte[] DEX_BYTES;
+     *   static {
+     *     CLASS_BYTES = null;
+     *     DEX_BYTES = null;
+     *   }
+     *
+     *   public EnumSet<RedefineState> redefine_states;
+     *   public RedefineTestObject() {
+     *     super();
+     *     redefine_states = EnumSet.noneOf(RedefineState.class);
+     *   }
+     *   public String toString() {
+     *     return "RedefineTestObject { states: " + redefine_states.toString()
+     *                                            + " current: REDEFINED }";
+     *   }
+     *   public void calledFunction() {
+     *     redefine_states.add(RedefineState.REDEFINED);  // line +0
+     *     // We will trigger the redefinition using a breakpoint on the next line.
+     *     doNothing();                                   // line +2
+     *   }
+     * }
+     */
+    public static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+      "yv66vgAAADUATQoADQAjBwAkCgAlACYJAAwAJwoAJQAoEgAAACwJAAIALQoAJQAuCgAvADAJAAwA" +
+      "MQkADAAyBwAzBwA0BwA2AQASUmVkZWZpbmVUZXN0T2JqZWN0AQAMSW5uZXJDbGFzc2VzAQANUmVk" +
+      "ZWZpbmVTdGF0ZQEAC0NMQVNTX0JZVEVTAQACW0IBAAlERVhfQllURVMBAA9yZWRlZmluZV9zdGF0" +
+      "ZXMBABNMamF2YS91dGlsL0VudW1TZXQ7AQAJU2lnbmF0dXJlAQBETGphdmEvdXRpbC9FbnVtU2V0" +
+      "PExhcnQvVGVzdDE5NTMkUmVkZWZpbmVUZXN0T2JqZWN0JFJlZGVmaW5lU3RhdGU7PjsBAAY8aW5p" +
+      "dD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAIdG9TdHJpbmcBABQoKUxqYXZhL2xh" +
+      "bmcvU3RyaW5nOwEADmNhbGxlZEZ1bmN0aW9uAQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQANVGVz" +
+      "dDE5NTMuamF2YQwAGQAaAQAtYXJ0L1Rlc3QxOTUzJFJlZGVmaW5lVGVzdE9iamVjdCRSZWRlZmlu" +
+      "ZVN0YXRlBwA3DAA4ADkMABUAFgwAHQAeAQAQQm9vdHN0cmFwTWV0aG9kcw8GADoIADsMADwAPQwA" +
+      "PgA/DABAAEEHAEIMAEMAGgwAEgATDAAUABMBAB9hcnQvVGVzdDE5NTMkUmVkZWZpbmVUZXN0T2Jq" +
+      "ZWN0AQAfYXJ0L1Rlc3QxOTUzJEFic3RyYWN0VGVzdE9iamVjdAEAEkFic3RyYWN0VGVzdE9iamVj" +
+      "dAEAEmphdmEvbGFuZy9SdW5uYWJsZQEAEWphdmEvdXRpbC9FbnVtU2V0AQAGbm9uZU9mAQAmKExq" +
+      "YXZhL2xhbmcvQ2xhc3M7KUxqYXZhL3V0aWwvRW51bVNldDsKAEQARQEAM1JlZGVmaW5lVGVzdE9i" +
+      "amVjdCB7IHN0YXRlczogASBjdXJyZW50OiBSRURFRklORUQgfQEAF21ha2VDb25jYXRXaXRoQ29u" +
+      "c3RhbnRzAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAlSRURFRklO" +
+      "RUQBAC9MYXJ0L1Rlc3QxOTUzJFJlZGVmaW5lVGVzdE9iamVjdCRSZWRlZmluZVN0YXRlOwEAA2Fk" +
+      "ZAEAFShMamF2YS9sYW5nL09iamVjdDspWgEADGFydC9UZXN0MTk1MwEACWRvTm90aGluZwcARgwA" +
+      "PABJAQAkamF2YS9sYW5nL2ludm9rZS9TdHJpbmdDb25jYXRGYWN0b3J5BwBLAQAGTG9va3VwAQCY" +
+      "KExqYXZhL2xhbmcvaW52b2tlL01ldGhvZEhhbmRsZXMkTG9va3VwO0xqYXZhL2xhbmcvU3RyaW5n" +
+      "O0xqYXZhL2xhbmcvaW52b2tlL01ldGhvZFR5cGU7TGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xh" +
+      "bmcvT2JqZWN0OylMamF2YS9sYW5nL2ludm9rZS9DYWxsU2l0ZTsHAEwBACVqYXZhL2xhbmcvaW52" +
+      "b2tlL01ldGhvZEhhbmRsZXMkTG9va3VwAQAeamF2YS9sYW5nL2ludm9rZS9NZXRob2RIYW5kbGVz" +
+      "ACEADAANAAEADgADABkAEgATAAAAGQAUABMAAAABABUAFgABABcAAAACABgABAABABkAGgABABsA" +
+      "AAAuAAIAAQAAAA4qtwABKhICuAADtQAEsQAAAAEAHAAAAA4AAwAAACEABAAiAA0AIwABAB0AHgAB" +
+      "ABsAAAAlAAEAAQAAAA0qtAAEtgAFugAGAACwAAAAAQAcAAAABgABAAAAJQABAB8AGgABABsAAAAv" +
+      "AAIAAQAAAA8qtAAEsgAHtgAIV7gACbEAAAABABwAAAAOAAMAAAApAAsAKwAOACwACAAgABoAAQAb" +
+      "AAAAKQABAAAAAAAJAbMACgGzAAuxAAAAAQAcAAAADgADAAAAGwAEABwACAAdAAMAIQAAAAIAIgAQ" +
+      "AAAAIgAEAAwALwAPAAkAAgAMABFAGQANAC8ANQQJAEcASgBIABkAKQAAAAgAAQAqAAEAKw==");
+    public static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+      "ZGV4CjAzNQAaR23N6WpunLRVX+BexSuzzNNiHNOvQpFoBwAAcAAAAHhWNBIAAAAAAAAAAKQGAAAq" +
+      "AAAAcAAAABEAAAAYAQAABQAAAFwBAAAEAAAAmAEAAAwAAAC4AQAAAQAAABgCAAAwBQAAOAIAACID" +
+      "AAA5AwAAQwMAAEsDAABPAwAAXAMAAGcDAABqAwAAbgMAAJEDAADCAwAA5QMAAPUDAAAZBAAAOQQA" +
+      "AFwEAAB7BAAAjgQAAKIEAAC4BAAAzAQAAOcEAAD8BAAAEQUAABwFAAAwBQAATwUAAF4FAABhBQAA" +
+      "ZAUAAGgFAABsBQAAeQUAAH4FAACGBQAAlgUAAKEFAACnBQAArwUAAMAFAADKBQAA0QUAAAgAAAAJ" +
+      "AAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAGwAAABwA" +
+      "AAAeAAAABgAAAAsAAAAAAAAABwAAAAwAAAAMAwAABwAAAA0AAAAUAwAAGwAAAA4AAAAAAAAAHQAA" +
+      "AA8AAAAcAwAAAQABABcAAAACABAABAAAAAIAEAAFAAAAAgANACYAAAAAAAMAAgAAAAIAAwABAAAA" +
+      "AgADAAIAAAACAAMAIgAAAAIAAAAnAAAAAwADACMAAAAMAAMAAgAAAAwAAQAhAAAADAAAACcAAAAN" +
+      "AAQAIAAAAA0AAgAlAAAADQAAACcAAAACAAAAAQAAAAAAAAAEAwAAGgAAAIwGAABRBgAAAAAAAAQA" +
+      "AQACAAAA+gIAAB0AAABUMAMAbhALAAAADAAiAQwAcBAGAAEAGgIZAG4gBwAhAG4gBwABABoAAABu" +
+      "IAcAAQBuEAgAAQAMABEAAAABAAAAAAAAAPQCAAAGAAAAEgBpAAEAaQACAA4AAgABAAEAAADuAgAA" +
+      "DAAAAHAQAAABABwAAQBxEAoAAAAMAFsQAwAOAAMAAQACAAAA/gIAAAsAAABUIAMAYgEAAG4gCQAQ" +
+      "AHEABQAAAA4AIQAOPIcAGwAOPC0AJQAOACkADnk8AAEAAAAKAAAAAQAAAAsAAAABAAAACAAAAAEA" +
+      "AAAJABUgY3VycmVudDogUkVERUZJTkVEIH0ACDxjbGluaXQ+AAY8aW5pdD4AAj47AAtDTEFTU19C" +
+      "WVRFUwAJREVYX0JZVEVTAAFMAAJMTAAhTGFydC9UZXN0MTk1MyRBYnN0cmFjdFRlc3RPYmplY3Q7" +
+      "AC9MYXJ0L1Rlc3QxOTUzJFJlZGVmaW5lVGVzdE9iamVjdCRSZWRlZmluZVN0YXRlOwAhTGFydC9U" +
+      "ZXN0MTk1MyRSZWRlZmluZVRlc3RPYmplY3Q7AA5MYXJ0L1Rlc3QxOTUzOwAiTGRhbHZpay9hbm5v" +
+      "dGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ACFM" +
+      "ZGFsdmlrL2Fubm90YXRpb24vTWVtYmVyQ2xhc3NlczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWdu" +
+      "YXR1cmU7ABFMamF2YS9sYW5nL0NsYXNzOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5n" +
+      "L1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7" +
+      "ABNMamF2YS91dGlsL0VudW1TZXQ7ABNMamF2YS91dGlsL0VudW1TZXQ8AAlSRURFRklORUQAElJl" +
+      "ZGVmaW5lVGVzdE9iamVjdAAdUmVkZWZpbmVUZXN0T2JqZWN0IHsgc3RhdGVzOiAADVRlc3QxOTUz" +
+      "LmphdmEAAVYAAVoAAlpMAAJbQgALYWNjZXNzRmxhZ3MAA2FkZAAGYXBwZW5kAA5jYWxsZWRGdW5j" +
+      "dGlvbgAJZG9Ob3RoaW5nAARuYW1lAAZub25lT2YAD3JlZGVmaW5lX3N0YXRlcwAIdG9TdHJpbmcA" +
+      "BXZhbHVlAFt+fkQ4eyJtaW4tYXBpIjoxLCJzaGEtMSI6IjUyNzNjM2RmZWUxMDQ2NzIwYWY0MjVm" +
+      "YTg1NTMxNmM5OWM4NmM4ZDIiLCJ2ZXJzaW9uIjoiMS4zLjE4LWRldiJ9AAIHASgcAxcWFwkXAwIE" +
+      "ASgYAwIFAh8ECSQXGAIGASgcARgBAgECAgEZARkDAQGIgASEBQGBgASgBQMByAUBAbgEAAAAAAAB" +
+      "AAAALgYAAAMAAAA6BgAAQAYAAEkGAAB8BgAAAQAAAAAAAAAAAAAAAwAAAHQGAAAQAAAAAAAAAAEA" +
+      "AAAAAAAAAQAAACoAAABwAAAAAgAAABEAAAAYAQAAAwAAAAUAAABcAQAABAAAAAQAAACYAQAABQAA" +
+      "AAwAAAC4AQAABgAAAAEAAAAYAgAAASAAAAQAAAA4AgAAAyAAAAQAAADuAgAAARAAAAQAAAAEAwAA" +
+      "AiAAACoAAAAiAwAABCAAAAQAAAAuBgAAACAAAAEAAABRBgAAAxAAAAMAAABwBgAABiAAAAEAAACM" +
+      "BgAAABAAAAEAAACkBgAA");
+
+    public EnumSet<RedefineState> redefine_states;
+    public RedefineTestObject() {
+      super();
+      redefine_states = EnumSet.noneOf(RedefineState.class);
+    }
+
+    public String toString() {
+      return "RedefineTestObject { states: " + redefine_states.toString() + " current: ORIGINAL }";
+    }
+
+    public void calledFunction() {
+      redefine_states.add(RedefineState.ORIGINAL);  // line +0
+      // We will trigger the redefinition using a breakpoint on the next line.
+      doNothing();                                  // line +2
+    }
+  }
+
+  public static class ClassLoadObject implements TestRunnable {
+    public int cnt;
+    public int baseCallCnt;
+
+    public static final String[] CLASS_NAMES = new String[] {
+      "Lart/Test1953$ClassLoadObject$TC0;",
+      "Lart/Test1953$ClassLoadObject$TC1;",
+      "Lart/Test1953$ClassLoadObject$TC2;",
+      "Lart/Test1953$ClassLoadObject$TC3;",
+      "Lart/Test1953$ClassLoadObject$TC4;",
+      "Lart/Test1953$ClassLoadObject$TC5;",
+      "Lart/Test1953$ClassLoadObject$TC6;",
+      "Lart/Test1953$ClassLoadObject$TC7;",
+      "Lart/Test1953$ClassLoadObject$TC8;",
+      "Lart/Test1953$ClassLoadObject$TC9;",
+    };
+
+    private static int curClass = 0;
+
+    private static class TC0 { public static int foo; static { foo = 1; } }
+    private static class TC1 { public static int foo; static { foo = 2; } }
+    private static class TC2 { public static int foo; static { foo = 3; } }
+    private static class TC3 { public static int foo; static { foo = 4; } }
+    private static class TC4 { public static int foo; static { foo = 5; } }
+    private static class TC5 { public static int foo; static { foo = 6; } }
+    private static class TC6 { public static int foo; static { foo = 7; } }
+    private static class TC7 { public static int foo; static { foo = 8; } }
+    private static class TC8 { public static int foo; static { foo = 9; } }
+    private static class TC9 { public static int foo; static { foo = 10; } }
+
+    public ClassLoadObject() {
+      super();
+      cnt = 0;
+      baseCallCnt = 0;
+    }
+
+    public int getBaseCallCount() {
+      return baseCallCnt;
+    }
+
+    public void run() {
+      baseCallCnt++;
+      if (curClass == 0) {
+        $noprecompile$calledFunction0();
+      } else if (curClass == 1) {
+        $noprecompile$calledFunction1();
+      } else if (curClass == 2) {
+        $noprecompile$calledFunction2();
+      } else if (curClass == 3) {
+        $noprecompile$calledFunction3();
+      } else if (curClass == 4) {
+        $noprecompile$calledFunction4();
+      } else if (curClass == 5) {
+        $noprecompile$calledFunction5();
+      } else if (curClass == 6) {
+        $noprecompile$calledFunction6();
+      } else if (curClass == 7) {
+        $noprecompile$calledFunction7();
+      } else if (curClass == 8) {
+        $noprecompile$calledFunction8();
+      } else if (curClass == 9) {
+        $noprecompile$calledFunction9();
+      }
+      curClass++;
+    }
+
+    public Method getCalledMethod() throws Exception {
+      return this.getClass().getMethod("jnoprecompile$calledFunction" + curClass);
+    }
+
+    // Give these all a tag to prevent 1954 from compiling them (and loading the class as a
+    // consequence).
+    public void $noprecompile$calledFunction0() {
+      cnt++;
+      System.out.println("TC0.foo == " + TC0.foo);
+    }
+
+    public void $noprecompile$calledFunction1() {
+      cnt++;
+      System.out.println("TC1.foo == " + TC1.foo);
+    }
+
+    public void $noprecompile$calledFunction2() {
+      cnt++;
+      System.out.println("TC2.foo == " + TC2.foo);
+    }
+
+    public void $noprecompile$calledFunction3() {
+      cnt++;
+      System.out.println("TC3.foo == " + TC3.foo);
+    }
+
+    public void $noprecompile$calledFunction4() {
+      cnt++;
+      System.out.println("TC4.foo == " + TC4.foo);
+    }
+
+    public void $noprecompile$calledFunction5() {
+      cnt++;
+      System.out.println("TC5.foo == " + TC5.foo);
+    }
+
+    public void $noprecompile$calledFunction6() {
+      cnt++;
+      System.out.println("TC6.foo == " + TC6.foo);
+    }
+
+    public void $noprecompile$calledFunction7() {
+      cnt++;
+      System.out.println("TC7.foo == " + TC7.foo);
+    }
+
+    public void $noprecompile$calledFunction8() {
+      cnt++;
+      System.out.println("TC8.foo == " + TC8.foo);
+    }
+
+    public void $noprecompile$calledFunction9() {
+      cnt++;
+      System.out.println("TC9.foo == " + TC9.foo);
+    }
+
+    public String toString() {
+      return "ClassLoadObject { cnt: " + cnt + ", curClass: " + curClass + "}";
+    }
+  }
+
+  public static class FieldBasedTestObject extends AbstractTestObject implements Runnable {
+    public int cnt;
+    public int TARGET_FIELD;
+    public FieldBasedTestObject() {
+      super();
+      cnt = 0;
+      TARGET_FIELD = 0;
+    }
+
+    public void calledFunction() {
+      cnt++;
+      // We put a watchpoint here and PopFrame when we are at it.
+      TARGET_FIELD += 10;
+      if (cnt == 1) { System.out.println("FAILED: No pop on first call!"); }
+    }
+
+    public String toString() {
+      return "FieldBasedTestObject { cnt: " + cnt + ", TARGET_FIELD: " + TARGET_FIELD + " }";
+    }
+  }
+
+  public static class StandardTestObject extends AbstractTestObject implements Runnable {
+    public int cnt;
+    public final boolean check;
+
+    public StandardTestObject(boolean check) {
+      super();
+      cnt = 0;
+      this.check = check;
+    }
+
+    public StandardTestObject() {
+      this(true);
+    }
+
+    public void calledFunction() {
+      cnt++;       // line +0
+      // We put a breakpoint here and PopFrame when we are at it.
+      doNothing(); // line +2
+      if (check && cnt == 1) { System.out.println("FAILED: No pop on first call!"); }
+    }
+
+    public String toString() {
+      return "StandardTestObject { cnt: " + cnt + " }";
+    }
+  }
+
+  public static class SynchronizedFunctionTestObject extends AbstractTestObject implements Runnable {
+    public int cnt;
+
+    public SynchronizedFunctionTestObject() {
+      super();
+      cnt = 0;
+    }
+
+    public synchronized void calledFunction() {
+      cnt++;               // line +0
+      // We put a breakpoint here and PopFrame when we are at it.
+      doNothing();         // line +2
+    }
+
+    public String toString() {
+      return "SynchronizedFunctionTestObject { cnt: " + cnt + " }";
+    }
+  }
+  public static class SynchronizedTestObject extends AbstractTestObject implements Runnable {
+    public int cnt;
+    public final Object lock;
+
+    public SynchronizedTestObject() {
+      super();
+      cnt = 0;
+      lock = new Object();
+    }
+
+    public void calledFunction() {
+      synchronized (lock) {  // line +0
+        cnt++;               // line +1
+        // We put a breakpoint here and PopFrame when we are at it.
+        doNothing();         // line +3
+      }
+    }
+
+    public String toString() {
+      return "SynchronizedTestObject { cnt: " + cnt + " }";
+    }
+  }
+
+  public static class ExceptionCatchTestObject extends AbstractTestObject implements Runnable {
+    public static class TestError extends Error {}
+
+    public int cnt;
+    public ExceptionCatchTestObject() {
+      super();
+      cnt = 0;
+    }
+
+    public void calledFunction() {
+      cnt++;
+      try {
+        doThrow();
+      } catch (TestError e) {
+        System.out.println(e.getClass().getName() + " caught in called function.");
+      }
+    }
+
+    public void doThrow() {
+      throw new TestError();
+    }
+
+    public String toString() {
+      return "ExceptionCatchTestObject { cnt: " + cnt + " }";
+    }
+  }
+
+  public static class ExceptionThrowFarTestObject implements TestRunnable {
+    public static class TestError extends Error {}
+
+    public int cnt;
+    public int baseCallCnt;
+    public final boolean catchInCalled;
+    public ExceptionThrowFarTestObject(boolean catchInCalled) {
+      super();
+      cnt = 0;
+      baseCallCnt = 0;
+      this.catchInCalled = catchInCalled;
+    }
+
+    public int getBaseCallCount() {
+      return baseCallCnt;
+    }
+
+    public void run() {
+      baseCallCnt++;
+      try {
+        callingFunction();
+      } catch (TestError e) {
+        System.out.println(e.getClass().getName() + " thrown and caught!");
+      }
+    }
+
+    public void callingFunction() {
+      calledFunction();
+    }
+    public void calledFunction() {
+      cnt++;
+      if (catchInCalled) {
+        try {
+          throw new TestError(); // We put a watch here.
+        } catch (TestError e) {
+          System.out.println(e.getClass().getName() + " caught in same function.");
+        }
+      } else {
+        throw new TestError(); // We put a watch here.
+      }
+    }
+
+    public Method getCallingMethod() throws Exception {
+      return this.getClass().getMethod("callingFunction");
+    }
+
+    public Method getCalledMethod() throws Exception {
+      return this.getClass().getMethod("calledFunction");
+    }
+
+    public String toString() {
+      return "ExceptionThrowFarTestObject { cnt: " + cnt + " }";
+    }
+  }
+
+  public static class ExceptionOnceObject extends AbstractTestObject {
+    public static final class TestError extends Error {}
+    public int cnt;
+    public final boolean throwInSub;
+    public ExceptionOnceObject(boolean throwInSub) {
+      super();
+      cnt = 0;
+      this.throwInSub = throwInSub;
+    }
+
+    public void calledFunction() {
+      cnt++;
+      if (cnt == 1) {
+        if (throwInSub) {
+          doThrow();
+        } else {
+          throw new TestError();
+        }
+      }
+    }
+
+    public void doThrow() {
+      throw new TestError();
+    }
+
+    public String toString() {
+      return "ExceptionOnceObject { cnt: " + cnt + ", throwInSub: " + throwInSub + " }";
+    }
+  }
+
+  public static class ExceptionThrowTestObject implements TestRunnable {
+    public static class TestError extends Error {}
+
+    public int cnt;
+    public int baseCallCnt;
+    public final boolean catchInCalled;
+    public ExceptionThrowTestObject(boolean catchInCalled) {
+      super();
+      cnt = 0;
+      baseCallCnt = 0;
+      this.catchInCalled = catchInCalled;
+    }
+
+    public int getBaseCallCount() {
+      return baseCallCnt;
+    }
+
+    public void run() {
+      baseCallCnt++;
+      try {
+        calledFunction();
+      } catch (TestError e) {
+        System.out.println(e.getClass().getName() + " thrown and caught!");
+      }
+    }
+
+    public void calledFunction() {
+      cnt++;
+      if (catchInCalled) {
+        try {
+          throw new TestError(); // We put a watch here.
+        } catch (TestError e) {
+          System.out.println(e.getClass().getName() + " caught in same function.");
+        }
+      } else {
+        throw new TestError(); // We put a watch here.
+      }
+    }
+
+    public Method getCalledMethod() throws Exception {
+      return this.getClass().getMethod("calledFunction");
+    }
+
+    public String toString() {
+      return "ExceptionThrowTestObject { cnt: " + cnt + " }";
+    }
+  }
+
+  public static class NativeCalledObject extends AbstractTestObject {
+    public int cnt = 0;
+
+    public native void calledFunction();
+
+    public String toString() {
+      return "NativeCalledObject { cnt: " + cnt + " }";
+    }
+  }
+
+  public static class NativeCallerObject implements TestRunnable {
+    public int baseCnt = 0;
+    public int cnt = 0;
+
+    public int getBaseCallCount() {
+      return baseCnt;
+    }
+
+    public native void run();
+
+    public void calledFunction() {
+      cnt++;
+      // We will stop using a MethodExit event.
+    }
+
+    public Method getCalledMethod() throws Exception {
+      return this.getClass().getMethod("calledFunction");
+    }
+
+    public String toString() {
+      return "NativeCallerObject { cnt: " + cnt + " }";
+    }
+  }
+  public static class SuspendSuddenlyObject extends AbstractTestObject {
+    public volatile boolean stop_spinning = false;
+    public volatile boolean is_spinning = false;
+    public int cnt = 0;
+
+    public void calledFunction() {
+      cnt++;
+      while (!stop_spinning) {
+        is_spinning = true;
+      }
+    }
+
+    public String toString() {
+      return "SuspendSuddenlyObject { cnt: " + cnt + " }";
+    }
+  }
+
+  public static void run(boolean canRunClassLoadTests) throws Exception {
+    new Test1953(canRunClassLoadTests, (x)-> {}).runTests();
+  }
+
+  // This entrypoint is used by CTS only. */
+  public static void run() throws Exception {
+    /* TODO: Due to the way that CTS tests are verified we cannot run class-load-tests since the
+     *       verifier will be delayed until runtime and then load the classes all at once. This
+     *       makes the test impossible to run.
+     */
+    run(/*canRunClassLoadTests*/ false);
+  }
+
+  public Test1953(boolean canRunClassLoadTests, Consumer<TestRunnable> preTest) {
+    this.canRunClassLoadTests = canRunClassLoadTests;
+    this.preTest = preTest;
+  }
+
+  private Consumer<TestRunnable> preTest;
+
+  public void runTests() throws Exception {
+    setupTest();
+
+    final Method calledFunction = StandardTestObject.class.getDeclaredMethod("calledFunction");
+    final Method doNothingMethod = Test1953.class.getDeclaredMethod("doNothing");
+    // Add a breakpoint on the second line after the start of the function
+    final int line = Breakpoint.locationToLine(calledFunction, 0) + 2;
+    final long loc = Breakpoint.lineToLocation(calledFunction, line);
+    System.out.println("Test stopped using breakpoint");
+    runTestOn(new StandardTestObject(),
+        (thr) -> setupSuspendBreakpointFor(calledFunction, loc, thr),
+        Test1953::clearSuspendBreakpointFor);
+
+    final Method syncFunctionCalledFunction =
+        SynchronizedFunctionTestObject.class.getDeclaredMethod("calledFunction");
+    // Add a breakpoint on the second line after the start of the function
+    // Annoyingly r8 generally has the first instruction (a monitor enter) not be marked as being
+    // on any line but javac has it marked as being on the first line of the function. Just use the
+    // second entry on the line-number table to get the breakpoint. This should be good for both.
+    final long syncFunctionLoc =
+        Breakpoint.getLineNumberTable(syncFunctionCalledFunction)[1].location;
+    System.out.println("Test stopped using breakpoint with declared synchronized function");
+    runTestOn(new SynchronizedFunctionTestObject(),
+        (thr) -> setupSuspendBreakpointFor(syncFunctionCalledFunction, syncFunctionLoc, thr),
+        Test1953::clearSuspendBreakpointFor);
+
+    final Method syncCalledFunction =
+        SynchronizedTestObject.class.getDeclaredMethod("calledFunction");
+    // Add a breakpoint on the second line after the start of the function
+    final int syncLine = Breakpoint.locationToLine(syncCalledFunction, 0) + 3;
+    final long syncLoc = Breakpoint.lineToLocation(syncCalledFunction, syncLine);
+    System.out.println("Test stopped using breakpoint with synchronized block");
+    runTestOn(new SynchronizedTestObject(),
+        (thr) -> setupSuspendBreakpointFor(syncCalledFunction, syncLoc, thr),
+        Test1953::clearSuspendBreakpointFor);
+
+    System.out.println("Test stopped on single step");
+    runTestOn(new StandardTestObject(),
+        (thr) -> setupSuspendSingleStepAt(calledFunction, loc, thr),
+        Test1953::clearSuspendSingleStepFor);
+
+    final Field target_field = FieldBasedTestObject.class.getDeclaredField("TARGET_FIELD");
+    System.out.println("Test stopped on field access");
+    runTestOn(new FieldBasedTestObject(),
+        (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, true, thr),
+        Test1953::clearFieldSuspendFor);
+
+    System.out.println("Test stopped on field modification");
+    runTestOn(new FieldBasedTestObject(),
+        (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, false, thr),
+        Test1953::clearFieldSuspendFor);
+
+    System.out.println("Test stopped during Method Exit of doNothing");
+    runTestOn(new StandardTestObject(false),
+        (thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ false, thr),
+        Test1953::clearSuspendMethodEvent);
+
+    // NB We need another test to make sure the MethodEntered event is triggered twice.
+    System.out.println("Test stopped during Method Enter of doNothing");
+    runTestOn(new StandardTestObject(false),
+        (thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ true, thr),
+        Test1953::clearSuspendMethodEvent);
+
+    System.out.println("Test stopped during Method Exit of calledFunction");
+    runTestOn(new StandardTestObject(false),
+        (thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ false, thr),
+        Test1953::clearSuspendMethodEvent);
+
+    System.out.println("Test stopped during Method Enter of calledFunction");
+    runTestOn(new StandardTestObject(false),
+        (thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ true, thr),
+        Test1953::clearSuspendMethodEvent);
+
+    final Method exceptionOnceCalledMethod =
+        ExceptionOnceObject.class.getDeclaredMethod("calledFunction");
+    System.out.println("Test stopped during Method Exit due to exception thrown in same function");
+    runTestOn(new ExceptionOnceObject(/*throwInSub*/ false),
+        (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr),
+        Test1953::clearSuspendMethodEvent);
+
+    System.out.println("Test stopped during Method Exit due to exception thrown in subroutine");
+    runTestOn(new ExceptionOnceObject(/*throwInSub*/ true),
+        (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr),
+        Test1953::clearSuspendMethodEvent);
+
+    System.out.println("Test stopped during notifyFramePop without exception on pop of calledFunction");
+    runTestOn(new StandardTestObject(false),
+        (thr) -> setupSuspendPopFrameEvent(1, doNothingMethod, thr),
+        Test1953::clearSuspendPopFrameEvent);
+
+    System.out.println("Test stopped during notifyFramePop without exception on pop of doNothing");
+    runTestOn(new StandardTestObject(false),
+        (thr) -> setupSuspendPopFrameEvent(0, doNothingMethod, thr),
+        Test1953::clearSuspendPopFrameEvent);
+
+    final Method exceptionThrowCalledMethod =
+        ExceptionThrowTestObject.class.getDeclaredMethod("calledFunction");
+    System.out.println("Test stopped during notifyFramePop with exception on pop of calledFunction");
+    runTestOn(new ExceptionThrowTestObject(false),
+        (thr) -> setupSuspendPopFrameEvent(0, exceptionThrowCalledMethod, thr),
+        Test1953::clearSuspendPopFrameEvent);
+
+    final Method exceptionCatchThrowMethod =
+        ExceptionCatchTestObject.class.getDeclaredMethod("doThrow");
+    System.out.println("Test stopped during notifyFramePop with exception on pop of doThrow");
+    runTestOn(new ExceptionCatchTestObject(),
+        (thr) -> setupSuspendPopFrameEvent(0, exceptionCatchThrowMethod, thr),
+        Test1953::clearSuspendPopFrameEvent);
+
+    System.out.println("Test stopped during ExceptionCatch event of calledFunction " +
+        "(catch in called function, throw in called function)");
+    runTestOn(new ExceptionThrowTestObject(true),
+        (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ true, thr),
+        Test1953::clearSuspendExceptionEvent);
+
+    final Method exceptionCatchCalledMethod =
+        ExceptionCatchTestObject.class.getDeclaredMethod("calledFunction");
+    System.out.println("Test stopped during ExceptionCatch event of calledFunction " +
+        "(catch in called function, throw in subroutine)");
+    runTestOn(new ExceptionCatchTestObject(),
+        (thr) -> setupSuspendExceptionEvent(exceptionCatchCalledMethod, /*catch*/ true, thr),
+        Test1953::clearSuspendExceptionEvent);
+
+    System.out.println("Test stopped during Exception event of calledFunction " +
+        "(catch in calling function)");
+    runTestOn(new ExceptionThrowTestObject(false),
+        (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr),
+        Test1953::clearSuspendExceptionEvent);
+
+    System.out.println("Test stopped during Exception event of calledFunction " +
+        "(catch in called function)");
+    runTestOn(new ExceptionThrowTestObject(true),
+        (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr),
+        Test1953::clearSuspendExceptionEvent);
+
+    final Method exceptionThrowFarCalledMethod =
+        ExceptionThrowFarTestObject.class.getDeclaredMethod("calledFunction");
+    System.out.println("Test stopped during Exception event of calledFunction " +
+        "(catch in parent of calling function)");
+    runTestOn(new ExceptionThrowFarTestObject(false),
+        (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr),
+        Test1953::clearSuspendExceptionEvent);
+
+    System.out.println("Test stopped during Exception event of calledFunction " +
+        "(catch in called function)");
+    runTestOn(new ExceptionThrowFarTestObject(true),
+        (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr),
+        Test1953::clearSuspendExceptionEvent);
+
+    // These tests are disabled for either the RI (b/116003018) or for jvmti-stress. For the
+    // later it is due to the additional agent causing classes to be loaded earlier as it forces
+    // deeper verification during class redefinition, causing failures.
+    // NB the agent is prevented from popping frames in either of these events in ART. See
+    // b/117615146 for more information about this restriction.
+    if (canRunClassLoadTests && CanRunClassLoadingTests()) {
+      // This test doesn't work on RI since the RI disallows use of PopFrame during a ClassLoad
+      // event. See b/116003018 for more information.
+      System.out.println("Test stopped during a ClassLoad event.");
+      runTestOn(new ClassLoadObject(),
+          (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_LOAD, ClassLoadObject.CLASS_NAMES, thr),
+          Test1953::clearSuspendClassEvent);
+
+      // The RI handles a PopFrame during a ClassPrepare event incorrectly. See b/116003018 for
+      // more information.
+      System.out.println("Test stopped during a ClassPrepare event.");
+      runTestOn(new ClassLoadObject(),
+          (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_PREPARE,
+                                          ClassLoadObject.CLASS_NAMES,
+                                          thr),
+          Test1953::clearSuspendClassEvent);
+    }
+    System.out.println("Test stopped during random Suspend.");
+    final SuspendSuddenlyObject sso = new SuspendSuddenlyObject();
+    runTestOn(
+        sso,
+        new TestSuspender() {
+          public void setup(Thread thr) { }
+          public void waitForSuspend(Thread thr) {
+            while (!sso.is_spinning) {}
+            Suspension.suspend(thr);
+          }
+          public void cleanup(Thread thr) {
+            sso.stop_spinning = true;
+          }
+        });
+
+    final Method redefineCalledFunction =
+       RedefineTestObject.class.getDeclaredMethod("calledFunction");
+    final int redefLine = Breakpoint.locationToLine(redefineCalledFunction, 0) + 2;
+    final long redefLoc = Breakpoint.lineToLocation(redefineCalledFunction, redefLine);
+    System.out.println("Test redefining frame being popped.");
+    runTestOn(new RedefineTestObject(),
+        (thr) -> setupSuspendBreakpointFor(redefineCalledFunction, redefLoc, thr),
+        (thr) -> {
+          clearSuspendBreakpointFor(thr);
+          Redefinition.doCommonClassRedefinition(RedefineTestObject.class,
+                                                 RedefineTestObject.CLASS_BYTES,
+                                                 RedefineTestObject.DEX_BYTES);
+        });
+
+    System.out.println("Test stopped during a native method fails");
+    runTestOn(new NativeCalledObject(),
+        Test1953::setupWaitForNativeCall,
+        Test1953::clearWaitForNativeCall);
+
+    System.out.println("Test stopped in a method called by native fails");
+    final Method nativeCallerMethod = NativeCallerObject.class.getDeclaredMethod("calledFunction");
+    runTestOn(new NativeCallerObject(),
+        (thr) -> setupSuspendMethodEvent(nativeCallerMethod, /*enter*/ false, thr),
+        Test1953::clearSuspendMethodEvent);
+  }
+
+  // Volatile is to prevent any future optimizations that could invalidate this test by doing
+  // constant propagation and eliminating the failing paths before the verifier is able to load the
+  // class.
+  static volatile boolean ranClassLoadTest = false;
+  static boolean classesPreverified = false;
+  private static final class RCLT0 { public void foo() {} }
+  private static final class RCLT1 { public void foo() {} }
+  // If classes are not preverified for some reason (interp-ac, no-image, etc) the verifier will
+  // actually load classes as it runs. This means that we cannot use the class-load tests as they
+  // are written. TODO Support this.
+  public boolean CanRunClassLoadingTests() {
+    if (ranClassLoadTest) {
+      return classesPreverified;
+    }
+    if (!ranClassLoadTest) {
+      // Only this will ever be executed.
+      new RCLT0().foo();
+    } else {
+      // This will never be executed. If classes are not preverified the verifier will load RCLT1
+      // when the enclosing method is run. This behavior makes the class-load/prepare test cases
+      // impossible to successfully run (they will deadlock).
+      new RCLT1().foo();
+      System.out.println("FAILURE: UNREACHABLE Location!");
+    }
+    classesPreverified = !isClassLoaded("Lart/Test1953$RCLT1;");
+    ranClassLoadTest = true;
+    return classesPreverified;
+  }
+
+  public static native boolean isClassLoaded(String name);
+
+  public static native void setupTest();
+  public static native void popFrame(Thread thr);
+
+  public static native void setupSuspendBreakpointFor(Executable meth, long loc, Thread thr);
+  public static native void clearSuspendBreakpointFor(Thread thr);
+
+  public static native void setupSuspendSingleStepAt(Executable meth, long loc, Thread thr);
+  public static native void clearSuspendSingleStepFor(Thread thr);
+
+  public static native void setupFieldSuspendFor(Class klass, Field f, boolean access, Thread thr);
+  public static native void clearFieldSuspendFor(Thread thr);
+
+  public static native void setupSuspendMethodEvent(Executable meth, boolean enter, Thread thr);
+  public static native void clearSuspendMethodEvent(Thread thr);
+
+  public static native void setupSuspendExceptionEvent(
+      Executable meth, boolean is_catch, Thread thr);
+  public static native void clearSuspendExceptionEvent(Thread thr);
+
+  public static native void setupSuspendPopFrameEvent(
+      int offset, Executable breakpointFunction, Thread thr);
+  public static native void clearSuspendPopFrameEvent(Thread thr);
+
+  public static final int EVENT_TYPE_CLASS_LOAD = 55;
+  public static final int EVENT_TYPE_CLASS_PREPARE = 56;
+  public static native void setupSuspendClassEvent(
+      int eventType, String[] interestingNames, Thread thr);
+  public static native void clearSuspendClassEvent(Thread thr);
+
+  public static native void setupWaitForNativeCall(Thread thr);
+  public static native void clearWaitForNativeCall(Thread thr);
+
+  public static native void waitForSuspendHit(Thread thr);
+}
diff --git a/test/1954-pop-frame-jit/check b/test/1954-pop-frame-jit/check
new file mode 100755
index 0000000..10b87cc
--- /dev/null
+++ b/test/1954-pop-frame-jit/check
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The RI has restrictions and bugs around some PopFrame behavior that ART lacks.
+# See b/116003018. Some configurations cannot handle the class load events in
+# quite the right way so they are disabled there too.
+./default-check "$@" || \
+  (patch -p0 expected.txt < jvm-expected.patch >/dev/null && ./default-check "$@")
diff --git a/test/1954-pop-frame-jit/expected.txt b/test/1954-pop-frame-jit/expected.txt
new file mode 100644
index 0000000..a20a045
--- /dev/null
+++ b/test/1954-pop-frame-jit/expected.txt
@@ -0,0 +1,118 @@
+Test stopped using breakpoint
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped using breakpoint with declared synchronized function
+Single call with PopFrame on SynchronizedFunctionTestObject { cnt: 0 } base-call-count: 0
+result is SynchronizedFunctionTestObject { cnt: 2 } base-call count: 1
+Test stopped using breakpoint with synchronized block
+Single call with PopFrame on SynchronizedTestObject { cnt: 0 } base-call-count: 0
+result is SynchronizedTestObject { cnt: 2 } base-call count: 1
+Test stopped on single step
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped on field access
+Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0
+result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1
+Test stopped on field modification
+Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0
+result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1
+Test stopped during Method Exit of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Enter of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Exit of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped during Method Enter of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Exit due to exception thrown in same function
+Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: false } base-call-count: 0
+result is ExceptionOnceObject { cnt: 2, throwInSub: false } base-call count: 1
+Test stopped during Method Exit due to exception thrown in subroutine
+Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: true } base-call-count: 0
+result is ExceptionOnceObject { cnt: 2, throwInSub: true } base-call count: 1
+Test stopped during notifyFramePop without exception on pop of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped during notifyFramePop without exception on pop of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during notifyFramePop with exception on pop of calledFunction
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError thrown and caught!
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during notifyFramePop with exception on pop of doThrow
+Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionCatchTestObject$TestError caught in called function.
+result is ExceptionCatchTestObject { cnt: 1 } base-call count: 1
+Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in called function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError caught in same function.
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in subroutine)
+Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionCatchTestObject$TestError caught in called function.
+result is ExceptionCatchTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in calling function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError thrown and caught!
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in called function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError caught in same function.
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in parent of calling function)
+Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowFarTestObject$TestError thrown and caught!
+result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in called function)
+Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowFarTestObject$TestError caught in same function.
+result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1
+Test stopped during a ClassLoad event.
+Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+TC0.foo == 1
+result is ClassLoadObject { cnt: 1, curClass: 1} base-call count: 1
+Test stopped during a ClassPrepare event.
+Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+TC1.foo == 2
+result is ClassLoadObject { cnt: 1, curClass: 2} base-call count: 1
+Test stopped during random Suspend.
+Single call with PopFrame on SuspendSuddenlyObject { cnt: 0 } base-call-count: 0
+result is SuspendSuddenlyObject { cnt: 2 } base-call count: 1
+Test redefining frame being popped.
+Single call with PopFrame on RedefineTestObject { states: [] current: ORIGINAL } base-call-count: 0
+result is RedefineTestObject { states: [ORIGINAL, REDEFINED] current: REDEFINED } base-call count: 1
+Test stopped during a native method fails
+Single call with PopFrame on NativeCalledObject { cnt: 0 } base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+result is NativeCalledObject { cnt: 1 } base-call count: 1
+Test stopped in a method called by native fails
+Single call with PopFrame on NativeCallerObject { cnt: 0 } base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+result is NativeCallerObject { cnt: 1 } base-call count: 1
diff --git a/test/1954-pop-frame-jit/info.txt b/test/1954-pop-frame-jit/info.txt
new file mode 100644
index 0000000..b5eb546
--- /dev/null
+++ b/test/1954-pop-frame-jit/info.txt
@@ -0,0 +1,7 @@
+Test basic JVMTI breakpoint functionality.
+
+This test places a breakpoint on the first instruction of a number of functions
+that are entered in every way possible for the given class of method.
+
+It also tests that breakpoints don't interfere with each other by having
+multiple breakpoints be set at once.
diff --git a/test/1954-pop-frame-jit/jvm-expected.patch b/test/1954-pop-frame-jit/jvm-expected.patch
new file mode 100644
index 0000000..718f8ad
--- /dev/null
+++ b/test/1954-pop-frame-jit/jvm-expected.patch
@@ -0,0 +1,21 @@
+75,94d74
+< Test stopped during a ClassLoad event.
+< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0
+< Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+< 	art.Test1953.popFrame(Native Method)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTests(Test1953.java)
+< 	<Additional frames hidden>
+< TC0.foo == 1
+< result is ClassLoadObject { cnt: 1, curClass: 1} base-call count: 1
+< Test stopped during a ClassPrepare event.
+< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0
+< Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+< 	art.Test1953.popFrame(Native Method)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTests(Test1953.java)
+< 	<Additional frames hidden>
+< TC1.foo == 2
+< result is ClassLoadObject { cnt: 1, curClass: 2} base-call count: 1
diff --git a/test/1954-pop-frame-jit/run b/test/1954-pop-frame-jit/run
new file mode 100755
index 0000000..d16d4e6
--- /dev/null
+++ b/test/1954-pop-frame-jit/run
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# On RI we need to turn class-load tests off since those events are buggy around
+# pop-frame (see b/116003018).
+ARGS=""
+if [[ "$TEST_RUNTIME" == "jvm" ]]; then
+  ARGS="--args DISABLE_CLASS_LOAD_TESTS"
+fi
+
+./default-run "$@" --jvmti $ARGS
diff --git a/test/1954-pop-frame-jit/src/Main.java b/test/1954-pop-frame-jit/src/Main.java
new file mode 100644
index 0000000..12defcd
--- /dev/null
+++ b/test/1954-pop-frame-jit/src/Main.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import java.time.Duration;
+
+import java.util.concurrent.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+import java.util.Stack;
+import java.util.Vector;
+
+import java.util.function.Supplier;
+
+import art.*;
+
+public class Main extends Test1953 {
+  public Main(boolean run_class_load_tests) {
+    super(run_class_load_tests, (testObj) -> {
+      try {
+        // Make sure everything is jitted in the method. We do this before calling setup since the
+        // suspend setup might make it impossible to jit the methods (by setting breakpoints or
+        // something).
+        for (Method m : testObj.getClass().getMethods()) {
+          if ((m.getModifiers() & Modifier.NATIVE) == 0 &&
+              !m.getName().startsWith("$noprecompile$")) {
+            ensureMethodJitCompiled(m);
+          }
+        }
+      } catch (Exception e) {}
+    });
+  }
+
+  public static void main(String[] args) throws Exception {
+    new Main(!Arrays.asList(args).contains("DISABLE_CLASS_LOAD_TESTS")).runTests();
+  }
+
+  public static native void ensureMethodJitCompiled(Method meth);
+}
diff --git a/test/1954-pop-frame-jit/src/art/Breakpoint.java b/test/1954-pop-frame-jit/src/art/Breakpoint.java
new file mode 100644
index 0000000..bbb89f7
--- /dev/null
+++ b/test/1954-pop-frame-jit/src/art/Breakpoint.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Executable;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Objects;
+
+public class Breakpoint {
+  public static class Manager {
+    public static class BP {
+      public final Executable method;
+      public final long location;
+
+      public BP(Executable method) {
+        this(method, getStartLocation(method));
+      }
+
+      public BP(Executable method, long location) {
+        this.method = method;
+        this.location = location;
+      }
+
+      @Override
+      public boolean equals(Object other) {
+        return (other instanceof BP) &&
+            method.equals(((BP)other).method) &&
+            location == ((BP)other).location;
+      }
+
+      @Override
+      public String toString() {
+        return method.toString() + " @ " + getLine();
+      }
+
+      @Override
+      public int hashCode() {
+        return Objects.hash(method, location);
+      }
+
+      public int getLine() {
+        try {
+          LineNumber[] lines = getLineNumberTable(method);
+          int best = -1;
+          for (LineNumber l : lines) {
+            if (l.location > location) {
+              break;
+            } else {
+              best = l.line;
+            }
+          }
+          return best;
+        } catch (Exception e) {
+          return -1;
+        }
+      }
+    }
+
+    private Set<BP> breaks = new HashSet<>();
+
+    public void setBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.add(b)) {
+          Breakpoint.setBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void setBreakpoint(Executable method, long location) {
+      setBreakpoints(new BP(method, location));
+    }
+
+    public void clearBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.remove(b)) {
+          Breakpoint.clearBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void clearBreakpoint(Executable method, long location) {
+      clearBreakpoints(new BP(method, location));
+    }
+
+    public void clearAllBreakpoints() {
+      clearBreakpoints(breaks.toArray(new BP[0]));
+    }
+  }
+
+  public static void startBreakpointWatch(Class<?> methodClass,
+                                          Executable breakpointReached,
+                                          Thread thr) {
+    startBreakpointWatch(methodClass, breakpointReached, false, thr);
+  }
+
+  /**
+   * Enables the trapping of breakpoint events.
+   *
+   * If allowRecursive == true then breakpoints will be sent even if one is currently being handled.
+   */
+  public static native void startBreakpointWatch(Class<?> methodClass,
+                                                 Executable breakpointReached,
+                                                 boolean allowRecursive,
+                                                 Thread thr);
+  public static native void stopBreakpointWatch(Thread thr);
+
+  public static final class LineNumber implements Comparable<LineNumber> {
+    public final long location;
+    public final int line;
+
+    private LineNumber(long loc, int line) {
+      this.location = loc;
+      this.line = line;
+    }
+
+    public boolean equals(Object other) {
+      return other instanceof LineNumber && ((LineNumber)other).line == line &&
+          ((LineNumber)other).location == location;
+    }
+
+    public int compareTo(LineNumber other) {
+      int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line));
+      if (v != 0) {
+        return v;
+      } else {
+        return Long.valueOf(location).compareTo(Long.valueOf(other.location));
+      }
+    }
+  }
+
+  public static native void setBreakpoint(Executable m, long loc);
+  public static void setBreakpoint(Executable m, LineNumber l) {
+    setBreakpoint(m, l.location);
+  }
+
+  public static native void clearBreakpoint(Executable m, long loc);
+  public static void clearBreakpoint(Executable m, LineNumber l) {
+    clearBreakpoint(m, l.location);
+  }
+
+  private static native Object[] getLineNumberTableNative(Executable m);
+  public static LineNumber[] getLineNumberTable(Executable m) {
+    Object[] nativeTable = getLineNumberTableNative(m);
+    long[] location = (long[])(nativeTable[0]);
+    int[] lines = (int[])(nativeTable[1]);
+    if (lines.length != location.length) {
+      throw new Error("Lines and locations have different lengths!");
+    }
+    LineNumber[] out = new LineNumber[lines.length];
+    for (int i = 0; i < lines.length; i++) {
+      out[i] = new LineNumber(location[i], lines[i]);
+    }
+    return out;
+  }
+
+  public static native long getStartLocation(Executable m);
+
+  public static int locationToLine(Executable m, long location) {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      int best = -1;
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.location > location) {
+          break;
+        } else {
+          best = l.line;
+        }
+      }
+      return best;
+    } catch (Exception e) {
+      return -1;
+    }
+  }
+
+  public static long lineToLocation(Executable m, int line) throws Exception {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.line == line) {
+          return l.location;
+        }
+      }
+      throw new Exception("Unable to find line " + line + " in " + m);
+    } catch (Exception e) {
+      throw new Exception("Unable to get line number info for " + m, e);
+    }
+  }
+}
+
diff --git a/test/1954-pop-frame-jit/src/art/Redefinition.java b/test/1954-pop-frame-jit/src/art/Redefinition.java
new file mode 100644
index 0000000..56d2938
--- /dev/null
+++ b/test/1954-pop-frame-jit/src/art/Redefinition.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+  public static final class CommonClassDefinition {
+    public final Class<?> target;
+    public final byte[] class_file_bytes;
+    public final byte[] dex_file_bytes;
+
+    public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+      this.target = target;
+      this.class_file_bytes = class_file_bytes;
+      this.dex_file_bytes = dex_file_bytes;
+    }
+  }
+
+  // A set of possible test configurations. Test should set this if they need to.
+  // This must be kept in sync with the defines in ti-agent/common_helper.cc
+  public static enum Config {
+    COMMON_REDEFINE(0),
+    COMMON_RETRANSFORM(1),
+    COMMON_TRANSFORM(2);
+
+    private final int val;
+    private Config(int val) {
+      this.val = val;
+    }
+  }
+
+  public static void setTestConfiguration(Config type) {
+    nativeSetTestConfiguration(type.val);
+  }
+
+  private static native void nativeSetTestConfiguration(int type);
+
+  // Transforms the class
+  public static native void doCommonClassRedefinition(Class<?> target,
+                                                      byte[] classfile,
+                                                      byte[] dexfile);
+
+  public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+    ArrayList<Class<?>> classes = new ArrayList<>();
+    ArrayList<byte[]> class_files = new ArrayList<>();
+    ArrayList<byte[]> dex_files = new ArrayList<>();
+
+    for (CommonClassDefinition d : defs) {
+      classes.add(d.target);
+      class_files.add(d.class_file_bytes);
+      dex_files.add(d.dex_file_bytes);
+    }
+    doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+                                   class_files.toArray(new byte[0][]),
+                                   dex_files.toArray(new byte[0][]));
+  }
+
+  public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+    for (CommonClassDefinition d : defs) {
+      addCommonTransformationResult(d.target.getCanonicalName(),
+                                    d.class_file_bytes,
+                                    d.dex_file_bytes);
+    }
+  }
+
+  public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+                                                           byte[][] classfiles,
+                                                           byte[][] dexfiles);
+  public static native void doCommonClassRetransformation(Class<?>... target);
+  public static native void setPopRetransformations(boolean pop);
+  public static native void popTransformationFor(String name);
+  public static native void enableCommonRetransformation(boolean enable);
+  public static native void addCommonTransformationResult(String target_name,
+                                                          byte[] class_bytes,
+                                                          byte[] dex_bytes);
+}
diff --git a/test/1954-pop-frame-jit/src/art/StackTrace.java b/test/1954-pop-frame-jit/src/art/StackTrace.java
new file mode 100644
index 0000000..2ea2f20
--- /dev/null
+++ b/test/1954-pop-frame-jit/src/art/StackTrace.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Executable;
+
+public class StackTrace {
+  public static class StackFrameData {
+    public final Thread thr;
+    public final Executable method;
+    public final long current_location;
+    public final int depth;
+
+    public StackFrameData(Thread thr, Executable e, long loc, int depth) {
+      this.thr = thr;
+      this.method = e;
+      this.current_location = loc;
+      this.depth = depth;
+    }
+    @Override
+    public String toString() {
+      return String.format(
+          "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }",
+          this.thr,
+          this.method,
+          this.current_location,
+          this.depth);
+    }
+  }
+
+  public static native int GetStackDepth(Thread thr);
+
+  private static native StackFrameData[] nativeGetStackTrace(Thread thr);
+
+  public static StackFrameData[] GetStackTrace(Thread thr) {
+    // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not
+    // suspended. The spec says that not being suspended is fine but since we want this to be
+    // consistent we will suspend for the RI.
+    boolean suspend_thread =
+        !System.getProperty("java.vm.name").equals("Dalvik") &&
+        !thr.equals(Thread.currentThread()) &&
+        !Suspension.isSuspended(thr);
+    if (suspend_thread) {
+      Suspension.suspend(thr);
+    }
+    StackFrameData[] out = nativeGetStackTrace(thr);
+    if (suspend_thread) {
+      Suspension.resume(thr);
+    }
+    return out;
+  }
+}
+
diff --git a/tools/cpp-define-generator/constant_card_table.def b/test/1954-pop-frame-jit/src/art/Suspension.java
similarity index 61%
copy from tools/cpp-define-generator/constant_card_table.def
copy to test/1954-pop-frame-jit/src/art/Suspension.java
index ae3e8f3..16e62cc 100644
--- a/tools/cpp-define-generator/constant_card_table.def
+++ b/test/1954-pop-frame-jit/src/art/Suspension.java
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
-// Export heap values.
+package art;
 
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "gc/accounting/card_table.h"
-#endif
+public class Suspension {
+  // Suspends a thread using jvmti.
+  public native static void suspend(Thread thr);
 
-// Size of references to the heap on the stack.
-DEFINE_EXPR(CARD_TABLE_CARD_SHIFT, size_t, art::gc::accounting::CardTable::kCardShift)
+  // Resumes a thread using jvmti.
+  public native static void resume(Thread thr);
 
+  public native static boolean isSuspended(Thread thr);
+
+  public native static int[] suspendList(Thread... threads);
+  public native static int[] resumeList(Thread... threads);
+}
diff --git a/test/1954-pop-frame-jit/src/art/Test1953.java b/test/1954-pop-frame-jit/src/art/Test1953.java
new file mode 120000
index 0000000..f281434
--- /dev/null
+++ b/test/1954-pop-frame-jit/src/art/Test1953.java
@@ -0,0 +1 @@
+../../../1953-pop-frame/src/art/Test1953.java
\ No newline at end of file
diff --git a/test/1955-pop-frame-jit-called/check b/test/1955-pop-frame-jit-called/check
new file mode 100755
index 0000000..10b87cc
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/check
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The RI has restrictions and bugs around some PopFrame behavior that ART lacks.
+# See b/116003018. Some configurations cannot handle the class load events in
+# quite the right way so they are disabled there too.
+./default-check "$@" || \
+  (patch -p0 expected.txt < jvm-expected.patch >/dev/null && ./default-check "$@")
diff --git a/test/1955-pop-frame-jit-called/expected.txt b/test/1955-pop-frame-jit-called/expected.txt
new file mode 100644
index 0000000..a20a045
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/expected.txt
@@ -0,0 +1,118 @@
+Test stopped using breakpoint
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped using breakpoint with declared synchronized function
+Single call with PopFrame on SynchronizedFunctionTestObject { cnt: 0 } base-call-count: 0
+result is SynchronizedFunctionTestObject { cnt: 2 } base-call count: 1
+Test stopped using breakpoint with synchronized block
+Single call with PopFrame on SynchronizedTestObject { cnt: 0 } base-call-count: 0
+result is SynchronizedTestObject { cnt: 2 } base-call count: 1
+Test stopped on single step
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped on field access
+Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0
+result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1
+Test stopped on field modification
+Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0
+result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1
+Test stopped during Method Exit of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Enter of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Exit of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped during Method Enter of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Exit due to exception thrown in same function
+Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: false } base-call-count: 0
+result is ExceptionOnceObject { cnt: 2, throwInSub: false } base-call count: 1
+Test stopped during Method Exit due to exception thrown in subroutine
+Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: true } base-call-count: 0
+result is ExceptionOnceObject { cnt: 2, throwInSub: true } base-call count: 1
+Test stopped during notifyFramePop without exception on pop of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped during notifyFramePop without exception on pop of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during notifyFramePop with exception on pop of calledFunction
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError thrown and caught!
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during notifyFramePop with exception on pop of doThrow
+Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionCatchTestObject$TestError caught in called function.
+result is ExceptionCatchTestObject { cnt: 1 } base-call count: 1
+Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in called function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError caught in same function.
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in subroutine)
+Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionCatchTestObject$TestError caught in called function.
+result is ExceptionCatchTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in calling function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError thrown and caught!
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in called function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError caught in same function.
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in parent of calling function)
+Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowFarTestObject$TestError thrown and caught!
+result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in called function)
+Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowFarTestObject$TestError caught in same function.
+result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1
+Test stopped during a ClassLoad event.
+Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+TC0.foo == 1
+result is ClassLoadObject { cnt: 1, curClass: 1} base-call count: 1
+Test stopped during a ClassPrepare event.
+Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+TC1.foo == 2
+result is ClassLoadObject { cnt: 1, curClass: 2} base-call count: 1
+Test stopped during random Suspend.
+Single call with PopFrame on SuspendSuddenlyObject { cnt: 0 } base-call-count: 0
+result is SuspendSuddenlyObject { cnt: 2 } base-call count: 1
+Test redefining frame being popped.
+Single call with PopFrame on RedefineTestObject { states: [] current: ORIGINAL } base-call-count: 0
+result is RedefineTestObject { states: [ORIGINAL, REDEFINED] current: REDEFINED } base-call count: 1
+Test stopped during a native method fails
+Single call with PopFrame on NativeCalledObject { cnt: 0 } base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+result is NativeCalledObject { cnt: 1 } base-call count: 1
+Test stopped in a method called by native fails
+Single call with PopFrame on NativeCallerObject { cnt: 0 } base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+result is NativeCallerObject { cnt: 1 } base-call count: 1
diff --git a/test/1955-pop-frame-jit-called/info.txt b/test/1955-pop-frame-jit-called/info.txt
new file mode 100644
index 0000000..b5eb546
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/info.txt
@@ -0,0 +1,7 @@
+Test basic JVMTI breakpoint functionality.
+
+This test places a breakpoint on the first instruction of a number of functions
+that are entered in every way possible for the given class of method.
+
+It also tests that breakpoints don't interfere with each other by having
+multiple breakpoints be set at once.
diff --git a/test/1955-pop-frame-jit-called/jvm-expected.patch b/test/1955-pop-frame-jit-called/jvm-expected.patch
new file mode 100644
index 0000000..718f8ad
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/jvm-expected.patch
@@ -0,0 +1,21 @@
+75,94d74
+< Test stopped during a ClassLoad event.
+< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0
+< Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+< 	art.Test1953.popFrame(Native Method)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTests(Test1953.java)
+< 	<Additional frames hidden>
+< TC0.foo == 1
+< result is ClassLoadObject { cnt: 1, curClass: 1} base-call count: 1
+< Test stopped during a ClassPrepare event.
+< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0
+< Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+< 	art.Test1953.popFrame(Native Method)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTests(Test1953.java)
+< 	<Additional frames hidden>
+< TC1.foo == 2
+< result is ClassLoadObject { cnt: 1, curClass: 2} base-call count: 1
diff --git a/test/1955-pop-frame-jit-called/run b/test/1955-pop-frame-jit-called/run
new file mode 100755
index 0000000..2984461
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/run
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# On RI we need to turn class-load tests off since those events are buggy around
+# pop-frame (see b/116003018).
+ARGS=""
+if [[ "$TEST_RUNTIME" == "jvm" ]]; then
+  ARGS="--args DISABLE_CLASS_LOAD_TESTS"
+fi
+
+# The jitthreshold prevents the jit from compiling anything except those which
+# we explicitly request.
+./default-run "$@" --android-runtime-option -Xjitthreshold:1000 --jvmti $ARGS
diff --git a/test/1955-pop-frame-jit-called/src/Main.java b/test/1955-pop-frame-jit-called/src/Main.java
new file mode 100644
index 0000000..30a42ea
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/src/Main.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import java.time.Duration;
+
+import java.util.concurrent.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+import java.util.Stack;
+import java.util.Vector;
+
+import java.util.function.Supplier;
+
+import art.*;
+
+public class Main extends Test1953 {
+  public Main(boolean run_class_load_tests) {
+    super(run_class_load_tests, (testObj) -> {
+      try {
+        // Make sure the called method is jitted
+        ensureMethodJitCompiled(testObj.getCalledMethod());
+      } catch (Exception e) {}
+    });
+  }
+
+  public static void main(String[] args) throws Exception {
+    new Main(!Arrays.asList(args).contains("DISABLE_CLASS_LOAD_TESTS")).runTests();
+  }
+
+  public static native void ensureMethodJitCompiled(Method meth);
+}
diff --git a/test/1955-pop-frame-jit-called/src/art/Breakpoint.java b/test/1955-pop-frame-jit-called/src/art/Breakpoint.java
new file mode 100644
index 0000000..bbb89f7
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/src/art/Breakpoint.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Executable;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Objects;
+
+public class Breakpoint {
+  public static class Manager {
+    public static class BP {
+      public final Executable method;
+      public final long location;
+
+      public BP(Executable method) {
+        this(method, getStartLocation(method));
+      }
+
+      public BP(Executable method, long location) {
+        this.method = method;
+        this.location = location;
+      }
+
+      @Override
+      public boolean equals(Object other) {
+        return (other instanceof BP) &&
+            method.equals(((BP)other).method) &&
+            location == ((BP)other).location;
+      }
+
+      @Override
+      public String toString() {
+        return method.toString() + " @ " + getLine();
+      }
+
+      @Override
+      public int hashCode() {
+        return Objects.hash(method, location);
+      }
+
+      public int getLine() {
+        try {
+          LineNumber[] lines = getLineNumberTable(method);
+          int best = -1;
+          for (LineNumber l : lines) {
+            if (l.location > location) {
+              break;
+            } else {
+              best = l.line;
+            }
+          }
+          return best;
+        } catch (Exception e) {
+          return -1;
+        }
+      }
+    }
+
+    private Set<BP> breaks = new HashSet<>();
+
+    public void setBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.add(b)) {
+          Breakpoint.setBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void setBreakpoint(Executable method, long location) {
+      setBreakpoints(new BP(method, location));
+    }
+
+    public void clearBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.remove(b)) {
+          Breakpoint.clearBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void clearBreakpoint(Executable method, long location) {
+      clearBreakpoints(new BP(method, location));
+    }
+
+    public void clearAllBreakpoints() {
+      clearBreakpoints(breaks.toArray(new BP[0]));
+    }
+  }
+
+  public static void startBreakpointWatch(Class<?> methodClass,
+                                          Executable breakpointReached,
+                                          Thread thr) {
+    startBreakpointWatch(methodClass, breakpointReached, false, thr);
+  }
+
+  /**
+   * Enables the trapping of breakpoint events.
+   *
+   * If allowRecursive == true then breakpoints will be sent even if one is currently being handled.
+   */
+  public static native void startBreakpointWatch(Class<?> methodClass,
+                                                 Executable breakpointReached,
+                                                 boolean allowRecursive,
+                                                 Thread thr);
+  public static native void stopBreakpointWatch(Thread thr);
+
+  public static final class LineNumber implements Comparable<LineNumber> {
+    public final long location;
+    public final int line;
+
+    private LineNumber(long loc, int line) {
+      this.location = loc;
+      this.line = line;
+    }
+
+    public boolean equals(Object other) {
+      return other instanceof LineNumber && ((LineNumber)other).line == line &&
+          ((LineNumber)other).location == location;
+    }
+
+    public int compareTo(LineNumber other) {
+      int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line));
+      if (v != 0) {
+        return v;
+      } else {
+        return Long.valueOf(location).compareTo(Long.valueOf(other.location));
+      }
+    }
+  }
+
+  public static native void setBreakpoint(Executable m, long loc);
+  public static void setBreakpoint(Executable m, LineNumber l) {
+    setBreakpoint(m, l.location);
+  }
+
+  public static native void clearBreakpoint(Executable m, long loc);
+  public static void clearBreakpoint(Executable m, LineNumber l) {
+    clearBreakpoint(m, l.location);
+  }
+
+  private static native Object[] getLineNumberTableNative(Executable m);
+  public static LineNumber[] getLineNumberTable(Executable m) {
+    Object[] nativeTable = getLineNumberTableNative(m);
+    long[] location = (long[])(nativeTable[0]);
+    int[] lines = (int[])(nativeTable[1]);
+    if (lines.length != location.length) {
+      throw new Error("Lines and locations have different lengths!");
+    }
+    LineNumber[] out = new LineNumber[lines.length];
+    for (int i = 0; i < lines.length; i++) {
+      out[i] = new LineNumber(location[i], lines[i]);
+    }
+    return out;
+  }
+
+  public static native long getStartLocation(Executable m);
+
+  public static int locationToLine(Executable m, long location) {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      int best = -1;
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.location > location) {
+          break;
+        } else {
+          best = l.line;
+        }
+      }
+      return best;
+    } catch (Exception e) {
+      return -1;
+    }
+  }
+
+  public static long lineToLocation(Executable m, int line) throws Exception {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.line == line) {
+          return l.location;
+        }
+      }
+      throw new Exception("Unable to find line " + line + " in " + m);
+    } catch (Exception e) {
+      throw new Exception("Unable to get line number info for " + m, e);
+    }
+  }
+}
+
diff --git a/test/1955-pop-frame-jit-called/src/art/Redefinition.java b/test/1955-pop-frame-jit-called/src/art/Redefinition.java
new file mode 100644
index 0000000..56d2938
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/src/art/Redefinition.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+  public static final class CommonClassDefinition {
+    public final Class<?> target;
+    public final byte[] class_file_bytes;
+    public final byte[] dex_file_bytes;
+
+    public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+      this.target = target;
+      this.class_file_bytes = class_file_bytes;
+      this.dex_file_bytes = dex_file_bytes;
+    }
+  }
+
+  // A set of possible test configurations. Test should set this if they need to.
+  // This must be kept in sync with the defines in ti-agent/common_helper.cc
+  public static enum Config {
+    COMMON_REDEFINE(0),
+    COMMON_RETRANSFORM(1),
+    COMMON_TRANSFORM(2);
+
+    private final int val;
+    private Config(int val) {
+      this.val = val;
+    }
+  }
+
+  public static void setTestConfiguration(Config type) {
+    nativeSetTestConfiguration(type.val);
+  }
+
+  private static native void nativeSetTestConfiguration(int type);
+
+  // Transforms the class
+  public static native void doCommonClassRedefinition(Class<?> target,
+                                                      byte[] classfile,
+                                                      byte[] dexfile);
+
+  public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+    ArrayList<Class<?>> classes = new ArrayList<>();
+    ArrayList<byte[]> class_files = new ArrayList<>();
+    ArrayList<byte[]> dex_files = new ArrayList<>();
+
+    for (CommonClassDefinition d : defs) {
+      classes.add(d.target);
+      class_files.add(d.class_file_bytes);
+      dex_files.add(d.dex_file_bytes);
+    }
+    doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+                                   class_files.toArray(new byte[0][]),
+                                   dex_files.toArray(new byte[0][]));
+  }
+
+  public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+    for (CommonClassDefinition d : defs) {
+      addCommonTransformationResult(d.target.getCanonicalName(),
+                                    d.class_file_bytes,
+                                    d.dex_file_bytes);
+    }
+  }
+
+  public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+                                                           byte[][] classfiles,
+                                                           byte[][] dexfiles);
+  public static native void doCommonClassRetransformation(Class<?>... target);
+  public static native void setPopRetransformations(boolean pop);
+  public static native void popTransformationFor(String name);
+  public static native void enableCommonRetransformation(boolean enable);
+  public static native void addCommonTransformationResult(String target_name,
+                                                          byte[] class_bytes,
+                                                          byte[] dex_bytes);
+}
diff --git a/test/1955-pop-frame-jit-called/src/art/StackTrace.java b/test/1955-pop-frame-jit-called/src/art/StackTrace.java
new file mode 100644
index 0000000..2ea2f20
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/src/art/StackTrace.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Executable;
+
+public class StackTrace {
+  public static class StackFrameData {
+    public final Thread thr;
+    public final Executable method;
+    public final long current_location;
+    public final int depth;
+
+    public StackFrameData(Thread thr, Executable e, long loc, int depth) {
+      this.thr = thr;
+      this.method = e;
+      this.current_location = loc;
+      this.depth = depth;
+    }
+    @Override
+    public String toString() {
+      return String.format(
+          "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }",
+          this.thr,
+          this.method,
+          this.current_location,
+          this.depth);
+    }
+  }
+
+  public static native int GetStackDepth(Thread thr);
+
+  private static native StackFrameData[] nativeGetStackTrace(Thread thr);
+
+  public static StackFrameData[] GetStackTrace(Thread thr) {
+    // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not
+    // suspended. The spec says that not being suspended is fine but since we want this to be
+    // consistent we will suspend for the RI.
+    boolean suspend_thread =
+        !System.getProperty("java.vm.name").equals("Dalvik") &&
+        !thr.equals(Thread.currentThread()) &&
+        !Suspension.isSuspended(thr);
+    if (suspend_thread) {
+      Suspension.suspend(thr);
+    }
+    StackFrameData[] out = nativeGetStackTrace(thr);
+    if (suspend_thread) {
+      Suspension.resume(thr);
+    }
+    return out;
+  }
+}
+
diff --git a/tools/cpp-define-generator/constant_card_table.def b/test/1955-pop-frame-jit-called/src/art/Suspension.java
similarity index 61%
copy from tools/cpp-define-generator/constant_card_table.def
copy to test/1955-pop-frame-jit-called/src/art/Suspension.java
index ae3e8f3..16e62cc 100644
--- a/tools/cpp-define-generator/constant_card_table.def
+++ b/test/1955-pop-frame-jit-called/src/art/Suspension.java
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
-// Export heap values.
+package art;
 
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "gc/accounting/card_table.h"
-#endif
+public class Suspension {
+  // Suspends a thread using jvmti.
+  public native static void suspend(Thread thr);
 
-// Size of references to the heap on the stack.
-DEFINE_EXPR(CARD_TABLE_CARD_SHIFT, size_t, art::gc::accounting::CardTable::kCardShift)
+  // Resumes a thread using jvmti.
+  public native static void resume(Thread thr);
 
+  public native static boolean isSuspended(Thread thr);
+
+  public native static int[] suspendList(Thread... threads);
+  public native static int[] resumeList(Thread... threads);
+}
diff --git a/test/1955-pop-frame-jit-called/src/art/Test1953.java b/test/1955-pop-frame-jit-called/src/art/Test1953.java
new file mode 120000
index 0000000..f281434
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/src/art/Test1953.java
@@ -0,0 +1 @@
+../../../1953-pop-frame/src/art/Test1953.java
\ No newline at end of file
diff --git a/test/1956-pop-frame-jit-calling/check b/test/1956-pop-frame-jit-calling/check
new file mode 100755
index 0000000..10b87cc
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/check
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The RI has restrictions and bugs around some PopFrame behavior that ART lacks.
+# See b/116003018. Some configurations cannot handle the class load events in
+# quite the right way so they are disabled there too.
+./default-check "$@" || \
+  (patch -p0 expected.txt < jvm-expected.patch >/dev/null && ./default-check "$@")
diff --git a/test/1956-pop-frame-jit-calling/expected.txt b/test/1956-pop-frame-jit-calling/expected.txt
new file mode 100644
index 0000000..a20a045
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/expected.txt
@@ -0,0 +1,118 @@
+Test stopped using breakpoint
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped using breakpoint with declared synchronized function
+Single call with PopFrame on SynchronizedFunctionTestObject { cnt: 0 } base-call-count: 0
+result is SynchronizedFunctionTestObject { cnt: 2 } base-call count: 1
+Test stopped using breakpoint with synchronized block
+Single call with PopFrame on SynchronizedTestObject { cnt: 0 } base-call-count: 0
+result is SynchronizedTestObject { cnt: 2 } base-call count: 1
+Test stopped on single step
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped on field access
+Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0
+result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1
+Test stopped on field modification
+Single call with PopFrame on FieldBasedTestObject { cnt: 0, TARGET_FIELD: 0 } base-call-count: 0
+result is FieldBasedTestObject { cnt: 2, TARGET_FIELD: 10 } base-call count: 1
+Test stopped during Method Exit of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Enter of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Exit of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped during Method Enter of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during Method Exit due to exception thrown in same function
+Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: false } base-call-count: 0
+result is ExceptionOnceObject { cnt: 2, throwInSub: false } base-call count: 1
+Test stopped during Method Exit due to exception thrown in subroutine
+Single call with PopFrame on ExceptionOnceObject { cnt: 0, throwInSub: true } base-call-count: 0
+result is ExceptionOnceObject { cnt: 2, throwInSub: true } base-call count: 1
+Test stopped during notifyFramePop without exception on pop of calledFunction
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 2 } base-call count: 1
+Test stopped during notifyFramePop without exception on pop of doNothing
+Single call with PopFrame on StandardTestObject { cnt: 0 } base-call-count: 0
+result is StandardTestObject { cnt: 1 } base-call count: 1
+Test stopped during notifyFramePop with exception on pop of calledFunction
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError thrown and caught!
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during notifyFramePop with exception on pop of doThrow
+Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionCatchTestObject$TestError caught in called function.
+result is ExceptionCatchTestObject { cnt: 1 } base-call count: 1
+Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in called function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError caught in same function.
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during ExceptionCatch event of calledFunction (catch in called function, throw in subroutine)
+Single call with PopFrame on ExceptionCatchTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionCatchTestObject$TestError caught in called function.
+result is ExceptionCatchTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in calling function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError thrown and caught!
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in called function)
+Single call with PopFrame on ExceptionThrowTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowTestObject$TestError caught in same function.
+result is ExceptionThrowTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in parent of calling function)
+Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowFarTestObject$TestError thrown and caught!
+result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1
+Test stopped during Exception event of calledFunction (catch in called function)
+Single call with PopFrame on ExceptionThrowFarTestObject { cnt: 0 } base-call-count: 0
+art.Test1953$ExceptionThrowFarTestObject$TestError caught in same function.
+result is ExceptionThrowFarTestObject { cnt: 2 } base-call count: 1
+Test stopped during a ClassLoad event.
+Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+TC0.foo == 1
+result is ClassLoadObject { cnt: 1, curClass: 1} base-call count: 1
+Test stopped during a ClassPrepare event.
+Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+TC1.foo == 2
+result is ClassLoadObject { cnt: 1, curClass: 2} base-call count: 1
+Test stopped during random Suspend.
+Single call with PopFrame on SuspendSuddenlyObject { cnt: 0 } base-call-count: 0
+result is SuspendSuddenlyObject { cnt: 2 } base-call count: 1
+Test redefining frame being popped.
+Single call with PopFrame on RedefineTestObject { states: [] current: ORIGINAL } base-call-count: 0
+result is RedefineTestObject { states: [ORIGINAL, REDEFINED] current: REDEFINED } base-call count: 1
+Test stopped during a native method fails
+Single call with PopFrame on NativeCalledObject { cnt: 0 } base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+result is NativeCalledObject { cnt: 1 } base-call count: 1
+Test stopped in a method called by native fails
+Single call with PopFrame on NativeCallerObject { cnt: 0 } base-call-count: 0
+Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+	art.Test1953.popFrame(Native Method)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTestOn(Test1953.java)
+	art.Test1953.runTests(Test1953.java)
+	<Additional frames hidden>
+result is NativeCallerObject { cnt: 1 } base-call count: 1
diff --git a/test/1956-pop-frame-jit-calling/info.txt b/test/1956-pop-frame-jit-calling/info.txt
new file mode 100644
index 0000000..b5eb546
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/info.txt
@@ -0,0 +1,7 @@
+Test basic JVMTI breakpoint functionality.
+
+This test places a breakpoint on the first instruction of a number of functions
+that are entered in every way possible for the given class of method.
+
+It also tests that breakpoints don't interfere with each other by having
+multiple breakpoints be set at once.
diff --git a/test/1956-pop-frame-jit-calling/jvm-expected.patch b/test/1956-pop-frame-jit-calling/jvm-expected.patch
new file mode 100644
index 0000000..718f8ad
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/jvm-expected.patch
@@ -0,0 +1,21 @@
+75,94d74
+< Test stopped during a ClassLoad event.
+< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 0} base-call-count: 0
+< Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+< 	art.Test1953.popFrame(Native Method)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTests(Test1953.java)
+< 	<Additional frames hidden>
+< TC0.foo == 1
+< result is ClassLoadObject { cnt: 1, curClass: 1} base-call count: 1
+< Test stopped during a ClassPrepare event.
+< Single call with PopFrame on ClassLoadObject { cnt: 0, curClass: 1} base-call-count: 0
+< Failed to pop frame due to java.lang.RuntimeException: JVMTI_ERROR_OPAQUE_FRAME
+< 	art.Test1953.popFrame(Native Method)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTestOn(Test1953.java)
+< 	art.Test1953.runTests(Test1953.java)
+< 	<Additional frames hidden>
+< TC1.foo == 2
+< result is ClassLoadObject { cnt: 1, curClass: 2} base-call count: 1
diff --git a/test/1956-pop-frame-jit-calling/run b/test/1956-pop-frame-jit-calling/run
new file mode 100755
index 0000000..2984461
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/run
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# On RI we need to turn class-load tests off since those events are buggy around
+# pop-frame (see b/116003018).
+ARGS=""
+if [[ "$TEST_RUNTIME" == "jvm" ]]; then
+  ARGS="--args DISABLE_CLASS_LOAD_TESTS"
+fi
+
+# The jitthreshold prevents the jit from compiling anything except those which
+# we explicitly request.
+./default-run "$@" --android-runtime-option -Xjitthreshold:1000 --jvmti $ARGS
diff --git a/test/1956-pop-frame-jit-calling/src/Main.java b/test/1956-pop-frame-jit-calling/src/Main.java
new file mode 100644
index 0000000..c44e035
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/src/Main.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import java.time.Duration;
+
+import java.util.concurrent.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+import java.util.Stack;
+import java.util.Vector;
+
+import java.util.function.Supplier;
+
+import art.*;
+
+public class Main extends Test1953 {
+  public Main(boolean run_class_load_tests) {
+    super(run_class_load_tests, (testObj) -> {
+      try {
+        // Make sure the calling method is jitted
+        ensureMethodJitCompiled(testObj.getCallingMethod());
+      } catch (Exception e) {}
+    });
+  }
+
+  public static void main(String[] args) throws Exception {
+    new Main(!Arrays.asList(args).contains("DISABLE_CLASS_LOAD_TESTS")).runTests();
+  }
+
+  public static native void ensureMethodJitCompiled(Method meth);
+}
diff --git a/test/1956-pop-frame-jit-calling/src/art/Breakpoint.java b/test/1956-pop-frame-jit-calling/src/art/Breakpoint.java
new file mode 100644
index 0000000..bbb89f7
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/src/art/Breakpoint.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Executable;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Objects;
+
+public class Breakpoint {
+  public static class Manager {
+    public static class BP {
+      public final Executable method;
+      public final long location;
+
+      public BP(Executable method) {
+        this(method, getStartLocation(method));
+      }
+
+      public BP(Executable method, long location) {
+        this.method = method;
+        this.location = location;
+      }
+
+      @Override
+      public boolean equals(Object other) {
+        return (other instanceof BP) &&
+            method.equals(((BP)other).method) &&
+            location == ((BP)other).location;
+      }
+
+      @Override
+      public String toString() {
+        return method.toString() + " @ " + getLine();
+      }
+
+      @Override
+      public int hashCode() {
+        return Objects.hash(method, location);
+      }
+
+      public int getLine() {
+        try {
+          LineNumber[] lines = getLineNumberTable(method);
+          int best = -1;
+          for (LineNumber l : lines) {
+            if (l.location > location) {
+              break;
+            } else {
+              best = l.line;
+            }
+          }
+          return best;
+        } catch (Exception e) {
+          return -1;
+        }
+      }
+    }
+
+    private Set<BP> breaks = new HashSet<>();
+
+    public void setBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.add(b)) {
+          Breakpoint.setBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void setBreakpoint(Executable method, long location) {
+      setBreakpoints(new BP(method, location));
+    }
+
+    public void clearBreakpoints(BP... bs) {
+      for (BP b : bs) {
+        if (breaks.remove(b)) {
+          Breakpoint.clearBreakpoint(b.method, b.location);
+        }
+      }
+    }
+    public void clearBreakpoint(Executable method, long location) {
+      clearBreakpoints(new BP(method, location));
+    }
+
+    public void clearAllBreakpoints() {
+      clearBreakpoints(breaks.toArray(new BP[0]));
+    }
+  }
+
+  public static void startBreakpointWatch(Class<?> methodClass,
+                                          Executable breakpointReached,
+                                          Thread thr) {
+    startBreakpointWatch(methodClass, breakpointReached, false, thr);
+  }
+
+  /**
+   * Enables the trapping of breakpoint events.
+   *
+   * If allowRecursive == true then breakpoints will be sent even if one is currently being handled.
+   */
+  public static native void startBreakpointWatch(Class<?> methodClass,
+                                                 Executable breakpointReached,
+                                                 boolean allowRecursive,
+                                                 Thread thr);
+  public static native void stopBreakpointWatch(Thread thr);
+
+  public static final class LineNumber implements Comparable<LineNumber> {
+    public final long location;
+    public final int line;
+
+    private LineNumber(long loc, int line) {
+      this.location = loc;
+      this.line = line;
+    }
+
+    public boolean equals(Object other) {
+      return other instanceof LineNumber && ((LineNumber)other).line == line &&
+          ((LineNumber)other).location == location;
+    }
+
+    public int compareTo(LineNumber other) {
+      int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line));
+      if (v != 0) {
+        return v;
+      } else {
+        return Long.valueOf(location).compareTo(Long.valueOf(other.location));
+      }
+    }
+  }
+
+  public static native void setBreakpoint(Executable m, long loc);
+  public static void setBreakpoint(Executable m, LineNumber l) {
+    setBreakpoint(m, l.location);
+  }
+
+  public static native void clearBreakpoint(Executable m, long loc);
+  public static void clearBreakpoint(Executable m, LineNumber l) {
+    clearBreakpoint(m, l.location);
+  }
+
+  private static native Object[] getLineNumberTableNative(Executable m);
+  public static LineNumber[] getLineNumberTable(Executable m) {
+    Object[] nativeTable = getLineNumberTableNative(m);
+    long[] location = (long[])(nativeTable[0]);
+    int[] lines = (int[])(nativeTable[1]);
+    if (lines.length != location.length) {
+      throw new Error("Lines and locations have different lengths!");
+    }
+    LineNumber[] out = new LineNumber[lines.length];
+    for (int i = 0; i < lines.length; i++) {
+      out[i] = new LineNumber(location[i], lines[i]);
+    }
+    return out;
+  }
+
+  public static native long getStartLocation(Executable m);
+
+  public static int locationToLine(Executable m, long location) {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      int best = -1;
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.location > location) {
+          break;
+        } else {
+          best = l.line;
+        }
+      }
+      return best;
+    } catch (Exception e) {
+      return -1;
+    }
+  }
+
+  public static long lineToLocation(Executable m, int line) throws Exception {
+    try {
+      Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
+      for (Breakpoint.LineNumber l : lines) {
+        if (l.line == line) {
+          return l.location;
+        }
+      }
+      throw new Exception("Unable to find line " + line + " in " + m);
+    } catch (Exception e) {
+      throw new Exception("Unable to get line number info for " + m, e);
+    }
+  }
+}
+
diff --git a/test/1956-pop-frame-jit-calling/src/art/Redefinition.java b/test/1956-pop-frame-jit-calling/src/art/Redefinition.java
new file mode 100644
index 0000000..56d2938
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/src/art/Redefinition.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.util.ArrayList;
+// Common Redefinition functions. Placed here for use by CTS
+public class Redefinition {
+  public static final class CommonClassDefinition {
+    public final Class<?> target;
+    public final byte[] class_file_bytes;
+    public final byte[] dex_file_bytes;
+
+    public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) {
+      this.target = target;
+      this.class_file_bytes = class_file_bytes;
+      this.dex_file_bytes = dex_file_bytes;
+    }
+  }
+
+  // A set of possible test configurations. Test should set this if they need to.
+  // This must be kept in sync with the defines in ti-agent/common_helper.cc
+  public static enum Config {
+    COMMON_REDEFINE(0),
+    COMMON_RETRANSFORM(1),
+    COMMON_TRANSFORM(2);
+
+    private final int val;
+    private Config(int val) {
+      this.val = val;
+    }
+  }
+
+  public static void setTestConfiguration(Config type) {
+    nativeSetTestConfiguration(type.val);
+  }
+
+  private static native void nativeSetTestConfiguration(int type);
+
+  // Transforms the class
+  public static native void doCommonClassRedefinition(Class<?> target,
+                                                      byte[] classfile,
+                                                      byte[] dexfile);
+
+  public static void doMultiClassRedefinition(CommonClassDefinition... defs) {
+    ArrayList<Class<?>> classes = new ArrayList<>();
+    ArrayList<byte[]> class_files = new ArrayList<>();
+    ArrayList<byte[]> dex_files = new ArrayList<>();
+
+    for (CommonClassDefinition d : defs) {
+      classes.add(d.target);
+      class_files.add(d.class_file_bytes);
+      dex_files.add(d.dex_file_bytes);
+    }
+    doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]),
+                                   class_files.toArray(new byte[0][]),
+                                   dex_files.toArray(new byte[0][]));
+  }
+
+  public static void addMultiTransformationResults(CommonClassDefinition... defs) {
+    for (CommonClassDefinition d : defs) {
+      addCommonTransformationResult(d.target.getCanonicalName(),
+                                    d.class_file_bytes,
+                                    d.dex_file_bytes);
+    }
+  }
+
+  public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
+                                                           byte[][] classfiles,
+                                                           byte[][] dexfiles);
+  public static native void doCommonClassRetransformation(Class<?>... target);
+  public static native void setPopRetransformations(boolean pop);
+  public static native void popTransformationFor(String name);
+  public static native void enableCommonRetransformation(boolean enable);
+  public static native void addCommonTransformationResult(String target_name,
+                                                          byte[] class_bytes,
+                                                          byte[] dex_bytes);
+}
diff --git a/test/1956-pop-frame-jit-calling/src/art/StackTrace.java b/test/1956-pop-frame-jit-calling/src/art/StackTrace.java
new file mode 100644
index 0000000..2ea2f20
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/src/art/StackTrace.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Executable;
+
+public class StackTrace {
+  public static class StackFrameData {
+    public final Thread thr;
+    public final Executable method;
+    public final long current_location;
+    public final int depth;
+
+    public StackFrameData(Thread thr, Executable e, long loc, int depth) {
+      this.thr = thr;
+      this.method = e;
+      this.current_location = loc;
+      this.depth = depth;
+    }
+    @Override
+    public String toString() {
+      return String.format(
+          "StackFrameData { thr: '%s', method: '%s', loc: %d, depth: %d }",
+          this.thr,
+          this.method,
+          this.current_location,
+          this.depth);
+    }
+  }
+
+  public static native int GetStackDepth(Thread thr);
+
+  private static native StackFrameData[] nativeGetStackTrace(Thread thr);
+
+  public static StackFrameData[] GetStackTrace(Thread thr) {
+    // The RI seems to give inconsistent (and sometimes nonsensical) results if the thread is not
+    // suspended. The spec says that not being suspended is fine but since we want this to be
+    // consistent we will suspend for the RI.
+    boolean suspend_thread =
+        !System.getProperty("java.vm.name").equals("Dalvik") &&
+        !thr.equals(Thread.currentThread()) &&
+        !Suspension.isSuspended(thr);
+    if (suspend_thread) {
+      Suspension.suspend(thr);
+    }
+    StackFrameData[] out = nativeGetStackTrace(thr);
+    if (suspend_thread) {
+      Suspension.resume(thr);
+    }
+    return out;
+  }
+}
+
diff --git a/tools/cpp-define-generator/constant_card_table.def b/test/1956-pop-frame-jit-calling/src/art/Suspension.java
similarity index 61%
copy from tools/cpp-define-generator/constant_card_table.def
copy to test/1956-pop-frame-jit-calling/src/art/Suspension.java
index ae3e8f3..16e62cc 100644
--- a/tools/cpp-define-generator/constant_card_table.def
+++ b/test/1956-pop-frame-jit-calling/src/art/Suspension.java
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
-// Export heap values.
+package art;
 
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "gc/accounting/card_table.h"
-#endif
+public class Suspension {
+  // Suspends a thread using jvmti.
+  public native static void suspend(Thread thr);
 
-// Size of references to the heap on the stack.
-DEFINE_EXPR(CARD_TABLE_CARD_SHIFT, size_t, art::gc::accounting::CardTable::kCardShift)
+  // Resumes a thread using jvmti.
+  public native static void resume(Thread thr);
 
+  public native static boolean isSuspended(Thread thr);
+
+  public native static int[] suspendList(Thread... threads);
+  public native static int[] resumeList(Thread... threads);
+}
diff --git a/test/1956-pop-frame-jit-calling/src/art/Test1953.java b/test/1956-pop-frame-jit-calling/src/art/Test1953.java
new file mode 120000
index 0000000..f281434
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/src/art/Test1953.java
@@ -0,0 +1 @@
+../../../1953-pop-frame/src/art/Test1953.java
\ No newline at end of file
diff --git a/test/616-cha-unloading/cha_unload.cc b/test/616-cha-unloading/cha_unload.cc
index b5166ce..f9d3874 100644
--- a/test/616-cha-unloading/cha_unload.cc
+++ b/test/616-cha-unloading/cha_unload.cc
@@ -19,6 +19,7 @@
 #include <iostream>
 
 #include "art_method.h"
+#include "base/casts.h"
 #include "class_linker.h"
 #include "jit/jit.h"
 #include "linear_alloc.h"
@@ -51,13 +52,13 @@
                                                           jobject java_method) {
   ScopedObjectAccess soa(env);
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, java_method);
-  return static_cast<jlong>(reinterpret_cast<uintptr_t>(method));
+  return reinterpret_cast64<jlong>(method);
 }
 
 extern "C" JNIEXPORT void JNICALL Java_Main_reuseArenaOfMethod(JNIEnv*,
                                                                jclass,
                                                                jlong art_method) {
-  void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(art_method));
+  void* ptr = reinterpret_cast64<void*>(art_method);
 
   ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
   ReaderMutexLock mu2(Thread::Current(), *Locks::classlinker_classes_lock_);
diff --git a/test/686-get-this/expected.txt b/test/686-get-this/expected.txt
new file mode 100644
index 0000000..6a5618e
--- /dev/null
+++ b/test/686-get-this/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/686-get-this/info.txt b/test/686-get-this/info.txt
new file mode 100644
index 0000000..7227bad
--- /dev/null
+++ b/test/686-get-this/info.txt
@@ -0,0 +1,2 @@
+Test that we can successfully call StackVisitor.GetThis() even when
+'this' gets overwritten.
diff --git a/test/686-get-this/smali/Test.smali b/test/686-get-this/smali/Test.smali
new file mode 100644
index 0000000..533f607
--- /dev/null
+++ b/test/686-get-this/smali/Test.smali
@@ -0,0 +1,45 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LTest;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+    .registers 2
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    const/4 v0, 0x1
+    sput v0, LTest;->field:I
+    return-void
+.end method
+
+
+.method public testEmpty()V
+  .registers 2
+  const/4 p0, 0x1
+  invoke-static {}, LMain;->getThisOfCaller()Ljava/lang/Object;
+  move-result-object v0
+  sput-object v0, LMain;->field:Ljava/lang/Object;
+  return-void
+.end method
+
+.method public testPrimitive()I
+  .registers 2
+  sget p0, LTest;->field:I
+  invoke-static {}, LMain;->getThisOfCaller()Ljava/lang/Object;
+  move-result-object v0
+  sput-object v0, LMain;->field:Ljava/lang/Object;
+  return p0
+.end method
+
+.field static public field:I
diff --git a/test/686-get-this/src/Main.java b/test/686-get-this/src/Main.java
new file mode 100644
index 0000000..4ea5301
--- /dev/null
+++ b/test/686-get-this/src/Main.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    System.loadLibrary(args[0]);
+
+    Class<?> c = Class.forName("Test");
+    ensureJitCompiled(c, "testEmpty");
+    ensureJitCompiled(c, "testPrimitive");
+
+    Method m = c.getMethod("testEmpty");
+    m.invoke(c.newInstance());
+    if (field != null) {
+      throw new Error("Expected null");
+    }
+
+    m = c.getMethod("testPrimitive");
+    int a = (Integer)m.invoke(c.newInstance());
+    if (a != 1) {
+      throw new Error("Expected 1, got " + a);
+    }
+    if (field != null) {
+      throw new Error("Expected null");
+    }
+  }
+
+  public static Object field;
+
+  private static native void ensureJitCompiled(Class<?> itf, String method_name);
+  public static native Object getThisOfCaller();
+}
diff --git a/test/Android.bp b/test/Android.bp
index 8f23058..8c1c1bf 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -291,6 +291,7 @@
         "1946-list-descriptors/descriptors.cc",
         "1950-unprepared-transform/unprepared_transform.cc",
         "1951-monitor-enter-no-suspend/raw_monitor.cc",
+        "1953-pop-frame/pop_frame.cc",
     ],
     // Use NDK-compatible headers for ctstiagent.
     header_libs: [
@@ -320,6 +321,7 @@
         "983-source-transform-verify/source_transform_art.cc",
         "1940-ddms-ext/ddm_ext.cc",
         "1944-sudden-exit/sudden_exit.cc",
+        // "1952-pop-frame-jit/pop_frame.cc",
     ],
     static_libs: [
         "libz",
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index ffaa2cd..64c1d4f 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -27,32 +27,32 @@
 
 # We need dex2oat and dalvikvm on the target as well as the core images (all images as we sync
 # only once).
-TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUTS)
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUTS)
 
 # Also need libartagent.
-TEST_ART_TARGET_SYNC_DEPS += libartagent-target libartagentd-target
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += libartagent-target libartagentd-target
 
 # Also need libtiagent.
-TEST_ART_TARGET_SYNC_DEPS += libtiagent-target libtiagentd-target
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += libtiagent-target libtiagentd-target
 
 # Also need libtistress.
-TEST_ART_TARGET_SYNC_DEPS += libtistress-target libtistressd-target
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += libtistress-target libtistressd-target
 
 # Also need libarttest.
-TEST_ART_TARGET_SYNC_DEPS += libarttest-target libarttestd-target
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += libarttest-target libarttestd-target
 
 # Also need libnativebridgetest.
-TEST_ART_TARGET_SYNC_DEPS += libnativebridgetest-target
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += libnativebridgetest-target
 
 # Also need libopenjdkjvmti.
-TEST_ART_TARGET_SYNC_DEPS += libopenjdkjvmti-target libopenjdkjvmtid-target
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += libopenjdkjvmti-target libopenjdkjvmtid-target
 
-TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar
-TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar
-TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/core-simple-testdex.jar
-TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/okhttp-testdex.jar
-TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/bouncycastle-testdex.jar
-TEST_ART_TARGET_SYNC_DEPS += $(TARGET_OUT_JAVA_LIBRARIES)/conscrypt-testdex.jar
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/core-simple-testdex.jar
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/okhttp-testdex.jar
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/bouncycastle-testdex.jar
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/conscrypt-testdex.jar
 
 # All tests require the host executables. The tests also depend on the core images, but on
 # specific version depending on the compiler.
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 4967834..65127fc 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -21,11 +21,13 @@
 
 #include "art_method-inl.h"
 #include "base/enums.h"
+#include "common_throws.h"
 #include "dex/dex_file-inl.h"
 #include "instrumentation.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
 #include "jit/profiling_info.h"
+#include "jni/jni_internal.h"
 #include "mirror/class-inl.h"
 #include "nativehelper/ScopedUtfChars.h"
 #include "oat_file.h"
@@ -195,6 +197,56 @@
   return jit->GetCodeCache()->ContainsMethod(method);
 }
 
+static void ForceJitCompiled(Thread* self, ArtMethod* method) REQUIRES(!Locks::mutator_lock_) {
+  {
+    ScopedObjectAccess soa(self);
+    if (method->IsNative()) {
+      std::string msg(method->PrettyMethod());
+      msg += ": is native";
+      ThrowIllegalArgumentException(msg.c_str());
+      return;
+    } else if (!Runtime::Current()->GetRuntimeCallbacks()->IsMethodSafeToJit(method)) {
+      std::string msg(method->PrettyMethod());
+      msg += ": is not safe to jit!";
+      ThrowIllegalStateException(msg.c_str());
+      return;
+    }
+  }
+  jit::Jit* jit = GetJitIfEnabled();
+  jit::JitCodeCache* code_cache = jit->GetCodeCache();
+  // Update the code cache to make sure the JIT code does not get deleted.
+  // Note: this will apply to all JIT compilations.
+  code_cache->SetGarbageCollectCode(false);
+  while (true) {
+    if (code_cache->WillExecuteJitCode(method)) {
+      break;
+    } else {
+      // Sleep to yield to the compiler thread.
+      usleep(1000);
+      ScopedObjectAccess soa(self);
+      // Make sure there is a profiling info, required by the compiler.
+      ProfilingInfo::Create(self, method, /* retry_allocation */ true);
+      // Will either ensure it's compiled or do the compilation itself.
+      jit->CompileMethod(method, self, /* osr */ false);
+    }
+  }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_ensureMethodJitCompiled(JNIEnv*, jclass, jobject meth) {
+  jit::Jit* jit = GetJitIfEnabled();
+  if (jit == nullptr) {
+    return;
+  }
+
+  Thread* self = Thread::Current();
+  ArtMethod* method;
+  {
+    ScopedObjectAccess soa(self);
+    method = ArtMethod::FromReflectedMethod(soa, meth);
+  }
+  ForceJitCompiled(self, method);
+}
+
 extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
                                                              jclass,
                                                              jclass cls,
@@ -219,24 +271,7 @@
     }
     DCHECK(method != nullptr) << "Unable to find method called " << chars.c_str();
   }
-
-  jit::JitCodeCache* code_cache = jit->GetCodeCache();
-  // Update the code cache to make sure the JIT code does not get deleted.
-  // Note: this will apply to all JIT compilations.
-  code_cache->SetGarbageCollectCode(false);
-  while (true) {
-    if (code_cache->WillExecuteJitCode(method)) {
-      break;
-    } else {
-      // Sleep to yield to the compiler thread.
-      usleep(1000);
-      ScopedObjectAccess soa(self);
-      // Make sure there is a profiling info, required by the compiler.
-      ProfilingInfo::Create(self, method, /* retry_allocation */ true);
-      // Will either ensure it's compiled or do the compilation itself.
-      jit->CompileMethod(method, self, /* osr */ false);
-    }
-  }
+  ForceJitCompiled(self, method);
 }
 
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasSingleImplementation(JNIEnv* env,
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index d74d2ef..581aa74 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -196,4 +196,24 @@
   }
 }
 
+struct GetCallingFrameVisitor : public StackVisitor {
+  GetCallingFrameVisitor(Thread* thread, Context* context)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {}
+
+  bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
+    // Discard stubs and Main.getThisOfCaller.
+    return GetMethod() == nullptr || GetMethod()->IsNative();
+  }
+};
+
+extern "C" JNIEXPORT jobject JNICALL Java_Main_getThisOfCaller(
+    JNIEnv* env, jclass cls ATTRIBUTE_UNUSED) {
+  ScopedObjectAccess soa(env);
+  std::unique_ptr<art::Context> context(art::Context::Create());
+  GetCallingFrameVisitor visitor(soa.Self(), context.get());
+  visitor.WalkStack();
+  return soa.AddLocalReference<jobject>(visitor.GetThisObject());
+}
+
 }  // namespace art
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index acd37e4..900b1d7 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -319,10 +319,6 @@
         TEST_DIRECTORY="nativetest64"
         ARCHITECTURES_PATTERN="${ARCHITECTURES_64}"
         shift
-    elif [ "x$1" = "x--pic-test" ]; then
-        FLAGS="${FLAGS} -Xcompiler-option --compile-pic"
-        COMPILE_FLAGS="${COMPILE_FLAGS} --compile-pic"
-        shift
     elif [ "x$1" = "x--experimental" ]; then
         if [ "$#" -lt 2 ]; then
             echo "missing --experimental option" 1>&2
diff --git a/test/knownfailures.json b/test/knownfailures.json
index e27a4d6..d769b48 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -947,6 +947,7 @@
           "676-resolve-field-type",
           "685-deoptimizeable",
           "685-shifts",
+          "686-get-this",
           "706-checker-scheduler",
           "707-checker-invalid-profile",
           "714-invoke-custom-lambda-metafactory",
@@ -1089,6 +1090,14 @@
         "description": ["We do not inline with debuggable."]
     },
     {
+        "tests": ["1955-pop-frame-jit-called", "1956-pop-frame-jit-calling"],
+        "variant": "jit-on-first-use",
+        "description": [
+          "These tests directly set -Xjitthreshold:1000 to prevent the jit from compiling any",
+          "extra methods. jit-at-first-use would disrupt this."
+        ]
+    },
+    {
         "tests": ["135-MirandaDispatch"],
         "variant": "interp-ac & 32 & host",
         "env_vars": {"SANITIZE_HOST": "address"},
@@ -1099,5 +1108,17 @@
         "tests": ["454-get-vreg", "457-regs"],
         "variant": "baseline",
         "description": ["Tests are expected to fail with baseline."]
+    },
+    {
+        "tests": ["050-sync-test"],
+        "variant": "target & gcstress & debug",
+        "bug": "b/117597114",
+        "description": ["Looks timing dependent"]
+    },
+    {
+        "tests": ["920-objects"],
+        "variant": "jit-on-first-use",
+        "bug": "b/117638896",
+        "description": ["SIGSEGVs on jit-on-first-use configuration."]
     }
 ]
diff --git a/test/run-test b/test/run-test
index 2517450..229e201 100755
--- a/test/run-test
+++ b/test/run-test
@@ -156,7 +156,6 @@
 always_clean="no"
 never_clean="no"
 have_image="yes"
-multi_image_suffix=""
 android_root="/system"
 bisection_search="no"
 suspend_timeout="500000"
@@ -201,12 +200,6 @@
     elif [ "x$1" = "x--no-image" ]; then
         have_image="no"
         shift
-    elif [ "x$1" = "x--multi-image" ]; then
-        multi_image_suffix="-multi"
-        shift
-    elif [ "x$1" = "x--pic-test" ]; then
-        run_args="${run_args} --pic-test"
-        shift
     elif [ "x$1" = "x--relocate" ]; then
         relocate="yes"
         shift
@@ -590,12 +583,12 @@
 elif [ "$runtime" = "art" ]; then
     if [ "$target_mode" = "no" ]; then
         guess_host_arch_name
-        run_args="${run_args} --boot ${ANDROID_HOST_OUT}/framework/core${image_suffix}${multi_image_suffix}.art"
+        run_args="${run_args} --boot ${ANDROID_HOST_OUT}/framework/core${image_suffix}.art"
         run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}:${ANDROID_HOST_OUT}/nativetest${suffix64}"
     else
         guess_target_arch_name
         run_args="${run_args} --runtime-option -Djava.library.path=/data/nativetest${suffix64}/art/${target_arch_name}"
-        run_args="${run_args} --boot /data/art-test/core${image_suffix}${multi_image_suffix}.art"
+        run_args="${run_args} --boot /data/art-test/core${image_suffix}.art"
     fi
     if [ "$relocate" = "yes" ]; then
       run_args="${run_args} --relocate"
@@ -734,9 +727,6 @@
         echo "    --dex2oat-swap        Use a dex2oat swap file."
         echo "    --instruction-set-features [string]"
         echo "                          Set instruction-set-features for compilation."
-        echo "    --multi-image         Use a set of images compiled with dex2oat multi-image for"
-        echo "                          the boot class path."
-        echo "    --pic-test            Compile the test code position independent."
         echo "    --quiet               Don't print anything except failure messages"
         echo "    --bisection-search    Perform bisection bug search."
         echo "    --vdex                Test using vdex as in input to dex2oat. Only works with --prebuild."
@@ -767,7 +757,7 @@
 echo "${test_dir}: building..." 1>&2
 
 rm -rf "$tmp_dir"
-cp -Rp "$test_dir" "$tmp_dir"
+cp -LRp "$test_dir" "$tmp_dir"
 cd "$tmp_dir"
 
 if [ '!' -r "$build" ]; then
diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py
index c532705..978e9cb3 100644
--- a/test/testrunner/target_config.py
+++ b/test/testrunner/target_config.py
@@ -50,8 +50,8 @@
         'run-test' : ['--jit-on-first-use']
     },
     'art-pictest' : {
-        'run-test' : ['--pictest',
-                      '--optimizing']
+        # Deprecated config: All AOT-compiled code is PIC now.
+        'run-test' : ['--optimizing']
     },
     'art-gcstress-gcverify': {
         # Do not exercise '--interpreter', '--optimizing', nor '--jit' in this
@@ -185,10 +185,9 @@
     },
     'art-preopt' : {
         # This test configuration is intended to be representative of the case
-        # of preopted apps, which are precompiled compiled pic against an
+        # of preopted apps, which are precompiled against an
         # unrelocated image, then used with a relocated image.
-        'run-test' : ['--pictest',
-                      '--prebuild',
+        'run-test' : ['--prebuild',
                       '--relocate',
                       '--jit']
     },
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index 4d3b3b1..4e873c1 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -31,7 +31,7 @@
 There are various options to invoke the script which are:
 -t: Either the test name as in art/test or the test name including the variant
     information. Eg, "-t 001-HelloWorld",
-    "-t test-art-host-run-test-debug-prebuild-optimizing-relocate-ntrace-cms-checkjni-picimage-npictest-ndebuggable-001-HelloWorld32"
+    "-t test-art-host-run-test-debug-prebuild-optimizing-relocate-ntrace-cms-checkjni-picimage-ndebuggable-001-HelloWorld32"
 -j: Number of thread workers to be used. Eg - "-j64"
 --dry-run: Instead of running the test name, just print its name.
 --verbose
@@ -139,11 +139,10 @@
   global TOTAL_VARIANTS_SET
   global DISABLED_TEST_CONTAINER
   # TODO: Avoid duplication of the variant names in different lists.
-  VARIANT_TYPE_DICT['pictest'] = {'pictest', 'npictest'}
   VARIANT_TYPE_DICT['run'] = {'ndebug', 'debug'}
   VARIANT_TYPE_DICT['target'] = {'target', 'host', 'jvm'}
   VARIANT_TYPE_DICT['trace'] = {'trace', 'ntrace', 'stream'}
-  VARIANT_TYPE_DICT['image'] = {'picimage', 'no-image', 'multipicimage'}
+  VARIANT_TYPE_DICT['image'] = {'picimage', 'no-image'}
   VARIANT_TYPE_DICT['debuggable'] = {'ndebuggable', 'debuggable'}
   VARIANT_TYPE_DICT['gc'] = {'gcstress', 'gcverify', 'cms'}
   VARIANT_TYPE_DICT['prebuild'] = {'no-prebuild', 'prebuild'}
@@ -181,7 +180,6 @@
   # These are the default variant-options we will use if nothing in the group is specified.
   default_variants = {
       'target': {'host', 'target'},
-      'pictest': {'npictest'},
       'prebuild': {'prebuild'},
       'cdex_level': {'cdex-fast'},
       'jvmti': { 'no-jvmti'},
@@ -195,7 +193,6 @@
       'gc': {'cms'},
       'jni': {'checkjni'},
       'image': {'picimage'},
-      'pictest': {'pictest'},
       'debuggable': {'ndebuggable'},
       'run': {'debug'},
       # address_sizes_target depends on the target so it is dealt with below.
@@ -346,7 +343,7 @@
                                  user_input_variants['prebuild'], user_input_variants['compiler'],
                                  user_input_variants['relocate'], user_input_variants['trace'],
                                  user_input_variants['gc'], user_input_variants['jni'],
-                                 user_input_variants['image'], user_input_variants['pictest'],
+                                 user_input_variants['image'],
                                  user_input_variants['debuggable'], user_input_variants['jvmti'],
                                  user_input_variants['cdex_level'])
     return config
@@ -359,13 +356,13 @@
       'prebuild': [''], 'compiler': [''],
       'relocate': [''], 'trace': [''],
       'gc': [''], 'jni': [''],
-      'image': [''], 'pictest': [''],
+      'image': [''],
       'debuggable': [''], 'jvmti': [''],
       'cdex_level': ['']})
 
   def start_combination(config_tuple, address_size):
       test, target, run, prebuild, compiler, relocate, trace, gc, \
-      jni, image, pictest, debuggable, jvmti, cdex_level = config_tuple
+      jni, image, debuggable, jvmti, cdex_level = config_tuple
 
       if stop_testrunner:
         # When ART_TEST_KEEP_GOING is set to false, then as soon as a test
@@ -387,7 +384,6 @@
       test_name += gc + '-'
       test_name += jni + '-'
       test_name += image + '-'
-      test_name += pictest + '-'
       test_name += debuggable + '-'
       test_name += jvmti + '-'
       test_name += cdex_level + '-'
@@ -395,7 +391,7 @@
       test_name += address_size
 
       variant_set = {target, run, prebuild, compiler, relocate, trace, gc, jni,
-                     image, pictest, debuggable, jvmti, cdex_level, address_size}
+                     image, debuggable, jvmti, cdex_level, address_size}
 
       options_test = options_all
 
@@ -462,11 +458,6 @@
 
       if image == 'no-image':
         options_test += ' --no-image'
-      elif image == 'multipicimage':
-        options_test += ' --multi-image'
-
-      if pictest == 'pictest':
-        options_test += ' --pic-test'
 
       if debuggable == 'debuggable':
         options_test += ' --debuggable'
@@ -819,7 +810,7 @@
   It supports two types of test_name:
   1) Like 001-HelloWorld. In this case, it will just verify if the test actually
   exists and if it does, it returns the testname.
-  2) Like test-art-host-run-test-debug-prebuild-interpreter-no-relocate-ntrace-cms-checkjni-picimage-npictest-ndebuggable-001-HelloWorld32
+  2) Like test-art-host-run-test-debug-prebuild-interpreter-no-relocate-ntrace-cms-checkjni-picimage-ndebuggable-001-HelloWorld32
   In this case, it will parse all the variants and check if they are placed
   correctly. If yes, it will set the various VARIANT_TYPES to use the
   variants required to run the test. Again, it returns the test_name
@@ -843,7 +834,6 @@
   regex += '(' + '|'.join(VARIANT_TYPE_DICT['gc']) + ')-'
   regex += '(' + '|'.join(VARIANT_TYPE_DICT['jni']) + ')-'
   regex += '(' + '|'.join(VARIANT_TYPE_DICT['image']) + ')-'
-  regex += '(' + '|'.join(VARIANT_TYPE_DICT['pictest']) + ')-'
   regex += '(' + '|'.join(VARIANT_TYPE_DICT['debuggable']) + ')-'
   regex += '(' + '|'.join(VARIANT_TYPE_DICT['jvmti']) + ')-'
   regex += '(' + '|'.join(VARIANT_TYPE_DICT['cdex_level']) + ')-'
@@ -860,12 +850,11 @@
     _user_input_variants['gc'].add(match.group(7))
     _user_input_variants['jni'].add(match.group(8))
     _user_input_variants['image'].add(match.group(9))
-    _user_input_variants['pictest'].add(match.group(10))
-    _user_input_variants['debuggable'].add(match.group(11))
-    _user_input_variants['jvmti'].add(match.group(12))
-    _user_input_variants['cdex_level'].add(match.group(13))
-    _user_input_variants['address_sizes'].add(match.group(15))
-    return {match.group(14)}
+    _user_input_variants['debuggable'].add(match.group(10))
+    _user_input_variants['jvmti'].add(match.group(11))
+    _user_input_variants['cdex_level'].add(match.group(12))
+    _user_input_variants['address_sizes'].add(match.group(14))
+    return {match.group(13)}
   raise ValueError(test_name + " is not a valid test")
 
 
@@ -1023,7 +1012,7 @@
       build_targets += 'test-art-target-run-test-dependencies '
     if 'jvm' in _user_input_variants['target']:
       build_targets += 'test-art-host-run-test-dependencies '
-    build_command = 'build/soong/soong_ui.bash --make-mode'
+    build_command = env.ANDROID_BUILD_TOP + '/build/soong/soong_ui.bash --make-mode'
     build_command += ' DX='
     build_command += ' ' + build_targets
     if subprocess.call(build_command.split()):
diff --git a/test/ti-agent/jni_binder.cc b/test/ti-agent/jni_binder.cc
index 585b4a4..a115c22 100644
--- a/test/ti-agent/jni_binder.cc
+++ b/test/ti-agent/jni_binder.cc
@@ -174,7 +174,7 @@
                                                          class_loader));
 }
 
-jclass FindClass(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name, jobject class_loader) {
+jclass GetClass(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name, jobject class_loader) {
   if (class_loader != nullptr) {
     return FindClassWithClassLoader(env, class_name, class_loader);
   }
@@ -251,7 +251,7 @@
 
 void BindFunctions(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name, jobject class_loader) {
   // Use JNI to load the class.
-  ScopedLocalRef<jclass> klass(env, FindClass(jvmti_env, env, class_name, class_loader));
+  ScopedLocalRef<jclass> klass(env, GetClass(jvmti_env, env, class_name, class_loader));
   CHECK(klass.get() != nullptr) << class_name;
   BindFunctionsOnClass(jvmti_env, env, klass.get());
 }
diff --git a/test/ti-agent/jni_binder.h b/test/ti-agent/jni_binder.h
index e998dc5..3d2ff9c 100644
--- a/test/ti-agent/jni_binder.h
+++ b/test/ti-agent/jni_binder.h
@@ -24,7 +24,7 @@
 
 // Find the given classname. First try the implied classloader, then the system classloader,
 // then use JVMTI to find all classloaders.
-jclass FindClass(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name, jobject class_loader);
+jclass GetClass(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name, jobject class_loader);
 
 // Load the class through JNI. Inspect it, find all native methods. Construct the corresponding
 // mangled name, run dlsym and bind the method.
diff --git a/tools/art_verifier/art_verifier.cc b/tools/art_verifier/art_verifier.cc
index 45c1a33..0ef6c06 100644
--- a/tools/art_verifier/art_verifier.cc
+++ b/tools/art_verifier/art_verifier.cc
@@ -46,8 +46,8 @@
   std::string error_msg;
   if (!dex_file_loader.Open(dex_filename.c_str(),
                             dex_filename.c_str(),
-                            /* verify */ true,
-                            /* verify_checksum */ true,
+                            /* verify= */ true,
+                            /* verify_checksum= */ true,
                             &error_msg,
                             dex_files)) {
     LOG(ERROR) << error_msg;
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index b5d39e1..3d70087 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -75,7 +75,7 @@
   make_command="make $j_arg $extra_args $showcommands build-art-target-tests $common_targets"
   make_command+=" libjavacrypto-target libnetd_client-target linker toybox toolbox sh"
   make_command+=" debuggerd su"
-  make_command+=" ${out_dir}/host/linux-x86/bin/adb libstdc++ "
+  make_command+=" libstdc++ "
   make_command+=" ${ANDROID_PRODUCT_OUT#"${ANDROID_BUILD_TOP}/"}/system/etc/public.libraries.txt"
   if [[ -n "$ART_TEST_CHROOT" ]]; then
     # These targets are needed for the chroot environment.
diff --git a/tools/buildbot-sync.sh b/tools/buildbot-sync.sh
new file mode 100755
index 0000000..01b3c0d
--- /dev/null
+++ b/tools/buildbot-sync.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+adb wait-for-device
+
+if [[ -z "${ANDROID_PRODUCT_OUT}" ]]; then
+  echo 'ANDROID_PRODUCT_OUT environment variable is empty; did you forget to run `lunch`?'
+  exit 1
+fi
+
+if [[ -z "${ART_TEST_CHROOT}" ]]; then
+  echo 'ART_TEST_CHROOT environment variable is empty'
+  exit 1
+fi
+
+adb push ${ANDROID_PRODUCT_OUT}/system ${ART_TEST_CHROOT}/
+adb push ${ANDROID_PRODUCT_OUT}/data ${ART_TEST_CHROOT}/
diff --git a/tools/cpp-define-generator/Android.bp b/tools/cpp-define-generator/Android.bp
index a94f404..027f128 100644
--- a/tools/cpp-define-generator/Android.bp
+++ b/tools/cpp-define-generator/Android.bp
@@ -14,16 +14,11 @@
 // limitations under the License.
 //
 
-// Build a "data" binary which will hold all the symbol values that will be parsed by the other scripts.
-//
-// Builds are for host only, target-specific define generation is possibly but is trickier and would need extra tooling.
-//
-// In the future we may wish to parameterize this on (32,64)x(read_barrier,no_read_barrier).
-
-cc_binary { // Do not use art_cc_binary because HOST_PREFER_32_BIT is incompatible with genrule.
-    name: "cpp-define-generator-data",
+// This produces human-readable asm_defines.s with the embedded compile-time constants.
+cc_object {
+    name: "asm_defines.s",
     host_supported: true,
-    device_supported: false,
+    device_supported: true,
     defaults: [
         "art_debug_defaults",
         "art_defaults",
@@ -33,20 +28,36 @@
         "art/libdexfile",
         "art/libartbase",
         "art/runtime",
+        "system/core/base/include",
     ],
-    srcs: ["main.cc"],
-    shared_libs: [
-        "libbase",
-    ],
+    // Produce text file rather than binary.
+    cflags: ["-S"],
+    srcs: ["asm_defines.cc"],
 }
 
-// Note: See $OUT_DIR/soong/build.ninja
-// For the exact filename that this generates to run make command on just
-// this rule later.
-genrule {
+// This extracts the compile-time constants from asm_defines.s and creates the header.
+cc_genrule {
     name: "cpp-define-generator-asm-support",
-    out: ["asm_support_gen.h"],
-    tools: ["cpp-define-generator-data"],
-    tool_files: ["*.def"],
-    cmd: "$(location cpp-define-generator-data) > \"$(out)\"",
+    host_supported: true,
+    device_supported: true,
+    srcs: [":asm_defines.s"],
+    out: ["asm_defines.h"],
+    tool_files: ["make_header.py"],
+    cmd: "$(location make_header.py) \"$(in)\" > \"$(out)\"",
+}
+
+cc_library_headers {
+    name: "cpp-define-generator-definitions",
+    host_supported: true,
+    export_include_dirs: ["."],
+}
+
+python_binary_host {
+    name: "cpp-define-generator-test",
+    main: "make_header_test.py",
+    srcs: [
+        "make_header.py",
+        "make_header_test.py",
+    ],
+    test_suites: ["general-tests"],
 }
diff --git a/tools/cpp-define-generator/art_method.def b/tools/cpp-define-generator/art_method.def
new file mode 100644
index 0000000..21859dc
--- /dev/null
+++ b/tools/cpp-define-generator/art_method.def
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "art_method.h"
+#endif
+
+ASM_DEFINE(ART_METHOD_ACCESS_FLAGS_OFFSET,
+           art::ArtMethod::AccessFlagsOffset().Int32Value())
+ASM_DEFINE(ART_METHOD_DECLARING_CLASS_OFFSET,
+           art::ArtMethod::DeclaringClassOffset().Int32Value())
+ASM_DEFINE(ART_METHOD_JNI_OFFSET_32,
+           art::ArtMethod::EntryPointFromJniOffset(art::PointerSize::k32).Int32Value())
+ASM_DEFINE(ART_METHOD_JNI_OFFSET_64,
+           art::ArtMethod::EntryPointFromJniOffset(art::PointerSize::k64).Int32Value())
+ASM_DEFINE(ART_METHOD_QUICK_CODE_OFFSET_32,
+           art::ArtMethod::EntryPointFromQuickCompiledCodeOffset(art::PointerSize::k32).Int32Value())
+ASM_DEFINE(ART_METHOD_QUICK_CODE_OFFSET_64,
+           art::ArtMethod::EntryPointFromQuickCompiledCodeOffset(art::PointerSize::k64).Int32Value())
diff --git a/tools/cpp-define-generator/asm_defines.cc b/tools/cpp-define-generator/asm_defines.cc
new file mode 100644
index 0000000..c105c1a
--- /dev/null
+++ b/tools/cpp-define-generator/asm_defines.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// This file is used to generate #defines for use in assembly source code.
+//
+// The content of this file will be used to compile an object file
+// (generated as human readable assembly text file, not as binary).
+// This text file will then be post-processed by a python script to find
+// and extract the constants and generate the final asm_defines.h header.
+//
+
+// We use "asm volatile" to generate text that will stand out in the
+// compiler generated intermediate assembly file (eg. ">>FOO 42 0<<").
+// We emit all values as 64-bit integers (which we will printed as text).
+// We also store a flag which specifies whether the constant is negative.
+// Note that "asm volatile" must be inside a method to please the compiler.
+#define ASM_DEFINE(NAME, EXPR) \
+void AsmDefineHelperFor_##NAME() { \
+  asm volatile("\n.ascii \">>" #NAME " %0 %1<<\"" \
+  :: "i" (static_cast<int64_t>(EXPR)), "i" (EXPR < 0 ? 1 : 0)); \
+}
+#include "asm_defines.def"
diff --git a/tools/cpp-define-generator/asm_defines.def b/tools/cpp-define-generator/asm_defines.def
new file mode 100644
index 0000000..7a77e8e
--- /dev/null
+++ b/tools/cpp-define-generator/asm_defines.def
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(ASM_DEFINE_INCLUDE_DEPENDENCIES)
+#define ASM_DEFINE_INCLUDE_DEPENDENCIES 1
+#endif
+
+#include "globals.def"
+#include "art_method.def"
+#include "lockword.def"
+#include "mirror_array.def"
+#include "mirror_class.def"
+#include "mirror_dex_cache.def"
+#include "mirror_object.def"
+#include "mirror_string.def"
+#include "rosalloc.def"
+#include "runtime.def"
+#include "shadow_frame.def"
+#include "thread.def"
diff --git a/tools/cpp-define-generator/common.def b/tools/cpp-define-generator/common.def
deleted file mode 100644
index 76c64c9..0000000
--- a/tools/cpp-define-generator/common.def
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Convenience macro to define an offset expression.
-
-#ifndef DEFINE_OFFSET_EXPR
-#define DEFINE_OFFSET_EXPR(holder_type, field_name, field_type, expr) \
-  DEFINE_EXPR(holder_type ## _ ## field_name ## _OFFSET, field_type, expr)
-#define DEFINE_OFFSET_EXPR_STANDARD_DEFINITION
-#endif
-
diff --git a/tools/cpp-define-generator/common_undef.def b/tools/cpp-define-generator/common_undef.def
deleted file mode 100644
index c44aba7..0000000
--- a/tools/cpp-define-generator/common_undef.def
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifdef DEFINE_OFFSET_EXPR_STANDARD_DEFINITION
-#undef DEFINE_OFFSET_EXPR_STANDARD_DEFINITION
-#undef DEFINE_OFFSET_EXPR
-#endif
diff --git a/tools/cpp-define-generator/constant_class.def b/tools/cpp-define-generator/constant_class.def
deleted file mode 100644
index 1310103..0000000
--- a/tools/cpp-define-generator/constant_class.def
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2016 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 defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "base/bit_utils.h"       // MostSignificantBit
-#include "dex/modifiers.h"        // kAccClassIsFinalizable
-#endif
-
-#define DEFINE_FLAG_OFFSET(type_name, field_name, expr) \
-  DEFINE_EXPR(type_name ## _ ## field_name, uint32_t, (expr))
-
-DEFINE_FLAG_OFFSET(ACCESS_FLAGS, CLASS_IS_FINALIZABLE,     art::kAccClassIsFinalizable)
-DEFINE_FLAG_OFFSET(ACCESS_FLAGS, CLASS_IS_INTERFACE,       art::kAccInterface)
-// TODO: We should really have a BitPosition which also checks it's a power of 2.
-DEFINE_FLAG_OFFSET(ACCESS_FLAGS, CLASS_IS_FINALIZABLE_BIT, art::MostSignificantBit(art::kAccClassIsFinalizable))
-
-#undef DEFINE_FLAG_OFFSET
diff --git a/tools/cpp-define-generator/constant_dexcache.def b/tools/cpp-define-generator/constant_dexcache.def
deleted file mode 100644
index 743ebb7..0000000
--- a/tools/cpp-define-generator/constant_dexcache.def
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2016 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 defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "mirror/dex_cache.h"   // art::mirror::DexCache, StringDexCachePair
-#endif
-
-DEFINE_EXPR(STRING_DEX_CACHE_ELEMENT_SIZE_SHIFT,       int32_t,
-    art::WhichPowerOf2(sizeof(art::mirror::StringDexCachePair)))
-DEFINE_EXPR(STRING_DEX_CACHE_SIZE_MINUS_ONE,           int32_t,
-    art::mirror::DexCache::kDexCacheStringCacheSize - 1)
-DEFINE_EXPR(STRING_DEX_CACHE_HASH_BITS,                int32_t,
-    art::LeastSignificantBit(art::mirror::DexCache::kDexCacheStringCacheSize))
-DEFINE_EXPR(STRING_DEX_CACHE_ELEMENT_SIZE,             int32_t,
-    sizeof(art::mirror::StringDexCachePair))
-DEFINE_EXPR(METHOD_DEX_CACHE_SIZE_MINUS_ONE,           int32_t,
-    art::mirror::DexCache::kDexCacheMethodCacheSize - 1)
-DEFINE_EXPR(METHOD_DEX_CACHE_HASH_BITS,                int32_t,
-    art::LeastSignificantBit(art::mirror::DexCache::kDexCacheMethodCacheSize))
diff --git a/tools/cpp-define-generator/constant_globals.def b/tools/cpp-define-generator/constant_globals.def
deleted file mode 100644
index d0d6350..0000000
--- a/tools/cpp-define-generator/constant_globals.def
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Export global values.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include <atomic>            // std::memory_order_relaxed
-#include "base/globals.h"    // art::kObjectAlignment
-#include "dex/modifiers.h"
-#endif
-
-DEFINE_EXPR(STD_MEMORY_ORDER_RELAXED, int32_t, std::memory_order_relaxed)
-
-#define DEFINE_OBJECT_EXPR(macro_name, type, constant_field_name) \
-  DEFINE_EXPR(OBJECT_ ## macro_name, type, constant_field_name)
-
-DEFINE_OBJECT_EXPR(ALIGNMENT_MASK,         size_t,   art::kObjectAlignment - 1)
-DEFINE_OBJECT_EXPR(ALIGNMENT_MASK_TOGGLED, uint32_t, ~static_cast<uint32_t>(art::kObjectAlignment - 1))
-DEFINE_OBJECT_EXPR(ALIGNMENT_MASK_TOGGLED64, uint64_t, ~static_cast<uint64_t>(art::kObjectAlignment - 1))
-
-DEFINE_EXPR(ACC_OBSOLETE_METHOD,           int32_t,  art::kAccObsoleteMethod)
-DEFINE_EXPR(ACC_OBSOLETE_METHOD_SHIFT,     int32_t,  art::WhichPowerOf2(art::kAccObsoleteMethod))
-
-#undef DEFINE_OBJECT_EXPR
-
diff --git a/tools/cpp-define-generator/constant_heap.def b/tools/cpp-define-generator/constant_heap.def
deleted file mode 100644
index dc76736..0000000
--- a/tools/cpp-define-generator/constant_heap.def
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Export heap values.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "gc/heap.h"
-#endif
-
-// Size of references to the heap on the stack.
-DEFINE_EXPR(MIN_LARGE_OBJECT_THRESHOLD, size_t, art::gc::Heap::kMinLargeObjectThreshold)
-
diff --git a/tools/cpp-define-generator/constant_jit.def b/tools/cpp-define-generator/constant_jit.def
deleted file mode 100644
index 5fa5194..0000000
--- a/tools/cpp-define-generator/constant_jit.def
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Constants within jit.h.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "jit/jit.h"   // art::kSuspendRequest, etc.
-#endif
-
-#define DEFINE_JIT_CONSTANT(macro_name, type, expr) \
-  DEFINE_EXPR(JIT_ ## macro_name, type, (expr))
-
-DEFINE_JIT_CONSTANT(CHECK_OSR,       int16_t, art::jit::kJitCheckForOSR)
-DEFINE_JIT_CONSTANT(HOTNESS_DISABLE, int16_t, art::jit::kJitHotnessDisabled)
-
-#undef DEFINE_JIT_CONSTANT
diff --git a/tools/cpp-define-generator/constant_lockword.def b/tools/cpp-define-generator/constant_lockword.def
deleted file mode 100644
index 977d1ca..0000000
--- a/tools/cpp-define-generator/constant_lockword.def
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Export lockword values.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "lock_word.h"         // art::LockWord
-#endif
-
-#define DEFINE_LOCK_WORD_EXPR(macro_name, type, constant_field_name) \
-  DEFINE_EXPR(LOCK_WORD_ ## macro_name, type, art::LockWord::constant_field_name)
-
-// FIXME: The naming is inconsistent, the `Shifted` -> `_SHIFTED` suffix is sometimes missing.
-DEFINE_LOCK_WORD_EXPR(STATE_SHIFT,               int32_t,  kStateShift)
-DEFINE_LOCK_WORD_EXPR(STATE_MASK_SHIFTED,        uint32_t, kStateMaskShifted)
-DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_SHIFT,  int32_t,  kReadBarrierStateShift)
-DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK,   uint32_t, kReadBarrierStateMaskShifted)
-DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK_TOGGLED, uint32_t, kReadBarrierStateMaskShiftedToggled)
-DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_SIZE,      int32_t,  kThinLockCountSize)
-DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_SHIFT,     int32_t,  kThinLockCountShift)
-DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_MASK_SHIFTED, uint32_t, kThinLockCountMaskShifted)
-DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_ONE,       uint32_t, kThinLockCountOne)
-DEFINE_LOCK_WORD_EXPR(THIN_LOCK_OWNER_MASK_SHIFTED, uint32_t, kThinLockOwnerMaskShifted)
-
-DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS,  uint32_t, kStateForwardingAddress)
-DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS_OVERFLOW, uint32_t, kStateForwardingAddressOverflow)
-DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS_SHIFT, uint32_t, kForwardingAddressShift)
-
-DEFINE_LOCK_WORD_EXPR(GC_STATE_MASK_SHIFTED,     uint32_t,  kGCStateMaskShifted)
-DEFINE_LOCK_WORD_EXPR(GC_STATE_MASK_SHIFTED_TOGGLED, uint32_t, kGCStateMaskShiftedToggled)
-DEFINE_LOCK_WORD_EXPR(GC_STATE_SIZE,             int32_t,  kGCStateSize)
-DEFINE_LOCK_WORD_EXPR(GC_STATE_SHIFT,            int32_t,  kGCStateShift)
-
-DEFINE_LOCK_WORD_EXPR(MARK_BIT_SHIFT,            int32_t,  kMarkBitStateShift)
-DEFINE_LOCK_WORD_EXPR(MARK_BIT_MASK_SHIFTED,     uint32_t, kMarkBitStateMaskShifted)
-
-#undef DEFINE_LOCK_WORD_EXPR
-
diff --git a/tools/cpp-define-generator/constant_reference.def b/tools/cpp-define-generator/constant_reference.def
deleted file mode 100644
index d312f76..0000000
--- a/tools/cpp-define-generator/constant_reference.def
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2016 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 defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "mirror/object.h"            // mirror::Object
-#include "stack.h"                    // StackReference
-#include "mirror/object_reference.h"  // mirror::CompressedReference
-#include "base/bit_utils.h"           // WhichPowerOf2
-#endif
-
-// Size of references to the heap on the stack.
-DEFINE_EXPR(STACK_REFERENCE_SIZE,            size_t, sizeof(art::StackReference<art::mirror::Object>))
-// Size of heap references
-DEFINE_EXPR(COMPRESSED_REFERENCE_SIZE,       size_t, sizeof(art::mirror::CompressedReference<art::mirror::Object>))
-DEFINE_EXPR(COMPRESSED_REFERENCE_SIZE_SHIFT, size_t, art::WhichPowerOf2(sizeof(art::mirror::CompressedReference<art::mirror::Object>)))
-
-#undef DEFINE_REFERENCE_OFFSET
diff --git a/tools/cpp-define-generator/constant_rosalloc.def b/tools/cpp-define-generator/constant_rosalloc.def
deleted file mode 100644
index 2007cef..0000000
--- a/tools/cpp-define-generator/constant_rosalloc.def
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Constants within RosAlloc.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "gc/allocator/rosalloc.h"   // art::gc::allocator::RosAlloc
-#endif
-
-#define DEFINE_ROSALLOC_CONSTANT(macro_name, type, expr) \
-  DEFINE_EXPR(ROSALLOC_ ## macro_name, type, (expr))
-
-DEFINE_ROSALLOC_CONSTANT(MAX_THREAD_LOCAL_BRACKET_SIZE, int32_t, art::gc::allocator::RosAlloc::kMaxThreadLocalBracketSize)
-DEFINE_ROSALLOC_CONSTANT(BRACKET_QUANTUM_SIZE_SHIFT,    int32_t, art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSizeShift)
-// TODO: This should be a BitUtils helper, e.g. BitMaskFromSize or something like that.
-DEFINE_ROSALLOC_CONSTANT(BRACKET_QUANTUM_SIZE_MASK,     int32_t, static_cast<int32_t>(art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSize - 1))
-DEFINE_ROSALLOC_CONSTANT(BRACKET_QUANTUM_SIZE_MASK_TOGGLED32,\
-                                                        uint32_t, ~static_cast<uint32_t>(art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSize - 1))
-DEFINE_ROSALLOC_CONSTANT(BRACKET_QUANTUM_SIZE_MASK_TOGGLED64,\
-                                                        uint64_t, ~static_cast<uint64_t>(art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSize - 1))
-DEFINE_ROSALLOC_CONSTANT(RUN_FREE_LIST_OFFSET,          int32_t, art::gc::allocator::RosAlloc::RunFreeListOffset())
-DEFINE_ROSALLOC_CONSTANT(RUN_FREE_LIST_HEAD_OFFSET,     int32_t, art::gc::allocator::RosAlloc::RunFreeListHeadOffset())
-DEFINE_ROSALLOC_CONSTANT(RUN_FREE_LIST_SIZE_OFFSET,     int32_t, art::gc::allocator::RosAlloc::RunFreeListSizeOffset())
-DEFINE_ROSALLOC_CONSTANT(SLOT_NEXT_OFFSET,              int32_t, art::gc::allocator::RosAlloc::RunSlotNextOffset())
-
-
-#undef DEFINE_ROSALLOC_CONSTANT
diff --git a/tools/cpp-define-generator/constant_thread.def b/tools/cpp-define-generator/constant_thread.def
deleted file mode 100644
index 7e1df6b..0000000
--- a/tools/cpp-define-generator/constant_thread.def
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Constants within thread.h.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "thread.h"   // art::kSuspendRequest, etc.
-#endif
-
-#define DEFINE_THREAD_CONSTANT(macro_name, type, expr) \
-  DEFINE_EXPR(THREAD_ ## macro_name, type, (expr))
-
-DEFINE_THREAD_CONSTANT(SUSPEND_REQUEST,    int32_t, art::kSuspendRequest)
-DEFINE_THREAD_CONSTANT(CHECKPOINT_REQUEST, int32_t, art::kCheckpointRequest)
-DEFINE_THREAD_CONSTANT(EMPTY_CHECKPOINT_REQUEST, int32_t, art::kEmptyCheckpointRequest)
-DEFINE_THREAD_CONSTANT(SUSPEND_OR_CHECKPOINT_REQUEST,  int32_t, art::kSuspendRequest | art::kCheckpointRequest | art::kEmptyCheckpointRequest)
-DEFINE_THREAD_CONSTANT(INTERPRETER_CACHE_SIZE_LOG2, int32_t, art::Thread::InterpreterCacheSizeLog2())
diff --git a/tools/cpp-define-generator/globals.def b/tools/cpp-define-generator/globals.def
new file mode 100644
index 0000000..2324f51
--- /dev/null
+++ b/tools/cpp-define-generator/globals.def
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "base/bit_utils.h"
+#include "base/callee_save_type.h"
+#include "base/enums.h"
+#include "base/globals.h"
+#include "dex/modifiers.h"
+#include "gc/accounting/card_table.h"
+#include "gc/heap.h"
+#include "jit/jit.h"
+#include "mirror/object.h"
+#include "mirror/object_reference.h"
+#include "stack.h"
+#endif
+
+ASM_DEFINE(ACCESS_FLAGS_CLASS_IS_FINALIZABLE,
+           art::kAccClassIsFinalizable)
+ASM_DEFINE(ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT,
+           art::MostSignificantBit(art::kAccClassIsFinalizable))
+ASM_DEFINE(ACCESS_FLAGS_CLASS_IS_INTERFACE,
+           art::kAccInterface)
+ASM_DEFINE(ACC_OBSOLETE_METHOD,
+           art::kAccObsoleteMethod)
+ASM_DEFINE(ACC_OBSOLETE_METHOD_SHIFT,
+           art::WhichPowerOf2(art::kAccObsoleteMethod))
+ASM_DEFINE(CARD_TABLE_CARD_SHIFT,
+           art::gc::accounting::CardTable::kCardShift)
+ASM_DEFINE(COMPRESSED_REFERENCE_SIZE,
+           sizeof(art::mirror::CompressedReference<art::mirror::Object>))
+ASM_DEFINE(COMPRESSED_REFERENCE_SIZE_SHIFT,
+           art::WhichPowerOf2(sizeof(art::mirror::CompressedReference<art::mirror::Object>)))
+ASM_DEFINE(JIT_CHECK_OSR,
+           art::jit::kJitCheckForOSR)
+ASM_DEFINE(JIT_HOTNESS_DISABLE,
+           art::jit::kJitHotnessDisabled)
+ASM_DEFINE(MIN_LARGE_OBJECT_THRESHOLD,
+           art::gc::Heap::kMinLargeObjectThreshold)
+ASM_DEFINE(OBJECT_ALIGNMENT_MASK,
+           art::kObjectAlignment - 1)
+ASM_DEFINE(OBJECT_ALIGNMENT_MASK_TOGGLED,
+           ~static_cast<uint32_t>(art::kObjectAlignment - 1))
+ASM_DEFINE(OBJECT_ALIGNMENT_MASK_TOGGLED64,
+           ~static_cast<uint64_t>(art::kObjectAlignment - 1))
+ASM_DEFINE(POINTER_SIZE,
+           static_cast<size_t>(art::kRuntimePointerSize))
+ASM_DEFINE(POINTER_SIZE_SHIFT,
+           art::WhichPowerOf2(static_cast<size_t>(art::kRuntimePointerSize)))
+ASM_DEFINE(STACK_REFERENCE_SIZE,
+           sizeof(art::StackReference<art::mirror::Object>))
+ASM_DEFINE(STD_MEMORY_ORDER_RELAXED,
+           std::memory_order_relaxed)
diff --git a/tools/cpp-define-generator/lockword.def b/tools/cpp-define-generator/lockword.def
new file mode 100644
index 0000000..a170c15
--- /dev/null
+++ b/tools/cpp-define-generator/lockword.def
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "lock_word.h"
+#endif
+
+ASM_DEFINE(LOCK_WORD_GC_STATE_MASK_SHIFTED,
+           art::LockWord::kGCStateMaskShifted)
+ASM_DEFINE(LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED,
+           art::LockWord::kGCStateMaskShiftedToggled)
+ASM_DEFINE(LOCK_WORD_GC_STATE_SHIFT,
+           art::LockWord::kGCStateShift)
+ASM_DEFINE(LOCK_WORD_GC_STATE_SIZE,
+           art::LockWord::kGCStateSize)
+ASM_DEFINE(LOCK_WORD_MARK_BIT_MASK_SHIFTED,
+           art::LockWord::kMarkBitStateMaskShifted)
+ASM_DEFINE(LOCK_WORD_MARK_BIT_SHIFT,
+           art::LockWord::kMarkBitStateShift)
+ASM_DEFINE(LOCK_WORD_READ_BARRIER_STATE_MASK,
+           art::LockWord::kReadBarrierStateMaskShifted)
+ASM_DEFINE(LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED,
+           art::LockWord::kReadBarrierStateMaskShiftedToggled)
+ASM_DEFINE(LOCK_WORD_READ_BARRIER_STATE_SHIFT,
+           art::LockWord::kReadBarrierStateShift)
+ASM_DEFINE(LOCK_WORD_STATE_FORWARDING_ADDRESS,
+           art::LockWord::kStateForwardingAddress)
+ASM_DEFINE(LOCK_WORD_STATE_FORWARDING_ADDRESS_OVERFLOW,
+           art::LockWord::kStateForwardingAddressOverflow)
+ASM_DEFINE(LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT,
+           art::LockWord::kForwardingAddressShift)
+ASM_DEFINE(LOCK_WORD_STATE_MASK_SHIFTED,
+           art::LockWord::kStateMaskShifted)
+ASM_DEFINE(LOCK_WORD_STATE_SHIFT,
+           art::LockWord::kStateShift)
+ASM_DEFINE(LOCK_WORD_THIN_LOCK_COUNT_MASK_SHIFTED,
+           art::LockWord::kThinLockCountMaskShifted)
+ASM_DEFINE(LOCK_WORD_THIN_LOCK_COUNT_ONE,
+           art::LockWord::kThinLockCountOne)
+ASM_DEFINE(LOCK_WORD_THIN_LOCK_COUNT_SHIFT,
+           art::LockWord::kThinLockCountShift)
+ASM_DEFINE(LOCK_WORD_THIN_LOCK_COUNT_SIZE,
+           art::LockWord::kThinLockCountSize)
+ASM_DEFINE(LOCK_WORD_THIN_LOCK_OWNER_MASK_SHIFTED,
+           art::LockWord::kThinLockOwnerMaskShifted)
diff --git a/tools/cpp-define-generator/main.cc b/tools/cpp-define-generator/main.cc
deleted file mode 100644
index 7c515be..0000000
--- a/tools/cpp-define-generator/main.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-#include <ios>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <type_traits>
-
-// Art Offset file dependencies
-#define DEFINE_INCLUDE_DEPENDENCIES
-#include "offsets_all.def"
-
-std::string to_upper(std::string input) {
-  std::transform(input.begin(), input.end(), input.begin(), ::toupper);
-  return input;
-}
-
-template <typename T, typename = void>
-typename std::enable_if<!std::is_signed<T>::value, std::string>::type
-pretty_format(T value) {
-  // Print most values as hex.
-  std::stringstream ss;
-  ss << std::showbase << std::hex << value;
-  return ss.str();
-}
-
-template <typename T, typename = void>
-typename std::enable_if<std::is_signed<T>::value, std::string>::type
-pretty_format(T value) {
-  // Print "signed" values as decimal so that the negativity doesn't get lost.
-  std::stringstream ss;
-
-  // For negative values add a (). Omit it from positive values for conciseness.
-  if (value < 0) {
-    ss << "(";
-  }
-
-  ss << value;
-
-  if (value < 0) {
-    ss << ")";
-  }
-  return ss.str();
-}
-
-template <typename T>
-void cpp_define(const std::string& name, T value) {
-  std::cout << "#define " << name << " " << pretty_format(value) << std::endl;
-}
-
-template <typename T>
-void emit_check_eq(T value, const std::string& expr) {
-  std::cout << "DEFINE_CHECK_EQ(" << value << ", (" << expr << "))" << std::endl;
-}
-
-const char *kFileHeader = /* // NOLINT [readability/multiline_string] [5] */ R"L1C3NS3(
-/*
- * Copyright (C) 2016 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_GENERATED_ASM_SUPPORT_GEN_H_
-#define ART_RUNTIME_GENERATED_ASM_SUPPORT_GEN_H_
-
-// This file has been auto-generated by cpp-define-generator; do not edit directly.
-)L1C3NS3";  // NOLINT [readability/multiline_string] [5]
-
-const char *kFileFooter = /* // NOLINT [readability/multiline_string] [5] */ R"F00T3R(
-#endif  // ART_RUNTIME_GENERATED_ASM_SUPPORT_GEN_H_
-)F00T3R";  // NOLINT [readability/multiline_string] [5]
-
-#define MACROIZE(holder_type, field_name) to_upper(#holder_type "_" #field_name "_OFFSET")
-
-int main() {
-  std::cout << kFileHeader << std::endl;
-
-  std::string z = "";
-
-  // Print every constant expression to stdout as a #define or a CHECK_EQ
-#define DEFINE_EXPR(macro_name, field_type, expr) \
-  cpp_define(to_upper(#macro_name), static_cast<field_type>(expr)); \
-  emit_check_eq(z + "static_cast<" #field_type ">(" + to_upper(#macro_name) + ")", \
-                "static_cast<" #field_type ">(" #expr ")");
-#include "offsets_all.def"
-
-  std::cout << kFileFooter << std::endl;
-  return 0;
-}
diff --git a/tools/cpp-define-generator/make_header.py b/tools/cpp-define-generator/make_header.py
new file mode 100755
index 0000000..1b13923
--- /dev/null
+++ b/tools/cpp-define-generator/make_header.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script looks through compiled object file (stored human readable text),
+# and looks for the compile-time constants (added through custom "asm" block).
+#   For example:  .ascii  ">>OBJECT_ALIGNMENT_MASK $7 $0<<"
+#
+# It will transform each such line to #define which is usabe in assembly code.
+#   For example:  #define OBJECT_ALIGNMENT_MASK 0x7
+#
+# Usage: make_header.py out/soong/.intermediates/.../asm_defines.o
+#
+
+import argparse
+import re
+import sys
+
+def convert(input):
+  """Find all defines in the compiler generated assembly and convert them to #define pragmas"""
+
+  asm_define_re = re.compile(r'">>(\w+) (?:\$|#)([-0-9]+) (?:\$|#)(0|1)<<"')
+  asm_defines = asm_define_re.findall(input)
+  if not asm_defines:
+    raise RuntimeError("Failed to find any asm defines in the input")
+
+  # Convert the found constants to #define pragmas.
+  # In case the C++ compiler decides to reorder the AsmDefinesFor_${name} functions,
+  # we don't want the order of the .h file to change from one compilation to another.
+  # Sorting ensures deterministic order of the #defines.
+  output = []
+  for name, value, negative_value in sorted(asm_defines):
+    value = int(value)
+    if value < 0 and negative_value == "0":
+      # Overflow - uint64_t constant was pretty printed as negative value.
+      value += 2 ** 64  # Python will use arbitrary precision arithmetic.
+    output.append("#define {0} {1:#x}".format(name, value))
+  return "\n".join(output)
+
+if __name__ == "__main__":
+  parser = argparse.ArgumentParser()
+  parser.add_argument('input', help="Object file as text")
+  args = parser.parse_args()
+  print(convert(open(args.input, "r").read()))
diff --git a/tools/cpp-define-generator/make_header_test.py b/tools/cpp-define-generator/make_header_test.py
new file mode 100755
index 0000000..a484285
--- /dev/null
+++ b/tools/cpp-define-generator/make_header_test.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+import make_header
+
+test_input = r'''
+// Check that the various other assembly lines are ignored.
+.globl  _Z49AsmDefineHelperFor_MIRROR_OBJECT_LOCK_WORD_OFFSETv
+.type   _Z49AsmDefineHelperFor_MIRROR_OBJECT_LOCK_WORD_OFFSETv,%function
+.ascii  ">>MIRROR_OBJECT_LOCK_WORD_OFFSET #4 #0<<"
+bx      lr
+
+// Check large positive 32-bit constant.
+.ascii  ">>OBJECT_ALIGNMENT_MASK_TOGGLED #4294967288 #0<<"
+
+// Check large positive 64-bit constant (it overflows into negative value).
+.ascii  ">>OBJECT_ALIGNMENT_MASK_TOGGLED64 #-8 #0<<"
+
+// Check negative constant.
+.ascii  ">>JIT_CHECK_OSR #-1 #1<<"
+'''
+
+test_output = r'''
+#define JIT_CHECK_OSR -0x1
+#define MIRROR_OBJECT_LOCK_WORD_OFFSET 0x4
+#define OBJECT_ALIGNMENT_MASK_TOGGLED 0xfffffff8
+#define OBJECT_ALIGNMENT_MASK_TOGGLED64 0xfffffffffffffff8
+'''
+
+class CppDefineGeneratorTest(unittest.TestCase):
+  def test_convert(self):
+    self.assertEqual(test_output.strip(), make_header.convert(test_input))
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/cpp-define-generator/mirror_array.def b/tools/cpp-define-generator/mirror_array.def
new file mode 100644
index 0000000..f600b41
--- /dev/null
+++ b/tools/cpp-define-generator/mirror_array.def
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "mirror/array.h"
+#endif
+
+ASM_DEFINE(MIRROR_ARRAY_LENGTH_OFFSET,
+           art::mirror::Array::LengthOffset().Int32Value())
+ASM_DEFINE(MIRROR_BOOLEAN_ARRAY_DATA_OFFSET,
+           art::mirror::Array::DataOffset(sizeof(uint8_t)).Int32Value())
+ASM_DEFINE(MIRROR_BYTE_ARRAY_DATA_OFFSET,
+           art::mirror::Array::DataOffset(sizeof(int8_t)).Int32Value())
+ASM_DEFINE(MIRROR_CHAR_ARRAY_DATA_OFFSET,
+           art::mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value())
+ASM_DEFINE(MIRROR_INT_ARRAY_DATA_OFFSET,
+           art::mirror::Array::DataOffset(sizeof(int32_t)).Int32Value())
+ASM_DEFINE(MIRROR_LONG_ARRAY_DATA_OFFSET,
+           art::mirror::Array::DataOffset(sizeof(uint64_t)).Int32Value())
+ASM_DEFINE(MIRROR_OBJECT_ARRAY_COMPONENT_SIZE,
+           sizeof(art::mirror::HeapReference<art::mirror::Object>))
+ASM_DEFINE(MIRROR_OBJECT_ARRAY_DATA_OFFSET,
+           art::mirror::Array::DataOffset(sizeof(art::mirror::HeapReference<art::mirror::Object>)).Int32Value())
+ASM_DEFINE(MIRROR_SHORT_ARRAY_DATA_OFFSET,
+           art::mirror::Array::DataOffset(sizeof(int16_t)).Int32Value())
+ASM_DEFINE(MIRROR_WIDE_ARRAY_DATA_OFFSET,
+           art::mirror::Array::DataOffset(sizeof(uint64_t)).Int32Value())
diff --git a/tools/cpp-define-generator/mirror_class.def b/tools/cpp-define-generator/mirror_class.def
new file mode 100644
index 0000000..c15ae92
--- /dev/null
+++ b/tools/cpp-define-generator/mirror_class.def
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "mirror/class.h"
+#endif
+
+ASM_DEFINE(MIRROR_CLASS_ACCESS_FLAGS_OFFSET,
+           art::mirror::Class::AccessFlagsOffset().Int32Value())
+ASM_DEFINE(MIRROR_CLASS_COMPONENT_TYPE_OFFSET,
+           art::mirror::Class::ComponentTypeOffset().Int32Value())
+ASM_DEFINE(MIRROR_CLASS_DEX_CACHE_OFFSET,
+           art::mirror::Class::DexCacheOffset().Int32Value())
+ASM_DEFINE(MIRROR_CLASS_IF_TABLE_OFFSET,
+           art::mirror::Class::IfTableOffset().Int32Value())
+ASM_DEFINE(MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET,
+           art::mirror::Class::PrimitiveTypeOffset().Int32Value())
+ASM_DEFINE(MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET,
+           art::mirror::Class::ObjectSizeAllocFastPathOffset().Int32Value())
+ASM_DEFINE(MIRROR_CLASS_OBJECT_SIZE_OFFSET,
+           art::mirror::Class::ObjectSizeOffset().Int32Value())
+ASM_DEFINE(MIRROR_CLASS_STATUS_OFFSET,
+           art::mirror::Class::StatusOffset().Int32Value())
+ASM_DEFINE(PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT,
+           art::mirror::Class::kPrimitiveTypeSizeShiftShift)
diff --git a/tools/cpp-define-generator/mirror_dex_cache.def b/tools/cpp-define-generator/mirror_dex_cache.def
new file mode 100644
index 0000000..5272e86
--- /dev/null
+++ b/tools/cpp-define-generator/mirror_dex_cache.def
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "mirror/dex_cache.h"
+#endif
+
+ASM_DEFINE(METHOD_DEX_CACHE_SIZE_MINUS_ONE,
+           art::mirror::DexCache::kDexCacheMethodCacheSize - 1)
+ASM_DEFINE(MIRROR_DEX_CACHE_RESOLVED_METHODS_OFFSET,
+           art::mirror::DexCache::ResolvedMethodsOffset().Int32Value())
+ASM_DEFINE(STRING_DEX_CACHE_ELEMENT_SIZE,
+           sizeof(art::mirror::StringDexCachePair))
+ASM_DEFINE(STRING_DEX_CACHE_ELEMENT_SIZE_SHIFT,
+           art::WhichPowerOf2(sizeof(art::mirror::StringDexCachePair)))
+ASM_DEFINE(STRING_DEX_CACHE_HASH_BITS,
+           art::LeastSignificantBit(art::mirror::DexCache::kDexCacheStringCacheSize))
+ASM_DEFINE(STRING_DEX_CACHE_SIZE_MINUS_ONE,
+           art::mirror::DexCache::kDexCacheStringCacheSize - 1)
+ASM_DEFINE(METHOD_DEX_CACHE_HASH_BITS,
+           art::LeastSignificantBit(art::mirror::DexCache::kDexCacheMethodCacheSize))
diff --git a/tools/cpp-define-generator/mirror_object.def b/tools/cpp-define-generator/mirror_object.def
new file mode 100644
index 0000000..facb037
--- /dev/null
+++ b/tools/cpp-define-generator/mirror_object.def
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "mirror/object.h"
+#endif
+
+ASM_DEFINE(MIRROR_OBJECT_CLASS_OFFSET,
+           art::mirror::Object::ClassOffset().Int32Value())
+ASM_DEFINE(MIRROR_OBJECT_HEADER_SIZE,
+           sizeof(art::mirror::Object))
+ASM_DEFINE(MIRROR_OBJECT_LOCK_WORD_OFFSET,
+           art::mirror::Object::MonitorOffset().Int32Value())
diff --git a/tools/cpp-define-generator/mirror_string.def b/tools/cpp-define-generator/mirror_string.def
new file mode 100644
index 0000000..3632b96
--- /dev/null
+++ b/tools/cpp-define-generator/mirror_string.def
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "mirror/string.h"
+#endif
+
+ASM_DEFINE(MIRROR_STRING_COUNT_OFFSET,
+           art::mirror::String::CountOffset().Int32Value())
+ASM_DEFINE(MIRROR_STRING_VALUE_OFFSET,
+           art::mirror::String::ValueOffset().Int32Value())
+ASM_DEFINE(STRING_COMPRESSION_FEATURE,
+           art::mirror::kUseStringCompression)
diff --git a/tools/cpp-define-generator/offset_art_method.def b/tools/cpp-define-generator/offset_art_method.def
deleted file mode 100644
index e6a0907..0000000
--- a/tools/cpp-define-generator/offset_art_method.def
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Offsets within art::ArtMethod.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "art_method.h"         // art::ArtMethod
-#include "base/enums.h"         // PointerSize
-#include "mirror/dex_cache.h"   // art::DexCache
-#endif
-
-#define DEFINE_ART_METHOD_OFFSET_SIZED(field_name, method_name) \
-  DEFINE_EXPR(ART_METHOD_ ## field_name ## _OFFSET_32, int32_t, art::ArtMethod::method_name##Offset(art::PointerSize::k32).Int32Value()) \
-  DEFINE_EXPR(ART_METHOD_ ## field_name ## _OFFSET_64, int32_t, art::ArtMethod::method_name##Offset(art::PointerSize::k64).Int32Value())
-
-#define DEFINE_ART_METHOD_OFFSET(field_name, method_name) \
-  DEFINE_EXPR(ART_METHOD_ ## field_name ## _OFFSET, int32_t, art::ArtMethod::method_name##Offset().Int32Value())
-
-#define DEFINE_DECLARING_CLASS_OFFSET(field_name, method_name) \
-  DEFINE_EXPR(DECLARING_CLASS_ ## field_name ## _OFFSET, int32_t, art::mirror::Class::method_name##Offset().Int32Value())
-
-//                         New macro suffix          Method Name (of the Offset method)
-DEFINE_ART_METHOD_OFFSET_SIZED(JNI,                  EntryPointFromJni)
-DEFINE_ART_METHOD_OFFSET_SIZED(QUICK_CODE,           EntryPointFromQuickCompiledCode)
-DEFINE_ART_METHOD_OFFSET(DECLARING_CLASS,            DeclaringClass)
-DEFINE_ART_METHOD_OFFSET(ACCESS_FLAGS,               AccessFlags)
-
-#undef DEFINE_ART_METHOD_OFFSET
-#undef DEFINE_ART_METHOD_OFFSET_32
-#undef DEFINE_DECLARING_CLASS_OFFSET
diff --git a/tools/cpp-define-generator/offset_mirror_class.def b/tools/cpp-define-generator/offset_mirror_class.def
deleted file mode 100644
index 9b7bfce..0000000
--- a/tools/cpp-define-generator/offset_mirror_class.def
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Offsets within java.lang.Class (mirror::Class).
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "mirror/class.h"         // art::mirror::Object
-#endif
-
-#include "common.def"        // DEFINE_OFFSET_EXPR
-
-#define DEFINE_MIRROR_CLASS_OFFSET(field_name, method_name) \
-  DEFINE_OFFSET_EXPR(MIRROR_CLASS, field_name, int32_t, art::mirror::Class::method_name##Offset().Int32Value())
-
-//                         New macro suffix             Method Name (of the Offset method)
-DEFINE_MIRROR_CLASS_OFFSET(DEX_CACHE,                   DexCache)
-
-#undef DEFINE_MIRROR_CLASS_OFFSET
-#include "common_undef.def"  // undef DEFINE_OFFSET_EXPR
diff --git a/tools/cpp-define-generator/offset_mirror_dex_cache.def b/tools/cpp-define-generator/offset_mirror_dex_cache.def
deleted file mode 100644
index 8f008bb..0000000
--- a/tools/cpp-define-generator/offset_mirror_dex_cache.def
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Offsets within java.lang.DexCache (mirror::DexCache).
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "mirror/class.h"         // art::mirror::Object
-#endif
-
-#include "common.def"        // DEFINE_OFFSET_EXPR
-
-#define DEFINE_MIRROR_DEX_CACHE_OFFSET(field_name, method_name) \
-  DEFINE_OFFSET_EXPR(MIRROR_DEX_CACHE, field_name, int32_t, art::mirror::DexCache::method_name##Offset().Int32Value())
-
-//                             New macro suffix         Method Name (of the Offset method)
-DEFINE_MIRROR_DEX_CACHE_OFFSET(RESOLVED_METHODS,        ResolvedMethods)
-
-#undef DEFINE_MIRROR_CLASS_OFFSET
-#include "common_undef.def"  // undef DEFINE_OFFSET_EXPR
diff --git a/tools/cpp-define-generator/offset_mirror_object.def b/tools/cpp-define-generator/offset_mirror_object.def
deleted file mode 100644
index 9b99634..0000000
--- a/tools/cpp-define-generator/offset_mirror_object.def
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Offsets within java.lang.Object (mirror::Object).
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "mirror/object.h"         // art::mirror::Object
-#endif
-
-#include "common.def"        // DEFINE_OFFSET_EXPR
-
-#define DEFINE_MIRROR_OBJECT_OFFSET(field_name, method_name) \
-  DEFINE_OFFSET_EXPR(MIRROR_OBJECT, field_name, int32_t, art::mirror::Object::method_name##Offset().Int32Value())
-
-//                          New macro suffix            Method Name (of the Offset method)
-DEFINE_MIRROR_OBJECT_OFFSET(CLASS,                      Class)
-DEFINE_MIRROR_OBJECT_OFFSET(LOCK_WORD,                  Monitor)
-
-#undef DEFINE_MIRROR_OBJECT_OFFSET
-#include "common_undef.def"  // undef DEFINE_OFFSET_EXPR
diff --git a/tools/cpp-define-generator/offset_runtime.def b/tools/cpp-define-generator/offset_runtime.def
deleted file mode 100644
index 1d5ce7d..0000000
--- a/tools/cpp-define-generator/offset_runtime.def
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Offsets within ShadowFrame.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "base/callee_save_type.h"  // art::CalleeSaveType
-#include "runtime.h"                // art::Runtime
-#endif
-
-#include "common.def"        // DEFINE_OFFSET_EXPR
-
-// Note: these callee save methods loads require read barriers.
-
-#define DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(field_name, constant_name) \
-  DEFINE_OFFSET_EXPR(Runtime, \
-                     field_name ## _METHOD, \
-                     size_t, \
-                     art::Runtime::GetCalleeSaveMethodOffset(constant_name))
-
-                    //     Macro substring       Constant name
-// Offset of field Runtime::callee_save_methods_[kSaveAllCalleeSaves]
-DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_ALL_CALLEE_SAVES, art::CalleeSaveType::kSaveAllCalleeSaves)
-// Offset of field Runtime::callee_save_methods_[kSaveRefsOnly]
-DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_REFS_ONLY, art::CalleeSaveType::kSaveRefsOnly)
-// Offset of field Runtime::callee_save_methods_[kSaveRefsAndArgs]
-DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_REFS_AND_ARGS, art::CalleeSaveType::kSaveRefsAndArgs)
-// Offset of field Runtime::callee_save_methods_[kSaveEverything]
-DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_EVERYTHING, art::CalleeSaveType::kSaveEverything)
-// Offset of field Runtime::callee_save_methods_[kSaveEverythingForClinit]
-DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_EVERYTHING_FOR_CLINIT, art::CalleeSaveType::kSaveEverythingForClinit)
-// Offset of field Runtime::callee_save_methods_[kSaveEverythingForSuspendCheck]
-DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_EVERYTHING_FOR_SUSPEND_CHECK, art::CalleeSaveType::kSaveEverythingForSuspendCheck)
-
-#undef DEFINE_RUNTIME_CALLEE_SAVE_OFFSET
-#include "common_undef.def"  // undef DEFINE_OFFSET_EXPR
diff --git a/tools/cpp-define-generator/offset_shadow_frame.def b/tools/cpp-define-generator/offset_shadow_frame.def
deleted file mode 100644
index b49a340..0000000
--- a/tools/cpp-define-generator/offset_shadow_frame.def
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Offsets within ShadowFrame.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "stack.h"         // art::ShadowFrame
-#endif
-
-#include "common.def"        // DEFINE_OFFSET_EXPR
-
-#define DEFINE_SHADOW_FRAME_OFFSET(field_name, method_name) \
-  DEFINE_OFFSET_EXPR(ShadowFrame, field_name, int32_t, art::ShadowFrame::method_name##Offset())
-
-//                         New macro suffix            Method Name (of the Offset method)
-DEFINE_SHADOW_FRAME_OFFSET(LINK,                       Link)
-DEFINE_SHADOW_FRAME_OFFSET(METHOD,                     Method)
-DEFINE_SHADOW_FRAME_OFFSET(RESULT_REGISTER,            ResultRegister)
-DEFINE_SHADOW_FRAME_OFFSET(DEX_PC_PTR,                 DexPCPtr)
-DEFINE_SHADOW_FRAME_OFFSET(CODE_ITEM,                  CodeItem)
-DEFINE_SHADOW_FRAME_OFFSET(LOCK_COUNT_DATA,            LockCountData)
-DEFINE_SHADOW_FRAME_OFFSET(NUMBER_OF_VREGS,            NumberOfVRegs)
-DEFINE_SHADOW_FRAME_OFFSET(DEX_PC,                     DexPC)
-DEFINE_SHADOW_FRAME_OFFSET(CACHED_HOTNESS_COUNTDOWN,   CachedHotnessCountdown)
-DEFINE_SHADOW_FRAME_OFFSET(VREGS,                      VRegs)
-
-#undef DEFINE_SHADOW_FRAME_OFFSET
-#include "common_undef.def"  // undef DEFINE_OFFSET_EXPR
diff --git a/tools/cpp-define-generator/offset_thread.def b/tools/cpp-define-generator/offset_thread.def
deleted file mode 100644
index 6f94d38..0000000
--- a/tools/cpp-define-generator/offset_thread.def
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Offsets within ShadowFrame.
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#include "base/enums.h"    // PointerSize
-#include "stack.h"         // art::ShadowFrame
-#endif
-
-#include "common.def"        // DEFINE_OFFSET_EXPR
-
-#define DEFINE_THREAD_OFFSET(field_name, method_name) \
-  DEFINE_OFFSET_EXPR(Thread, field_name, int32_t, art::Thread::method_name##Offset<art::kRuntimePointerSize>().Int32Value())
-
-//                   New macro suffix            Method Name (of the Offset method)
-DEFINE_THREAD_OFFSET(FLAGS,                      ThreadFlags)
-DEFINE_THREAD_OFFSET(ID,                         ThinLockId)
-DEFINE_THREAD_OFFSET(IS_GC_MARKING,              IsGcMarking)
-DEFINE_THREAD_OFFSET(CARD_TABLE,                 CardTable)
-
-// TODO: The rest of the offsets
-// are dependent on __SIZEOF_POINTER__
-
-#undef DEFINE_THREAD_OFFSET
-
-#include "common_undef.def"  // undef DEFINE_OFFSET_EXPR
diff --git a/tools/cpp-define-generator/offsets_all.def b/tools/cpp-define-generator/offsets_all.def
deleted file mode 100644
index 31587d8..0000000
--- a/tools/cpp-define-generator/offsets_all.def
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Includes every single offset file in art.
-// Useful for processing every single offset together.
-
-// Usage:
-// #define DEFINE_INCLUDE_DEPENDENCIES
-// #include "offsets_all.def"
-// to automatically include each def file's header dependencies.
-//
-// Afterwards,
-// #define DEFINE_EXPR(define_name, field_type, expr) ...
-// #include "offsets_all.def"
-// to process each offset however one wants.
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#define DEFINE_EXPR(define_name, field_type, expr)
-#endif
-
-#if !defined(DEFINE_EXPR)
-#error "Either DEFINE_INCLUDE_DEPENDENCIES or DEFINE_EXPR must be defined"
-#endif
-
-#include "constant_reference.def"
-#include "offset_runtime.def"
-// TODO: rest of THREAD_ offsets (depends on __SIZEOF__POINTER__).
-#include "offset_thread.def"
-// TODO: SHADOW_FRAME depends on __SIZEOF__POINTER__
-// #include "offset_shadow_frame.def"
-// TODO: MIRROR_OBJECT_HEADER_SIZE (depends on #ifdef read barrier)
-#include "offset_mirror_class.def"
-#include "offset_mirror_dex_cache.def"
-#include "offset_mirror_object.def"
-#include "constant_class.def"
-// TODO: MIRROR_*_ARRAY offsets (depends on header size)
-// TODO: MIRROR_STRING offsets (depends on header size)
-#include "offset_art_method.def"
-#include "constant_dexcache.def"
-#include "constant_card_table.def"
-#include "constant_heap.def"
-#include "constant_lockword.def"
-#include "constant_globals.def"
-#include "constant_rosalloc.def"
-#include "constant_thread.def"
-#include "constant_jit.def"
-
-// TODO: MIRROR_OBJECT_HEADER_SIZE #ifdef depends on read barriers
-// TODO: Array offsets (depends on MIRROR_OBJECT_HEADER_SIZE)
-
-#if defined(DEFINE_INCLUDE_DEPENDENCIES)
-#undef DEFINE_EXPR
-#undef DEFINE_INCLUDE_DEPENDENCIES
-#endif
-
-
diff --git a/tools/cpp-define-generator/rosalloc.def b/tools/cpp-define-generator/rosalloc.def
new file mode 100644
index 0000000..eb8d8f2
--- /dev/null
+++ b/tools/cpp-define-generator/rosalloc.def
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "gc/allocator/rosalloc.h"
+#endif
+
+ASM_DEFINE(ROSALLOC_BRACKET_QUANTUM_SIZE_MASK,
+           art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSize - 1)
+ASM_DEFINE(ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED32,
+           ~static_cast<uint32_t>(art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSize - 1))
+ASM_DEFINE(ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED64,
+           ~static_cast<uint64_t>(art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSize - 1))
+ASM_DEFINE(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT,
+           art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSizeShift)
+ASM_DEFINE(ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE,
+           art::gc::allocator::RosAlloc::kMaxThreadLocalBracketSize)
+ASM_DEFINE(ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET,
+           art::gc::allocator::RosAlloc::RunFreeListHeadOffset())
+ASM_DEFINE(ROSALLOC_RUN_FREE_LIST_OFFSET,
+           art::gc::allocator::RosAlloc::RunFreeListOffset())
+ASM_DEFINE(ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET,
+           art::gc::allocator::RosAlloc::RunFreeListSizeOffset())
+ASM_DEFINE(ROSALLOC_SLOT_NEXT_OFFSET,
+           art::gc::allocator::RosAlloc::RunSlotNextOffset())
diff --git a/tools/cpp-define-generator/runtime.def b/tools/cpp-define-generator/runtime.def
new file mode 100644
index 0000000..2a2e303
--- /dev/null
+++ b/tools/cpp-define-generator/runtime.def
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "runtime.h"
+#endif
+
+ASM_DEFINE(RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET,
+           art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveAllCalleeSaves))
+ASM_DEFINE(RUNTIME_SAVE_EVERYTHING_FOR_CLINIT_METHOD_OFFSET,
+           art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveEverythingForClinit))
+ASM_DEFINE(RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET,
+           art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveEverythingForSuspendCheck))
+ASM_DEFINE(RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET,
+           art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveEverything))
+ASM_DEFINE(RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET,
+           art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveRefsAndArgs))
+ASM_DEFINE(RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET,
+           art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveRefsOnly))
diff --git a/tools/cpp-define-generator/shadow_frame.def b/tools/cpp-define-generator/shadow_frame.def
new file mode 100644
index 0000000..10a309c
--- /dev/null
+++ b/tools/cpp-define-generator/shadow_frame.def
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "interpreter/shadow_frame.h"
+#endif
+
+ASM_DEFINE(SHADOWFRAME_CACHED_HOTNESS_COUNTDOWN_OFFSET,
+           art::ShadowFrame::CachedHotnessCountdownOffset())
+ASM_DEFINE(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET,
+           art::ShadowFrame::DexInstructionsOffset())
+ASM_DEFINE(SHADOWFRAME_DEX_PC_OFFSET,
+           art::ShadowFrame::DexPCOffset())
+ASM_DEFINE(SHADOWFRAME_DEX_PC_PTR_OFFSET,
+           art::ShadowFrame::DexPCPtrOffset())
+ASM_DEFINE(SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET,
+           art::ShadowFrame::HotnessCountdownOffset())
+ASM_DEFINE(SHADOWFRAME_LINK_OFFSET,
+           art::ShadowFrame::LinkOffset())
+ASM_DEFINE(SHADOWFRAME_LOCK_COUNT_DATA_OFFSET,
+           art::ShadowFrame::LockCountDataOffset())
+ASM_DEFINE(SHADOWFRAME_METHOD_OFFSET,
+           art::ShadowFrame::MethodOffset())
+ASM_DEFINE(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET,
+           art::ShadowFrame::NumberOfVRegsOffset())
+ASM_DEFINE(SHADOWFRAME_RESULT_REGISTER_OFFSET,
+           art::ShadowFrame::ResultRegisterOffset())
+ASM_DEFINE(SHADOWFRAME_VREGS_OFFSET,
+           art::ShadowFrame::VRegsOffset())
diff --git a/tools/cpp-define-generator/thread.def b/tools/cpp-define-generator/thread.def
new file mode 100644
index 0000000..2dd90fa
--- /dev/null
+++ b/tools/cpp-define-generator/thread.def
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ASM_DEFINE_INCLUDE_DEPENDENCIES
+#include "thread.h"
+#endif
+
+ASM_DEFINE(THREAD_ALT_IBASE_OFFSET,
+           art::Thread::MterpAltIBaseOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_CARD_TABLE_OFFSET,
+           art::Thread::CardTableOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_CHECKPOINT_REQUEST,
+           art::kCheckpointRequest)
+ASM_DEFINE(THREAD_CURRENT_IBASE_OFFSET,
+           art::Thread::MterpCurrentIBaseOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_DEFAULT_IBASE_OFFSET,
+           art::Thread::MterpDefaultIBaseOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_EMPTY_CHECKPOINT_REQUEST,
+           art::kEmptyCheckpointRequest)
+ASM_DEFINE(THREAD_EXCEPTION_OFFSET,
+           art::Thread::ExceptionOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_FLAGS_OFFSET,
+           art::Thread::ThreadFlagsOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_ID_OFFSET,
+           art::Thread::ThinLockIdOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_INTERPRETER_CACHE_OFFSET,
+           art::Thread::InterpreterCacheOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_INTERPRETER_CACHE_SIZE_LOG2,
+           art::Thread::InterpreterCacheSizeLog2())
+ASM_DEFINE(THREAD_IS_GC_MARKING_OFFSET,
+           art::Thread::IsGcMarkingOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_LOCAL_ALLOC_STACK_END_OFFSET,
+           art::Thread::ThreadLocalAllocStackEndOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET,
+           art::Thread::ThreadLocalAllocStackTopOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_LOCAL_END_OFFSET,
+           art::Thread::ThreadLocalEndOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_LOCAL_OBJECTS_OFFSET,
+           art::Thread::ThreadLocalObjectsOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_LOCAL_POS_OFFSET,
+           art::Thread::ThreadLocalPosOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_ROSALLOC_RUNS_OFFSET,
+           art::Thread::RosAllocRunsOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_SELF_OFFSET,
+           art::Thread::SelfOffset<art::kRuntimePointerSize>().Int32Value())
+ASM_DEFINE(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST,
+           art::kSuspendRequest | art::kCheckpointRequest | art::kEmptyCheckpointRequest)
+ASM_DEFINE(THREAD_SUSPEND_REQUEST,
+           art::kSuspendRequest)
+ASM_DEFINE(THREAD_TOP_QUICK_FRAME_OFFSET,
+           art::Thread::TopOfManagedStackOffset<art::kRuntimePointerSize>().Int32Value())
diff --git a/tools/dexanalyze/dexanalyze_bytecode.cc b/tools/dexanalyze/dexanalyze_bytecode.cc
index 659a940..88db672 100644
--- a/tools/dexanalyze/dexanalyze_bytecode.cc
+++ b/tools/dexanalyze/dexanalyze_bytecode.cc
@@ -118,7 +118,7 @@
         ProcessCodeItem(*dex_file,
                         method.GetInstructionsAndData(),
                         accessor.GetClassIdx(),
-                        /*count_types*/ true,
+                        /*count_types=*/ true,
                         types);
       }
     }
@@ -143,7 +143,7 @@
         ProcessCodeItem(*dex_file,
                         data,
                         accessor.GetClassIdx(),
-                        /*count_types*/ false,
+                        /*count_types=*/ false,
                         types);
         std::vector<uint8_t> buffer = std::move(buffer_);
         buffer_.clear();
diff --git a/tools/dexanalyze/dexanalyze_test.cc b/tools/dexanalyze/dexanalyze_test.cc
index 96be3f9..c6648c0 100644
--- a/tools/dexanalyze/dexanalyze_test.cc
+++ b/tools/dexanalyze/dexanalyze_test.cc
@@ -37,23 +37,23 @@
 };
 
 TEST_F(DexAnalyzeTest, NoInputFileGiven) {
-  DexAnalyzeExec({ "-a" }, /*expect_success*/ false);
+  DexAnalyzeExec({ "-a" }, /*expect_success=*/ false);
 }
 
 TEST_F(DexAnalyzeTest, CantOpenInput) {
-  DexAnalyzeExec({ "-a", "/non/existent/path" }, /*expect_success*/ false);
+  DexAnalyzeExec({ "-a", "/non/existent/path" }, /*expect_success=*/ false);
 }
 
 TEST_F(DexAnalyzeTest, TestAnalyzeMultidex) {
-  DexAnalyzeExec({ "-a", GetTestDexFileName("MultiDex") }, /*expect_success*/ true);
+  DexAnalyzeExec({ "-a", GetTestDexFileName("MultiDex") }, /*expect_success=*/ true);
 }
 
 TEST_F(DexAnalyzeTest, TestAnalizeCoreDex) {
-  DexAnalyzeExec({ "-a", GetLibCoreDexFileNames()[0] }, /*expect_success*/ true);
+  DexAnalyzeExec({ "-a", GetLibCoreDexFileNames()[0] }, /*expect_success=*/ true);
 }
 
 TEST_F(DexAnalyzeTest, TestInvalidArg) {
-  DexAnalyzeExec({ "-invalid-option" }, /*expect_success*/ false);
+  DexAnalyzeExec({ "-invalid-option" }, /*expect_success=*/ false);
 }
 
 }  // namespace art
diff --git a/tools/field-null-percent/fieldnull.cc b/tools/field-null-percent/fieldnull.cc
index 1bd122a..8f5b389 100644
--- a/tools/field-null-percent/fieldnull.cc
+++ b/tools/field-null-percent/fieldnull.cc
@@ -167,7 +167,7 @@
 }
 
 static jint AgentStart(JavaVM* vm, char* options, bool is_onload) {
-  android::base::InitLogging(/* argv */nullptr);
+  android::base::InitLogging(/* argv= */nullptr);
   java_vm = vm;
   jvmtiEnv* jvmti = nullptr;
   if (SetupJvmtiEnv(vm, &jvmti) != JNI_OK) {
@@ -204,14 +204,14 @@
 extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm,
                                                  char* options,
                                                  void* reserved ATTRIBUTE_UNUSED) {
-  return AgentStart(vm, options, /*is_onload*/false);
+  return AgentStart(vm, options, /*is_onload=*/false);
 }
 
 // Early attachment
 extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* jvm,
                                                char* options,
                                                void* reserved ATTRIBUTE_UNUSED) {
-  return AgentStart(jvm, options, /*is_onload*/true);
+  return AgentStart(jvm, options, /*is_onload=*/true);
 }
 
 }  // namespace fieldnull
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index 6d9b6fb..68211a1 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -278,7 +278,7 @@
 
     if (open_writable) {
       for (const std::string& filename : dex_paths) {
-        File fd(filename.c_str(), O_RDWR, /* check_usage */ false);
+        File fd(filename.c_str(), O_RDWR, /* check_usage= */ false);
         CHECK_NE(fd.Fd(), -1) << "Unable to open file '" << filename << "': " << strerror(errno);
 
         // Memory-map the dex file with MAP_SHARED flag so that changes in memory
@@ -288,10 +288,10 @@
         // We do those checks here and skip them when loading the processed file
         // into boot class path.
         std::unique_ptr<const DexFile> dex_file(dex_loader.OpenDex(fd.Release(),
-                                                                   /* location */ filename,
-                                                                   /* verify */ true,
-                                                                   /* verify_checksum */ true,
-                                                                   /* mmap_shared */ true,
+                                                                   /* location= */ filename,
+                                                                   /* verify= */ true,
+                                                                   /* verify_checksum= */ true,
+                                                                   /* mmap_shared= */ true,
                                                                    &error_msg));
         CHECK(dex_file.get() != nullptr) << "Open failed for '" << filename << "' " << error_msg;
         CHECK(dex_file->IsStandardDexFile()) << "Expected a standard dex file '" << filename << "'";
@@ -302,9 +302,9 @@
     } else {
       for (const std::string& filename : dex_paths) {
         bool success = dex_loader.Open(filename.c_str(),
-                                       /* location */ filename,
-                                       /* verify */ true,
-                                       /* verify_checksum */ true,
+                                       /* location= */ filename,
+                                       /* verify= */ true,
+                                       /* verify_checksum= */ true,
                                        &error_msg,
                                        &dex_files_);
         CHECK(success) << "Open failed for '" << filename << "' " << error_msg;
@@ -640,7 +640,7 @@
     OpenApiFile(blacklist_path_, api_list, HiddenApiAccessFlags::kBlacklist);
 
     // Open all dex files.
-    ClassPath boot_classpath(boot_dex_paths_, /* open_writable */ true);
+    ClassPath boot_classpath(boot_dex_paths_, /* open_writable= */ true);
 
     // Set access flags of all members.
     boot_classpath.ForEachDexMember([&api_list](const DexMember& boot_member) {
@@ -688,7 +688,7 @@
     std::set<std::string> unresolved;
 
     // Open all dex files.
-    ClassPath boot_classpath(boot_dex_paths_, /* open_writable */ false);
+    ClassPath boot_classpath(boot_dex_paths_, /* open_writable= */ false);
     Hierarchy boot_hierarchy(boot_classpath);
 
     // Mark all boot dex members private.
@@ -698,7 +698,7 @@
 
     // Resolve each SDK dex member against the framework and mark it white.
     for (const std::vector<std::string>& stub_classpath_dex : stub_classpaths_) {
-      ClassPath stub_classpath(stub_classpath_dex, /* open_writable */ false);
+      ClassPath stub_classpath(stub_classpath_dex, /* open_writable= */ false);
       Hierarchy stub_hierarchy(stub_classpath);
       stub_classpath.ForEachDexMember(
           [&stub_hierarchy, &boot_hierarchy, &boot_members, &unresolved](
diff --git a/tools/hiddenapi/hiddenapi_test.cc b/tools/hiddenapi/hiddenapi_test.cc
index b50f684..799546e 100644
--- a/tools/hiddenapi/hiddenapi_test.cc
+++ b/tools/hiddenapi/hiddenapi_test.cc
@@ -85,15 +85,15 @@
     ArtDexFileLoader dex_loader;
     std::string error_msg;
 
-    File fd(file.GetFilename(), O_RDONLY, /* check_usage */ false);
+    File fd(file.GetFilename(), O_RDONLY, /* check_usage= */ false);
     if (fd.Fd() == -1) {
       LOG(FATAL) << "Unable to open file '" << file.GetFilename() << "': " << strerror(errno);
       UNREACHABLE();
     }
 
     std::unique_ptr<const DexFile> dex_file(dex_loader.OpenDex(
-        fd.Release(), /* location */ file.GetFilename(), /* verify */ false,
-        /* verify_checksum */ true, /* mmap_shared */ false, &error_msg));
+        fd.Release(), /* location= */ file.GetFilename(), /* verify= */ false,
+        /* verify_checksum= */ true, /* mmap_shared= */ false, &error_msg));
     if (dex_file.get() == nullptr) {
       LOG(FATAL) << "Open failed for '" << file.GetFilename() << "' " << error_msg;
       UNREACHABLE();
@@ -179,22 +179,31 @@
 
   HiddenApiAccessFlags::ApiList GetIMethodHiddenFlags(const DexFile& dex_file) {
     return GetMethodHiddenFlags(
-        "imethod", 0, /* native */ false, FindClass("LMain;", dex_file), dex_file);
+        "imethod", 0, /* expected_native= */ false, FindClass("LMain;", dex_file), dex_file);
   }
 
   HiddenApiAccessFlags::ApiList GetSMethodHiddenFlags(const DexFile& dex_file) {
-    return GetMethodHiddenFlags(
-        "smethod", kAccPublic, /* native */ false, FindClass("LMain;", dex_file), dex_file);
+    return GetMethodHiddenFlags("smethod",
+                                kAccPublic,
+                                /* expected_native= */ false,
+                                FindClass("LMain;", dex_file),
+                                dex_file);
   }
 
   HiddenApiAccessFlags::ApiList GetINMethodHiddenFlags(const DexFile& dex_file) {
-    return GetMethodHiddenFlags(
-        "inmethod", kAccPublic, /* native */ true, FindClass("LMain;", dex_file), dex_file);
+    return GetMethodHiddenFlags("inmethod",
+                                kAccPublic,
+                                /* expected_native= */ true,
+                                FindClass("LMain;", dex_file),
+                                dex_file);
   }
 
   HiddenApiAccessFlags::ApiList GetSNMethodHiddenFlags(const DexFile& dex_file) {
-    return GetMethodHiddenFlags(
-        "snmethod", kAccProtected, /* native */ true, FindClass("LMain;", dex_file), dex_file);
+    return GetMethodHiddenFlags("snmethod",
+                                kAccProtected,
+                                /* expected_native= */ true,
+                                FindClass("LMain;", dex_file),
+                                dex_file);
   }
 };
 
diff --git a/tools/jit-load/jitload.cc b/tools/jit-load/jitload.cc
index d67eef0..7e715de 100644
--- a/tools/jit-load/jitload.cc
+++ b/tools/jit-load/jitload.cc
@@ -90,7 +90,7 @@
 }
 
 static jvmtiEnv* SetupJvmti(JavaVM* vm, const char* options) {
-  android::base::InitLogging(/* argv */nullptr);
+  android::base::InitLogging(/* argv= */nullptr);
 
   jvmtiEnv* jvmti = nullptr;
   if (vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0) != JNI_OK &&
diff --git a/tools/libcore_gcstress_debug_failures.txt b/tools/libcore_gcstress_debug_failures.txt
index b8ad955..23533af 100644
--- a/tools/libcore_gcstress_debug_failures.txt
+++ b/tools/libcore_gcstress_debug_failures.txt
@@ -45,8 +45,7 @@
     "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringAbbrev",
     "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringCTS",
     "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringFrench",
-    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringGerman",
-    "org.apache.harmony.tests.java.lang.ProcessManagerTest#testSleep"
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringGerman"
   ]
 }
 ]
diff --git a/tools/ti-fast/tifast.cc b/tools/ti-fast/tifast.cc
index 85c433b..00ef656 100644
--- a/tools/ti-fast/tifast.cc
+++ b/tools/ti-fast/tifast.cc
@@ -528,7 +528,7 @@
 template<typename ...Args>
 void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, Args... args) {
   ScopedClassInfo sci(jvmti, klass);
-  if (sci.Init(/*get_generic*/event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) {
+  if (sci.Init(/*get_generic=*/event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) {
     stream << ", jclass[" << sci << "]";
   } else {
     stream << ", jclass[TYPE UNKNOWN]";
diff --git a/tools/titrace/titrace.cc b/tools/titrace/titrace.cc
index ca568d7..1e49c0b 100644
--- a/tools/titrace/titrace.cc
+++ b/tools/titrace/titrace.cc
@@ -237,7 +237,7 @@
                                     void* /* reserved */) {
   using namespace titrace;  // NOLINT [build/namespaces] [5]
 
-  android::base::InitLogging(/* argv */nullptr);
+  android::base::InitLogging(/* argv= */nullptr);
 
   jvmtiEnv* jvmti = nullptr;
   {
diff --git a/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc
index 69f7def..e925e1d 100644
--- a/tools/veridex/flow_analysis.cc
+++ b/tools/veridex/flow_analysis.cc
@@ -318,7 +318,7 @@
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_SUPER:
     case Instruction::INVOKE_VIRTUAL: {
-      last_result_ = AnalyzeInvoke(instruction, /* is_range */ false);
+      last_result_ = AnalyzeInvoke(instruction, /* is_range= */ false);
       break;
     }
 
@@ -327,7 +327,7 @@
     case Instruction::INVOKE_STATIC_RANGE:
     case Instruction::INVOKE_SUPER_RANGE:
     case Instruction::INVOKE_VIRTUAL_RANGE: {
-      last_result_ = AnalyzeInvoke(instruction, /* is_range */ true);
+      last_result_ = AnalyzeInvoke(instruction, /* is_range= */ true);
       break;
     }
 
@@ -702,14 +702,14 @@
     // second parameter for the field name.
     RegisterValue cls = GetRegister(GetParameterAt(instruction, is_range, args, 0));
     RegisterValue name = GetRegister(GetParameterAt(instruction, is_range, args, 1));
-    uses_.push_back(ReflectAccessInfo(cls, name, /* is_method */ false));
+    uses_.push_back(ReflectAccessInfo(cls, name, /* is_method= */ false));
     return GetReturnType(id);
   } else if (IsGetMethod(method)) {
     // Class.getMethod or Class.getDeclaredMethod. Fetch the first parameter for the class, and the
     // second parameter for the field name.
     RegisterValue cls = GetRegister(GetParameterAt(instruction, is_range, args, 0));
     RegisterValue name = GetRegister(GetParameterAt(instruction, is_range, args, 1));
-    uses_.push_back(ReflectAccessInfo(cls, name, /* is_method */ true));
+    uses_.push_back(ReflectAccessInfo(cls, name, /* is_method= */ true));
     return GetReturnType(id);
   } else if (method == VeriClass::getClass_) {
     // Get the type of the first parameter.
diff --git a/tools/veridex/flow_analysis.h b/tools/veridex/flow_analysis.h
index 865b9df..2151a41 100644
--- a/tools/veridex/flow_analysis.h
+++ b/tools/veridex/flow_analysis.h
@@ -174,7 +174,8 @@
   RegisterValue name;
   bool is_method;
 
-  ReflectAccessInfo(RegisterValue c, RegisterValue n, bool m) : cls(c), name(n), is_method(m) {}
+  ReflectAccessInfo(RegisterValue c, RegisterValue n, bool is_method)
+      : cls(c), name(n), is_method(is_method) {}
 
   bool IsConcrete() const {
     // We capture RegisterSource::kString for the class, for example in Class.forName.