Merge "[veridex] Resolve all type_id/method_id/field_id in app dex files."
diff --git a/compiler/optimizing/code_sinking.cc b/compiler/optimizing/code_sinking.cc
index f4760d6..2e31d35 100644
--- a/compiler/optimizing/code_sinking.cc
+++ b/compiler/optimizing/code_sinking.cc
@@ -214,6 +214,11 @@
     DCHECK(target_block != nullptr);
   }
 
+  // Bail if the instruction can throw and we are about to move into a catch block.
+  if (instruction->CanThrow() && target_block->GetTryCatchInformation() != nullptr) {
+    return nullptr;
+  }
+
   // Find insertion position. No need to filter anymore, as we have found a
   // target block.
   HInstruction* insert_pos = nullptr;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2b6f905..0b2297d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -852,7 +852,7 @@
 static HInstruction* NewIntegralAbs(ArenaAllocator* allocator,
                                     HInstruction* x,
                                     HInstruction* cursor) {
-  DataType::Type type = x->GetType();
+  DataType::Type type = DataType::Kind(x->GetType());
   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
   HAbs* abs = new (allocator) HAbs(type, x, cursor->GetDexPc());
   cursor->GetBlock()->InsertInstructionBefore(abs, cursor);
@@ -865,7 +865,7 @@
                                        HInstruction* y,
                                        HInstruction* cursor,
                                        bool is_min) {
-  DataType::Type type = x->GetType();
+  DataType::Type type = DataType::Kind(x->GetType());
   DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
   HBinaryOperation* minmax = nullptr;
   if (is_min) {
@@ -939,9 +939,9 @@
     DataType::Type t_type = true_value->GetType();
     DataType::Type f_type = false_value->GetType();
     // Here we have a <cmp> b ? true_value : false_value.
-    // Test if both values are same-typed int or long.
-    if (t_type == f_type &&
-        (t_type == DataType::Type::kInt32 || t_type == DataType::Type::kInt64)) {
+    // Test if both values are compatible integral types (resulting
+    // MIN/MAX/ABS type will be int or long, like the condition).
+    if (DataType::IsIntegralType(t_type) && DataType::Kind(t_type) == DataType::Kind(f_type)) {
       // Try to replace typical integral MIN/MAX/ABS constructs.
       if ((cmp == kCondLT || cmp == kCondLE || cmp == kCondGT || cmp == kCondGE) &&
           ((a == true_value && b == false_value) ||
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 9b37017..6950b93 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1609,11 +1609,9 @@
         // Unzip or copy dex files straight to the oat file.
         std::vector<std::unique_ptr<MemMap>> opened_dex_files_map;
         std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
-        // No need to verify the dex file for:
-        // 1) Dexlayout since it does the verification. It also may not pass the verification since
-        // we don't update the dex checksum.
-        // 2) when we have a vdex file, which means it was already verified.
-        const bool verify = !DoDexLayoutOptimizations() && (input_vdex_file_ == nullptr);
+        // No need to verify the dex file when we have a vdex file, which means it was already
+        // verified.
+        const bool verify = (input_vdex_file_ == nullptr);
         if (!oat_writers_[i]->WriteAndOpenDexFiles(
             vdex_files_[i].get(),
             rodata_.back(),
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 5590c8b..0cd39ac 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -2013,4 +2013,84 @@
   ASSERT_EQ(vdex_unquickened->FlushCloseOrErase(), 0) << "Could not flush and close";
 }
 
+// Test that compact dex generation with invalid dex files doesn't crash dex2oat. b/75970654
+TEST_F(Dex2oatTest, CompactDexInvalidSource) {
+  ScratchFile invalid_dex;
+  {
+    FILE* file = fdopen(invalid_dex.GetFd(), "w+b");
+    ZipWriter writer(file);
+    writer.StartEntry("classes.dex", ZipWriter::kAlign32);
+    DexFile::Header header = {};
+    StandardDexFile::WriteMagic(header.magic_);
+    StandardDexFile::WriteCurrentVersion(header.magic_);
+    header.file_size_ = 4 * KB;
+    header.data_size_ = 4 * KB;
+    header.data_off_ = 10 * MB;
+    header.map_off_ = 10 * MB;
+    header.class_defs_off_ = 10 * MB;
+    header.class_defs_size_ = 10000;
+    ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0);
+    writer.FinishEntry();
+    writer.Finish();
+    ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0);
+  }
+  const std::string dex_location = invalid_dex.GetFilename();
+  const std::string odex_location = GetOdexDir() + "/output.odex";
+  std::string error_msg;
+  int status = GenerateOdexForTestWithStatus(
+      {dex_location},
+      odex_location,
+      CompilerFilter::kQuicken,
+      &error_msg,
+      { "--compact-dex-level=fast" });
+  ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
+}
+
+// Test that dex2oat with a CompactDex file in the APK fails.
+TEST_F(Dex2oatTest, CompactDexInZip) {
+  CompactDexFile::Header header = {};
+  CompactDexFile::WriteMagic(header.magic_);
+  CompactDexFile::WriteCurrentVersion(header.magic_);
+  header.file_size_ = sizeof(CompactDexFile::Header);
+  header.data_off_ = 10 * MB;
+  header.map_off_ = 10 * MB;
+  header.class_defs_off_ = 10 * MB;
+  header.class_defs_size_ = 10000;
+  // Create a zip containing the invalid dex.
+  ScratchFile invalid_dex_zip;
+  {
+    FILE* file = fdopen(invalid_dex_zip.GetFd(), "w+b");
+    ZipWriter writer(file);
+    writer.StartEntry("classes.dex", ZipWriter::kCompress);
+    ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0);
+    writer.FinishEntry();
+    writer.Finish();
+    ASSERT_EQ(invalid_dex_zip.GetFile()->Flush(), 0);
+  }
+  // Create the dex file directly.
+  ScratchFile invalid_dex;
+  {
+    ASSERT_GE(invalid_dex.GetFile()->WriteFully(&header, sizeof(header)), 0);
+    ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0);
+  }
+  std::string error_msg;
+  int status = 0u;
+
+  status = GenerateOdexForTestWithStatus(
+      { invalid_dex_zip.GetFilename() },
+      GetOdexDir() + "/output_apk.odex",
+      CompilerFilter::kQuicken,
+      &error_msg,
+      { "--compact-dex-level=fast" });
+  ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
+
+  status = GenerateOdexForTestWithStatus(
+      { invalid_dex.GetFilename() },
+      GetOdexDir() + "/output.odex",
+      CompilerFilter::kQuicken,
+      &error_msg,
+      { "--compact-dex-level=fast" });
+  ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
+}
+
 }  // namespace art
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 758a2f0..1e0f5ac 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -348,6 +348,8 @@
                                       location_checksum,
                                       oat_dex_file,
                                       std::move(container)));
+    // Disable verification for CompactDex input.
+    verify = false;
   } else {
     *error_msg = "Invalid or truncated dex file";
   }
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 07b1529..de67871 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -940,9 +940,6 @@
   }
   art::ScopedThreadStateChange stsc(art::Thread::Current(), art::ThreadState::kNative);
   art::instrumentation::Instrumentation* instr = art::Runtime::Current()->GetInstrumentation();
-  art::gc::ScopedGCCriticalSection gcs(art::Thread::Current(),
-                                       art::gc::kGcCauseInstrumentation,
-                                       art::gc::kCollectorTypeInstrumentation);
   art::ScopedSuspendAll ssa("jvmti method tracing installation");
   if (enable) {
     instr->AddListener(listener, new_events);
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 83d64ef..bf2e6cd 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -42,6 +42,7 @@
 #include "dex/dex_file_types.h"
 #include "dex/modifiers.h"
 #include "events-inl.h"
+#include "gc_root-inl.h"
 #include "jit/jit.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
@@ -546,13 +547,12 @@
 
 class CommonLocalVariableClosure : public art::Closure {
  public:
-  CommonLocalVariableClosure(art::Thread* caller,
-                             jint depth,
-                             jint slot)
-      : result_(ERR(INTERNAL)), caller_(caller), depth_(depth), slot_(slot) {}
+  CommonLocalVariableClosure(jint depth, jint slot)
+      : result_(ERR(INTERNAL)), depth_(depth), slot_(slot) {}
 
   void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
     art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
+    art::ScopedAssertNoThreadSuspension sants("CommonLocalVariableClosure::Run");
     std::unique_ptr<art::Context> context(art::Context::Create());
     FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
     visitor.WalkStack();
@@ -597,17 +597,17 @@
     }
   }
 
-  jvmtiError GetResult() const {
+  virtual jvmtiError GetResult() {
     return result_;
   }
 
  protected:
   virtual jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
-      REQUIRES(art::Locks::mutator_lock_) = 0;
+      REQUIRES_SHARED(art::Locks::mutator_lock_) = 0;
   virtual jvmtiError GetTypeError(art::ArtMethod* method,
                                   art::Primitive::Type type,
                                   const std::string& descriptor)
-      REQUIRES(art::Locks::mutator_lock_)  = 0;
+      REQUIRES_SHARED(art::Locks::mutator_lock_)  = 0;
 
   jvmtiError GetSlotType(art::ArtMethod* method,
                          uint32_t dex_pc,
@@ -674,25 +674,35 @@
   }
 
   jvmtiError result_;
-  art::Thread* caller_;
   jint depth_;
   jint slot_;
 };
 
 class GetLocalVariableClosure : public CommonLocalVariableClosure {
  public:
-  GetLocalVariableClosure(art::Thread* caller,
-                          jint depth,
+  GetLocalVariableClosure(jint depth,
                           jint slot,
                           art::Primitive::Type type,
                           jvalue* val)
-      : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
+      : CommonLocalVariableClosure(depth, slot),
+        type_(type),
+        val_(val),
+        obj_val_(nullptr) {}
+
+  virtual jvmtiError GetResult() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    if (result_ == OK && type_ == art::Primitive::kPrimNot) {
+      val_->l = obj_val_.IsNull()
+          ? nullptr
+          : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(obj_val_.Read());
+    }
+    return CommonLocalVariableClosure::GetResult();
+  }
 
  protected:
   jvmtiError GetTypeError(art::ArtMethod* method ATTRIBUTE_UNUSED,
                           art::Primitive::Type slot_type,
                           const std::string& descriptor ATTRIBUTE_UNUSED)
-      OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+      OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
     switch (slot_type) {
       case art::Primitive::kPrimByte:
       case art::Primitive::kPrimChar:
@@ -712,7 +722,7 @@
   }
 
   jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
-      OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+      OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
     switch (type_) {
       case art::Primitive::kPrimNot: {
         uint32_t ptr_val;
@@ -722,8 +732,8 @@
                              &ptr_val)) {
           return ERR(OPAQUE_FRAME);
         }
-        art::ObjPtr<art::mirror::Object> obj(reinterpret_cast<art::mirror::Object*>(ptr_val));
-        val_->l = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
+        obj_val_ = art::GcRoot<art::mirror::Object>(
+            reinterpret_cast<art::mirror::Object*>(ptr_val));
         break;
       }
       case art::Primitive::kPrimInt:
@@ -760,6 +770,7 @@
  private:
   art::Primitive::Type type_;
   jvalue* val_;
+  art::GcRoot<art::mirror::Object> obj_val_;
 };
 
 jvmtiError MethodUtil::GetLocalVariableGeneric(jvmtiEnv* env ATTRIBUTE_UNUSED,
@@ -782,9 +793,12 @@
     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
     return err;
   }
-  GetLocalVariableClosure c(self, depth, slot, type, val);
-  // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-  if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &c)) {
+  art::ScopedAssertNoThreadSuspension sants("Performing GetLocalVariable");
+  GetLocalVariableClosure c(depth, slot, type, val);
+  // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.  We
+  // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
+  // transfering a GcRoot across threads.
+  if (!target->RequestSynchronousCheckpoint(&c, art::ThreadState::kRunnable)) {
     return ERR(THREAD_NOT_ALIVE);
   } else {
     return c.GetResult();
@@ -798,13 +812,13 @@
                           jint slot,
                           art::Primitive::Type type,
                           jvalue val)
-      : CommonLocalVariableClosure(caller, depth, slot), type_(type), val_(val) {}
+      : CommonLocalVariableClosure(depth, slot), caller_(caller), type_(type), val_(val) {}
 
  protected:
   jvmtiError GetTypeError(art::ArtMethod* method,
                           art::Primitive::Type slot_type,
                           const std::string& descriptor)
-      OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+      OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
     switch (slot_type) {
       case art::Primitive::kPrimNot: {
         if (type_ != art::Primitive::kPrimNot) {
@@ -840,7 +854,7 @@
   }
 
   jvmtiError Execute(art::ArtMethod* method, art::StackVisitor& visitor)
-      OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+      OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
     switch (type_) {
       case art::Primitive::kPrimNot: {
         uint32_t ptr_val;
@@ -887,6 +901,7 @@
   }
 
  private:
+  art::Thread* caller_;
   art::Primitive::Type type_;
   jvalue val_;
 };
@@ -913,7 +928,7 @@
   }
   SetLocalVariableClosure c(self, depth, slot, type, val);
   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-  if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &c)) {
+  if (!target->RequestSynchronousCheckpoint(&c)) {
     return ERR(THREAD_NOT_ALIVE);
   } else {
     return c.GetResult();
@@ -922,13 +937,13 @@
 
 class GetLocalInstanceClosure : public art::Closure {
  public:
-  GetLocalInstanceClosure(art::Thread* caller, jint depth, jobject* val)
+  explicit GetLocalInstanceClosure(jint depth)
       : result_(ERR(INTERNAL)),
-        caller_(caller),
         depth_(depth),
-        val_(val) {}
+        val_(nullptr) {}
 
   void Run(art::Thread* self) OVERRIDE REQUIRES(art::Locks::mutator_lock_) {
+    art::ScopedAssertNoThreadSuspension sants("GetLocalInstanceClosure::Run");
     art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
     std::unique_ptr<art::Context> context(art::Context::Create());
     FindFrameAtDepthVisitor visitor(self, context.get(), depth_);
@@ -939,19 +954,22 @@
       return;
     }
     result_ = OK;
-    art::ObjPtr<art::mirror::Object> obj = visitor.GetThisObject();
-    *val_ = obj.IsNull() ? nullptr : caller_->GetJniEnv()->AddLocalReference<jobject>(obj);
+    val_ = art::GcRoot<art::mirror::Object>(visitor.GetThisObject());
   }
 
-  jvmtiError GetResult() const {
+  jvmtiError GetResult(jobject* data_out) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    if (result_ == OK) {
+      *data_out = val_.IsNull()
+          ? nullptr
+          : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(val_.Read());
+    }
     return result_;
   }
 
  private:
   jvmtiError result_;
-  art::Thread* caller_;
   jint depth_;
-  jobject* val_;
+  art::GcRoot<art::mirror::Object> val_;
 };
 
 jvmtiError MethodUtil::GetLocalInstance(jvmtiEnv* env ATTRIBUTE_UNUSED,
@@ -970,12 +988,15 @@
     art::Locks::thread_list_lock_->ExclusiveUnlock(self);
     return err;
   }
-  GetLocalInstanceClosure c(self, depth, data);
-  // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-  if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &c)) {
+  art::ScopedAssertNoThreadSuspension sants("Performing GetLocalInstance");
+  GetLocalInstanceClosure c(depth);
+  // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.  We
+  // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
+  // transfering a GcRoot across threads.
+  if (!target->RequestSynchronousCheckpoint(&c, art::ThreadState::kRunnable)) {
     return ERR(THREAD_NOT_ALIVE);
   } else {
-    return c.GetResult();
+    return c.GetResult(data);
   }
 }
 
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index 94408ba..1cfc64a 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -37,6 +37,7 @@
 #include <mutex>
 
 #include "art_jvmti.h"
+#include "gc_root-inl.h"
 #include "monitor.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
@@ -351,19 +352,17 @@
   }
   struct GetContendedMonitorClosure : public art::Closure {
    public:
-    explicit GetContendedMonitorClosure(art::Thread* current, jobject* out)
-        : result_thread_(current), out_(out) {}
+    GetContendedMonitorClosure() : out_(nullptr) {}
 
     void Run(art::Thread* target_thread) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+      art::ScopedAssertNoThreadSuspension sants("GetContendedMonitorClosure::Run");
       switch (target_thread->GetState()) {
         // These three we are actually currently waiting on a monitor and have sent the appropriate
         // events (if anyone is listening).
         case art::kBlocked:
         case art::kTimedWaiting:
         case art::kWaiting: {
-          art::mirror::Object* mon = art::Monitor::GetContendedMonitor(target_thread);
-          *out_ = (mon == nullptr) ? nullptr
-                                   : result_thread_->GetJniEnv()->AddLocalReference<jobject>(mon);
+          out_ = art::GcRoot<art::mirror::Object>(art::Monitor::GetContendedMonitor(target_thread));
           return;
         }
         case art::kTerminated:
@@ -390,22 +389,30 @@
         case art::kStarting:
         case art::kNative:
         case art::kSuspended: {
-          // We aren't currently (explicitly) waiting for a monitor anything so just return null.
-          *out_ = nullptr;
+          // We aren't currently (explicitly) waiting for a monitor so just return null.
           return;
         }
       }
     }
 
+    jobject GetResult() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+      return out_.IsNull()
+          ? nullptr
+          : art::Thread::Current()->GetJniEnv()->AddLocalReference<jobject>(out_.Read());
+    }
+
    private:
-    art::Thread* result_thread_;
-    jobject* out_;
+    art::GcRoot<art::mirror::Object> out_;
   };
-  GetContendedMonitorClosure closure(self, monitor);
-  // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-  if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &closure)) {
+  art::ScopedAssertNoThreadSuspension sants("Performing GetCurrentContendedMonitor");
+  GetContendedMonitorClosure closure;
+  // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.  We
+  // need to avoid suspending as we wait for the checkpoint to occur since we are (potentially)
+  // transfering a GcRoot across threads.
+  if (!target->RequestSynchronousCheckpoint(&closure, art::ThreadState::kRunnable)) {
     return ERR(THREAD_NOT_ALIVE);
   }
+  *monitor = closure.GetResult();
   return OK;
 }
 
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index 373944f..41a649b 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -258,7 +258,7 @@
                                        static_cast<size_t>(start_depth),
                                        static_cast<size_t>(max_frame_count));
     // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-    if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(thread, &closure)) {
+    if (!thread->RequestSynchronousCheckpoint(&closure)) {
       return ERR(THREAD_NOT_ALIVE);
     }
     *count_ptr = static_cast<jint>(closure.index);
@@ -269,7 +269,7 @@
   } else {
     GetStackTraceVectorClosure closure(0, 0);
     // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-    if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(thread, &closure)) {
+    if (!thread->RequestSynchronousCheckpoint(&closure)) {
       return ERR(THREAD_NOT_ALIVE);
     }
 
@@ -484,7 +484,7 @@
     *stack_info_ptr = nullptr;
     return ERR(NONE);
   }
-  if (stack_info_ptr == nullptr || stack_info_ptr == nullptr) {
+  if (thread_list == nullptr || stack_info_ptr == nullptr) {
     return ERR(NULL_POINTER);
   }
 
@@ -713,7 +713,7 @@
 
   GetFrameCountClosure closure;
   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-  if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(thread, &closure)) {
+  if (!thread->RequestSynchronousCheckpoint(&closure)) {
     return ERR(THREAD_NOT_ALIVE);
   }
 
@@ -803,7 +803,7 @@
 
   GetLocationClosure closure(static_cast<size_t>(depth));
   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-  if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(thread, &closure)) {
+  if (!thread->RequestSynchronousCheckpoint(&closure)) {
     return ERR(THREAD_NOT_ALIVE);
   }
 
@@ -882,8 +882,8 @@
 template<typename Fn>
 struct MonitorInfoClosure : public art::Closure {
  public:
-  MonitorInfoClosure(art::ScopedObjectAccess& soa, Fn handle_results)
-      : soa_(soa), err_(OK), handle_results_(handle_results) {}
+  explicit MonitorInfoClosure(Fn handle_results)
+      : err_(OK), handle_results_(handle_results) {}
 
   void Run(art::Thread* target) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
     art::Locks::mutator_lock_->AssertSharedHeld(art::Thread::Current());
@@ -893,7 +893,7 @@
     // Find any other monitors, including ones acquired in native code.
     art::RootInfo root_info(art::kRootVMInternal);
     target->GetJniEnv()->VisitMonitorRoots(&visitor, root_info);
-    err_ = handle_results_(soa_, visitor);
+    err_ = handle_results_(visitor);
   }
 
   jvmtiError GetError() {
@@ -901,17 +901,18 @@
   }
 
  private:
-  art::ScopedObjectAccess& soa_;
   jvmtiError err_;
   Fn handle_results_;
 };
 
 
 template <typename Fn>
-static jvmtiError GetOwnedMonitorInfoCommon(jthread thread, Fn handle_results) {
+static jvmtiError GetOwnedMonitorInfoCommon(const art::ScopedObjectAccessAlreadyRunnable& soa,
+                                            jthread thread,
+                                            Fn handle_results)
+    REQUIRES_SHARED(art::Locks::mutator_lock_) {
   art::Thread* self = art::Thread::Current();
-  art::ScopedObjectAccess soa(self);
-  MonitorInfoClosure<Fn> closure(soa, handle_results);
+  MonitorInfoClosure<Fn> closure(handle_results);
   bool called_method = false;
   {
     art::Locks::thread_list_lock_->ExclusiveLock(self);
@@ -924,7 +925,7 @@
     if (target != self) {
       called_method = true;
       // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-      if (!ThreadUtil::RequestGCSafeSynchronousCheckpoint(target, &closure)) {
+      if (!target->RequestSynchronousCheckpoint(&closure)) {
         return ERR(THREAD_NOT_ALIVE);
       }
     } else {
@@ -948,47 +949,64 @@
   if (info_cnt == nullptr || info_ptr == nullptr) {
     return ERR(NULL_POINTER);
   }
-  auto handle_fun = [&] (art::ScopedObjectAccess& soa, MonitorVisitor& visitor)
-      REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    auto nbytes = sizeof(jvmtiMonitorStackDepthInfo) * visitor.monitors.size();
-    jvmtiError err = env->Allocate(nbytes, reinterpret_cast<unsigned char**>(info_ptr));
-    if (err != OK) {
-      return err;
-    }
-    *info_cnt = visitor.monitors.size();
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  std::vector<art::GcRoot<art::mirror::Object>> mons;
+  std::vector<uint32_t> depths;
+  auto handle_fun = [&] (MonitorVisitor& visitor) REQUIRES_SHARED(art::Locks::mutator_lock_) {
     for (size_t i = 0; i < visitor.monitors.size(); i++) {
-      (*info_ptr)[i] = {
-        soa.Env()->AddLocalReference<jobject>(visitor.monitors[i].Get()),
-        visitor.stack_depths[i]
-      };
+      mons.push_back(art::GcRoot<art::mirror::Object>(visitor.monitors[i].Get()));
+      depths.push_back(visitor.stack_depths[i]);
     }
     return OK;
   };
-  return GetOwnedMonitorInfoCommon(thread, handle_fun);
+  jvmtiError err = GetOwnedMonitorInfoCommon(soa, thread, handle_fun);
+  if (err != OK) {
+    return err;
+  }
+  auto nbytes = sizeof(jvmtiMonitorStackDepthInfo) * mons.size();
+  err = env->Allocate(nbytes, reinterpret_cast<unsigned char**>(info_ptr));
+  if (err != OK) {
+    return err;
+  }
+  *info_cnt = mons.size();
+  for (uint32_t i = 0; i < mons.size(); i++) {
+    (*info_ptr)[i] = {
+      soa.AddLocalReference<jobject>(mons[i].Read()),
+      static_cast<jint>(depths[i])
+    };
+  }
+  return err;
 }
 
 jvmtiError StackUtil::GetOwnedMonitorInfo(jvmtiEnv* env,
                                           jthread thread,
                                           jint* owned_monitor_count_ptr,
                                           jobject** owned_monitors_ptr) {
-  if (owned_monitors_ptr == nullptr || owned_monitors_ptr == nullptr) {
+  if (owned_monitor_count_ptr == nullptr || owned_monitors_ptr == nullptr) {
     return ERR(NULL_POINTER);
   }
-  auto handle_fun = [&] (art::ScopedObjectAccess& soa, MonitorVisitor& visitor)
-      REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    auto nbytes = sizeof(jobject) * visitor.monitors.size();
-    jvmtiError err = env->Allocate(nbytes, reinterpret_cast<unsigned char**>(owned_monitors_ptr));
-    if (err != OK) {
-      return err;
-    }
-    *owned_monitor_count_ptr = visitor.monitors.size();
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  std::vector<art::GcRoot<art::mirror::Object>> mons;
+  auto handle_fun = [&] (MonitorVisitor& visitor) REQUIRES_SHARED(art::Locks::mutator_lock_) {
     for (size_t i = 0; i < visitor.monitors.size(); i++) {
-      (*owned_monitors_ptr)[i] =
-          soa.Env()->AddLocalReference<jobject>(visitor.monitors[i].Get());
+      mons.push_back(art::GcRoot<art::mirror::Object>(visitor.monitors[i].Get()));
     }
     return OK;
   };
-  return GetOwnedMonitorInfoCommon(thread, handle_fun);
+  jvmtiError err = GetOwnedMonitorInfoCommon(soa, thread, handle_fun);
+  if (err != OK) {
+    return err;
+  }
+  auto nbytes = sizeof(jobject) * mons.size();
+  err = env->Allocate(nbytes, reinterpret_cast<unsigned char**>(owned_monitors_ptr));
+  if (err != OK) {
+    return err;
+  }
+  *owned_monitor_count_ptr = mons.size();
+  for (uint32_t i = 0; i < mons.size(); i++) {
+    (*owned_monitors_ptr)[i] = soa.AddLocalReference<jobject>(mons[i].Read());
+  }
+  return err;
 }
 
 jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth) {
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index 555c5a7..414139c 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -1077,7 +1077,7 @@
   };
   StopThreadClosure c(exc);
   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-  if (RequestGCSafeSynchronousCheckpoint(target, &c)) {
+  if (target->RequestSynchronousCheckpoint(&c)) {
     return OK;
   } else {
     // Something went wrong, probably the thread died.
@@ -1100,29 +1100,4 @@
   return OK;
 }
 
-class GcCriticalSectionClosure : public art::Closure {
- public:
-  explicit GcCriticalSectionClosure(art::Closure* wrapped) : wrapped_(wrapped) {}
-
-  void Run(art::Thread* self) OVERRIDE {
-    if (art::kIsDebugBuild) {
-      art::Locks::thread_list_lock_->AssertNotHeld(art::Thread::Current());
-    }
-    // This might block as it waits for any in-progress GCs to finish but this is fine since we
-    // released the Thread-list-lock prior to calling this in RequestSynchronousCheckpoint.
-    art::gc::ScopedGCCriticalSection sgccs(art::Thread::Current(),
-                                           art::gc::kGcCauseDebugger,
-                                           art::gc::kCollectorTypeDebugger);
-    wrapped_->Run(self);
-  }
-
- private:
-  art::Closure* wrapped_;
-};
-
-bool ThreadUtil::RequestGCSafeSynchronousCheckpoint(art::Thread* thr, art::Closure* function) {
-  GcCriticalSectionClosure gccsc(function);
-  return thr->RequestSynchronousCheckpoint(&gccsc);
-}
-
 }  // namespace openjdkjvmti
diff --git a/openjdkjvmti/ti_thread.h b/openjdkjvmti/ti_thread.h
index 341bffe..c6b6af1 100644
--- a/openjdkjvmti/ti_thread.h
+++ b/openjdkjvmti/ti_thread.h
@@ -134,16 +134,6 @@
     REQUIRES(!art::Locks::user_code_suspension_lock_,
              !art::Locks::thread_suspend_count_lock_);
 
-  // This will request a synchronous checkpoint in such a way as to prevent gc races if a local
-  // variable is taken from one thread's stack and placed in the stack of another thread.
-  // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution. This is
-  // due to the fact that Thread::Current() needs to go to sleep to allow the targeted thread to
-  // execute the checkpoint for us if it is Runnable.
-  static bool RequestGCSafeSynchronousCheckpoint(art::Thread* thr, art::Closure* function)
-      REQUIRES_SHARED(art::Locks::mutator_lock_)
-      RELEASE(art::Locks::thread_list_lock_)
-      REQUIRES(!art::Locks::thread_suspend_count_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/runtime/barrier.cc b/runtime/barrier.cc
index 4329a5a..8d3cf45 100644
--- a/runtime/barrier.cc
+++ b/runtime/barrier.cc
@@ -31,6 +31,9 @@
       condition_("GC barrier condition", lock_) {
 }
 
+template void Barrier::Increment<Barrier::kAllowHoldingLocks>(Thread* self, int delta);
+template void Barrier::Increment<Barrier::kDisallowHoldingLocks>(Thread* self, int delta);
+
 void Barrier::Pass(Thread* self) {
   MutexLock mu(self, lock_);
   SetCountLocked(self, count_ - 1);
@@ -45,6 +48,7 @@
   SetCountLocked(self, count);
 }
 
+template <Barrier::LockHandling locks>
 void Barrier::Increment(Thread* self, int delta) {
   MutexLock mu(self, lock_);
   SetCountLocked(self, count_ + delta);
@@ -57,7 +61,11 @@
   // be decremented to zero and a Broadcast will be made on the
   // condition variable, thus waking this up.
   while (count_ != 0) {
-    condition_.Wait(self);
+    if (locks == kAllowHoldingLocks) {
+      condition_.WaitHoldingLocks(self);
+    } else {
+      condition_.Wait(self);
+    }
   }
 }
 
diff --git a/runtime/barrier.h b/runtime/barrier.h
index d7c4661..8a38c4c 100644
--- a/runtime/barrier.h
+++ b/runtime/barrier.h
@@ -35,6 +35,11 @@
 // TODO: Maybe give this a better name.
 class Barrier {
  public:
+  enum LockHandling {
+    kAllowHoldingLocks,
+    kDisallowHoldingLocks,
+  };
+
   explicit Barrier(int count);
   virtual ~Barrier();
 
@@ -50,7 +55,9 @@
   // If these calls are made in that situation, the offending thread is likely to go back
   // to sleep, resulting in a deadlock.
 
-  // Increment the count by delta, wait on condition if count is non zero.
+  // Increment the count by delta, wait on condition if count is non zero.  If LockHandling is
+  // kAllowHoldingLocks we will not check that all locks are released when waiting.
+  template <Barrier::LockHandling locks = kDisallowHoldingLocks>
   void Increment(Thread* self, int delta) REQUIRES(!lock_);
 
   // Increment the count by delta, wait on condition if count is non zero, with a timeout. Returns
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 8a29ff3..1d72b46 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -5863,14 +5863,6 @@
       // smaller as we go on.
       uint32_t hash_index = hash_table.FindAndRemove(&super_method_name_comparator);
       if (hash_index != hash_table.GetNotFoundIndex()) {
-        // Run a check whether we are going to override a method which is hidden
-        // to `klass`, but ignore the result as we only warn at the moment.
-        // We cannot do this test earlier because we need to establish that
-        // a method is being overridden first. ShouldBlockAccessToMember would
-        // print bogus warnings otherwise.
-        hiddenapi::ShouldBlockAccessToMember(
-            super_method, klass->GetClassLoader(), hiddenapi::kOverride);
-
         ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(
             hash_index, image_pointer_size_);
         if (super_method->IsFinal()) {
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
index c456764..9802c69 100644
--- a/runtime/dex/art_dex_file_loader.cc
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -205,6 +205,12 @@
                                                  error_msg,
                                                  std::make_unique<MemMapContainer>(std::move(map)),
                                                  /*verify_result*/ nullptr);
+  // Opening CompactDex is only supported from vdex files.
+  if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
+    *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
+                              location.c_str());
+    return nullptr;
+  }
   return dex_file;
 }
 
@@ -329,6 +335,12 @@
                                                  std::make_unique<MemMapContainer>(std::move(map)),
                                                  /*verify_result*/ nullptr);
 
+  // Opening CompactDex is only supported from vdex files.
+  if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
+    *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
+                              location.c_str());
+    return nullptr;
+  }
   return dex_file;
 }
 
@@ -397,6 +409,11 @@
                                                  error_msg,
                                                  std::make_unique<MemMapContainer>(std::move(map)),
                                                  &verify_result);
+  if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
+    *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
+                              location.c_str());
+    return nullptr;
+  }
   if (dex_file == nullptr) {
     if (verify_result == VerifyResult::kVerifyNotAttempted) {
       *error_code = ZipOpenErrorCode::kDexFileError;
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index f2ea2fd..5c6b4b5 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -27,6 +27,23 @@
 namespace art {
 namespace hiddenapi {
 
+// Hidden API enforcement policy
+// This must be kept in sync with ApplicationInfo.ApiEnforcementPolicy in
+// frameworks/base/core/java/android/content/pm/ApplicationInfo.java
+enum class EnforcementPolicy {
+  kNoChecks             = 0,
+  kAllLists             = 1,  // ban anything but whitelist
+  kDarkGreyAndBlackList = 2,  // ban dark grey & blacklist
+  kBlacklistOnly        = 3,  // ban blacklist violations only
+  kMax = kBlacklistOnly,
+};
+
+inline EnforcementPolicy EnforcementPolicyFromInt(int api_policy_int) {
+  DCHECK_GE(api_policy_int, 0);
+  DCHECK_LE(api_policy_int, static_cast<int>(EnforcementPolicy::kMax));
+  return static_cast<EnforcementPolicy>(api_policy_int);
+}
+
 enum Action {
   kAllow,
   kAllowButWarn,
@@ -38,7 +55,6 @@
   kReflection,
   kJNI,
   kLinking,
-  kOverride,
 };
 
 inline std::ostream& operator<<(std::ostream& os, AccessMethod value) {
@@ -52,23 +68,42 @@
     case kLinking:
       os << "linking";
       break;
-    case kOverride:
-      os << "override";
-      break;
   }
   return os;
 }
 
+static constexpr bool EnumsEqual(EnforcementPolicy policy, HiddenApiAccessFlags::ApiList apiList) {
+  return static_cast<int>(policy) == static_cast<int>(apiList);
+}
+
 inline Action GetMemberAction(uint32_t access_flags) {
-  switch (HiddenApiAccessFlags::DecodeFromRuntime(access_flags)) {
-    case HiddenApiAccessFlags::kWhitelist:
-      return kAllow;
-    case HiddenApiAccessFlags::kLightGreylist:
-      return kAllowButWarn;
-    case HiddenApiAccessFlags::kDarkGreylist:
-      return kAllowButWarnAndToast;
-    case HiddenApiAccessFlags::kBlacklist:
-      return kDeny;
+  EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
+  if (policy == EnforcementPolicy::kNoChecks) {
+    // Exit early. Nothing to enforce.
+    return kAllow;
+  }
+
+  HiddenApiAccessFlags::ApiList api_list = HiddenApiAccessFlags::DecodeFromRuntime(access_flags);
+  if (api_list == HiddenApiAccessFlags::kWhitelist) {
+    return kAllow;
+  }
+  // The logic below relies on equality of values in the enums EnforcementPolicy and
+  // HiddenApiAccessFlags::ApiList, and their ordering. Assert that this is as expected.
+  static_assert(
+      EnumsEqual(EnforcementPolicy::kAllLists, HiddenApiAccessFlags::kLightGreylist) &&
+      EnumsEqual(EnforcementPolicy::kDarkGreyAndBlackList, HiddenApiAccessFlags::kDarkGreylist) &&
+      EnumsEqual(EnforcementPolicy::kBlacklistOnly, HiddenApiAccessFlags::kBlacklist),
+      "Mismatch between EnforcementPolicy and ApiList enums");
+  static_assert(
+      EnforcementPolicy::kAllLists < EnforcementPolicy::kDarkGreyAndBlackList &&
+      EnforcementPolicy::kDarkGreyAndBlackList < EnforcementPolicy::kBlacklistOnly,
+      "EnforcementPolicy values ordering not correct");
+  if (static_cast<int>(policy) > static_cast<int>(api_list)) {
+    return api_list == HiddenApiAccessFlags::kDarkGreylist
+        ? kAllowButWarnAndToast
+        : kAllowButWarn;
+  } else {
+    return kDeny;
   }
 }
 
@@ -107,12 +142,6 @@
                                       AccessMethod access_method)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(member != nullptr);
-  Runtime* runtime = Runtime::Current();
-
-  if (!runtime->AreHiddenApiChecksEnabled()) {
-    // Exit early. Nothing to enforce.
-    return false;
-  }
 
   Action action = GetMemberAction(member->GetAccessFlags());
   if (action == kAllow) {
@@ -133,14 +162,16 @@
   // We do this regardless of whether we block the access or not.
   WarnAboutMemberAccess(member, access_method);
 
-  // Block access if on blacklist.
   if (action == kDeny) {
+    // Block access
     return true;
   }
 
   // Allow access to this member but print a warning.
   DCHECK(action == kAllowButWarn || action == kAllowButWarnAndToast);
 
+  Runtime* runtime = Runtime::Current();
+
   // Depending on a runtime flag, we might move the member into whitelist and
   // skip the warning the next time the member is accessed.
   if (runtime->ShouldDedupeHiddenApiWarnings()) {
@@ -150,7 +181,7 @@
 
   // If this action requires a UI warning, set the appropriate flag.
   if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) {
-    Runtime::Current()->SetPendingHiddenApiWarning(true);
+    runtime->SetPendingHiddenApiWarning(true);
   }
 
   return false;
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index fc94266..3692a30 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -89,17 +89,27 @@
 
 static void VMDebug_startMethodTracingDdmsImpl(JNIEnv*, jclass, jint bufferSize, jint flags,
                                                jboolean samplingEnabled, jint intervalUs) {
-  Trace::Start("[DDMS]", -1, bufferSize, flags, Trace::TraceOutputMode::kDDMS,
-               samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
-               intervalUs);
+  Trace::StartDDMS(bufferSize,
+                   flags,
+                   samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
+                   intervalUs);
 }
 
-static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceFilename,
-                                         jint javaFd, jint bufferSize, jint flags,
-                                         jboolean samplingEnabled, jint intervalUs,
+static void VMDebug_startMethodTracingFd(JNIEnv* env,
+                                         jclass,
+                                         jstring javaTraceFilename ATTRIBUTE_UNUSED,
+                                         jint javaFd,
+                                         jint bufferSize,
+                                         jint flags,
+                                         jboolean samplingEnabled,
+                                         jint intervalUs,
                                          jboolean streamingOutput) {
   int originalFd = javaFd;
   if (originalFd < 0) {
+    ScopedObjectAccess soa(env);
+    soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
+                                   "Trace fd is invalid: %d",
+                                   originalFd);
     return;
   }
 
@@ -107,18 +117,20 @@
   if (fd < 0) {
     ScopedObjectAccess soa(env);
     soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
-                                   "dup(%d) failed: %s", originalFd, strerror(errno));
+                                   "dup(%d) failed: %s",
+                                   originalFd,
+                                   strerror(errno));
     return;
   }
 
-  ScopedUtfChars traceFilename(env, javaTraceFilename);
-  if (traceFilename.c_str() == nullptr) {
-    return;
-  }
+  // Ignore the traceFilename.
   Trace::TraceOutputMode outputMode = streamingOutput
                                           ? Trace::TraceOutputMode::kStreaming
                                           : Trace::TraceOutputMode::kFile;
-  Trace::Start(traceFilename.c_str(), fd, bufferSize, flags, outputMode,
+  Trace::Start(fd,
+               bufferSize,
+               flags,
+               outputMode,
                samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
                intervalUs);
 }
@@ -130,7 +142,10 @@
   if (traceFilename.c_str() == nullptr) {
     return;
   }
-  Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, Trace::TraceOutputMode::kFile,
+  Trace::Start(traceFilename.c_str(),
+               bufferSize,
+               flags,
+               Trace::TraceOutputMode::kFile,
                samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
                intervalUs);
 }
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 8913569..d9a5096 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -162,19 +162,24 @@
 
 // Must match values in com.android.internal.os.Zygote.
 enum {
-  DEBUG_ENABLE_JDWP               = 1,
-  DEBUG_ENABLE_CHECKJNI           = 1 << 1,
-  DEBUG_ENABLE_ASSERT             = 1 << 2,
-  DEBUG_ENABLE_SAFEMODE           = 1 << 3,
-  DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
-  DEBUG_GENERATE_DEBUG_INFO       = 1 << 5,
-  DEBUG_ALWAYS_JIT                = 1 << 6,
-  DEBUG_NATIVE_DEBUGGABLE         = 1 << 7,
-  DEBUG_JAVA_DEBUGGABLE           = 1 << 8,
-  DISABLE_VERIFIER                = 1 << 9,
-  ONLY_USE_SYSTEM_OAT_FILES       = 1 << 10,
-  ENABLE_HIDDEN_API_CHECKS        = 1 << 11,
-  DEBUG_GENERATE_MINI_DEBUG_INFO  = 1 << 12,
+  DEBUG_ENABLE_JDWP                  = 1,
+  DEBUG_ENABLE_CHECKJNI              = 1 << 1,
+  DEBUG_ENABLE_ASSERT                = 1 << 2,
+  DEBUG_ENABLE_SAFEMODE              = 1 << 3,
+  DEBUG_ENABLE_JNI_LOGGING           = 1 << 4,
+  DEBUG_GENERATE_DEBUG_INFO          = 1 << 5,
+  DEBUG_ALWAYS_JIT                   = 1 << 6,
+  DEBUG_NATIVE_DEBUGGABLE            = 1 << 7,
+  DEBUG_JAVA_DEBUGGABLE              = 1 << 8,
+  DISABLE_VERIFIER                   = 1 << 9,
+  ONLY_USE_SYSTEM_OAT_FILES          = 1 << 10,
+  DEBUG_GENERATE_MINI_DEBUG_INFO     = 1 << 11,
+  HIDDEN_API_ENFORCEMENT_POLICY_MASK = (1 << 12)
+                                     | (1 << 13),
+
+  // bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value
+  // corresponding to hiddenapi::EnforcementPolicy
+  API_ENFORCEMENT_POLICY_SHIFT = CTZ(HIDDEN_API_ENFORCEMENT_POLICY_MASK),
 };
 
 static uint32_t EnableDebugFeatures(uint32_t runtime_flags) {
@@ -285,7 +290,8 @@
   // Our system thread ID, etc, has changed so reset Thread state.
   thread->InitAfterFork();
   runtime_flags = EnableDebugFeatures(runtime_flags);
-  bool do_hidden_api_checks = false;
+  hiddenapi::EnforcementPolicy api_enforcement_policy = hiddenapi::EnforcementPolicy::kNoChecks;
+  bool dedupe_hidden_api_warnings = true;
 
   if ((runtime_flags & DISABLE_VERIFIER) != 0) {
     Runtime::Current()->DisableVerifier();
@@ -297,10 +303,9 @@
     runtime_flags &= ~ONLY_USE_SYSTEM_OAT_FILES;
   }
 
-  if ((runtime_flags & ENABLE_HIDDEN_API_CHECKS) != 0) {
-    do_hidden_api_checks = true;
-    runtime_flags &= ~ENABLE_HIDDEN_API_CHECKS;
-  }
+  api_enforcement_policy = hiddenapi::EnforcementPolicyFromInt(
+      (runtime_flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT);
+  runtime_flags &= ~HIDDEN_API_ENFORCEMENT_POLICY_MASK;
 
   if (runtime_flags != 0) {
     LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
@@ -338,7 +343,6 @@
 
       std::string trace_file = StringPrintf("/data/misc/trace/%s.trace.bin", proc_name.c_str());
       Trace::Start(trace_file.c_str(),
-                   -1,
                    buffer_size,
                    0,   // TODO: Expose flags.
                    output_mode,
@@ -351,11 +355,13 @@
     }
   }
 
+  bool do_hidden_api_checks = api_enforcement_policy != hiddenapi::EnforcementPolicy::kNoChecks;
   DCHECK(!(is_system_server && do_hidden_api_checks))
-      << "SystemServer should be forked with ENABLE_HIDDEN_API_CHECKS";
+      << "SystemServer should be forked with EnforcementPolicy::kDisable";
   DCHECK(!(is_zygote && do_hidden_api_checks))
-      << "Child zygote processes should be forked with ENABLE_HIDDEN_API_CHECKS";
-  Runtime::Current()->SetHiddenApiChecksEnabled(do_hidden_api_checks);
+      << "Child zygote processes should be forked with EnforcementPolicy::kDisable";
+  Runtime::Current()->SetHiddenApiEnforcementPolicy(api_enforcement_policy);
+  Runtime::Current()->SetDedupeHiddenApiWarnings(dedupe_hidden_api_warnings);
 
   // Clear the hidden API warning flag, in case it was set.
   Runtime::Current()->SetPendingHiddenApiWarning(false);
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 25d5037..fc61c95 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -89,8 +89,8 @@
 // access hidden APIs. This can be *very* expensive. Never call this in a loop.
 ALWAYS_INLINE static bool ShouldEnforceHiddenApi(Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  return Runtime::Current()->AreHiddenApiChecksEnabled() &&
-         !IsCallerInBootClassPath(self);
+  hiddenapi::EnforcementPolicy policy = Runtime::Current()->GetHiddenApiEnforcementPolicy();
+  return policy != hiddenapi::EnforcementPolicy::kNoChecks && !IsCallerInBootClassPath(self);
 }
 
 // Returns true if the first non-ClassClass caller up the stack should not be
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 7d9d342..9a626ba 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -267,7 +267,7 @@
       oat_file_manager_(nullptr),
       is_low_memory_mode_(false),
       safe_mode_(false),
-      do_hidden_api_checks_(false),
+      hidden_api_policy_(hiddenapi::EnforcementPolicy::kNoChecks),
       pending_hidden_api_warning_(false),
       dedupe_hidden_api_warnings_(true),
       always_set_hidden_api_warning_flag_(false),
@@ -839,7 +839,6 @@
   if (trace_config_.get() != nullptr && trace_config_->trace_file != "") {
     ScopedThreadStateChange tsc(self, kWaitingForMethodTracingStart);
     Trace::Start(trace_config_->trace_file.c_str(),
-                 -1,
                  static_cast<int>(trace_config_->trace_file_size),
                  0,
                  trace_config_->trace_output_mode,
@@ -1196,9 +1195,14 @@
   // by default and we only enable them if:
   // (a) runtime was started with a flag that enables the checks, or
   // (b) Zygote forked a new process that is not exempt (see ZygoteHooks).
-  do_hidden_api_checks_ = runtime_options.Exists(Opt::HiddenApiChecks);
-  DCHECK(!is_zygote_ || !do_hidden_api_checks_)
-      << "Zygote should not be started with hidden API checks";
+  bool do_hidden_api_checks = runtime_options.Exists(Opt::HiddenApiChecks);
+  DCHECK(!is_zygote_ || !do_hidden_api_checks);
+  // TODO pass the actual enforcement policy in, rather than just a single bit.
+  // As is, we're encoding some logic here about which specific policy to use, which would be better
+  // controlled by the framework.
+  hidden_api_policy_ = do_hidden_api_checks
+      ? hiddenapi::EnforcementPolicy::kBlacklistOnly
+      : hiddenapi::EnforcementPolicy::kNoChecks;
 
   no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
   force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index c7f650e..dba31b2 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -49,6 +49,10 @@
 class Heap;
 }  // namespace gc
 
+namespace hiddenapi {
+enum class EnforcementPolicy;
+}  // namespace hiddenapi
+
 namespace jit {
 class Jit;
 class JitOptions;
@@ -520,12 +524,12 @@
   bool IsVerificationEnabled() const;
   bool IsVerificationSoftFail() const;
 
-  void SetHiddenApiChecksEnabled(bool value) {
-    do_hidden_api_checks_ = value;
+  void SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy policy) {
+    hidden_api_policy_ = policy;
   }
 
-  bool AreHiddenApiChecksEnabled() const {
-    return do_hidden_api_checks_;
+  hiddenapi::EnforcementPolicy GetHiddenApiEnforcementPolicy() const {
+    return hidden_api_policy_;
   }
 
   void SetPendingHiddenApiWarning(bool value) {
@@ -990,7 +994,7 @@
   bool safe_mode_;
 
   // Whether access checks on hidden API should be performed.
-  bool do_hidden_api_checks_;
+  hiddenapi::EnforcementPolicy hidden_api_policy_;
 
   // Whether the application has used an API which is not restricted but we
   // should issue a warning about it.
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 5b03c2d..c0deda8 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1438,8 +1438,12 @@
     barrier_.Pass(self);
   }
 
-  void Wait(Thread* self) {
-    barrier_.Increment(self, 1);
+  void Wait(Thread* self, ThreadState suspend_state) {
+    if (suspend_state != ThreadState::kRunnable) {
+      barrier_.Increment<Barrier::kDisallowHoldingLocks>(self, 1);
+    } else {
+      barrier_.Increment<Barrier::kAllowHoldingLocks>(self, 1);
+    }
   }
 
  private:
@@ -1448,7 +1452,7 @@
 };
 
 // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution.
-bool Thread::RequestSynchronousCheckpoint(Closure* function) {
+bool Thread::RequestSynchronousCheckpoint(Closure* function, ThreadState suspend_state) {
   Thread* self = Thread::Current();
   if (this == Thread::Current()) {
     Locks::thread_list_lock_->AssertExclusiveHeld(self);
@@ -1496,8 +1500,8 @@
         // Relinquish the thread-list lock. We should not wait holding any locks. We cannot
         // reacquire it since we don't know if 'this' hasn't been deleted yet.
         Locks::thread_list_lock_->ExclusiveUnlock(self);
-        ScopedThreadSuspension sts(self, ThreadState::kWaiting);
-        barrier_closure.Wait(self);
+        ScopedThreadStateChange sts(self, suspend_state);
+        barrier_closure.Wait(self, suspend_state);
         return true;
       }
       // Fall-through.
@@ -1521,7 +1525,7 @@
       // that we can call ModifySuspendCount without racing against ThreadList::Unregister.
       ScopedThreadListLockUnlock stllu(self);
       {
-        ScopedThreadSuspension sts(self, ThreadState::kWaiting);
+        ScopedThreadStateChange sts(self, suspend_state);
         while (GetState() == ThreadState::kRunnable) {
           // We became runnable again. Wait till the suspend triggered in ModifySuspendCount
           // moves us to suspended.
diff --git a/runtime/thread.h b/runtime/thread.h
index 6549fc1..9adae96 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -263,16 +263,31 @@
       WARN_UNUSED
       REQUIRES(Locks::thread_suspend_count_lock_);
 
+  // Requests a checkpoint closure to run on another thread. The closure will be run when the thread
+  // gets suspended. This will return true if the closure was added and will (eventually) be
+  // executed. It returns false otherwise.
+  //
+  // Since multiple closures can be queued and some closures can delay other threads from running no
+  // closure should attempt to suspend another thread while running.
+  // TODO We should add some debug option that verifies this.
   bool RequestCheckpoint(Closure* function)
       REQUIRES(Locks::thread_suspend_count_lock_);
 
   // RequestSynchronousCheckpoint releases the thread_list_lock_ as a part of its execution. This is
   // due to the fact that Thread::Current() needs to go to sleep to allow the targeted thread to
-  // execute the checkpoint for us if it is Runnable.
-  bool RequestSynchronousCheckpoint(Closure* function)
+  // execute the checkpoint for us if it is Runnable. The suspend_state is the state that the thread
+  // will go into while it is awaiting the checkpoint to be run.
+  // NB Passing ThreadState::kRunnable may cause the current thread to wait in a condition variable
+  // while holding the mutator_lock_.  Callers should ensure that this will not cause any problems
+  // for the closure or the rest of the system.
+  // NB Since multiple closures can be queued and some closures can delay other threads from running
+  // no closure should attempt to suspend another thread while running.
+  bool RequestSynchronousCheckpoint(Closure* function,
+                                    ThreadState suspend_state = ThreadState::kWaiting)
       REQUIRES_SHARED(Locks::mutator_lock_)
       RELEASE(Locks::thread_list_lock_)
       REQUIRES(!Locks::thread_suspend_count_lock_);
+
   bool RequestEmptyCheckpoint()
       REQUIRES(Locks::thread_suspend_count_lock_);
 
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 0f321b6..91d2b37 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -319,8 +319,74 @@
   return nullptr;
 }
 
-void Trace::Start(const char* trace_filename, int trace_fd, size_t buffer_size, int flags,
-                  TraceOutputMode output_mode, TraceMode trace_mode, int interval_us) {
+void Trace::Start(const char* trace_filename,
+                  size_t buffer_size,
+                  int flags,
+                  TraceOutputMode output_mode,
+                  TraceMode trace_mode,
+                  int interval_us) {
+  std::unique_ptr<File> file(OS::CreateEmptyFileWriteOnly(trace_filename));
+  if (file == nullptr) {
+    std::string msg = android::base::StringPrintf("Unable to open trace file '%s'", trace_filename);
+    PLOG(ERROR) << msg;
+    ScopedObjectAccess soa(Thread::Current());
+    Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;", msg.c_str());
+    return;
+  }
+  Start(std::move(file), buffer_size, flags, output_mode, trace_mode, interval_us);
+}
+
+void Trace::Start(int trace_fd,
+                  size_t buffer_size,
+                  int flags,
+                  TraceOutputMode output_mode,
+                  TraceMode trace_mode,
+                  int interval_us) {
+  if (trace_fd < 0) {
+    std::string msg = android::base::StringPrintf("Unable to start tracing with invalid fd %d",
+                                                  trace_fd);
+    LOG(ERROR) << msg;
+    ScopedObjectAccess soa(Thread::Current());
+    Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;", msg.c_str());
+    return;
+  }
+  std::unique_ptr<File> file(new File(trace_fd, "tracefile"));
+  Start(std::move(file), buffer_size, flags, output_mode, trace_mode, interval_us);
+}
+
+void Trace::StartDDMS(size_t buffer_size,
+                      int flags,
+                      TraceMode trace_mode,
+                      int interval_us) {
+  Start(std::unique_ptr<File>(),
+        buffer_size,
+        flags,
+        TraceOutputMode::kDDMS,
+        trace_mode,
+        interval_us);
+}
+
+void Trace::Start(std::unique_ptr<File>&& trace_file_in,
+                  size_t buffer_size,
+                  int flags,
+                  TraceOutputMode output_mode,
+                  TraceMode trace_mode,
+                  int interval_us) {
+  // We own trace_file now and are responsible for closing it. To account for error situations, use
+  // a specialized unique_ptr to ensure we close it on the way out (if it hasn't been passed to a
+  // Trace instance).
+  auto deleter = [](File* file) {
+    if (file != nullptr) {
+      file->MarkUnchecked();  // Don't deal with flushing requirements.
+      int result ATTRIBUTE_UNUSED = file->Close();
+      delete file;
+    }
+  };
+  std::unique_ptr<File, decltype(deleter)> trace_file(trace_file_in.release(), deleter);
+  if (trace_file != nullptr) {
+    trace_file->DisableAutoClose();
+  }
+
   Thread* self = Thread::Current();
   {
     MutexLock mu(self, *Locks::trace_lock_);
@@ -338,23 +404,6 @@
     return;
   }
 
-  // Open trace file if not going directly to ddms.
-  std::unique_ptr<File> trace_file;
-  if (output_mode != TraceOutputMode::kDDMS) {
-    if (trace_fd < 0) {
-      trace_file.reset(OS::CreateEmptyFileWriteOnly(trace_filename));
-    } else {
-      trace_file.reset(new File(trace_fd, "tracefile"));
-      trace_file->DisableAutoClose();
-    }
-    if (trace_file.get() == nullptr) {
-      PLOG(ERROR) << "Unable to open trace file '" << trace_filename << "'";
-      ScopedObjectAccess soa(self);
-      ThrowRuntimeException("Unable to open trace file '%s'", trace_filename);
-      return;
-    }
-  }
-
   Runtime* runtime = Runtime::Current();
 
   // Enable count of allocs if specified in the flags.
@@ -372,8 +421,7 @@
       LOG(ERROR) << "Trace already in progress, ignoring this request";
     } else {
       enable_stats = (flags && kTraceCountAllocs) != 0;
-      the_trace_ = new Trace(trace_file.release(), trace_filename, buffer_size, flags, output_mode,
-                             trace_mode);
+      the_trace_ = new Trace(trace_file.release(), buffer_size, flags, output_mode, trace_mode);
       if (trace_mode == TraceMode::kSampling) {
         CHECK_PTHREAD_CALL(pthread_create, (&sampling_pthread_, nullptr, &RunSamplingThread,
                                             reinterpret_cast<void*>(interval_us)),
@@ -595,8 +643,11 @@
 
 static constexpr size_t kMinBufSize = 18U;  // Trace header is up to 18B.
 
-Trace::Trace(File* trace_file, const char* trace_name, size_t buffer_size, int flags,
-             TraceOutputMode output_mode, TraceMode trace_mode)
+Trace::Trace(File* trace_file,
+             size_t buffer_size,
+             int flags,
+             TraceOutputMode output_mode,
+             TraceMode trace_mode)
     : trace_file_(trace_file),
       buf_(new uint8_t[std::max(kMinBufSize, buffer_size)]()),
       flags_(flags), trace_output_mode_(output_mode), trace_mode_(trace_mode),
@@ -605,6 +656,8 @@
       start_time_(MicroTime()), clock_overhead_ns_(GetClockOverheadNanoSeconds()), cur_offset_(0),
       overflow_(false), interval_us_(0), streaming_lock_(nullptr),
       unique_methods_lock_(new Mutex("unique methods lock", kTracingUniqueMethodsLock)) {
+  CHECK(trace_file != nullptr || output_mode == TraceOutputMode::kDDMS);
+
   uint16_t trace_version = GetTraceVersion(clock_source_);
   if (output_mode == TraceOutputMode::kStreaming) {
     trace_version |= 0xF0U;
@@ -625,7 +678,6 @@
   cur_offset_.StoreRelaxed(kTraceHeaderLength);
 
   if (output_mode == TraceOutputMode::kStreaming) {
-    streaming_file_name_ = trace_name;
     streaming_lock_ = new Mutex("tracing lock", LockLevel::kTracingStreamingLock);
     seen_threads_.reset(new ThreadIDBitSet());
   }
diff --git a/runtime/trace.h b/runtime/trace.h
index 86b8d00..7171f75 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -33,6 +33,10 @@
 #include "globals.h"
 #include "instrumentation.h"
 
+namespace unix_file {
+class FdFile;
+}  // namespace unix_file
+
 namespace art {
 
 class ArtField;
@@ -115,10 +119,37 @@
 
   static void SetDefaultClockSource(TraceClockSource clock_source);
 
-  static void Start(const char* trace_filename, int trace_fd, size_t buffer_size, int flags,
-                    TraceOutputMode output_mode, TraceMode trace_mode, int interval_us)
+  static void Start(const char* trace_filename,
+                    size_t buffer_size,
+                    int flags,
+                    TraceOutputMode output_mode,
+                    TraceMode trace_mode,
+                    int interval_us)
       REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
                !Locks::trace_lock_);
+  static void Start(int trace_fd,
+                    size_t buffer_size,
+                    int flags,
+                    TraceOutputMode output_mode,
+                    TraceMode trace_mode,
+                    int interval_us)
+      REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
+               !Locks::trace_lock_);
+  static void Start(std::unique_ptr<unix_file::FdFile>&& file,
+                    size_t buffer_size,
+                    int flags,
+                    TraceOutputMode output_mode,
+                    TraceMode trace_mode,
+                    int interval_us)
+      REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
+               !Locks::trace_lock_);
+  static void StartDDMS(size_t buffer_size,
+                        int flags,
+                        TraceMode trace_mode,
+                        int interval_us)
+      REQUIRES(!Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_,
+               !Locks::trace_lock_);
+
   static void Pause() REQUIRES(!Locks::trace_lock_, !Locks::thread_list_lock_);
   static void Resume() REQUIRES(!Locks::trace_lock_);
 
@@ -212,8 +243,11 @@
   static bool IsTracingEnabled() REQUIRES(!Locks::trace_lock_);
 
  private:
-  Trace(File* trace_file, const char* trace_name, size_t buffer_size, int flags,
-        TraceOutputMode output_mode, TraceMode trace_mode);
+  Trace(File* trace_file,
+        size_t buffer_size,
+        int flags,
+        TraceOutputMode output_mode,
+        TraceMode trace_mode);
 
   // The sampling interval in microseconds is passed as an argument.
   static void* RunSamplingThread(void* arg) REQUIRES(!Locks::trace_lock_);
@@ -318,7 +352,6 @@
   int interval_us_;
 
   // Streaming mode data.
-  std::string streaming_file_name_;
   Mutex* streaming_lock_;
   std::map<const DexFile*, DexIndexBitSet*> seen_methods_;
   std::unique_ptr<ThreadIDBitSet> seen_threads_;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index b07001e..cee7176 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2765,47 +2765,61 @@
       break;
 
     case Instruction::IGET_BOOLEAN:
+    case Instruction::IGET_BOOLEAN_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IGET_BYTE:
+    case Instruction::IGET_BYTE_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IGET_CHAR:
+    case Instruction::IGET_CHAR_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IGET_SHORT:
+    case Instruction::IGET_SHORT_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IGET:
+    case Instruction::IGET_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IGET_WIDE:
+    case Instruction::IGET_WIDE_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IGET_OBJECT:
+    case Instruction::IGET_OBJECT_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false,
                                                     false);
       break;
 
     case Instruction::IPUT_BOOLEAN:
+    case Instruction::IPUT_BOOLEAN_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IPUT_BYTE:
+    case Instruction::IPUT_BYTE_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IPUT_CHAR:
+    case Instruction::IPUT_CHAR_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IPUT_SHORT:
+    case Instruction::IPUT_SHORT_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IPUT:
+    case Instruction::IPUT_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IPUT_WIDE:
+    case Instruction::IPUT_WIDE_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IPUT_OBJECT:
+    case Instruction::IPUT_OBJECT_QUICK:
       VerifyISFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false,
                                                     false);
       break;
@@ -2859,9 +2873,12 @@
     case Instruction::INVOKE_VIRTUAL:
     case Instruction::INVOKE_VIRTUAL_RANGE:
     case Instruction::INVOKE_SUPER:
-    case Instruction::INVOKE_SUPER_RANGE: {
+    case Instruction::INVOKE_SUPER_RANGE:
+    case Instruction::INVOKE_VIRTUAL_QUICK:
+    case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
       bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
-                       inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
+                       inst->Opcode() == Instruction::INVOKE_SUPER_RANGE ||
+                       inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
       bool is_super = (inst->Opcode() == Instruction::INVOKE_SUPER ||
                        inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
       MethodType type = is_super ? METHOD_SUPER : METHOD_VIRTUAL;
@@ -2881,7 +2898,7 @@
         }
       }
       if (return_type == nullptr) {
-        uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+        uint32_t method_idx = GetMethodIdxOfInvoke(inst);
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
         dex::TypeIndex return_type_idx =
             dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
@@ -3368,67 +3385,6 @@
         }
       }
       break;
-    // Note: the following instructions encode offsets derived from class linking.
-    // As such they use Class*/Field*/Executable* as these offsets only have
-    // meaning if the class linking and resolution were successful.
-    case Instruction::IGET_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Integer(), true);
-      break;
-    case Instruction::IGET_WIDE_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.LongLo(), true);
-      break;
-    case Instruction::IGET_OBJECT_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.JavaLangObject(false), false);
-      break;
-    case Instruction::IGET_BOOLEAN_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Boolean(), true);
-      break;
-    case Instruction::IGET_BYTE_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Byte(), true);
-      break;
-    case Instruction::IGET_CHAR_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Char(), true);
-      break;
-    case Instruction::IGET_SHORT_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccGet>(inst, reg_types_.Short(), true);
-      break;
-    case Instruction::IPUT_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Integer(), true);
-      break;
-    case Instruction::IPUT_BOOLEAN_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Boolean(), true);
-      break;
-    case Instruction::IPUT_BYTE_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Byte(), true);
-      break;
-    case Instruction::IPUT_CHAR_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Char(), true);
-      break;
-    case Instruction::IPUT_SHORT_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.Short(), true);
-      break;
-    case Instruction::IPUT_WIDE_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.LongLo(), true);
-      break;
-    case Instruction::IPUT_OBJECT_QUICK:
-      VerifyQuickFieldAccess<FieldAccessType::kAccPut>(inst, reg_types_.JavaLangObject(false), false);
-      break;
-    case Instruction::INVOKE_VIRTUAL_QUICK:
-    case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
-      bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
-      ArtMethod* called_method = VerifyInvokeVirtualQuickArgs(inst, is_range);
-      if (called_method != nullptr) {
-        const char* descriptor = called_method->GetReturnTypeDescriptor();
-        const RegType& return_type = reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
-        if (!return_type.IsLowHalf()) {
-          work_line_->SetResultRegisterType(this, return_type);
-        } else {
-          work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(&reg_types_));
-        }
-        just_set_result = true;
-      }
-      break;
-    }
 
     /* These should never appear during verification. */
     case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
@@ -3995,7 +3951,7 @@
         }
       } else {
         // Check whether the name of the called method is "<init>"
-        const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+        const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
         if (strcmp(dex_file_->GetMethodName(dex_file_->GetMethodId(method_idx)), "<init>") != 0) {
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'this' arg must be initialized";
           return nullptr;
@@ -4017,7 +3973,7 @@
         res_method_class = &FromClass(klass->GetDescriptor(&temp), klass,
                                       klass->CannotBeAssignedFromOtherTypes());
       } else {
-        const uint32_t method_idx = inst->VRegB();
+        const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
         const dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
         res_method_class = &reg_types_.FromDescriptor(
             GetClassLoader(),
@@ -4108,7 +4064,7 @@
   // As the method may not have been resolved, make this static check against what we expect.
   // The main reason for this code block is to fail hard when we find an illegal use, e.g.,
   // wrong number of arguments or wrong primitive types, even if the method could not be resolved.
-  const uint32_t method_idx = inst->VRegB();
+  const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
   DexFileParameterIterator it(*dex_file_,
                               dex_file_->GetProtoId(dex_file_->GetMethodId(method_idx).proto_idx_));
   VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, nullptr);
@@ -4181,7 +4137,7 @@
     const Instruction* inst, MethodType method_type, bool is_range) {
   // Resolve the method. This could be an abstract or concrete method depending on what sort of call
   // we're making.
-  const uint32_t method_idx = inst->VRegB();
+  const uint32_t method_idx = GetMethodIdxOfInvoke(inst);
   ArtMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type);
   if (res_method == nullptr) {  // error or class is unresolved
     // Check what we can statically.
@@ -4334,122 +4290,34 @@
   return true;
 }
 
-ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, bool is_range) {
-  if (is_range) {
-    DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
-  } else {
-    DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_VIRTUAL_QUICK);
+uint16_t MethodVerifier::GetMethodIdxOfInvoke(const Instruction* inst) {
+  switch (inst->Opcode()) {
+    case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+    case Instruction::INVOKE_VIRTUAL_QUICK: {
+      DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_)
+          << dex_file_->PrettyMethod(dex_method_idx_, true) << "@" << work_insn_idx_;
+      DCHECK(method_being_verified_ != nullptr);
+      uint16_t method_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_);
+      CHECK_NE(method_idx, DexFile::kDexNoIndex16);
+      return method_idx;
+    }
+    default: {
+      return inst->VRegB();
+    }
   }
-
-  DCHECK(method_being_verified_ != nullptr);
-  uint16_t method_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_);
-  CHECK_NE(method_idx, DexFile::kDexNoIndex16);
-  return ResolveMethodAndCheckAccess(method_idx, METHOD_VIRTUAL);
 }
 
-ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst, bool is_range) {
-  DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_)
-      << dex_file_->PrettyMethod(dex_method_idx_, true) << "@" << work_insn_idx_;
-
-  ArtMethod* res_method = GetQuickInvokedMethod(inst, is_range);
-  if (res_method == nullptr) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer method from " << inst->Name();
-    return nullptr;
-  }
-  if (FailOrAbort(!res_method->IsDirect(),
-                  "Quick-invoked method is direct at ",
-                  work_insn_idx_)) {
-    return nullptr;
-  }
-  if (FailOrAbort(!res_method->IsStatic(),
-                  "Quick-invoked method is static at ",
-                  work_insn_idx_)) {
-    return nullptr;
-  }
-
-  // We use vAA as our expected arg count, rather than res_method->insSize, because we need to
-  // match the call to the signature. Also, we might be calling through an abstract method
-  // definition (which doesn't have register count values).
-  const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst);
-  if (actual_arg_type.IsConflict()) {  // GetInvocationThis failed.
-    return nullptr;
-  }
-  const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
-  /* caught by static verifier */
-  DCHECK(is_range || expected_args <= 5);
-  if (expected_args > code_item_accessor_.OutsSize()) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
-        << ") exceeds outsSize (" << code_item_accessor_.OutsSize() << ")";
-    return nullptr;
-  }
-
-  /*
-   * Check the "this" argument, which must be an instance of the class that declared the method.
-   * For an interface class, we don't do the full interface merge (see JoinClass), so we can't do a
-   * rigorous check here (which is okay since we have to do it at runtime).
-   */
-  // Note: given an uninitialized type, this should always fail. Constructors aren't virtual.
-  if (actual_arg_type.IsUninitializedTypes() && !res_method->IsConstructor()) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'this' arg must be initialized";
-    return nullptr;
-  }
-  if (!actual_arg_type.IsZeroOrNull()) {
-    mirror::Class* klass = res_method->GetDeclaringClass();
-    std::string temp;
-    const RegType& res_method_class =
-        FromClass(klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes());
-    if (!res_method_class.IsAssignableFrom(actual_arg_type, this)) {
-      Fail(actual_arg_type.IsUninitializedTypes()    // Just overcautious - should have never
-               ? VERIFY_ERROR_BAD_CLASS_HARD         // quickened this.
-               : actual_arg_type.IsUnresolvedTypes()
-                     ? VERIFY_ERROR_NO_CLASS
-                     : VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
-          << "' not instance of '" << res_method_class << "'";
-      return nullptr;
-    }
-  }
-  /*
-   * Process the target method's signature. This signature may or may not
-   * have been verified, so we can't assume it's properly formed.
-   */
-  const DexFile::TypeList* params = res_method->GetParameterTypeList();
-  size_t params_size = params == nullptr ? 0 : params->Size();
-  uint32_t arg[5];
-  if (!is_range) {
-    inst->GetVarArgs(arg);
-  }
-  size_t actual_args = 1;
-  for (size_t param_index = 0; param_index < params_size; param_index++) {
-    if (actual_args >= expected_args) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invalid call to '"
-                                        << res_method->PrettyMethod()
-                                        << "'. Expected " << expected_args
-                                         << " arguments, processing argument " << actual_args
-                                        << " (where longs/doubles count twice).";
-      return nullptr;
-    }
-    const char* descriptor =
-        res_method->GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
-    if (descriptor == nullptr) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of "
-                                        << res_method->PrettyMethod()
-                                        << " missing signature component";
-      return nullptr;
-    }
-    const RegType& reg_type = reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
-    uint32_t get_reg = is_range ? inst->VRegC_3rc() + actual_args : arg[actual_args];
-    if (!work_line_->VerifyRegisterType(this, get_reg, reg_type)) {
-      return res_method;
-    }
-    actual_args = reg_type.IsLongOrDoubleTypes() ? actual_args + 2 : actual_args + 1;
-  }
-  if (actual_args != expected_args) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of "
-                                      << res_method->PrettyMethod() << " expected "
-                                      << expected_args << " arguments, found " << actual_args;
-    return nullptr;
+uint16_t MethodVerifier::GetFieldIdxOfFieldAccess(const Instruction* inst, bool is_static) {
+  if (is_static) {
+    return inst->VRegB_21c();
+  } else if (inst->IsQuickened()) {
+    DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
+    DCHECK(method_being_verified_ != nullptr);
+    uint16_t field_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_);
+    CHECK_NE(field_idx, DexFile::kDexNoIndex16);
+    return field_idx;
   } else {
-    return res_method;
+    return inst->VRegC_22c();
   }
 }
 
@@ -4819,7 +4687,7 @@
 template <MethodVerifier::FieldAccessType kAccType>
 void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType& insn_type,
                                          bool is_primitive, bool is_static) {
-  uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
+  uint32_t field_idx = GetFieldIdxOfFieldAccess(inst, is_static);
   ArtField* field;
   if (is_static) {
     field = GetStaticField(field_idx);
@@ -4972,151 +4840,6 @@
   }
 }
 
-ArtField* MethodVerifier::GetQuickAccessedField() {
-  DCHECK(method_being_verified_ != nullptr);
-  uint16_t field_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_);
-  CHECK_NE(field_idx, DexFile::kDexNoIndex16);
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  ArtField* field = class_linker->ResolveFieldJLS(field_idx, dex_cache_, class_loader_);
-  if (field == nullptr) {
-    DCHECK(self_->IsExceptionPending());
-    self_->ClearException();
-  }
-  return field;
-}
-
-template <MethodVerifier::FieldAccessType kAccType>
-void MethodVerifier::VerifyQuickFieldAccess(const Instruction* inst, const RegType& insn_type,
-                                            bool is_primitive) {
-  DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
-
-  ArtField* field = GetQuickAccessedField();
-  if (field == nullptr) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
-    return;
-  }
-
-  // For an IPUT_QUICK, we now test for final flag of the field.
-  if (kAccType == FieldAccessType::kAccPut) {
-    if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
-      Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << field->PrettyField()
-                                      << " from other class " << GetDeclaringClass();
-      return;
-    }
-  }
-
-  // Get the field type.
-  const RegType* field_type;
-  {
-    ObjPtr<mirror::Class> field_type_class =
-        can_load_classes_ ? field->ResolveType() : field->LookupResolvedType();
-
-    if (field_type_class != nullptr) {
-      field_type = &FromClass(field->GetTypeDescriptor(),
-                              field_type_class.Ptr(),
-                              field_type_class->CannotBeAssignedFromOtherTypes());
-    } else {
-      Thread* self = Thread::Current();
-      DCHECK(!can_load_classes_ || self->IsExceptionPending());
-      self->ClearException();
-      field_type = &reg_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(),
-                                              field->GetTypeDescriptor(),
-                                              false);
-    }
-    if (field_type == nullptr) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field type from " << inst->Name();
-      return;
-    }
-  }
-
-  const uint32_t vregA = inst->VRegA_22c();
-  static_assert(kAccType == FieldAccessType::kAccPut || kAccType == FieldAccessType::kAccGet,
-                "Unexpected third access type");
-  if (kAccType == FieldAccessType::kAccPut) {
-    if (is_primitive) {
-      // Primitive field assignability rules are weaker than regular assignability rules
-      bool instruction_compatible;
-      bool value_compatible;
-      const RegType& value_type = work_line_->GetRegisterType(this, vregA);
-      if (field_type->IsIntegralTypes()) {
-        instruction_compatible = insn_type.IsIntegralTypes();
-        value_compatible = value_type.IsIntegralTypes();
-      } else if (field_type->IsFloat()) {
-        instruction_compatible = insn_type.IsInteger();  // no [is]put-float, so expect [is]put-int
-        value_compatible = value_type.IsFloatTypes();
-      } else if (field_type->IsLong()) {
-        instruction_compatible = insn_type.IsLong();
-        value_compatible = value_type.IsLongTypes();
-      } else if (field_type->IsDouble()) {
-        instruction_compatible = insn_type.IsLong();  // no [is]put-double, so expect [is]put-long
-        value_compatible = value_type.IsDoubleTypes();
-      } else {
-        instruction_compatible = false;  // reference field with primitive store
-        value_compatible = false;  // unused
-      }
-      if (!instruction_compatible) {
-        // This is a global failure rather than a class change failure as the instructions and
-        // the descriptors for the type should have been consistent within the same file at
-        // compile time
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << ArtField::PrettyField(field)
-                                          << " to be of type '" << insn_type
-                                          << "' but found type '" << *field_type
-                                          << "' in put";
-        return;
-      }
-      if (!value_compatible) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
-            << " of type " << value_type
-            << " but expected " << *field_type
-            << " for store to " << ArtField::PrettyField(field) << " in put";
-        return;
-      }
-    } else {
-      if (!insn_type.IsAssignableFrom(*field_type, this)) {
-        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << ArtField::PrettyField(field)
-                                          << " to be compatible with type '" << insn_type
-                                          << "' but found type '" << *field_type
-                                          << "' in put-object";
-        return;
-      }
-      work_line_->VerifyRegisterType(this, vregA, *field_type);
-    }
-  } else if (kAccType == FieldAccessType::kAccGet) {
-    if (is_primitive) {
-      if (field_type->Equals(insn_type) ||
-          (field_type->IsFloat() && insn_type.IsIntegralTypes()) ||
-          (field_type->IsDouble() && insn_type.IsLongTypes())) {
-        // expected that read is of the correct primitive type or that int reads are reading
-        // floats or long reads are reading doubles
-      } else {
-        // This is a global failure rather than a class change failure as the instructions and
-        // the descriptors for the type should have been consistent within the same file at
-        // compile time
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << ArtField::PrettyField(field)
-                                          << " to be of type '" << insn_type
-                                          << "' but found type '" << *field_type << "' in Get";
-        return;
-      }
-    } else {
-      if (!insn_type.IsAssignableFrom(*field_type, this)) {
-        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << ArtField::PrettyField(field)
-                                          << " to be compatible with type '" << insn_type
-                                          << "' but found type '" << *field_type
-                                          << "' in get-object";
-        work_line_->SetRegisterType<LockOp::kClear>(this, vregA, reg_types_.Conflict());
-        return;
-      }
-    }
-    if (!field_type->IsLowHalf()) {
-      work_line_->SetRegisterType<LockOp::kClear>(this, vregA, *field_type);
-    } else {
-      work_line_->SetRegisterTypeWide(this, vregA, *field_type, field_type->HighHalf(&reg_types_));
-    }
-  } else {
-    LOG(FATAL) << "Unexpected case.";
-  }
-}
-
 bool MethodVerifier::CheckNotMoveException(const uint16_t* insns, int insn_idx) {
   if ((insns[insn_idx] & 0xff) == Instruction::MOVE_EXCEPTION) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid use of move-exception";
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 9237a8b..531d3da 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -209,12 +209,12 @@
 
   const RegType& ResolveCheckedClass(dex::TypeIndex class_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  // Returns the method of a quick invoke or null if it cannot be found.
-  ArtMethod* GetQuickInvokedMethod(const Instruction* inst, bool is_range)
+  // Returns the method index of an invoke instruction.
+  uint16_t GetMethodIdxOfInvoke(const Instruction* inst)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  // Returns the access field of a quick field access (iget/iput-quick) or null
-  // if it cannot be found.
-  ArtField* GetQuickAccessedField() REQUIRES_SHARED(Locks::mutator_lock_);
+  // Returns the field index of a field access instruction.
+  uint16_t GetFieldIdxOfFieldAccess(const Instruction* inst, bool is_static)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   uint32_t GetEncounteredFailureTypes() {
     return encountered_failure_types_;
@@ -575,10 +575,6 @@
                            bool is_primitive, bool is_static)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  template <FieldAccessType kAccType>
-  void VerifyQuickFieldAccess(const Instruction* inst, const RegType& insn_type, bool is_primitive)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   enum class CheckAccess {  // private.
     kYes,
     kNo,
@@ -642,9 +638,6 @@
                                                       ArtMethod* res_method)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ArtMethod* VerifyInvokeVirtualQuickArgs(const Instruction* inst, bool is_range)
-  REQUIRES_SHARED(Locks::mutator_lock_);
-
   /*
    * Verify the arguments present for a call site. Returns "true" if all is well, "false" otherwise.
    */
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 67ea64b..bf36ccf 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -24,6 +24,7 @@
 #include <android-base/stringprintf.h>
 
 #include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "hidden_api.h"
 #include "jni_internal.h"
 #include "mirror/class.h"
 #include "mirror/throwable.h"
@@ -287,17 +288,17 @@
  public:
   explicit ScopedHiddenApiExemption(Runtime* runtime)
       : runtime_(runtime),
-        initially_enabled_(runtime_->AreHiddenApiChecksEnabled()) {
-    runtime_->SetHiddenApiChecksEnabled(false);
+        initial_policy_(runtime_->GetHiddenApiEnforcementPolicy()) {
+    runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kNoChecks);
   }
 
   ~ScopedHiddenApiExemption() {
-    runtime_->SetHiddenApiChecksEnabled(initially_enabled_);
+    runtime_->SetHiddenApiEnforcementPolicy(initial_policy_);
   }
 
  private:
   Runtime* runtime_;
-  const bool initially_enabled_;
+  const hiddenapi::EnforcementPolicy initial_policy_;
   DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiExemption);
 };
 
diff --git a/test/121-modifiers/classes/A$B.class b/test/121-modifiers/classes/A$B.class
deleted file mode 100644
index bd7ebfe..0000000
--- a/test/121-modifiers/classes/A$B.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/A$C.class b/test/121-modifiers/classes/A$C.class
deleted file mode 100644
index 3ae872e..0000000
--- a/test/121-modifiers/classes/A$C.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/A.class b/test/121-modifiers/classes/A.class
deleted file mode 100644
index d89d029..0000000
--- a/test/121-modifiers/classes/A.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/Inf.class b/test/121-modifiers/classes/Inf.class
deleted file mode 100644
index e8dd680..0000000
--- a/test/121-modifiers/classes/Inf.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/Main.class b/test/121-modifiers/classes/Main.class
deleted file mode 100644
index e044074..0000000
--- a/test/121-modifiers/classes/Main.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/classes/NonInf.class b/test/121-modifiers/classes/NonInf.class
deleted file mode 100644
index 0f1e826..0000000
--- a/test/121-modifiers/classes/NonInf.class
+++ /dev/null
Binary files differ
diff --git a/test/121-modifiers/info.txt b/test/121-modifiers/info.txt
index 335df53..7dba113 100644
--- a/test/121-modifiers/info.txt
+++ b/test/121-modifiers/info.txt
@@ -10,9 +10,9 @@
 javac Inf.java NonInf.java Main.java
 javac -cp asm.jar:asm-tree.jar:. Asm.java
 java -cp asm.jar:asm-tree.jar:. Asm
-mv Inf.out classes/Inf.class
-mv NonInf.out classes/NonInf.class
-mv Main.class A.class A\$B.class A\$C.class classes/
+mv Inf.out classes_tmp/Inf.class
+mv NonInf.out classes_tmp/NonInf.class
+mv Main.class A.class A\$B.class A\$C.class classes_tmp/
 dx --debug --dex --output=classes.dex classes
 baksmali disassemble classes.dex
 mv out/*.smali smali/
diff --git a/test/161-final-abstract-class/smali/Main.smali b/test/161-final-abstract-class/smali/Main.smali
new file mode 100644
index 0000000..588854c
--- /dev/null
+++ b/test/161-final-abstract-class/smali/Main.smali
@@ -0,0 +1,214 @@
+# Created with baksmali.
+
+# Java file for reference.
+
+# import java.lang.reflect.InvocationTargetException;
+# import java.lang.reflect.Method;
+#
+# public class Main {
+#     public static void main(String[] args) {
+#         try {
+#             // Make sure that the abstract final class is marked as erroneous.
+#             Class.forName("AbstractFinal");
+#             System.out.println("UNREACHABLE!");
+#         } catch (VerifyError expected) {
+#         } catch (Throwable t) {
+#             t.printStackTrace(System.out);
+#         }
+#         try {
+#             // Verification of TestClass.test() used to crash when processing
+#             // the final abstract (erroneous) class.
+#             Class<?> tc = Class.forName("TestClass");
+#             Method test = tc.getDeclaredMethod("test");
+#             test.invoke(null);
+#             System.out.println("UNREACHABLE!");
+#         } catch (InvocationTargetException ite) {
+#             if (ite.getCause() instanceof InstantiationError) {
+#                 System.out.println(
+#                     ite.getCause().getClass().getName() + ": " + ite.getCause().getMessage());
+#             } else {
+#                 ite.printStackTrace(System.out);
+#             }
+#         } catch (Throwable t) {
+#             t.printStackTrace(System.out);
+#         }
+#     }
+# }
+
+.class public LMain;
+.super Ljava/lang/Object;
+.source "Main.java"
+
+
+# direct methods
+.method public constructor <init>()V
+    .registers 1
+
+    .line 20
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+    return-void
+.end method
+
+.method public static main([Ljava/lang/String;)V
+    .registers 4
+
+    .line 24
+    :try_start_0
+    const-string p0, "AbstractFinal"
+
+    invoke-static {p0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
+
+    .line 25
+    sget-object p0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    const-string v0, "UNREACHABLE!"
+
+    invoke-virtual {p0, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+    :try_end_c
+    .catch Ljava/lang/VerifyError; {:try_start_0 .. :try_end_c} :catch_14
+    .catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_c} :catch_d
+
+    goto :goto_15
+
+    .line 27
+    :catch_d
+    move-exception p0
+
+    .line 28
+    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    invoke-virtual {p0, v0}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V
+
+    goto :goto_16
+
+    .line 26
+    :catch_14
+    move-exception p0
+
+    .line 29
+    :goto_15
+    nop
+
+    .line 33
+    :goto_16
+    :try_start_16
+    const-string p0, "TestClass"
+
+    invoke-static {p0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;
+
+    move-result-object p0
+
+    .line 34
+    const-string v0, "test"
+
+    const/4 v1, 0x0
+
+    new-array v2, v1, [Ljava/lang/Class;
+
+    invoke-virtual {p0, v0, v2}, Ljava/lang/Class;->getDeclaredMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
+
+    move-result-object p0
+
+    .line 35
+    const/4 v0, 0x0
+
+    new-array v1, v1, [Ljava/lang/Object;
+
+    invoke-virtual {p0, v0, v1}, Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
+
+    .line 36
+    sget-object p0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    const-string v0, "UNREACHABLE!"
+
+    invoke-virtual {p0, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+    :try_end_32
+    .catch Ljava/lang/reflect/InvocationTargetException; {:try_start_16 .. :try_end_32} :catch_3a
+    .catch Ljava/lang/Throwable; {:try_start_16 .. :try_end_32} :catch_33
+
+    goto :goto_76
+
+    .line 44
+    :catch_33
+    move-exception p0
+
+    .line 45
+    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    invoke-virtual {p0, v0}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V
+
+    goto :goto_77
+
+    .line 37
+    :catch_3a
+    move-exception p0
+
+    .line 38
+    invoke-virtual {p0}, Ljava/lang/reflect/InvocationTargetException;->getCause()Ljava/lang/Throwable;
+
+    move-result-object v0
+
+    instance-of v0, v0, Ljava/lang/InstantiationError;
+
+    if-eqz v0, :cond_71
+
+    .line 39
+    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    new-instance v1, Ljava/lang/StringBuilder;
+
+    invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
+
+    .line 40
+    invoke-virtual {p0}, Ljava/lang/reflect/InvocationTargetException;->getCause()Ljava/lang/Throwable;
+
+    move-result-object v2
+
+    invoke-virtual {v2}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+
+    move-result-object v2
+
+    invoke-virtual {v2}, Ljava/lang/Class;->getName()Ljava/lang/String;
+
+    move-result-object v2
+
+    invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+    const-string v2, ": "
+
+    invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+    invoke-virtual {p0}, Ljava/lang/reflect/InvocationTargetException;->getCause()Ljava/lang/Throwable;
+
+    move-result-object p0
+
+    invoke-virtual {p0}, Ljava/lang/Throwable;->getMessage()Ljava/lang/String;
+
+    move-result-object p0
+
+    invoke-virtual {v1, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+    invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+
+    move-result-object p0
+
+    .line 39
+    invoke-virtual {v0, p0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    goto :goto_76
+
+    .line 42
+    :cond_71
+    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    invoke-virtual {p0, v0}, Ljava/lang/reflect/InvocationTargetException;->printStackTrace(Ljava/io/PrintStream;)V
+
+    .line 46
+    :goto_76
+    nop
+
+    .line 47
+    :goto_77
+    return-void
+.end method
diff --git a/test/161-final-abstract-class/src/Main.java b/test/161-final-abstract-class/src/Main.java
deleted file mode 100644
index 2452490..0000000
--- a/test/161-final-abstract-class/src/Main.java
+++ /dev/null
@@ -1,48 +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.
- */
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-public class Main {
-    public static void main(String[] args) {
-        try {
-            // Make sure that the abstract final class is marked as erroneous.
-            Class.forName("AbstractFinal");
-            System.out.println("UNREACHABLE!");
-        } catch (VerifyError expected) {
-        } catch (Throwable t) {
-            t.printStackTrace(System.out);
-        }
-        try {
-            // Verification of TestClass.test() used to crash when processing
-            // the final abstract (erroneous) class.
-            Class<?> tc = Class.forName("TestClass");
-            Method test = tc.getDeclaredMethod("test");
-            test.invoke(null);
-            System.out.println("UNREACHABLE!");
-        } catch (InvocationTargetException ite) {
-            if (ite.getCause() instanceof InstantiationError) {
-                System.out.println(
-                    ite.getCause().getClass().getName() + ": " + ite.getCause().getMessage());
-            } else {
-                ite.printStackTrace(System.out);
-            }
-        } catch (Throwable t) {
-            t.printStackTrace(System.out);
-        }
-    }
-}
diff --git a/test/1929-exception-catch-exception/expected.txt b/test/1929-exception-catch-exception/expected.txt
index bc5608a..a82b732 100644
--- a/test/1929-exception-catch-exception/expected.txt
+++ b/test/1929-exception-catch-exception/expected.txt
@@ -1,11 +1,11 @@
 Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: doThrow
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 298
 Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$DoNothingHandler"
@@ -17,71 +17,71 @@
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
 		public static void art.Test1929.throwCatchBaseTestException() @ line = 140
 		public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 	Doing nothing!
 Caught art.Test1929$TestException: "throwCatchBaseTestException"
 Test "art.Test1929$DoThrowCatchBaseTestException": No error caught with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161
-		public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197
-		public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157
+		public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 203
+		public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 210
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException
+main: public static void art.Test1929.throwCatchTestException() @ line = 216 caught class art.Test1929$TestException: throwCatchTestException
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.throwCatchTestException() @ line = 207
-		public void art.Test1929$DoThrowCatchTestException.run() @ line = 216
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929.throwCatchTestException() @ line = 216
+		public void art.Test1929$DoThrowCatchTestException.run() @ line = 225
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 	Doing nothing!
 Caught art.Test1929$TestException: "throwCatchTestException"
 Test "art.Test1929$DoThrowCatchTestException": No error caught with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179
-		public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222
-		public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175
+		public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 234
+		public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 241
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 Caught art.Test1929$TestException: "throwCatchTestExceptionTwice"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$DoNothingHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 298
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$DoNothingHandler"
 Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: doThrow
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 298
 Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
@@ -93,73 +93,73 @@
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
 		public static void art.Test1929.throwCatchBaseTestException() @ line = 140
 		public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 	Throwing BaseTestException and catching it!
 Caught art.Test1929$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1929.throwCatchBaseTestException() @ line = 140"
 Caught art.Test1929$TestException: "throwCatchBaseTestException"
 Test "art.Test1929$DoThrowCatchBaseTestException": No error caught with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161
-		public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197
-		public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157
+		public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 203
+		public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 210
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException
+main: public static void art.Test1929.throwCatchTestException() @ line = 216 caught class art.Test1929$TestException: throwCatchTestException
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.throwCatchTestException() @ line = 207
-		public void art.Test1929$DoThrowCatchTestException.run() @ line = 216
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929.throwCatchTestException() @ line = 216
+		public void art.Test1929$DoThrowCatchTestException.run() @ line = 225
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 	Throwing BaseTestException and catching it!
-Caught art.Test1929$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 207"
+Caught art.Test1929$BaseTestException: "ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 216"
 Caught art.Test1929$TestException: "throwCatchTestException"
 Test "art.Test1929$DoThrowCatchTestException": No error caught with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179
-		public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222
-		public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175
+		public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 234
+		public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 241
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 Caught art.Test1929$TestException: "throwCatchTestExceptionTwice"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$ThrowCatchBase"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 298
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$ThrowCatchBase"
 Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: doThrow
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 298
 Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
@@ -171,69 +171,69 @@
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
 		public static void art.Test1929.throwCatchBaseTestException() @ line = 140
 		public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 	Throwing BaseTestException!
 Test "art.Test1929$DoThrowCatchBaseTestException": Caught error art.Test1929$BaseTestException:"ThrowBaseHandler during throw from public static void art.Test1929.throwCatchBaseTestException() @ line = 140" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161
-		public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197
-		public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157
+		public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 203
+		public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 210
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException
+main: public static void art.Test1929.throwCatchTestException() @ line = 216 caught class art.Test1929$TestException: throwCatchTestException
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.throwCatchTestException() @ line = 207
-		public void art.Test1929$DoThrowCatchTestException.run() @ line = 216
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929.throwCatchTestException() @ line = 216
+		public void art.Test1929$DoThrowCatchTestException.run() @ line = 225
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 	Throwing BaseTestException!
-Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$BaseTestException:"ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 207" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
+Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$BaseTestException:"ThrowBaseHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 216" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179
-		public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222
-		public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175
+		public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 234
+		public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 241
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 Caught art.Test1929$TestException: "throwCatchTestExceptionTwice"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$ThrowBaseTestExceptionHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 298
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$ThrowBaseTestExceptionHandler"
 Test "art.Test1929$DoThrowClass": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: doThrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: doThrow
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 298
 Test "art.Test1929$DoThrowClass": Caught error art.Test1929$TestException:"doThrow" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowClass": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchBaseTestException": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
@@ -245,58 +245,58 @@
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
 		public static void art.Test1929.throwCatchBaseTestException() @ line = 140
 		public void art.Test1929$DoThrowCatchBaseTestException.run() @ line = 149
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 	Throwing TestExceptionNoRethrow!
 Test "art.Test1929$DoThrowCatchBaseTestException": Caught error art.Test1929$TestExceptionNoRethrow:"ThrowTestExceptionNoRethrowHandler during throw from public static void art.Test1929.throwCatchBaseTestException() @ line = 140" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchBaseTestException": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157 caught class art.Test1929$TestException: throwCatchBaseTestExceptionTwice
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 161
-		public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 197
-		public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 201
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929$Impl.throwCatchBaseTestExceptionTwiceImpl() @ line = 157
+		public static void art.Test1929.throwCatchBaseTestExceptionTwice() @ line = 203
+		public void art.Test1929$DoThrowCatchBaseTestExceptionTwice.run() @ line = 210
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 Caught art.Test1929$TestException: "throwCatchBaseTestExceptionTwice"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": No error caught with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchBaseTestExceptionTwice": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchTestException": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929.throwCatchTestException() @ line = 207 caught class art.Test1929$TestException: throwCatchTestException
+main: public static void art.Test1929.throwCatchTestException() @ line = 216 caught class art.Test1929$TestException: throwCatchTestException
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.throwCatchTestException() @ line = 207
-		public void art.Test1929$DoThrowCatchTestException.run() @ line = 216
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929.throwCatchTestException() @ line = 216
+		public void art.Test1929$DoThrowCatchTestException.run() @ line = 225
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 	Throwing TestExceptionNoRethrow!
-Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$TestExceptionNoRethrow:"ThrowTestExceptionNoRethrowHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 207" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
+Test "art.Test1929$DoThrowCatchTestException": Caught error art.Test1929$TestExceptionNoRethrow:"ThrowTestExceptionNoRethrowHandler during throw from public static void art.Test1929.throwCatchTestException() @ line = 216" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchTestException": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
+main: public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175 caught class art.Test1929$TestException: throwCatchTestExceptionTwice
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 179
-		public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 222
-		public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 226
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 280
+		public static void art.Test1929$Impl.throwCatchTestExceptionTwiceImpl() @ line = 175
+		public static void art.Test1929.throwCatchTestExceptionTwice() @ line = 234
+		public void art.Test1929$DoThrowCatchTestExceptionTwice.run() @ line = 241
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 295
 Caught art.Test1929$TestException: "throwCatchTestExceptionTwice"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": No error caught with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionTwice": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Running breakpoint with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
-main: public static void art.Test1929.run() throws java.lang.Exception @ line = 283 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
+main: public static void art.Test1929.run() throws java.lang.Exception @ line = 298 caught class art.Test1929$TestException: throwCatchTestExceptionNoRethrow
 	Current Stack:
 		private static native art.StackTrace$StackFrameData[] art.StackTrace.nativeGetStackTrace(java.lang.Thread) @ line = -1
 		public static art.StackTrace$StackFrameData[] art.StackTrace.GetStackTrace(java.lang.Thread) @ line = 61
 		private static void art.Test1929.PrintStack() @ line = 52
 		public static void art.Test1929.ExceptionCatchEvent(java.lang.Thread,java.lang.reflect.Executable,long,java.lang.Throwable) @ line = 65
-		public static void art.Test1929.run() throws java.lang.Exception @ line = 283
+		public static void art.Test1929.run() throws java.lang.Exception @ line = 298
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Caught error art.Test1929$TestException:"throwCatchTestExceptionNoRethrow" with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
 Test "art.Test1929$DoThrowCatchTestExceptionNoRethrow": Finished running with handler "art.Test1929$ThrowTestExceptionNoRethrowHandler"
diff --git a/test/1929-exception-catch-exception/src/art/Test1929.java b/test/1929-exception-catch-exception/src/art/Test1929.java
index 07d2087..e2deb3f 100644
--- a/test/1929-exception-catch-exception/src/art/Test1929.java
+++ b/test/1929-exception-catch-exception/src/art/Test1929.java
@@ -152,49 +152,58 @@
   // dx/d8/jack all do an optimization around catch blocks that (while legal) breaks assumptions
   // this test relies on so we have the actual implementation be corrected smali. This does work
   // for RI however.
-  public static final class Impl {
-    private Impl() {}
-    public static void throwCatchBaseTestExceptionTwiceImpl() {
-      try {
-        try {
-          throw new TestException("throwCatchBaseTestExceptionTwice");
-        } catch (BaseTestException t) {
-          System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
-          if (PRINT_FULL_EXCEPTION) {
-            t.printStackTrace(System.out);
-          }
-        }
-      } catch (BaseTestException t) {
-        System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
-        if (PRINT_FULL_EXCEPTION) {
-          t.printStackTrace(System.out);
-        }
-      }
-    }
 
-    public static void throwCatchTestExceptionTwiceImpl() {
-      try {
-        try {
-          throw new TestException("throwCatchTestExceptionTwice");
-        } catch (TestException t) {
-          System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
-          if (PRINT_FULL_EXCEPTION) {
-            t.printStackTrace(System.out);
-          }
-        }
-      } catch (TestException t) {
-        System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
-        if (PRINT_FULL_EXCEPTION) {
-          t.printStackTrace(System.out);
-        }
-      }
-    }
-  }
+  // For reference:
+
+  // public static final class Impl {
+  //   private Impl() {}
+  //   public static void throwCatchBaseTestExceptionTwiceImpl() {
+  //     try {
+  //       try {
+  //         throw new TestException("throwCatchBaseTestExceptionTwice");
+  //       } catch (BaseTestException t) {
+  //         System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
+  //         if (PRINT_FULL_EXCEPTION) {
+  //           t.printStackTrace(System.out);
+  //         }
+  //       }
+  //     } catch (BaseTestException t) {
+  //       System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
+  //       if (PRINT_FULL_EXCEPTION) {
+  //         t.printStackTrace(System.out);
+  //       }
+  //     }
+  //   }
+
+  //   public static void throwCatchTestExceptionTwiceImpl() {
+  //     try {
+  //       try {
+  //         throw new TestException("throwCatchTestExceptionTwice");
+  //       } catch (TestException t) {
+  //         System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
+  //         if (PRINT_FULL_EXCEPTION) {
+  //           t.printStackTrace(System.out);
+  //         }
+  //       }
+  //     } catch (TestException t) {
+  //       System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\"");
+  //       if (PRINT_FULL_EXCEPTION) {
+  //         t.printStackTrace(System.out);
+  //       }
+  //     }
+  //   }
+  // }
 
   public static void throwCatchBaseTestExceptionTwice() {
     // The implementation of this has to change depending upon the runtime slightly due to compiler
     // optimizations present in DX/D8/Jack.
-    Impl.throwCatchBaseTestExceptionTwiceImpl();
+    try {
+      Class<?> Impl = Class.forName("art.Test1929$Impl");
+      Method m = Impl.getMethod("throwCatchBaseTestExceptionTwiceImpl");
+      m.invoke(null);
+    } catch (Exception e) {
+      e.printStackTrace(System.out);
+    }
   }
 
   public static class DoThrowCatchBaseTestExceptionTwice implements Runnable {
@@ -219,7 +228,13 @@
   public static void throwCatchTestExceptionTwice() {
     // The implementation of this has to change depending upon the runtime slightly due to compiler
     // optimizations present in DX/D8/Jack.
-    Impl.throwCatchTestExceptionTwiceImpl();
+    try {
+      Class<?> Impl = Class.forName("art.Test1929$Impl");
+      Method m = Impl.getMethod("throwCatchTestExceptionTwiceImpl");
+      m.invoke(null);
+    } catch (Exception e) {
+      e.printStackTrace(System.out);
+    }
   }
 
   public static class DoThrowCatchTestExceptionTwice implements Runnable {
diff --git a/test/674-hiddenapi/hiddenapi.cc b/test/674-hiddenapi/hiddenapi.cc
index effa37a..04c3fbf 100644
--- a/test/674-hiddenapi/hiddenapi.cc
+++ b/test/674-hiddenapi/hiddenapi.cc
@@ -16,6 +16,7 @@
 
 #include "class_linker.h"
 #include "dex/art_dex_file_loader.h"
+#include "hidden_api.h"
 #include "jni.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
@@ -27,7 +28,7 @@
 
 extern "C" JNIEXPORT void JNICALL Java_Main_init(JNIEnv*, jclass) {
   Runtime* runtime = Runtime::Current();
-  runtime->SetHiddenApiChecksEnabled(true);
+  runtime->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kBlacklistOnly);
   runtime->SetDedupeHiddenApiWarnings(false);
   runtime->AlwaysSetHiddenApiWarningFlag();
 }
diff --git a/test/674-hiddenapi/src-ex/ChildClass.java b/test/674-hiddenapi/src-ex/ChildClass.java
index 8cd237a..582e907 100644
--- a/test/674-hiddenapi/src-ex/ChildClass.java
+++ b/test/674-hiddenapi/src-ex/ChildClass.java
@@ -123,9 +123,6 @@
           // Check whether one can use an interface default method.
           String name = "method" + visibility.name() + "Default" + hiddenness.name();
           checkMethod(ParentInterface.class, name, /*isStatic*/ false, visibility, expected);
-
-          // Check whether one can override this method.
-          checkOverriding(suffix, isStatic, visibility, expected);
         }
 
         // Test whether static linking succeeds.
@@ -406,37 +403,6 @@
     }
   }
 
-  private static void checkOverriding(String suffix,
-                                      boolean isStatic,
-                                      Visibility visibility,
-                                      Behaviour behaviour) throws Exception {
-    if (isStatic || visibility == Visibility.Private) {
-      // Does not make sense to override a static or private method.
-      return;
-    }
-
-    // The classes are in the same package, but will be able to access each
-    // other only if loaded with the same class loader, here the boot class loader.
-    boolean canAccess = (visibility != Visibility.Package) || (isParentInBoot && isChildInBoot);
-    boolean setsWarning = false;  // warnings may be set during vtable linking
-
-    String methodName = "callMethod" + visibility.name() + suffix;
-
-    // Force the test class to link its vtable, which may cause warnings, before
-    // the actual test.
-    new OverrideClass().methodPublicWhitelist();
-
-    clearWarning();
-    if (Linking.canOverride(methodName) != canAccess) {
-      throw new RuntimeException("Expected to " + (canAccess ? "" : "not ") +
-          "be able to override " + methodName + "." +
-          "isParentInBoot = " + isParentInBoot + ", " + "isChildInBoot = " + isChildInBoot);
-    }
-    if (canAccess && hasPendingWarning() != setsWarning) {
-      throwWarningException(ParentClass.class, methodName, false, "static linking", setsWarning);
-    }
-  }
-
   private static void throwDiscoveryException(Class<?> klass, String name, boolean isField,
       String fn, boolean canAccess) {
     throw new RuntimeException("Expected " + (isField ? "field " : "method ") + klass.getName() +
diff --git a/test/674-hiddenapi/src-ex/Linking.java b/test/674-hiddenapi/src-ex/Linking.java
index b416250..a89b92b 100644
--- a/test/674-hiddenapi/src-ex/Linking.java
+++ b/test/674-hiddenapi/src-ex/Linking.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-import java.lang.reflect.Method;
 import java.lang.reflect.InvocationTargetException;
 
 public class Linking {
@@ -35,16 +34,6 @@
       }
     }
   }
-
-  public static boolean canOverride(String methodName) throws Exception {
-    // ParentClass returns only positive numbers, OverrideClass only negative.
-    // This way we can tell if OverrideClass managed to override the original
-    // method or not.
-    Method method = ParentClass.class.getDeclaredMethod(methodName);
-    int result1 = (int) method.invoke(new ParentClass());
-    int result2 = (int) method.invoke(new OverrideClass());
-    return (result1 > 0) && (result2 < 0);
-  }
 }
 
 // INSTANCE FIELD GET
diff --git a/test/674-hiddenapi/src-ex/OverrideClass.java b/test/674-hiddenapi/src-ex/OverrideClass.java
deleted file mode 100644
index 1f1f4d6..0000000
--- a/test/674-hiddenapi/src-ex/OverrideClass.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.
- */
-
-public class OverrideClass extends ParentClass {
-
-  @Override public int methodPublicWhitelist() { return -411; }
-  @Override int methodPackageWhitelist() { return -412; }
-  @Override protected int methodProtectedWhitelist() { return -413; }
-
-  @Override public int methodPublicLightGreylist() { return -421; }
-  @Override int methodPackageLightGreylist() { return -422; }
-  @Override protected int methodProtectedLightGreylist() { return -423; }
-
-  @Override public int methodPublicDarkGreylist() { return -431; }
-  @Override int methodPackageDarkGreylist() { return -432; }
-  @Override protected int methodProtectedDarkGreylist() { return -433; }
-
-  @Override public int methodPublicBlacklist() { return -441; }
-  @Override int methodPackageBlacklist() { return -442; }
-  @Override protected int methodProtectedBlacklist() { return -443; }
-
-}
diff --git a/test/679-checker-minmax/src/Main.java b/test/679-checker-minmax/src/Main.java
index d016de6..38085bb 100644
--- a/test/679-checker-minmax/src/Main.java
+++ b/test/679-checker-minmax/src/Main.java
@@ -79,6 +79,51 @@
     return a >= b ? b : a;
   }
 
+  /// CHECK-START: int Main.min5(short, short) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:s\d+>>,<<Op2:s\d+>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.min5(short, short) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Min:i\d+>> Min
+  /// CHECK-DAG:              Return [<<Min>>]
+  //
+  /// CHECK-START: int Main.min5(short, short) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int min5(short a, short b) {
+    return a >= b ? b : a;
+  }
+
+  /// CHECK-START: int Main.min6(byte, byte) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:b\d+>>,<<Op2:b\d+>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.min6(byte, byte) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Min:i\d+>> Min
+  /// CHECK-DAG:              Return [<<Min>>]
+  //
+  /// CHECK-START: int Main.min6(byte, byte) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int min6(byte a, byte b) {
+    return a >= b ? b : a;
+  }
+
+  /// CHECK-START: long Main.min7(long, long) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:j\d+>>,<<Op2:j\d+>>]
+  /// CHECK-DAG: <<Sel:j\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: long Main.min7(long, long) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Min:j\d+>> Min
+  /// CHECK-DAG:              Return [<<Min>>]
+  //
+  /// CHECK-START: long Main.min7(long, long) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static long min7(long a, long b) {
+    return a >= b ? b : a;
+  }
+
   /// CHECK-START: int Main.max1(int, int) instruction_simplifier$after_inlining (before)
   /// CHECK-DAG: <<Cnd:z\d+>> GreaterThanOrEqual [<<Op1:i\d+>>,<<Op2:i\d+>>]
   /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
@@ -139,15 +184,66 @@
     return a >= b ? a : b;
   }
 
+  /// CHECK-START: int Main.max5(short, short) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:s\d+>>,<<Op2:s\d+>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.max5(short, short) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Max:i\d+>> Max
+  /// CHECK-DAG:              Return [<<Max>>]
+  //
+  /// CHECK-START: int Main.max5(short, short) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int max5(short a, short b) {
+    return a >= b ? a : b;
+  }
+
+  /// CHECK-START: int Main.max6(byte, byte) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:b\d+>>,<<Op2:b\d+>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.max6(byte, byte) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Max:i\d+>> Max
+  /// CHECK-DAG:              Return [<<Max>>]
+  //
+  /// CHECK-START: int Main.max6(byte, byte) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int max6(byte a, byte b) {
+    return a >= b ? a : b;
+  }
+
+  /// CHECK-START: long Main.max7(long, long) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:j\d+>>,<<Op2:j\d+>>]
+  /// CHECK-DAG: <<Sel:j\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: long Main.max7(long, long) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Max:j\d+>> Max
+  /// CHECK-DAG:              Return [<<Max>>]
+  //
+  /// CHECK-START: long Main.max7(long, long) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static long max7(long a, long b) {
+    return a >= b ? a : b;
+  }
+
   public static void main(String[] args) {
     expectEquals(10, min1(10, 20));
     expectEquals(10, min2(10, 20));
     expectEquals(10, min3(10, 20));
     expectEquals(10, min4(10, 20));
+    expectEquals(10, min5((short) 10, (short) 20));
+    expectEquals(10, min6((byte) 10, (byte) 20));
+    expectEquals(10L, min7(10L, 20L));
     expectEquals(20, max1(10, 20));
     expectEquals(20, max2(10, 20));
     expectEquals(20, max3(10, 20));
     expectEquals(20, max4(10, 20));
+    expectEquals(20, max5((short) 10, (short) 20));
+    expectEquals(20, max6((byte) 10, (byte) 20));
+    expectEquals(20L, max7(10L, 20L));
     System.out.println("passed");
   }
 
@@ -156,4 +252,10 @@
       throw new Error("Expected: " + expected + ", found: " + result);
     }
   }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
 }
diff --git a/test/679-locks/expected.txt b/test/679-locks/expected.txt
new file mode 100644
index 0000000..85a20be
--- /dev/null
+++ b/test/679-locks/expected.txt
@@ -0,0 +1,2 @@
+JNI_OnLoad called
+MyString
diff --git a/test/679-locks/info.txt b/test/679-locks/info.txt
new file mode 100644
index 0000000..7ada490
--- /dev/null
+++ b/test/679-locks/info.txt
@@ -0,0 +1,2 @@
+Ensure FindLocksAtDexPc is able to pass through quickened instructions related
+to unresolved classes.
diff --git a/test/679-locks/run b/test/679-locks/run
new file mode 100644
index 0000000..0cc87f3
--- /dev/null
+++ b/test/679-locks/run
@@ -0,0 +1,18 @@
+#!/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.i
+
+# Run without an app image to prevent the class NotLoaded to be loaded at startup.
+exec ${RUN} "${@}" --no-app-image
diff --git a/test/679-locks/src/Main.java b/test/679-locks/src/Main.java
new file mode 100644
index 0000000..fbc8c53
--- /dev/null
+++ b/test/679-locks/src/Main.java
@@ -0,0 +1,50 @@
+/*
+ * 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 NotLoaded {
+  public void foo() {}
+}
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        System.loadLibrary(args[0]);
+        TestSync.run();
+    }
+
+    public static void run() {
+        testVisitLocks();
+    }
+
+    static Object myStatic;
+
+    // Note: declared in 167-visit-locks.
+    public static native void testVisitLocks();
+}
+
+// 167-visit-locks/visit-locks.cc looks at the locks held in TestSync.run().
+class TestSync {
+  public static void run() {
+    Object o = Main.myStatic;
+    if (o != null) {
+      if (o instanceof NotLoaded) {
+        ((NotLoaded)o).foo();
+      }
+    }
+    synchronized ("MyString") {
+      Main.testVisitLocks();
+    }
+  }
+}
diff --git a/test/680-sink-regression/expected.txt b/test/680-sink-regression/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/680-sink-regression/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/680-sink-regression/info.txt b/test/680-sink-regression/info.txt
new file mode 100644
index 0000000..547e3b8
--- /dev/null
+++ b/test/680-sink-regression/info.txt
@@ -0,0 +1 @@
+Regression test for code sinking with exceptions (b/75971227).
diff --git a/test/680-sink-regression/src/Main.java b/test/680-sink-regression/src/Main.java
new file mode 100644
index 0000000..642c3ab
--- /dev/null
+++ b/test/680-sink-regression/src/Main.java
@@ -0,0 +1,87 @@
+/*
+ * 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.io.*;
+
+/**
+ * Regression test for b/75971227 (code sinking with exceptions).
+ */
+public class Main {
+
+  public static class N {
+    int x;
+  }
+
+  private int f;
+
+  public int doit(N n1) throws FileNotFoundException {
+    int x = 1;
+    N n3 = new N();
+    try {
+      if (n1.x == 0) {
+        f = 11;
+        x = 3;
+      } else {
+        f = x;
+      }
+      throw new FileNotFoundException("n3" + n3.x);
+    } catch (NullPointerException e) {
+    }
+    return x;
+  }
+
+
+  public static void main(String[] args) {
+    N n = new N();
+    Main t = new Main();
+    int x = 0;
+
+    // Main 1, null pointer argument.
+    t.f = 0;
+    try {
+      x = t.doit(null);
+    } catch (FileNotFoundException e) {
+      x = -1;
+    }
+    if (x != 1 || t.f != 0) {
+      throw new Error("Main 1: x=" + x + " f=" + t.f);
+    }
+
+    // Main 2, n.x is 0.
+    n.x = 0;
+    try {
+      x = t.doit(n);
+    } catch (FileNotFoundException e) {
+      x = -1;
+    }
+    if (x != -1 || t.f != 11) {
+      throw new Error("Main 2: x=" + x + " f=" + t.f);
+    }
+
+    // Main 3, n.x is not 0.
+    n.x = 1;
+    try {
+      x = t.doit(n);
+    } catch (FileNotFoundException e) {
+      x = -1;
+    }
+    if (x != -1 || t.f != 1) {
+      throw new Error("Main 3: x=" + x + " f=" + t.f);
+    }
+
+    System.out.println("passed");
+  }
+}
diff --git a/test/681-checker-abs/expected.txt b/test/681-checker-abs/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/681-checker-abs/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/681-checker-abs/info.txt b/test/681-checker-abs/info.txt
new file mode 100644
index 0000000..d36e76e
--- /dev/null
+++ b/test/681-checker-abs/info.txt
@@ -0,0 +1 @@
+Functional tests on detecting abs.
diff --git a/test/681-checker-abs/src/Main.java b/test/681-checker-abs/src/Main.java
new file mode 100644
index 0000000..8064b1d
--- /dev/null
+++ b/test/681-checker-abs/src/Main.java
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+/**
+ * Functional tests for detecting abs.
+ */
+public class Main {
+
+  /// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+  /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+  /// CHECK-DAG: <<Cnd:z\d+>> GreaterThanOrEqual [<<Par>>,<<Zer>>]
+  /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Neg>>,<<Par>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+  /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+  /// CHECK-DAG:              Return [<<Abs>>]
+  //
+  /// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int abs1(int a) {
+    return a < 0 ? -a : a;
+  }
+
+  /// CHECK-START: int Main.abs2(int) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+  /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+  /// CHECK-DAG: <<Cnd:z\d+>> GreaterThan [<<Par>>,<<Zer>>]
+  /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Neg>>,<<Par>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.abs2(int) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+  /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+  /// CHECK-DAG:              Return [<<Abs>>]
+  //
+  /// CHECK-START: int Main.abs2(int) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int abs2(int a) {
+    return a <= 0 ? -a : a;
+  }
+
+  /// CHECK-START: int Main.abs3(int) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+  /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThanOrEqual [<<Par>>,<<Zer>>]
+  /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.abs3(int) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+  /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+  /// CHECK-DAG:              Return [<<Abs>>]
+  //
+  /// CHECK-START: int Main.abs3(int) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int abs3(int a) {
+    return a > 0 ? a : -a;
+  }
+
+  /// CHECK-START: int Main.abs4(int) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+  /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+  /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.abs4(int) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+  /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+  /// CHECK-DAG:              Return [<<Abs>>]
+  //
+  /// CHECK-START: int Main.abs4(int) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int abs4(int a) {
+    return a >= 0 ? a : -a;
+  }
+
+  /// CHECK-START: int Main.abs5(short) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Par:s\d+>> ParameterValue
+  /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+  /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.abs5(short) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Par:s\d+>> ParameterValue
+  /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+  /// CHECK-DAG:              Return [<<Abs>>]
+  //
+  /// CHECK-START: int Main.abs5(short) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int abs5(short a) {
+    return a >= 0 ? a : -a;
+  }
+
+  /// CHECK-START: int Main.abs6(byte) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Par:b\d+>> ParameterValue
+  /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+  /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+  /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: int Main.abs6(byte) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Par:b\d+>> ParameterValue
+  /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+  /// CHECK-DAG:              Return [<<Abs>>]
+  //
+  /// CHECK-START: int Main.abs6(byte) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static int abs6(byte a) {
+    return a >= 0 ? a : -a;
+  }
+
+  /// CHECK-START: long Main.abs7(long) instruction_simplifier$after_inlining (before)
+  /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+  /// CHECK-DAG: <<Zer:j\d+>> LongConstant 0
+  /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+  /// CHECK-DAG: <<Neg:j\d+>> [<<Par>>]
+  /// CHECK-DAG: <<Sel:j\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+  /// CHECK-DAG:              Return [<<Sel>>]
+  //
+  /// CHECK-START: long Main.abs7(long) instruction_simplifier$after_inlining (after)
+  /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+  /// CHECK-DAG: <<Abs:j\d+>> Abs [<<Par>>]
+  /// CHECK-DAG:              Return [<<Abs>>]
+  //
+  /// CHECK-START: long Main.abs7(long) instruction_simplifier$after_inlining (after)
+  /// CHECK-NOT:              Select
+  public static long abs7(long a) {
+    return a >= 0 ? a : -a;
+  }
+
+  public static void main(String[] args) {
+    expectEquals(10, abs1(-10));
+    expectEquals(20, abs1(20));
+    expectEquals(10, abs2(-10));
+    expectEquals(20, abs2(20));
+    expectEquals(10, abs3(-10));
+    expectEquals(20, abs3(20));
+    expectEquals(10, abs4(-10));
+    expectEquals(20, abs4(20));
+    expectEquals(10, abs4((short) -10));
+    expectEquals(20, abs4((short) 20));
+    expectEquals(10, abs6((byte) -10));
+    expectEquals(20, abs6((byte) 20));
+    expectEquals(10L, abs7(-10L));
+    expectEquals(20L, abs7(20L));
+    System.out.println("passed");
+  }
+
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index cf781d7..6633958 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -24,7 +24,6 @@
   $(HOST_OUT_EXECUTABLES)/hiddenapi \
   $(HOST_OUT_EXECUTABLES)/jasmin \
   $(HOST_OUT_EXECUTABLES)/smali \
-  $(HOST_OUT_EXECUTABLES)/dexmerger \
   $(HOST_OUT_JAVA_LIBRARIES)/desugar.jar
 
 # Add d8 dependency, if enabled.
@@ -103,7 +102,7 @@
 # Host executables.
 host_prereq_rules := $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES)
 
-# Required for dx, jasmin, smali, dexmerger.
+# Required for dx, jasmin, smali.
 host_prereq_rules += $(TEST_ART_RUN_TEST_DEPENDENCIES)
 
 # Sync test files to the target, depends upon all things that must be pushed
diff --git a/test/etc/default-build b/test/etc/default-build
index 3e6577c..9de7294 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -341,8 +341,26 @@
     shift
   done
 
-  # Should have at least 1 dex_files_to_merge here, otherwise dxmerger will print the help.
-  ${DXMERGER} "$dst_file" "${dex_files_to_merge[@]}"
+  # Skip merge if we are not merging anything. IE: input = output.
+  if [[ "${#dex_files_to_merge[@]}" -eq "1" ]]; then
+    local single_input=${dex_files_to_merge[0]}
+    if [[ "$dst_file" != "$single_input" ]]; then
+     mv "$single_input" "$dst_file";
+     return
+    fi
+  fi
+
+  # We assume the dexer did all the API level checks and just merge away.
+  mkdir d8_merge_out
+  ${DXMERGER} --min-api 1000 --output ./d8_merge_out "${dex_files_to_merge[@]}"
+
+  if [[ -e "./d8_merge_out/classes2.dex" ]]; then
+    echo "Cannot merge all dex files into a single dex"
+    exit 1
+  fi
+
+  mv ./d8_merge_out/classes.dex "$dst_file";
+  rmdir d8_merge_out
 }
 
 function make_hiddenapi() {
diff --git a/test/knownfailures.json b/test/knownfailures.json
index a7e76d1..22c370a 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -954,7 +954,8 @@
     },
     {
         "tests": ["616-cha-unloading",
-                  "678-quickening"],
+                  "678-quickening",
+                  "679-locks"],
         "variant": "jvm",
         "description": ["Doesn't run on RI."]
     },
diff --git a/test/run-test b/test/run-test
index 260a65a..5b43b52 100755
--- a/test/run-test
+++ b/test/run-test
@@ -50,11 +50,18 @@
 export USE_DESUGAR="true"
 export SMALI_ARGS=""
 
+# If d8 was not set by the environment variable, assume it is in the path.
+if [ -z "$D8" ]; then
+  export D8="d8"
+fi
+
 # If dx was not set by the environment variable, assume it is in the path.
 if [ -z "$DX" ]; then
   export DX="dx"
 fi
 
+export DXMERGER="$D8"
+
 # If jasmin was not set by the environment variable, assume it is in the path.
 if [ -z "$JASMIN" ]; then
   export JASMIN="jasmin"
@@ -65,11 +72,6 @@
   export SMALI="smali"
 fi
 
-# If dexmerger was not set by the environment variable, assume it is in the path.
-if [ -z "$DXMERGER" ]; then
-  export DXMERGER="dexmerger"
-fi
-
 # If jack was not set by the environment variable, assume it is in the path.
 if [ -z "$JACK" ]; then
   export JACK="jack"
diff --git a/test/testrunner/env.py b/test/testrunner/env.py
index 70efce5..5394991 100644
--- a/test/testrunner/env.py
+++ b/test/testrunner/env.py
@@ -136,9 +136,8 @@
                                     _get_build_var("HOST_OUT_EXECUTABLES"))
 
 # Set up default values for $JACK, $DX, $SMALI, etc to the $HOST_OUT_EXECUTABLES/$name path.
-for tool in ['jack', 'dx', 'smali', 'jasmin', 'dxmerger']:
-  binary = tool if tool != 'dxmerger' else 'dexmerger'
-  os.environ.setdefault(tool.upper(), HOST_OUT_EXECUTABLES + '/' + binary)
+for tool in ['jack', 'dx', 'smali', 'jasmin', 'd8']:
+  os.environ.setdefault(tool.upper(), HOST_OUT_EXECUTABLES + '/' + tool)
 
 ANDROID_JAVA_TOOLCHAIN = os.path.join(ANDROID_BUILD_TOP,
                                      _get_build_var('ANDROID_JAVA_TOOLCHAIN'))
diff --git a/tools/ahat/Android.bp b/tools/ahat/Android.bp
new file mode 100644
index 0000000..dc9f098
--- /dev/null
+++ b/tools/ahat/Android.bp
@@ -0,0 +1,25 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// 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.
+
+droiddoc_host {
+    name: "ahat-docs",
+    srcs: [
+        "src/main/**/*.java",
+    ],
+    custom_template: "droiddoc-templates-sdk",
+    args: "-stubpackages com.android.ahat:com.android.ahat.*",
+    api_tag_name: "AHAT",
+    api_filename: "ahat_api.txt",
+    removed_api_filename: "ahat_removed_api.txt",
+}
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index bf79751..ad33233 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -37,23 +37,10 @@
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 AHAT_JAR := $(LOCAL_BUILT_MODULE)
-AHAT_API := $(intermediates.COMMON)/ahat_api.txt
-AHAT_REMOVED_API := $(intermediates.COMMON)/ahat_removed_api.txt
 
 # --- api check for ahat.jar ----------
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main)
-LOCAL_IS_HOST_MODULE := true
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_MODULE := ahat
-LOCAL_DROIDDOC_OPTIONS := \
-  -stubpackages com.android.ahat:com.android.ahat.* \
-  -api $(AHAT_API) \
-  -removedApi $(AHAT_REMOVED_API)
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := external/doclava/res/assets/templates-sdk
-include $(BUILD_DROIDDOC)
-$(AHAT_API): $(full_target)
+AHAT_API := $(INTERNAL_PLATFORM_AHAT_API_FILE)
+AHAT_REMOVED_API := $(INTERNAL_PLATFORM_AHAT_REMOVED_API_FILE)
 
 $(eval $(call check-api, \
   ahat-check-api, \