Merge "inliner: Do not assume that the outermost_graph has an art method" into oc-dev
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index c733feb..3f9ea15 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -56,11 +56,11 @@
     core_dex2oat_dependency := $(DEX2OAT)
   endif
   ifeq ($(1),interpreter)
-    core_compile_options += --compiler-filter=interpret-only
+    core_compile_options += --compiler-filter=quicken
     core_infix := -interpreter
   endif
   ifeq ($(1),interp-ac)
-    core_compile_options += --compiler-filter=verify-at-runtime --runtime-arg -Xverify:softfail
+    core_compile_options += --compiler-filter=extract --runtime-arg -Xverify:softfail
     core_infix := -interp-ac
   endif
   ifneq ($(filter-out interpreter interp-ac optimizing,$(1)),)
@@ -166,11 +166,11 @@
     core_dex2oat_dependency := $(DEX2OAT)
   endif
   ifeq ($(1),interpreter)
-    core_compile_options += --compiler-filter=interpret-only
+    core_compile_options += --compiler-filter=quicken
     core_infix := -interpreter
   endif
   ifeq ($(1),interp-ac)
-    core_compile_options += --compiler-filter=verify-at-runtime --runtime-arg -Xverify:softfail
+    core_compile_options += --compiler-filter=extract --runtime-arg -Xverify:softfail
     core_infix := -interp-ac
   endif
   ifneq ($(filter-out interpreter interp-ac optimizing,$(1)),)
diff --git a/compiler/Android.bp b/compiler/Android.bp
index dec8b57..6ef866a 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -28,7 +28,6 @@
         "compiled_method.cc",
         "debug/elf_debug_writer.cc",
         "dex/dex_to_dex_compiler.cc",
-        "dex/dex_to_dex_decompiler.cc",
         "dex/inline_method_analyser.cc",
         "dex/verified_method.cc",
         "dex/verification_results.cc",
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index 9a8d27c..e486e2e 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "dex/dex_to_dex_decompiler.h"
+#include "dex_to_dex_decompiler.h"
 
 #include "class_linker.h"
 #include "compiler/common_compiler_test.h"
@@ -38,7 +38,7 @@
     TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
     TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
     compiler_options_->boot_image_ = false;
-    compiler_options_->SetCompilerFilter(CompilerFilter::kInterpretOnly);
+    compiler_options_->SetCompilerFilter(CompilerFilter::kQuicken);
     compiler_driver_->CompileAll(class_loader,
                                  GetDexFiles(class_loader),
                                  /* verifier_deps */ nullptr,
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 00a7d44..3f0df3b 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -104,11 +104,12 @@
   // This method should only be called for classes verified at compile time,
   // which have no verifier error, nor has methods that we know will throw
   // at runtime.
-  AtomicMap::InsertResult result = atomic_verified_methods_.Insert(
+  atomic_verified_methods_.Insert(
       ref,
       /*expected*/ nullptr,
       new VerifiedMethod(/* encountered_error_types */ 0, /* has_runtime_throw */ false));
-  DCHECK_EQ(result, AtomicMap::kInsertResultSuccess);
+  // We don't check the result of `Insert` as we could insert twice for the same
+  // MethodReference in the presence of duplicate methods.
 }
 
 void VerificationResults::AddRejectedClass(ClassReference ref) {
@@ -126,7 +127,7 @@
 
 bool VerificationResults::IsCandidateForCompilation(MethodReference&,
                                                     const uint32_t access_flags) {
-  if (!compiler_options_->IsBytecodeCompilationEnabled()) {
+  if (!compiler_options_->IsAotCompilationEnabled()) {
     return false;
   }
   // Don't compile class initializers unless kEverything.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f77b3dd..fbfa087 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -45,7 +45,6 @@
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
 #include "dex/dex_to_dex_compiler.h"
-#include "dex/dex_to_dex_decompiler.h"
 #include "dex/verification_results.h"
 #include "dex/verified_method.h"
 #include "driver/compiler_options.h"
@@ -421,7 +420,7 @@
   // Compile:
   // 1) Compile all classes and methods enabled for compilation. May fall back to dex-to-dex
   //    compilation.
-  if (GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+  if (GetCompilerOptions().IsAnyCompilationEnabled()) {
     Compile(class_loader, dex_files, timings);
   }
   if (dump_stats_) {
@@ -431,61 +430,6 @@
   FreeThreadPools();
 }
 
-// In-place unquicken the given `dex_files` based on `quickening_info`.
-static void Unquicken(const std::vector<const DexFile*>& dex_files,
-                      const ArrayRef<const uint8_t>& quickening_info,
-                      bool decompile_return_instruction) {
-  const uint8_t* quickening_info_ptr = quickening_info.data();
-  const uint8_t* const quickening_info_end = quickening_info.data() + quickening_info.size();
-  for (const DexFile* dex_file : dex_files) {
-    for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
-      const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
-      const uint8_t* class_data = dex_file->GetClassData(class_def);
-      if (class_data == nullptr) {
-        continue;
-      }
-      ClassDataItemIterator it(*dex_file, class_data);
-      // Skip fields
-      while (it.HasNextStaticField()) {
-        it.Next();
-      }
-      while (it.HasNextInstanceField()) {
-        it.Next();
-      }
-
-      while (it.HasNextDirectMethod()) {
-        const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
-        if (code_item != nullptr) {
-          uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
-          quickening_info_ptr += sizeof(uint32_t);
-          optimizer::ArtDecompileDEX(*code_item,
-                                     ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
-                                     decompile_return_instruction);
-          quickening_info_ptr += quickening_size;
-        }
-        it.Next();
-      }
-
-      while (it.HasNextVirtualMethod()) {
-        const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
-        if (code_item != nullptr) {
-          uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
-          quickening_info_ptr += sizeof(uint32_t);
-          optimizer::ArtDecompileDEX(*code_item,
-                                     ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
-                                     decompile_return_instruction);
-          quickening_info_ptr += quickening_size;
-        }
-        it.Next();
-      }
-      DCHECK(!it.HasNext());
-    }
-  }
-  if (quickening_info_ptr != quickening_info_end) {
-    LOG(FATAL) << "Failed to use all quickening info";
-  }
-}
-
 void CompilerDriver::CompileAll(jobject class_loader,
                                 const std::vector<const DexFile*>& dex_files,
                                 VdexFile* vdex_file,
@@ -494,15 +438,12 @@
     // TODO: we unquicken unconditionnally, as we don't know
     // if the boot image has changed. How exactly we'll know is under
     // experimentation.
-    if (vdex_file->GetQuickeningInfo().size() != 0) {
-      TimingLogger::ScopedTiming t("Unquicken", timings);
-      // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
-      // optimization does not depend on the boot image (the optimization relies on not
-      // having final fields in a class, which does not change for an app).
-      Unquicken(dex_files,
-                vdex_file->GetQuickeningInfo(),
-                /* decompile_return_instruction */ false);
-    }
+    TimingLogger::ScopedTiming t("Unquicken", timings);
+    // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
+    // optimization does not depend on the boot image (the optimization relies on not
+    // having final fields in a class, which does not change for an app).
+    VdexFile::Unquicken(dex_files, vdex_file->GetQuickeningInfo());
+
     Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
         new verifier::VerifierDeps(dex_files, vdex_file->GetVerifierDepsData()));
   }
@@ -514,7 +455,7 @@
     const DexFile& dex_file, const DexFile::ClassDef& class_def)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   auto* const runtime = Runtime::Current();
-  DCHECK(driver.GetCompilerOptions().IsAnyMethodCompilationEnabled());
+  DCHECK(driver.GetCompilerOptions().IsQuickeningCompilationEnabled());
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
   ClassLinker* class_linker = runtime->GetClassLinker();
   mirror::Class* klass = class_linker->FindClass(self, descriptor, class_loader);
@@ -986,7 +927,8 @@
   LoadImageClasses(timings);
   VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false);
 
-  if (compiler_options_->IsAnyMethodCompilationEnabled()) {
+  if (compiler_options_->IsAnyCompilationEnabled()) {
+    // Resolve eagerly to prepare for compilation.
     Resolve(class_loader, dex_files, timings);
     VLOG(compiler) << "Resolve: " << GetMemoryUsageString(false);
   }
@@ -1014,7 +956,7 @@
                << "situations. Please check the log.";
   }
 
-  if (compiler_options_->IsAnyMethodCompilationEnabled()) {
+  if (compiler_options_->IsAnyCompilationEnabled()) {
     if (kIsDebugBuild) {
       EnsureVerifiedOrVerifyAtRuntime(class_loader, dex_files);
     }
@@ -2017,7 +1959,7 @@
     return false;
   }
 
-  bool compiler_only_verifies = !GetCompilerOptions().IsAnyMethodCompilationEnabled();
+  bool compiler_only_verifies = !GetCompilerOptions().IsAnyCompilationEnabled();
 
   // We successfully validated the dependencies, now update class status
   // of verified classes. Note that the dependencies also record which classes
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 42ff1e7..17854fd 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -325,7 +325,7 @@
 class CompilerDriverVerifyTest : public CompilerDriverTest {
  protected:
   CompilerFilter::Filter GetCompilerFilter() const OVERRIDE {
-    return CompilerFilter::kVerifyProfile;
+    return CompilerFilter::kVerify;
   }
 
   void CheckVerifiedClass(jobject class_loader, const std::string& clazz) const {
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 2376fbf..957ea99 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -84,32 +84,32 @@
     compiler_filter_ = compiler_filter;
   }
 
-  bool VerifyAtRuntime() const {
-    return compiler_filter_ == CompilerFilter::kVerifyAtRuntime;
-  }
-
-  bool IsBytecodeCompilationEnabled() const {
-    return CompilerFilter::IsBytecodeCompilationEnabled(compiler_filter_);
+  bool IsAotCompilationEnabled() const {
+    return CompilerFilter::IsAotCompilationEnabled(compiler_filter_);
   }
 
   bool IsJniCompilationEnabled() const {
     return CompilerFilter::IsJniCompilationEnabled(compiler_filter_);
   }
 
+  bool IsQuickeningCompilationEnabled() const {
+    return CompilerFilter::IsQuickeningCompilationEnabled(compiler_filter_);
+  }
+
   bool IsVerificationEnabled() const {
     return CompilerFilter::IsVerificationEnabled(compiler_filter_);
   }
 
   bool AssumeClassesAreVerified() const {
-    return compiler_filter_ == CompilerFilter::kVerifyNone;
+    return compiler_filter_ == CompilerFilter::kAssumeVerified;
   }
 
-  bool VerifyOnlyProfile() const {
-    return compiler_filter_ == CompilerFilter::kVerifyProfile;
+  bool VerifyAtRuntime() const {
+    return compiler_filter_ == CompilerFilter::kExtract;
   }
 
-  bool IsAnyMethodCompilationEnabled() const {
-    return CompilerFilter::IsAnyMethodCompilationEnabled(compiler_filter_);
+  bool IsAnyCompilationEnabled() const {
+    return CompilerFilter::IsAnyCompilationEnabled(compiler_filter_);
   }
 
   size_t GetHugeMethodThreshold() const {
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index ead4124..1578c0c 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -519,7 +519,7 @@
   if (insn_set == kArm) insn_set = kThumb2;
   std::string error_msg;
   std::vector<std::string> compiler_options;
-  compiler_options.push_back("--compiler-filter=verify-at-runtime");
+  compiler_options.push_back("--compiler-filter=extract");
   SetupCompiler(compiler_kind, insn_set, compiler_options, /*out*/ &error_msg);
 
   jobject class_loader;
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index af60def..6b5387a 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -1675,7 +1675,7 @@
       if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
         return false;
       }
-      if (compiler_driver_->GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+      if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
         const uint8_t* class_data = dex_file->GetClassData(class_def);
         if (class_data != nullptr) {  // ie not an empty class, such as a marker interface
@@ -1757,7 +1757,7 @@
 }
 
 size_t OatWriter::InitOatMaps(size_t offset) {
-  if (!compiler_driver_->GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+  if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
     return offset;
   }
   {
@@ -1813,7 +1813,7 @@
 }
 
 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
-  if (!compiler_driver_->GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+  if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
     return offset;
   }
   InitCodeMethodVisitor code_visitor(this, offset, vdex_quickening_info_offset_);
@@ -1982,7 +1982,7 @@
     return false;
   }
 
-  if (compiler_driver_->GetCompilerOptions().IsAnyMethodCompilationEnabled()) {
+  if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
     WriteQuickeningInfoMethodVisitor visitor(this, vdex_out, start_offset);
     if (!VisitDexMethods(&visitor)) {
       PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
@@ -2474,11 +2474,28 @@
                              /* verify */ true,
                              /* verify_checksum */ true,
                              &error_msg);
-  } else {
-    CHECK(oat_dex_file->source_.IsRawFile())
-        << static_cast<size_t>(oat_dex_file->source_.GetType());
+  } else if (oat_dex_file->source_.IsRawFile()) {
     File* raw_file = oat_dex_file->source_.GetRawFile();
     dex_file = DexFile::OpenDex(raw_file->Fd(), location, /* verify_checksum */ true, &error_msg);
+  } else {
+    // The source data is a vdex file.
+    CHECK(oat_dex_file->source_.IsRawData())
+        << static_cast<size_t>(oat_dex_file->source_.GetType());
+    const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
+    // Note: The raw data has already been checked to contain the header
+    // and all the data that the header specifies as the file size.
+    DCHECK(raw_dex_file != nullptr);
+    DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
+    const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
+    // Since the source may have had its layout changed, or may be quickened, don't verify it.
+    dex_file = DexFile::Open(raw_dex_file,
+                             header->file_size_,
+                             location,
+                             oat_dex_file->dex_file_location_checksum_,
+                             nullptr,
+                             /* verify */ false,
+                             /* verify_checksum */ false,
+                             &error_msg);
   }
   if (dex_file == nullptr) {
     LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 5a95abd..8f52812 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -839,17 +839,22 @@
     // TODO: accept symbolic, albeit loop invariant shift factors.
     HInstruction* opa = instruction->InputAt(0);
     HInstruction* opb = instruction->InputAt(1);
-    if (VectorizeUse(node, opa, generate_code, type, restrictions) && opb->IsIntConstant()) {
-      if (generate_code) {
-        // Make sure shift factor only looks at lower bits, as defined for sequential shifts.
-        // Note that even the narrower SIMD shifts do the right thing after that.
-        int32_t mask = (instruction->GetType() == Primitive::kPrimLong)
-            ? kMaxLongShiftDistance
-            : kMaxIntShiftDistance;
-        HInstruction* s = graph_->GetIntConstant(opb->AsIntConstant()->GetValue() & mask);
-        GenerateVecOp(instruction, vector_map_->Get(opa), s, type);
+    int64_t value = 0;
+    if (VectorizeUse(node, opa, generate_code, type, restrictions) && IsInt64AndGet(opb, &value)) {
+      // Make sure shift distance only looks at lower bits, as defined for sequential shifts.
+      int64_t mask = (instruction->GetType() == Primitive::kPrimLong)
+          ? kMaxLongShiftDistance
+          : kMaxIntShiftDistance;
+      int64_t distance = value & mask;
+      // Restrict shift distance to packed data type width.
+      int64_t max_distance = Primitive::ComponentSize(type) * 8;
+      if (0 <= distance && distance < max_distance) {
+        if (generate_code) {
+          HInstruction* s = graph_->GetIntConstant(distance);
+          GenerateVecOp(instruction, vector_map_->Get(opa), s, type);
+        }
+        return true;
       }
-      return true;
     }
   } else if (instruction->IsInvokeStaticOrDirect()) {
     // Accept particular intrinsics.
@@ -1001,8 +1006,9 @@
       vector = new (global_allocator_) HVecStore(
           global_allocator_, org->InputAt(0), opa, opb, type, vector_length_);
     } else  {
+      bool is_string_char_at = org->AsArrayGet()->IsStringCharAt();
       vector = new (global_allocator_) HVecLoad(
-          global_allocator_, org->InputAt(0), opa, type, vector_length_);
+          global_allocator_, org->InputAt(0), opa, type, vector_length_, is_string_char_at);
     }
   } else {
     // Scalar store or load.
@@ -1010,7 +1016,9 @@
     if (opb != nullptr) {
       vector = new (global_allocator_) HArraySet(org->InputAt(0), opa, opb, type, kNoDexPc);
     } else  {
-      vector = new (global_allocator_) HArrayGet(org->InputAt(0), opa, type, kNoDexPc);
+      bool is_string_char_at = org->AsArrayGet()->IsStringCharAt();
+      vector = new (global_allocator_) HArrayGet(
+          org->InputAt(0), opa, type, kNoDexPc, is_string_char_at);
     }
   }
   vector_map_->Put(org, vector);
diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h
index fb9dfb7..52c247b 100644
--- a/compiler/optimizing/nodes_vector.h
+++ b/compiler/optimizing/nodes_vector.h
@@ -98,7 +98,7 @@
 
   DECLARE_ABSTRACT_INSTRUCTION(VecOperation);
 
- private:
+ protected:
   // Additional packed bits.
   static constexpr size_t kFieldType = HInstruction::kNumberOfGenericPackedBits;
   static constexpr size_t kFieldTypeSize =
@@ -107,6 +107,7 @@
   static_assert(kNumberOfVectorOpPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
   using TypeField = BitField<Primitive::Type, kFieldType, kFieldTypeSize>;
 
+ private:
   const size_t vector_length_;
 
   DISALLOW_COPY_AND_ASSIGN(HVecOperation);
@@ -191,6 +192,24 @@
   DISALLOW_COPY_AND_ASSIGN(HVecMemoryOperation);
 };
 
+// Packed type consistency checker (same vector length integral types may mix freely).
+inline static bool HasConsistentPackedTypes(HInstruction* input, Primitive::Type type) {
+  DCHECK(input->IsVecOperation());
+  Primitive::Type input_type = input->AsVecOperation()->GetPackedType();
+  switch (input_type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+      return type == Primitive::kPrimBoolean ||
+             type == Primitive::kPrimByte;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      return type == Primitive::kPrimChar ||
+             type == Primitive::kPrimShort;
+    default:
+      return type == input_type;
+  }
+}
+
 //
 // Definitions of concrete unary vector operations in HIR.
 //
@@ -221,8 +240,7 @@
                 size_t vector_length,
                 uint32_t dex_pc = kNoDexPc)
       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
-    DCHECK(input->IsVecOperation());
-    DCHECK_EQ(input->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(input, packed_type));
   }
 
   // TODO: probably integral promotion
@@ -244,7 +262,7 @@
           uint32_t dex_pc = kNoDexPc)
       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
     DCHECK(input->IsVecOperation());
-    DCHECK_NE(input->AsVecOperation()->GetPackedType(), packed_type);  // actual convert
+    DCHECK_NE(GetInputType(), GetResultType());  // actual convert
   }
 
   Primitive::Type GetInputType() const { return InputAt(0)->AsVecOperation()->GetPackedType(); }
@@ -266,8 +284,7 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
-    DCHECK(input->IsVecOperation());
-    DCHECK_EQ(input->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(input, packed_type));
   }
   DECLARE_INSTRUCTION(VecNeg);
  private:
@@ -284,8 +301,7 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
-    DCHECK(input->IsVecOperation());
-    DCHECK_EQ(input->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(input, packed_type));
   }
   DECLARE_INSTRUCTION(VecAbs);
  private:
@@ -325,9 +341,8 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
-    DCHECK(left->IsVecOperation() && right->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
-    DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
+    DCHECK(HasConsistentPackedTypes(right, packed_type));
   }
   DECLARE_INSTRUCTION(VecAdd);
  private:
@@ -348,22 +363,24 @@
                  bool is_unsigned,
                  bool is_rounded,
                  uint32_t dex_pc = kNoDexPc)
-      : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc),
-        is_unsigned_(is_unsigned),
-        is_rounded_(is_rounded) {
-    DCHECK(left->IsVecOperation() && right->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
-    DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
+      : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
+    DCHECK(HasConsistentPackedTypes(right, packed_type));
+    SetPackedFlag<kFieldHAddIsUnsigned>(is_unsigned);
+    SetPackedFlag<kFieldHAddIsRounded>(is_rounded);
   }
 
-  bool IsUnsigned() const { return is_unsigned_; }
-  bool IsRounded() const { return is_rounded_; }
+  bool IsUnsigned() const { return GetPackedFlag<kFieldHAddIsUnsigned>(); }
+  bool IsRounded() const { return GetPackedFlag<kFieldHAddIsRounded>(); }
 
   DECLARE_INSTRUCTION(VecHalvingAdd);
 
  private:
-  bool is_unsigned_;
-  bool is_rounded_;
+  // Additional packed bits.
+  static constexpr size_t kFieldHAddIsUnsigned = HVecOperation::kNumberOfVectorOpPackedBits;
+  static constexpr size_t kFieldHAddIsRounded = kFieldHAddIsUnsigned + 1;
+  static constexpr size_t kNumberOfHAddPackedBits = kFieldHAddIsRounded + 1;
+  static_assert(kNumberOfHAddPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
 
   DISALLOW_COPY_AND_ASSIGN(HVecHalvingAdd);
 };
@@ -379,9 +396,8 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
-    DCHECK(left->IsVecOperation() && right->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
-    DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
+    DCHECK(HasConsistentPackedTypes(right, packed_type));
   }
   DECLARE_INSTRUCTION(VecSub);
  private:
@@ -399,9 +415,8 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
-    DCHECK(left->IsVecOperation() && right->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
-    DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
+    DCHECK(HasConsistentPackedTypes(right, packed_type));
   }
   DECLARE_INSTRUCTION(VecMul);
  private:
@@ -419,9 +434,8 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
-    DCHECK(left->IsVecOperation() && right->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
-    DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
+    DCHECK(HasConsistentPackedTypes(right, packed_type));
   }
   DECLARE_INSTRUCTION(VecDiv);
  private:
@@ -439,9 +453,8 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
-    DCHECK(left->IsVecOperation() && right->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
-    DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
+    DCHECK(HasConsistentPackedTypes(right, packed_type));
   }
   DECLARE_INSTRUCTION(VecMin);
  private:
@@ -459,9 +472,8 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
-    DCHECK(left->IsVecOperation() && right->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
-    DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
+    DCHECK(HasConsistentPackedTypes(right, packed_type));
   }
   DECLARE_INSTRUCTION(VecMax);
  private:
@@ -551,8 +563,7 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
-    DCHECK(left->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
   }
   DECLARE_INSTRUCTION(VecShl);
  private:
@@ -570,8 +581,7 @@
           size_t vector_length,
           uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
-    DCHECK(left->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
   }
   DECLARE_INSTRUCTION(VecShr);
  private:
@@ -589,8 +599,7 @@
            size_t vector_length,
            uint32_t dex_pc = kNoDexPc)
       : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
-    DCHECK(left->IsVecOperation());
-    DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(left, packed_type));
   }
   DECLARE_INSTRUCTION(VecUShr);
  private:
@@ -646,12 +655,9 @@
                       dex_pc),
         op_kind_(op) {
     DCHECK(op == InstructionKind::kAdd || op == InstructionKind::kSub);
-    DCHECK(accumulator->IsVecOperation());
-    DCHECK(mul_left->IsVecOperation() && mul_right->IsVecOperation());
-    DCHECK_EQ(accumulator->AsVecOperation()->GetPackedType(), packed_type);
-    DCHECK_EQ(mul_left->AsVecOperation()->GetPackedType(), packed_type);
-    DCHECK_EQ(mul_right->AsVecOperation()->GetPackedType(), packed_type);
-
+    DCHECK(HasConsistentPackedTypes(accumulator, packed_type));
+    DCHECK(HasConsistentPackedTypes(mul_left, packed_type));
+    DCHECK(HasConsistentPackedTypes(mul_right, packed_type));
     SetRawInputAt(kInputAccumulatorIndex, accumulator);
     SetRawInputAt(kInputMulLeftIndex, mul_left);
     SetRawInputAt(kInputMulRightIndex, mul_right);
@@ -687,6 +693,7 @@
            HInstruction* index,
            Primitive::Type packed_type,
            size_t vector_length,
+           bool is_string_char_at,
            uint32_t dex_pc = kNoDexPc)
       : HVecMemoryOperation(arena,
                             packed_type,
@@ -696,9 +703,18 @@
                             dex_pc) {
     SetRawInputAt(0, base);
     SetRawInputAt(1, index);
+    SetPackedFlag<kFieldIsStringCharAt>(is_string_char_at);
   }
   DECLARE_INSTRUCTION(VecLoad);
+
+  bool IsStringCharAt() const { return GetPackedFlag<kFieldIsStringCharAt>(); }
+
  private:
+  // Additional packed bits.
+  static constexpr size_t kFieldIsStringCharAt = HVecOperation::kNumberOfVectorOpPackedBits;
+  static constexpr size_t kNumberOfVecLoadPackedBits = kFieldIsStringCharAt + 1;
+  static_assert(kNumberOfVecLoadPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
+
   DISALLOW_COPY_AND_ASSIGN(HVecLoad);
 };
 
@@ -719,8 +735,7 @@
                             /* number_of_inputs */ 3,
                             vector_length,
                             dex_pc) {
-    DCHECK(value->IsVecOperation());
-    DCHECK_EQ(value->AsVecOperation()->GetPackedType(), packed_type);
+    DCHECK(HasConsistentPackedTypes(value, packed_type));
     SetRawInputAt(0, base);
     SetRawInputAt(1, index);
     SetRawInputAt(2, value);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 5090c11..4cba36a 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -268,20 +268,17 @@
   UsageError("      Default: Optimizing");
   UsageError("");
   UsageError("  --compiler-filter="
-                "(verify-none"
-                "|verify-at-runtime"
-                "|verify-profile"
-                "|interpret-only"
-                "|time"
+                "(assume-verified"
+                "|extract"
+                "|verify"
+                "|quicken"
                 "|space-profile"
                 "|space"
-                "|balanced"
                 "|speed-profile"
                 "|speed"
                 "|everything-profile"
                 "|everything):");
   UsageError("      select compiler filter.");
-  UsageError("      verify-profile requires a --profile(-fd) to also be passed in.");
   UsageError("      Example: --compiler-filter=everything");
   UsageError("      Default: speed");
   UsageError("");
@@ -721,6 +718,10 @@
       Usage("Can't have both --input-vdex-fd and --input-vdex");
     }
 
+    if (output_vdex_fd_ != -1 && !output_vdex_.empty()) {
+      Usage("Can't have both --output-vdex-fd and --output-vdex");
+    }
+
     if (!oat_filenames_.empty() && oat_fd_ != -1) {
       Usage("--oat-file should not be used with --oat-fd");
     }
@@ -1125,6 +1126,8 @@
         ParseInputVdexFd(option);
       } else if (option.starts_with("--input-vdex=")) {
         input_vdex_ = option.substr(strlen("--input-vdex=")).data();
+      } else if (option.starts_with("--output-vdex=")) {
+        output_vdex_ = option.substr(strlen("--output-vdex=")).data();
       } else if (option.starts_with("--output-vdex-fd=")) {
         ParseOutputVdexFd(option);
       } else if (option.starts_with("--oat-file=")) {
@@ -1260,6 +1263,7 @@
     }
 
     // OAT and VDEX file handling
+    bool eagerly_unquicken_vdex = DoDexLayoutOptimizations();
 
     if (oat_fd_ == -1) {
       DCHECK(!oat_filenames_.empty());
@@ -1281,12 +1285,15 @@
           input_vdex_file_ = VdexFile::Open(input_vdex_,
                                             /* writable */ false,
                                             /* low_4gb */ false,
+                                            eagerly_unquicken_vdex,
                                             &error_msg);
         }
 
         DCHECK_EQ(output_vdex_fd_, -1);
-        std::string vdex_filename = ReplaceFileExtension(oat_filename, "vdex");
-        if (vdex_filename == input_vdex_) {
+        std::string vdex_filename = output_vdex_.empty()
+            ? ReplaceFileExtension(oat_filename, "vdex")
+            : output_vdex_;
+        if (vdex_filename == input_vdex_ && output_vdex_.empty()) {
           update_input_vdex_ = true;
           std::unique_ptr<File> vdex_file(OS::OpenFileReadWrite(vdex_filename.c_str()));
           vdex_files_.push_back(std::move(vdex_file));
@@ -1328,6 +1335,7 @@
                                             "vdex",
                                             /* writable */ false,
                                             /* low_4gb */ false,
+                                            eagerly_unquicken_vdex,
                                             &error_msg);
           // If there's any problem with the passed vdex, just warn and proceed
           // without it.
@@ -1570,14 +1578,14 @@
 
     // If we need to downgrade the compiler-filter for size reasons, do that check now.
     if (!IsBootImage() && IsVeryLarge(dex_files_)) {
-      if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
+      if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kExtract,
                                       compiler_options_->GetCompilerFilter())) {
-        LOG(INFO) << "Very large app, downgrading to verify-at-runtime.";
+        LOG(INFO) << "Very large app, downgrading to extract.";
         // Note: this change won't be reflected in the key-value store, as that had to be
         //       finalized before loading the dex files. This setup is currently required
         //       to get the size from the DexFile objects.
         // TODO: refactor. b/29790079
-        compiler_options_->SetCompilerFilter(CompilerFilter::kVerifyAtRuntime);
+        compiler_options_->SetCompilerFilter(CompilerFilter::kExtract);
       }
     }
 
@@ -2085,17 +2093,13 @@
   }
 
   bool DoProfileGuidedOptimizations() const {
-    return UseProfile() && compiler_options_->GetCompilerFilter() != CompilerFilter::kVerifyProfile;
+    return UseProfile();
   }
 
   bool DoDexLayoutOptimizations() const {
     return DoProfileGuidedOptimizations();
   }
 
-  bool HasInputVdexFile() const {
-    return input_vdex_file_ != nullptr || input_vdex_fd_ != -1 || !input_vdex_.empty();
-  }
-
   bool LoadProfile() {
     DCHECK(UseProfile());
 
@@ -2151,16 +2155,6 @@
     return dex_files_size >= very_large_threshold_;
   }
 
-  template <typename T>
-  static std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) {
-    std::vector<T*> result;
-    result.reserve(src.size());
-    for (const std::unique_ptr<T>& t : src) {
-      result.push_back(t.get());
-    }
-    return result;
-  }
-
   std::vector<std::string> GetClassPathLocations(const std::string& class_path) {
     // This function is used only for apps and for an app we have exactly one oat file.
     DCHECK(!IsBootImage());
@@ -2693,6 +2687,7 @@
   int input_vdex_fd_;
   int output_vdex_fd_;
   std::string input_vdex_;
+  std::string output_vdex_;
   std::unique_ptr<VdexFile> input_vdex_file_;
   std::vector<const char*> dex_filenames_;
   std::vector<const char*> dex_locations_;
@@ -2899,13 +2894,6 @@
     }
   }
 
-  if (dex2oat->DoDexLayoutOptimizations()) {
-    if (dex2oat->HasInputVdexFile()) {
-      LOG(ERROR) << "Dexlayout is incompatible with an input VDEX";
-      return dex2oat::ReturnCode::kOther;
-    }
-  }
-
   art::MemMap::Init();  // For ZipEntry::ExtractToMemMap, and vdex.
 
   // Check early that the result of compilation can be written
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 8c14b50..a267766 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -161,7 +161,7 @@
     runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
 
     if (!runtime->IsVerificationEnabled()) {
-      argv.push_back("--compiler-filter=verify-none");
+      argv.push_back("--compiler-filter=assume-verified");
     }
 
     if (runtime->MustRelocateIfPossible()) {
@@ -514,7 +514,7 @@
       }
 
       // If the input filter was "below," it should have been used.
-      if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime, filter)) {
+      if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kExtract, filter)) {
         EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
       }
     } else {
@@ -536,11 +536,11 @@
   void CheckHostResult(bool expect_large) {
     if (!kIsTargetBuild) {
       if (expect_large) {
-        EXPECT_NE(output_.find("Very large app, downgrading to verify-at-runtime."),
+        EXPECT_NE(output_.find("Very large app, downgrading to extract."),
                   std::string::npos)
             << output_;
       } else {
-        EXPECT_EQ(output_.find("Very large app, downgrading to verify-at-runtime."),
+        EXPECT_EQ(output_.find("Very large app, downgrading to extract."),
                   std::string::npos)
             << output_;
       }
@@ -567,21 +567,21 @@
 };
 
 TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
-  RunTest(CompilerFilter::kVerifyNone, false);
-  RunTest(CompilerFilter::kVerifyAtRuntime, false);
-  RunTest(CompilerFilter::kInterpretOnly, false);
+  RunTest(CompilerFilter::kAssumeVerified, false);
+  RunTest(CompilerFilter::kExtract, false);
+  RunTest(CompilerFilter::kQuicken, false);
   RunTest(CompilerFilter::kSpeed, false);
 
-  RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=1000000" });
-  RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=1000000" });
-  RunTest(CompilerFilter::kInterpretOnly, false, { "--very-large-app-threshold=1000000" });
+  RunTest(CompilerFilter::kAssumeVerified, false, { "--very-large-app-threshold=1000000" });
+  RunTest(CompilerFilter::kExtract, false, { "--very-large-app-threshold=1000000" });
+  RunTest(CompilerFilter::kQuicken, false, { "--very-large-app-threshold=1000000" });
   RunTest(CompilerFilter::kSpeed, false, { "--very-large-app-threshold=1000000" });
 }
 
 TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
-  RunTest(CompilerFilter::kVerifyNone, false, { "--very-large-app-threshold=100" });
-  RunTest(CompilerFilter::kVerifyAtRuntime, false, { "--very-large-app-threshold=100" });
-  RunTest(CompilerFilter::kInterpretOnly, true, { "--very-large-app-threshold=100" });
+  RunTest(CompilerFilter::kAssumeVerified, false, { "--very-large-app-threshold=100" });
+  RunTest(CompilerFilter::kExtract, false, { "--very-large-app-threshold=100" });
+  RunTest(CompilerFilter::kQuicken, true, { "--very-large-app-threshold=100" });
   RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
 }
 
@@ -736,12 +736,12 @@
                          /* use_fd */ true,
                          /* num_profile_classes */ 1,
                          { input_vdex, output_vdex },
-                         /* expect_success */ false);
-      EXPECT_EQ(vdex_file2.GetFile()->GetLength(), 0u);
+                         /* expect_success */ true);
+      EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
     }
     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
     CheckValidity();
-    ASSERT_FALSE(success_);
+    ASSERT_TRUE(success_);
   }
 
   void CheckResult(const std::string& dex_location,
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 688201b..ea2679a 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -313,6 +313,7 @@
   std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
                                                 false /*writeable*/,
                                                 false /*low_4gb*/,
+                                                false /*unquicken */,
                                                 &error_msg /*out*/));
   if (vdex == nullptr) {
     std::cerr << "Could not open vdex file "
diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc
index 57d3f1f..1703ff4 100644
--- a/dexoptanalyzer/dexoptanalyzer_test.cc
+++ b/dexoptanalyzer/dexoptanalyzer_test.cc
@@ -89,8 +89,8 @@
   Copy(GetDexSrc1(), dex_location);
 
   Verify(dex_location, CompilerFilter::kSpeed);
-  Verify(dex_location, CompilerFilter::kVerifyAtRuntime);
-  Verify(dex_location, CompilerFilter::kInterpretOnly);
+  Verify(dex_location, CompilerFilter::kExtract);
+  Verify(dex_location, CompilerFilter::kQuicken);
   Verify(dex_location, CompilerFilter::kSpeedProfile);
 }
 
@@ -101,8 +101,8 @@
   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
 
   Verify(dex_location, CompilerFilter::kSpeed);
-  Verify(dex_location, CompilerFilter::kInterpretOnly);
-  Verify(dex_location, CompilerFilter::kVerifyAtRuntime);
+  Verify(dex_location, CompilerFilter::kQuicken);
+  Verify(dex_location, CompilerFilter::kExtract);
   Verify(dex_location, CompilerFilter::kEverything);
 }
 
@@ -113,9 +113,9 @@
   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
 
   Verify(dex_location, CompilerFilter::kSpeedProfile, false);
-  Verify(dex_location, CompilerFilter::kInterpretOnly, false);
+  Verify(dex_location, CompilerFilter::kQuicken, false);
   Verify(dex_location, CompilerFilter::kSpeedProfile, true);
-  Verify(dex_location, CompilerFilter::kInterpretOnly, true);
+  Verify(dex_location, CompilerFilter::kQuicken, true);
 }
 
 // Case: We have a MultiDEX file and up-to-date OAT file for it.
@@ -154,7 +154,7 @@
   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
   Copy(GetDexSrc2(), dex_location);
 
-  Verify(dex_location, CompilerFilter::kVerifyAtRuntime);
+  Verify(dex_location, CompilerFilter::kExtract);
   Verify(dex_location, CompilerFilter::kSpeed);
 }
 
@@ -170,8 +170,8 @@
                      /*pic*/false,
                      /*with_alternate_image*/true);
 
-  Verify(dex_location, CompilerFilter::kVerifyAtRuntime);
-  Verify(dex_location, CompilerFilter::kInterpretOnly);
+  Verify(dex_location, CompilerFilter::kExtract);
+  Verify(dex_location, CompilerFilter::kQuicken);
   Verify(dex_location, CompilerFilter::kSpeed);
 }
 
@@ -184,13 +184,13 @@
 
   Copy(GetDexSrc1(), dex_location);
   GenerateOatForTest(dex_location.c_str(),
-                     CompilerFilter::kVerifyAtRuntime,
+                     CompilerFilter::kExtract,
                      /*relocate*/true,
                      /*pic*/false,
                      /*with_alternate_image*/true);
 
-  Verify(dex_location, CompilerFilter::kVerifyAtRuntime);
-  Verify(dex_location, CompilerFilter::kInterpretOnly);
+  Verify(dex_location, CompilerFilter::kExtract);
+  Verify(dex_location, CompilerFilter::kQuicken);
 }
 
 // Case: We have a DEX file and an ODEX file, but no OAT file.
@@ -201,7 +201,7 @@
   Copy(GetDexSrc1(), dex_location);
   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
 
-  Verify(dex_location, CompilerFilter::kVerifyAtRuntime);
+  Verify(dex_location, CompilerFilter::kExtract);
   Verify(dex_location, CompilerFilter::kSpeed);
 }
 
@@ -235,7 +235,7 @@
   // Strip the dex file.
   Copy(GetStrippedDexSrc1(), dex_location);
 
-  Verify(dex_location, CompilerFilter::kVerifyAtRuntime);
+  Verify(dex_location, CompilerFilter::kExtract);
   Verify(dex_location, CompilerFilter::kSpeed);
   Verify(dex_location, CompilerFilter::kEverything);
 }
@@ -248,8 +248,8 @@
   Copy(GetStrippedDexSrc1(), dex_location);
 
   Verify(dex_location, CompilerFilter::kSpeed);
-  Verify(dex_location, CompilerFilter::kVerifyAtRuntime);
-  Verify(dex_location, CompilerFilter::kInterpretOnly);
+  Verify(dex_location, CompilerFilter::kExtract);
+  Verify(dex_location, CompilerFilter::kQuicken);
 }
 
 // Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and
@@ -287,9 +287,9 @@
   std::string odex_location = GetOdexDir() + "/DexVerifyAtRuntimeOdexNoOat.odex";
 
   Copy(GetDexSrc1(), dex_location);
-  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kVerifyAtRuntime);
+  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract);
 
-  Verify(dex_location, CompilerFilter::kVerifyAtRuntime);
+  Verify(dex_location, CompilerFilter::kExtract);
   Verify(dex_location, CompilerFilter::kSpeed);
 }
 
diff --git a/runtime/Android.bp b/runtime/Android.bp
index cff2cbc..1869968 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -57,6 +57,7 @@
         "dex_file_annotations.cc",
         "dex_file_verifier.cc",
         "dex_instruction.cc",
+        "dex_to_dex_decompiler.cc",
         "elf_file.cc",
         "exec_utils.cc",
         "fault_handler.cc",
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index d5f375a..cfe27f3 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -194,6 +194,17 @@
   to_update.insert(other.begin(), other.end());
 }
 
+// Returns a copy of the passed vector that doesn't memory-own its entries.
+template <typename T>
+static inline std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) {
+  std::vector<T*> result;
+  result.reserve(src.size());
+  for (const std::unique_ptr<T>& t : src) {
+    result.push_back(t.get());
+  }
+  return result;
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_BASE_STL_UTIL_H_
diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc
index dc55ab8..dbfcdfe 100644
--- a/runtime/compiler_filter.cc
+++ b/runtime/compiler_filter.cc
@@ -20,17 +20,15 @@
 
 namespace art {
 
-bool CompilerFilter::IsBytecodeCompilationEnabled(Filter filter) {
+bool CompilerFilter::IsAotCompilationEnabled(Filter filter) {
   switch (filter) {
-    case CompilerFilter::kVerifyNone:
-    case CompilerFilter::kVerifyAtRuntime:
-    case CompilerFilter::kVerifyProfile:
-    case CompilerFilter::kInterpretOnly: return false;
+    case CompilerFilter::kAssumeVerified:
+    case CompilerFilter::kExtract:
+    case CompilerFilter::kVerify:
+    case CompilerFilter::kQuicken: return false;
 
     case CompilerFilter::kSpaceProfile:
     case CompilerFilter::kSpace:
-    case CompilerFilter::kBalanced:
-    case CompilerFilter::kTime:
     case CompilerFilter::kSpeedProfile:
     case CompilerFilter::kSpeed:
     case CompilerFilter::kEverythingProfile:
@@ -41,15 +39,13 @@
 
 bool CompilerFilter::IsJniCompilationEnabled(Filter filter) {
   switch (filter) {
-    case CompilerFilter::kVerifyNone:
-    case CompilerFilter::kVerifyAtRuntime: return false;
+    case CompilerFilter::kAssumeVerified:
+    case CompilerFilter::kExtract:
+    case CompilerFilter::kVerify: return false;
 
-    case CompilerFilter::kVerifyProfile:
-    case CompilerFilter::kInterpretOnly:
+    case CompilerFilter::kQuicken:
     case CompilerFilter::kSpaceProfile:
     case CompilerFilter::kSpace:
-    case CompilerFilter::kBalanced:
-    case CompilerFilter::kTime:
     case CompilerFilter::kSpeedProfile:
     case CompilerFilter::kSpeed:
     case CompilerFilter::kEverythingProfile:
@@ -58,17 +54,15 @@
   UNREACHABLE();
 }
 
-bool CompilerFilter::IsAnyMethodCompilationEnabled(Filter filter) {
+bool CompilerFilter::IsQuickeningCompilationEnabled(Filter filter) {
   switch (filter) {
-    case CompilerFilter::kVerifyNone:
-    case CompilerFilter::kVerifyAtRuntime:
-    case CompilerFilter::kVerifyProfile: return false;
+    case CompilerFilter::kAssumeVerified:
+    case CompilerFilter::kExtract:
+    case CompilerFilter::kVerify: return false;
 
-    case CompilerFilter::kInterpretOnly:
+    case CompilerFilter::kQuicken:
     case CompilerFilter::kSpaceProfile:
     case CompilerFilter::kSpace:
-    case CompilerFilter::kBalanced:
-    case CompilerFilter::kTime:
     case CompilerFilter::kSpeedProfile:
     case CompilerFilter::kSpeed:
     case CompilerFilter::kEverythingProfile:
@@ -77,17 +71,21 @@
   UNREACHABLE();
 }
 
+bool CompilerFilter::IsAnyCompilationEnabled(Filter filter) {
+  return IsJniCompilationEnabled(filter) ||
+      IsQuickeningCompilationEnabled(filter) ||
+      IsAotCompilationEnabled(filter);
+}
+
 bool CompilerFilter::IsVerificationEnabled(Filter filter) {
   switch (filter) {
-    case CompilerFilter::kVerifyNone:
-    case CompilerFilter::kVerifyAtRuntime: return false;
+    case CompilerFilter::kAssumeVerified:
+    case CompilerFilter::kExtract: return false;
 
-    case CompilerFilter::kVerifyProfile:
-    case CompilerFilter::kInterpretOnly:
+    case CompilerFilter::kVerify:
+    case CompilerFilter::kQuicken:
     case CompilerFilter::kSpaceProfile:
     case CompilerFilter::kSpace:
-    case CompilerFilter::kBalanced:
-    case CompilerFilter::kTime:
     case CompilerFilter::kSpeedProfile:
     case CompilerFilter::kSpeed:
     case CompilerFilter::kEverythingProfile:
@@ -104,19 +102,14 @@
 
 bool CompilerFilter::DependsOnProfile(Filter filter) {
   switch (filter) {
-    case CompilerFilter::kVerifyNone:
-    case CompilerFilter::kVerifyAtRuntime:
-    case CompilerFilter::kInterpretOnly:
+    case CompilerFilter::kAssumeVerified:
+    case CompilerFilter::kExtract:
+    case CompilerFilter::kVerify:
+    case CompilerFilter::kQuicken:
     case CompilerFilter::kSpace:
-    case CompilerFilter::kBalanced:
-    case CompilerFilter::kTime:
     case CompilerFilter::kSpeed:
     case CompilerFilter::kEverything: return false;
 
-    // verify-profile doesn't look at profiles anymore.
-    // TODO(ngeoffray): this will be cleaned up with b/34715556.
-    case CompilerFilter::kVerifyProfile: return false;
-
     case CompilerFilter::kSpaceProfile:
     case CompilerFilter::kSpeedProfile:
     case CompilerFilter::kEverythingProfile: return true;
@@ -126,21 +119,15 @@
 
 CompilerFilter::Filter CompilerFilter::GetNonProfileDependentFilterFrom(Filter filter) {
   switch (filter) {
-    case CompilerFilter::kVerifyNone:
-    case CompilerFilter::kVerifyAtRuntime:
-    case CompilerFilter::kInterpretOnly:
+    case CompilerFilter::kAssumeVerified:
+    case CompilerFilter::kExtract:
+    case CompilerFilter::kVerify:
+    case CompilerFilter::kQuicken:
     case CompilerFilter::kSpace:
-    case CompilerFilter::kBalanced:
-    case CompilerFilter::kTime:
     case CompilerFilter::kSpeed:
     case CompilerFilter::kEverything:
       return filter;
 
-    case CompilerFilter::kVerifyProfile:
-      // verify-profile doesn't look at profiles anymore.
-      // TODO(ngeoffray): this will be cleaned up with b/34715556.
-      return filter;
-
     case CompilerFilter::kSpaceProfile:
       return CompilerFilter::kSpace;
 
@@ -160,14 +147,12 @@
 
 std::string CompilerFilter::NameOfFilter(Filter filter) {
   switch (filter) {
-    case CompilerFilter::kVerifyNone: return "verify-none";
-    case CompilerFilter::kVerifyAtRuntime: return "verify-at-runtime";
-    case CompilerFilter::kVerifyProfile: return "verify-profile";
-    case CompilerFilter::kInterpretOnly: return "interpret-only";
+    case CompilerFilter::kAssumeVerified: return "assume-verified";
+    case CompilerFilter::kExtract: return "extract";
+    case CompilerFilter::kVerify: return "verify";
+    case CompilerFilter::kQuicken: return "quicken";
     case CompilerFilter::kSpaceProfile: return "space-profile";
     case CompilerFilter::kSpace: return "space";
-    case CompilerFilter::kBalanced: return "balanced";
-    case CompilerFilter::kTime: return "time";
     case CompilerFilter::kSpeedProfile: return "speed-profile";
     case CompilerFilter::kSpeed: return "speed";
     case CompilerFilter::kEverythingProfile: return "everything-profile";
@@ -180,19 +165,41 @@
   CHECK(filter != nullptr);
 
   if (strcmp(option, "verify-none") == 0) {
-    *filter = kVerifyNone;
+    LOG(WARNING) << "'verify-none' is an obsolete compiler filter name that will be "
+                 << "removed in future releases, please use 'assume-verified' instead.";
+    *filter = kAssumeVerified;
   } else if (strcmp(option, "interpret-only") == 0) {
-    *filter = kInterpretOnly;
+    LOG(WARNING) << "'interpret-only' is an obsolete compiler filter name that will be "
+                 << "removed in future releases, please use 'quicken' instead.";
+    *filter = kQuicken;
   } else if (strcmp(option, "verify-profile") == 0) {
-    *filter = kVerifyProfile;
+    LOG(WARNING) << "'verify-profile' is an obsolete compiler filter name that will be "
+                 << "removed in future releases, please use 'verify' instead.";
+    *filter = kVerify;
   } else if (strcmp(option, "verify-at-runtime") == 0) {
-    *filter = kVerifyAtRuntime;
+    LOG(WARNING) << "'verify-at-runtime' is an obsolete compiler filter name that will be "
+                 << "removed in future releases, please use 'extract' instead.";
+    *filter = kExtract;
+  } else if (strcmp(option, "balanced") == 0) {
+    LOG(WARNING) << "'balanced' is an obsolete compiler filter name that will be "
+                 << "removed in future releases, please use 'speed' instead.";
+    *filter = kSpeed;
+  } else if (strcmp(option, "time") == 0) {
+    LOG(WARNING) << "'time' is an obsolete compiler filter name that will be "
+                 << "removed in future releases, please use 'space' instead.";
+    *filter = kSpace;
+  } else if (strcmp(option, "assume-verified") == 0) {
+    *filter = kAssumeVerified;
+  } else if (strcmp(option, "extract") == 0) {
+    *filter = kExtract;
+  } else if (strcmp(option, "verify") == 0) {
+    *filter = kVerify;
+  } else if (strcmp(option, "quicken") == 0) {
+    *filter = kQuicken;
   } else if (strcmp(option, "space") == 0) {
     *filter = kSpace;
   } else if (strcmp(option, "space-profile") == 0) {
     *filter = kSpaceProfile;
-  } else if (strcmp(option, "balanced") == 0) {
-    *filter = kBalanced;
   } else if (strcmp(option, "speed") == 0) {
     *filter = kSpeed;
   } else if (strcmp(option, "speed-profile") == 0) {
@@ -201,8 +208,6 @@
     *filter = kEverything;
   } else if (strcmp(option, "everything-profile") == 0) {
     *filter = kEverythingProfile;
-  } else if (strcmp(option, "time") == 0) {
-    *filter = kTime;
   } else {
     return false;
   }
diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h
index 796f4aa..9cb54b1 100644
--- a/runtime/compiler_filter.h
+++ b/runtime/compiler_filter.h
@@ -30,14 +30,12 @@
   // Note: Order here matters. Later filter choices are considered "as good
   // as" earlier filter choices.
   enum Filter {
-    kVerifyNone,          // Skip verification but mark all classes as verified anyway.
-    kVerifyAtRuntime,     // Delay verication to runtime, do not compile anything.
-    kVerifyProfile,       // Verify only the classes in the profile, compile only JNI stubs.
-    kInterpretOnly,       // Verify everything, compile only JNI stubs.
-    kTime,                // Compile methods, but minimize compilation time.
+    kAssumeVerified,      // Skip verification but mark all classes as verified anyway.
+    kExtract,             // Delay verication to runtime, do not compile anything.
+    kVerify,              // Only verify classes.
+    kQuicken,             // Verify, quicken, and compile JNI stubs.
     kSpaceProfile,        // Maximize space savings based on profile.
     kSpace,               // Maximize space savings.
-    kBalanced,            // Good performance return on compilation investment.
     kSpeedProfile,        // Maximize runtime performance based on profile.
     kSpeed,               // Maximize runtime performance.
     kEverythingProfile,   // Compile everything capable of being compiled based on profile.
@@ -48,17 +46,21 @@
 
   // Returns true if an oat file with this compiler filter contains
   // compiled executable code for bytecode.
-  static bool IsBytecodeCompilationEnabled(Filter filter);
+  static bool IsAotCompilationEnabled(Filter filter);
 
   // Returns true if an oat file with this compiler filter contains
   // compiled executable code for bytecode, JNI methods, or quickened dex
   // bytecode.
-  static bool IsAnyMethodCompilationEnabled(Filter filter);
+  static bool IsAnyCompilationEnabled(Filter filter);
 
   // Returns true if an oat file with this compiler filter contains
   // compiled executable code for JNI methods.
   static bool IsJniCompilationEnabled(Filter filter);
 
+  // Returns true if an oat file with this compiler filter contains
+  // quickened dex bytecode.
+  static bool IsQuickeningCompilationEnabled(Filter filter);
+
   // Returns true if this compiler filter requires running verification.
   static bool IsVerificationEnabled(Filter filter);
 
diff --git a/runtime/compiler_filter_test.cc b/runtime/compiler_filter_test.cc
index c603be6..a59165f 100644
--- a/runtime/compiler_filter_test.cc
+++ b/runtime/compiler_filter_test.cc
@@ -33,14 +33,12 @@
 TEST(CompilerFilterTest, ParseCompilerFilter) {
   CompilerFilter::Filter filter;
 
-  TestCompilerFilterName(CompilerFilter::kVerifyNone, "verify-none");
-  TestCompilerFilterName(CompilerFilter::kVerifyAtRuntime, "verify-at-runtime");
-  TestCompilerFilterName(CompilerFilter::kVerifyProfile, "verify-profile");
-  TestCompilerFilterName(CompilerFilter::kInterpretOnly, "interpret-only");
-  TestCompilerFilterName(CompilerFilter::kTime, "time");
+  TestCompilerFilterName(CompilerFilter::kAssumeVerified, "assume-verified");
+  TestCompilerFilterName(CompilerFilter::kExtract, "extract");
+  TestCompilerFilterName(CompilerFilter::kVerify, "verify");
+  TestCompilerFilterName(CompilerFilter::kQuicken, "quicken");
   TestCompilerFilterName(CompilerFilter::kSpaceProfile, "space-profile");
   TestCompilerFilterName(CompilerFilter::kSpace, "space");
-  TestCompilerFilterName(CompilerFilter::kBalanced, "balanced");
   TestCompilerFilterName(CompilerFilter::kSpeedProfile, "speed-profile");
   TestCompilerFilterName(CompilerFilter::kSpeed, "speed");
   TestCompilerFilterName(CompilerFilter::kEverythingProfile, "everything-profile");
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 625794e..eaf144b 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -1044,7 +1044,7 @@
         }
 
         uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
-        uint32_t descriptor_idx = DecodeUnsignedLeb128P1(&stream);
+        uint16_t descriptor_idx = DecodeUnsignedLeb128P1(&stream);
         uint32_t signature_idx = kDexNoIndex;
         if (opcode == DBG_START_LOCAL_EXTENDED) {
           signature_idx = DecodeUnsignedLeb128P1(&stream);
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index f811287..6627550 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -171,6 +171,17 @@
   "AAACAAAAnAAAAAYAAAABAAAArAAAAAEgAAABAAAAzAAAAAIgAAAFAAAA5AAAAAMgAAABAAAAEAEA"
   "AAAgAAABAAAAFQEAAAAQAAABAAAAIAEAAA==";
 
+static const char kRawDexDebugInfoLocalNullType[] =
+    "ZGV4CjAzNQA+Kwj2g6OZMH88OvK9Ey6ycdIsFCt18ED8AQAAcAAAAHhWNBIAAAAAAAAAAHQBAAAI"
+    "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAMAQAA8AAAABwB"
+    "AAAkAQAALAEAAC8BAAA0AQAASAEAAEsBAABOAQAAAgAAAAMAAAAEAAAABQAAAAIAAAAAAAAAAAAA"
+    "AAUAAAADAAAAAAAAAAEAAQAAAAAAAQAAAAYAAAACAAEAAAAAAAEAAAABAAAAAgAAAAAAAAABAAAA"
+    "AAAAAGMBAAAAAAAAAQABAAEAAABUAQAABAAAAHAQAgAAAA4AAgABAAAAAABZAQAAAgAAABIQDwAG"
+    "PGluaXQ+AAZBLmphdmEAAUkAA0xBOwASTGphdmEvbGFuZy9PYmplY3Q7AAFWAAFhAAR0aGlzAAEA"
+    "Bw4AAwAHDh4DAAcAAAAAAQEAgYAE8AEBAIgCAAAACwAAAAAAAAABAAAAAAAAAAEAAAAIAAAAcAAA"
+    "AAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAAuAAAAAYAAAABAAAA0AAAAAEgAAACAAAA"
+    "8AAAAAIgAAAIAAAAHAEAAAMgAAACAAAAVAEAAAAgAAABAAAAYwEAAAAQAAABAAAAdAEAAA==";
+
 static void DecodeAndWriteDexFile(const char* base64, const char* location) {
   // decode base64
   CHECK(base64 != nullptr);
@@ -598,4 +609,17 @@
   EXPECT_EQ(raw->StringByTypeIdx(idx), nullptr);
 }
 
+static void Callback(void* context ATTRIBUTE_UNUSED,
+                     const DexFile::LocalInfo& entry ATTRIBUTE_UNUSED) {
+}
+
+TEST_F(DexFileTest, OpenDexDebugInfoLocalNullType) {
+  ScratchFile tmp;
+  std::unique_ptr<const DexFile> raw = OpenDexFileInMemoryBase64(
+      kRawDexDebugInfoLocalNullType, tmp.GetFilename().c_str(), 0xf25f2b38U, true);
+  const DexFile::ClassDef& class_def = raw->GetClassDef(0);
+  const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def, 1));
+  ASSERT_TRUE(raw->DecodeDebugLocalInfo(code_item, true, 1, Callback, nullptr));
+}
+
 }  // namespace art
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index 091085a..9f34c12 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -515,6 +515,30 @@
   return os.str();
 }
 
+// Add some checks that ensure the flags make sense. We need a subclass to be in the context of
+// Instruction. Otherwise the flags from the instruction list don't work.
+struct InstructionStaticAsserts : private Instruction {
+  #define IMPLIES(a, b) (!(a) || (b))
+
+  #define VAR_ARGS_CHECK(o, c, pname, f, i, a, v) \
+    static_assert(IMPLIES((f) == k35c || (f) == k45cc, \
+                          ((v) & (kVerifyVarArg | kVerifyVarArgNonZero)) != 0), \
+                  "Missing var-arg verification");
+  #include "dex_instruction_list.h"
+    DEX_INSTRUCTION_LIST(VAR_ARGS_CHECK)
+  #undef DEX_INSTRUCTION_LIST
+  #undef VAR_ARGS_CHECK
+
+  #define VAR_ARGS_RANGE_CHECK(o, c, pname, f, i, a, v) \
+    static_assert(IMPLIES((f) == k3rc || (f) == k4rcc, \
+                          ((v) & (kVerifyVarArgRange | kVerifyVarArgRangeNonZero)) != 0), \
+                  "Missing var-arg verification");
+  #include "dex_instruction_list.h"
+    DEX_INSTRUCTION_LIST(VAR_ARGS_RANGE_CHECK)
+  #undef DEX_INSTRUCTION_LIST
+  #undef VAR_ARGS_RANGE_CHECK
+};
+
 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) {
   return os << Instruction::Name(code);
 }
diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h
index a5ce3c2..11dc7e2 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex_instruction_list.h
@@ -271,8 +271,8 @@
   V(0xF9, UNUSED_F9, "unused-f9", k10x, kIndexUnknown, 0, kVerifyError) \
   V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero | kVerifyRegHPrototype) \
   V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kVerifyRegHPrototype) \
-  V(0xFC, INVOKE_CUSTOM, "invoke-custom", k35c, kIndexCallSiteRef, kContinue | kThrow, kVerifyRegBCallSite) \
-  V(0xFD, INVOKE_CUSTOM_RANGE, "invoke-custom/range", k3rc, kIndexCallSiteRef, kContinue | kThrow, kVerifyRegBCallSite) \
+  V(0xFC, INVOKE_CUSTOM, "invoke-custom", k35c, kIndexCallSiteRef, kContinue | kThrow, kVerifyRegBCallSite | kVerifyVarArg) \
+  V(0xFD, INVOKE_CUSTOM_RANGE, "invoke-custom/range", k3rc, kIndexCallSiteRef, kContinue | kThrow, kVerifyRegBCallSite | kVerifyVarArgRange) \
   V(0xFE, UNUSED_FE, "unused-fe", k10x, kIndexUnknown, 0, kVerifyError) \
   V(0xFF, UNUSED_FF, "unused-ff", k10x, kIndexUnknown, 0, kVerifyError)
 
diff --git a/compiler/dex/dex_to_dex_decompiler.cc b/runtime/dex_to_dex_decompiler.cc
similarity index 100%
rename from compiler/dex/dex_to_dex_decompiler.cc
rename to runtime/dex_to_dex_decompiler.cc
diff --git a/compiler/dex/dex_to_dex_decompiler.h b/runtime/dex_to_dex_decompiler.h
similarity index 88%
rename from compiler/dex/dex_to_dex_decompiler.h
rename to runtime/dex_to_dex_decompiler.h
index b5d5b91..d7cb164 100644
--- a/compiler/dex/dex_to_dex_decompiler.h
+++ b/runtime/dex_to_dex_decompiler.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
-#define ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
+#ifndef ART_RUNTIME_DEX_TO_DEX_DECOMPILER_H_
+#define ART_RUNTIME_DEX_TO_DEX_DECOMPILER_H_
 
 #include "base/array_ref.h"
 #include "dex_file.h"
@@ -36,4 +36,4 @@
 }  // namespace optimizer
 }  // namespace art
 
-#endif  // ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
+#endif  // ART_RUNTIME_DEX_TO_DEX_DECOMPILER_H_
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index db65e40..24b1abb 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -122,7 +122,7 @@
   }
 
   if (!with_alternate_image) {
-    if (CompilerFilter::IsBytecodeCompilationEnabled(filter)) {
+    if (CompilerFilter::IsAotCompilationEnabled(filter)) {
       if (relocate) {
         EXPECT_EQ(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()),
             oat_header.GetImageFileLocationOatDataBegin());
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 2eaa8c7..0515ec6 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -192,8 +192,8 @@
 
   const bool safe_mode = (debug_flags & DEBUG_ENABLE_SAFEMODE) != 0;
   if (safe_mode) {
-    // Ensure that any (secondary) oat files will be interpreted.
-    runtime->AddCompilerOption("--compiler-filter=interpret-only");
+    // Only quicken oat files.
+    runtime->AddCompilerOption("--compiler-filter=quicken");
     runtime->SetSafeMode(true);
     debug_flags &= ~DEBUG_ENABLE_SAFEMODE;
   }
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 4a85d479..9affeb0 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -193,7 +193,7 @@
                            bool writable,
                            bool low_4gb,
                            std::string* error_msg) {
-  vdex_ = VdexFile::Open(vdex_filename, writable, low_4gb, error_msg);
+  vdex_ = VdexFile::Open(vdex_filename, writable, low_4gb, /* unquicken*/ false, error_msg);
   if (vdex_.get() == nullptr) {
     *error_msg = StringPrintf("Failed to load vdex file '%s' %s",
                               vdex_filename.c_str(),
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index a7be73a..2c2b6fd 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -439,7 +439,7 @@
     VLOG(oat) << "Image checksum test skipped for compiler filter " << current_compiler_filter;
   }
 
-  if (CompilerFilter::IsBytecodeCompilationEnabled(current_compiler_filter)) {
+  if (CompilerFilter::IsAotCompilationEnabled(current_compiler_filter)) {
     if (!file.IsPic()) {
       const ImageInfo* image_info = GetImageInfo();
       if (image_info == nullptr) {
@@ -808,6 +808,7 @@
       std::unique_ptr<VdexFile> vdex = VdexFile::Open(vdex_filename,
                                                       /*writeable*/false,
                                                       /*low_4gb*/false,
+                                                      /*unquicken*/false,
                                                       &error_msg);
       if (vdex == nullptr) {
         status_ = kOatCannotOpen;
@@ -834,7 +835,7 @@
 
 OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
     CompilerFilter::Filter target, bool profile_changed) {
-  bool compilation_desired = CompilerFilter::IsBytecodeCompilationEnabled(target);
+  bool compilation_desired = CompilerFilter::IsAotCompilationEnabled(target);
   bool filter_okay = CompilerFilterIsOkay(target, profile_changed);
 
   if (filter_okay && Status() == kOatUpToDate) {
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 4a738ab..198f8e6 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -53,9 +53,9 @@
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
 
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
@@ -99,9 +99,9 @@
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
 
@@ -204,11 +204,11 @@
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, false));
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly, false));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken, false));
   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, true));
   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly, true));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken, true));
 
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
@@ -269,7 +269,7 @@
   // Compile the odex from GetMultiDexSrc2, which has a different non-main
   // dex checksum.
   Copy(GetMultiDexSrc2(), dex_location);
-  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kInterpretOnly);
+  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kQuicken);
 
   // Strip the dex file.
   Copy(GetStrippedDexSrc1(), dex_location);
@@ -332,7 +332,7 @@
 
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
 
@@ -406,9 +406,9 @@
 
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
 
@@ -427,16 +427,16 @@
 
   Copy(GetDexSrc1(), dex_location);
   GenerateOatForTest(dex_location.c_str(),
-                     CompilerFilter::kVerifyAtRuntime,
+                     CompilerFilter::kExtract,
                      /*relocate*/true,
                      /*pic*/false,
                      /*with_alternate_image*/true);
 
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
 
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
@@ -457,7 +457,7 @@
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
   EXPECT_EQ(-OatFileAssistant::kDex2OatForRelocation,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
 
@@ -523,7 +523,7 @@
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,  // Can't run dex2oat because dex file is stripped.
@@ -556,9 +556,9 @@
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
 
   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
@@ -653,13 +653,13 @@
 
   // Create the dex and odex files
   Copy(GetDexSrc1(), dex_location);
-  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kVerifyAtRuntime);
+  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract);
 
   // Verify the status.
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
 
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
   EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
 
@@ -688,13 +688,13 @@
   EXPECT_EQ(1u, dex_files.size());
 }
 
-// Case: We have a DEX file and up-to-date interpret-only OAT file for it.
+// Case: We have a DEX file and up-to-date quicken OAT file for it.
 // Expect: We should still load the oat file as executable.
 TEST_F(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) {
   std::string dex_location = GetScratchDir() + "/LoadExecInterpretOnlyOatUpToDate.jar";
 
   Copy(GetDexSrc1(), dex_location);
-  GenerateOatForTest(dex_location.c_str(), CompilerFilter::kInterpretOnly);
+  GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken);
 
   // Load the oat using an oat file assistant.
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
@@ -1003,11 +1003,11 @@
   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
 
   std::string error_msg;
-  Runtime::Current()->AddCompilerOption("--compiler-filter=interpret-only");
+  Runtime::Current()->AddCompilerOption("--compiler-filter=quicken");
   EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
       oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
 
@@ -1015,7 +1015,7 @@
   EXPECT_EQ(OatFileAssistant::kUpdateSucceeded,
       oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
 
diff --git a/runtime/openjdkjvmti/fixed_up_dex_file.cc b/runtime/openjdkjvmti/fixed_up_dex_file.cc
index 3338358..29aebae 100644
--- a/runtime/openjdkjvmti/fixed_up_dex_file.cc
+++ b/runtime/openjdkjvmti/fixed_up_dex_file.cc
@@ -32,10 +32,8 @@
 #include "fixed_up_dex_file.h"
 #include "dex_file-inl.h"
 
-// Compiler includes.
-#include "dex/dex_to_dex_decompiler.h"
-
 // Runtime includes.
+#include "dex_to_dex_decompiler.h"
 #include "oat_file.h"
 #include "vdex_file.h"
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 93b416c..7afbe72 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -905,6 +905,7 @@
     std::unique_ptr<VdexFile> vdex_file(VdexFile::Open(vdex_filename,
                                                        false /* writable */,
                                                        false /* low_4gb */,
+                                                       false, /* unquicken */
                                                        &error_msg));
     if (vdex_file.get() == nullptr) {
       return false;
@@ -2132,7 +2133,7 @@
 void Runtime::AddCurrentRuntimeFeaturesAsDex2OatArguments(std::vector<std::string>* argv)
     const {
   if (GetInstrumentation()->InterpretOnly()) {
-    argv->push_back("--compiler-filter=interpret-only");
+    argv->push_back("--compiler-filter=quicken");
   }
 
   // Make the dex2oat instruction set match that of the launching runtime. If we have multiple
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 945f08b..e93f04d 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -21,8 +21,10 @@
 #include <memory>
 
 #include "base/logging.h"
+#include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file.h"
+#include "dex_to_dex_decompiler.h"
 
 namespace art {
 
@@ -54,6 +56,7 @@
 std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename,
                                          bool writable,
                                          bool low_4gb,
+                                         bool unquicken,
                                          std::string* error_msg) {
   if (!OS::FileExists(vdex_filename.c_str())) {
     *error_msg = "File " + vdex_filename + " does not exist.";
@@ -78,7 +81,7 @@
     return nullptr;
   }
 
-  return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, error_msg);
+  return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, unquicken, error_msg);
 }
 
 std::unique_ptr<VdexFile> VdexFile::Open(int file_fd,
@@ -86,15 +89,17 @@
                                          const std::string& vdex_filename,
                                          bool writable,
                                          bool low_4gb,
+                                         bool unquicken,
                                          std::string* error_msg) {
-  std::unique_ptr<MemMap> mmap(MemMap::MapFile(vdex_length,
-                                               writable ? PROT_READ | PROT_WRITE : PROT_READ,
-                                               MAP_SHARED,
-                                               file_fd,
-                                               0 /* start offset */,
-                                               low_4gb,
-                                               vdex_filename.c_str(),
-                                               error_msg));
+  std::unique_ptr<MemMap> mmap(MemMap::MapFile(
+      vdex_length,
+      (writable || unquicken) ? PROT_READ | PROT_WRITE : PROT_READ,
+      unquicken ? MAP_PRIVATE : MAP_SHARED,
+      file_fd,
+      0 /* start offset */,
+      low_4gb,
+      vdex_filename.c_str(),
+      error_msg));
   if (mmap == nullptr) {
     *error_msg = "Failed to mmap file " + vdex_filename + " : " + *error_msg;
     return nullptr;
@@ -106,6 +111,16 @@
     return nullptr;
   }
 
+  if (unquicken) {
+    std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files;
+    if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
+      return nullptr;
+    }
+    Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files), vdex->GetQuickeningInfo());
+    // Update the quickening info size to pretend there isn't any.
+    reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0;
+  }
+
   *error_msg = "Success";
   return vdex;
 }
@@ -148,4 +163,62 @@
   return true;
 }
 
+void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
+                         const ArrayRef<const uint8_t>& quickening_info) {
+  if (quickening_info.size() == 0) {
+    // If there is no quickening info, we bail early, as the code below expects at
+    // least the size of quickening data for each method that has a code item.
+    return;
+  }
+  const uint8_t* quickening_info_ptr = quickening_info.data();
+  const uint8_t* const quickening_info_end = quickening_info.data() + quickening_info.size();
+  for (const DexFile* dex_file : dex_files) {
+    for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+      const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+      const uint8_t* class_data = dex_file->GetClassData(class_def);
+      if (class_data == nullptr) {
+        continue;
+      }
+      ClassDataItemIterator it(*dex_file, class_data);
+      // Skip fields
+      while (it.HasNextStaticField()) {
+        it.Next();
+      }
+      while (it.HasNextInstanceField()) {
+        it.Next();
+      }
+
+      while (it.HasNextDirectMethod()) {
+        const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+        if (code_item != nullptr) {
+          uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
+          quickening_info_ptr += sizeof(uint32_t);
+          optimizer::ArtDecompileDEX(*code_item,
+                                     ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
+                                     /* decompile_return_instruction */ false);
+          quickening_info_ptr += quickening_size;
+        }
+        it.Next();
+      }
+
+      while (it.HasNextVirtualMethod()) {
+        const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+        if (code_item != nullptr) {
+          uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
+          quickening_info_ptr += sizeof(uint32_t);
+          optimizer::ArtDecompileDEX(*code_item,
+                                     ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
+                                     /* decompile_return_instruction */ false);
+          quickening_info_ptr += quickening_size;
+        }
+        it.Next();
+      }
+      DCHECK(!it.HasNext());
+    }
+  }
+  if (quickening_info_ptr != quickening_info_end) {
+    LOG(FATAL) << "Failed to use all quickening info";
+  }
+}
+
 }  // namespace art
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 9840555..9c0d9db 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -71,6 +71,8 @@
     uint32_t dex_size_;
     uint32_t verifier_deps_size_;
     uint32_t quickening_info_size_;
+
+    friend class VdexFile;
   };
 
   typedef uint32_t VdexChecksum;
@@ -79,6 +81,7 @@
   static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
                                         bool writable,
                                         bool low_4gb,
+                                        bool unquicken,
                                         std::string* error_msg);
 
   // Returns nullptr if the vdex file cannot be opened or is not valid.
@@ -87,6 +90,7 @@
                                         const std::string& vdex_filename,
                                         bool writable,
                                         bool low_4gb,
+                                        bool unquicken,
                                         std::string* error_msg);
 
   const uint8_t* Begin() const { return mmap_->Begin(); }
@@ -124,12 +128,14 @@
     return reinterpret_cast<const uint32_t*>(Begin() + sizeof(Header))[dex_file_index];
   }
 
-  // Opens all the dex files contained in this vdex file.  This is currently
-  // used for dumping tools only, and has not been tested for use by the
-  // remainder of the runtime.
+  // Opens all the dex files contained in this vdex file.
   bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
                        std::string* error_msg);
 
+  // In-place unquicken the given `dex_files` based on `quickening_info`.
+  static void Unquicken(const std::vector<const DexFile*>& dex_files,
+                        const ArrayRef<const uint8_t>& quickening_info);
+
  private:
   explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
 
diff --git a/runtime/vdex_file_test.cc b/runtime/vdex_file_test.cc
index 909e117..ced6e28 100644
--- a/runtime/vdex_file_test.cc
+++ b/runtime/vdex_file_test.cc
@@ -36,10 +36,12 @@
                                                   tmp.GetFilename(),
                                                   /*writable*/false,
                                                   /*low_4gb*/false,
+                                                  /*quicken*/false,
                                                   &error_msg);
   EXPECT_TRUE(vdex == nullptr);
 
-  vdex = VdexFile::Open(tmp.GetFilename(), /*writable*/false, /*low_4gb*/false, &error_msg);
+  vdex = VdexFile::Open(
+      tmp.GetFilename(), /*writable*/false, /*low_4gb*/false, /*quicken*/ false, &error_msg);
   EXPECT_TRUE(vdex == nullptr);
 }
 
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 2b0c612..cb9c605 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3764,7 +3764,7 @@
     const RegType& referrer = GetDeclaringClass();
     if (!referrer.IsUnresolvedTypes() && !referrer.CanAccess(*result)) {
       Fail(VERIFY_ERROR_ACCESS_CLASS) << "illegal class access: '"
-                                      << referrer << "' -> '" << result << "'";
+                                      << referrer << "' -> '" << *result << "'";
     }
   }
   return *result;
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index 3236bde..2248fc4 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -56,7 +56,7 @@
 
     const OatFile* oat_file = oat_dex_file->GetOatFile();
     return !oat_file->IsPic()
-        && CompilerFilter::IsBytecodeCompilationEnabled(oat_file->GetCompilerFilter());
+        && CompilerFilter::IsAotCompilationEnabled(oat_file->GetCompilerFilter());
   }
 };
 
diff --git a/test/157-void-class/run b/test/157-void-class/run
index 59e852c..8c6159f 100755
--- a/test/157-void-class/run
+++ b/test/157-void-class/run
@@ -14,9 +14,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Let the test build its own core image with --no-image and use verify-profile,
+# Let the test build its own core image with --no-image and use verify,
 # so that the compiler does not try to initialize classes. This leaves the
 # java.lang.Void compile-time verified but uninitialized.
 ./default-run "$@" --no-image \
     --runtime-option -Ximage-compiler-option \
-    --runtime-option --compiler-filter=verify-profile
+    --runtime-option --compiler-filter=verify
diff --git a/test/595-profile-saving/run b/test/595-profile-saving/run
index 068ad03..fce6ac1 100644
--- a/test/595-profile-saving/run
+++ b/test/595-profile-saving/run
@@ -15,13 +15,13 @@
 # limitations under the License.
 
 # Use
-# --compiler-filter=interpret-only to make sure that the test is not compiled AOT
+# --compiler-filter=quicken to make sure that the test is not compiled AOT
 # and to make sure the test is not compiled  when loaded (by PathClassLoader)
 # -Xjitsaveprofilinginfo to enable profile saving
 # -Xusejit:false to disable jit and only test profiles.
 exec ${RUN} \
-  -Xcompiler-option --compiler-filter=interpret-only \
-  --runtime-option '-Xcompiler-option --compiler-filter=interpret-only' \
+  -Xcompiler-option --compiler-filter=quicken \
+  --runtime-option '-Xcompiler-option --compiler-filter=quicken' \
   --runtime-option -Xjitsaveprofilinginfo \
   --runtime-option -Xusejit:false \
   "${@}"
diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java
index 2b30986..6efc168 100644
--- a/test/623-checker-loop-regressions/src/Main.java
+++ b/test/623-checker-loop-regressions/src/Main.java
@@ -310,6 +310,27 @@
     }
   }
 
+  /// CHECK-START: void Main.oneBoth(short[], char[]) loop_optimization (before)
+  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                       loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START-ARM64: void Main.oneBoth(short[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                        loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]         loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>>      outer_loop:none
+  //
+  // Bug b/37764324: integral same-length packed types can be mixed freely.
+  private static void oneBoth(short[] a, char[] b) {
+    for (int i = 0; i < Math.min(a.length, b.length); i++) {
+      a[i] = 1;
+      b[i] = 1;
+    }
+  }
+
   public static void main(String[] args) {
     expectEquals(10, earlyExitFirst(-1));
     for (int i = 0; i <= 10; i++) {
@@ -393,6 +414,13 @@
 
     envUsesInCond();
 
+    short[] dd = new short[23];
+    oneBoth(dd, aa);
+    for (int i = 0; i < aa.length; i++) {
+      expectEquals(aa[i], 1);
+      expectEquals(dd[i], 1);
+    }
+
     System.out.println("passed");
   }
 
diff --git a/test/628-vdex/run b/test/628-vdex/run
index 4cbcea3..bf0ac91 100644
--- a/test/628-vdex/run
+++ b/test/628-vdex/run
@@ -14,4 +14,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-exec ${RUN} -Xcompiler-option --compiler-filter=verify-profile --vdex "${@}"
+exec ${RUN} -Xcompiler-option --compiler-filter=verify --vdex "${@}"
diff --git a/test/634-vdex-duplicate/run b/test/634-vdex-duplicate/run
index 1ccb841..571ccd9 100644
--- a/test/634-vdex-duplicate/run
+++ b/test/634-vdex-duplicate/run
@@ -14,4 +14,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-exec ${RUN} -Xcompiler-option --compiler-filter=verify-profile --vdex-filter speed --vdex "${@}"
+exec ${RUN} -Xcompiler-option --compiler-filter=verify --vdex-filter speed --vdex "${@}"
diff --git a/test/640-checker-byte-simd/src/Main.java b/test/640-checker-byte-simd/src/Main.java
index 0f7452b..10b20b8 100644
--- a/test/640-checker-byte-simd/src/Main.java
+++ b/test/640-checker-byte-simd/src/Main.java
@@ -179,6 +179,11 @@
       a[i] >>>= 33;  // 1, since & 31
   }
 
+  static void shl9() {
+    for (int i = 0; i < 128; i++)
+      a[i] <<= 9;  // yields all-zeros
+  }
+
   //
   // Loop bounds.
   //
@@ -259,6 +264,10 @@
     shr33();
     for (int i = 0; i < 128; i++) {
       expectEquals((byte) 0x09, a[i], "shr33");
+    }
+    shl9();
+    for (int i = 0; i < 128; i++) {
+      expectEquals((byte) 0x00, a[i], "shl9");
       a[i] = (byte) 0xf0;  // reset
     }
     not();
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index efffb99..73aecf5 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -451,15 +451,15 @@
 if [ "$INTERPRETER" = "y" ]; then
     INT_OPTS="-Xint"
     if [ "$VERIFY" = "y" ] ; then
-      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=interpret-only"
-      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
+      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=quicken"
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=quicken"
     elif [ "$VERIFY" = "s" ]; then
-      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-at-runtime"
-      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-at-runtime"
+      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=extract"
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=extract"
       DEX_VERIFY="${DEX_VERIFY} -Xverify:softfail"
     else # VERIFY = "n"
-      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-none"
-      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none"
+      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=assume-verified"
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=assume-verified"
       DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
     fi
 fi
@@ -467,11 +467,11 @@
 if [ "$JIT" = "y" ]; then
     INT_OPTS="-Xusejit:true"
     if [ "$VERIFY" = "y" ] ; then
-      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=interpret-only"
-      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
+      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=quicken"
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=quicken"
     else
-      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-none"
-      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none"
+      INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=assume-verified"
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=assume-verified"
       DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
     fi
 fi
@@ -590,8 +590,12 @@
     # Use -k 1m to SIGKILL it a minute later if it hasn't ended.
     dex2oat_cmdline="timeout -k 1m -s SIGRTMIN+2 1m ${dex2oat_cmdline}"
   fi
-  if [ "$TEST_VDEX" = "y" ]; then
+  if [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
+    vdex_cmdline="${dex2oat_cmdline} ${VDEX_FILTER} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
+  elif [ "$TEST_VDEX" = "y" ]; then
     vdex_cmdline="${dex2oat_cmdline} ${VDEX_FILTER} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
+  elif [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
+    vdex_cmdline="${dex2oat_cmdline} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
   fi
 fi
 
diff --git a/tools/art b/tools/art
index 933ad7a..0bc08f0 100644
--- a/tools/art
+++ b/tools/art
@@ -46,17 +46,17 @@
   fi
 }
 
-function replace_compiler_filter_with_interepret_only() {
-  ARGS_WITH_INTERPRET_ONLY=("$@")
+function replace_compiler_filter_with_quicken() {
+  ARGS_WITH_QUICKEN=("$@")
 
   found="false"
   ((index=0))
   while ((index <= $#)); do
-    what="${ARGS_WITH_INTERPRET_ONLY[$index]}"
+    what="${ARGS_WITH_QUICKEN[$index]}"
 
     case "$what" in
       --compiler-filter=*)
-        ARGS_WITH_INTERPRET_ONLY[$index]="--compiler-filter=interpret-only"
+        ARGS_WITH_QUICKEN[$index]="--compiler-filter=quicken"
         found="true"
         ;;
     esac
@@ -65,7 +65,7 @@
     shift
   done
   if [ "$found" != "true" ]; then
-    ARGS_WITH_INTERPRET_ONLY=(-Xcompiler-option --compiler-filter=interpret-only "${ARGS_WITH_INTERPRET_ONLY[@]}")
+    ARGS_WITH_QUICKEN=(-Xcompiler-option --compiler-filter=quicken "${ARGS_WITH_QUICKEN[@]}")
   fi
 }
 
@@ -224,10 +224,10 @@
   PROFILE_PATH="$ANDROID_DATA/primary.prof"
   touch $PROFILE_PATH
 
-  # Replace the compiler filter with interpret-only so that we
+  # Replace the compiler filter with quicken so that we
   # can capture the profile.
-  ARGS_WITH_INTERPRET_ONLY=
-  replace_compiler_filter_with_interepret_only "$@"
+  ARGS_WITH_QUICKEN=
+  replace_compiler_filter_with_quicken "$@"
 
   run_art -Xjitsaveprofilinginfo               \
           -Xps-min-methods-to-save:1           \
@@ -235,7 +235,7 @@
           -Xps-min-notification-before-wake:10 \
           -Xps-profile-path:$PROFILE_PATH      \
           -Xusejit:true                        \
-          "${ARGS_WITH_INTERPRET_ONLY[@]}"     \
+          "${ARGS_WITH_QUICKEN[@]}"            \
           "&>" "$ANDROID_DATA/profile_gen.log"
   EXIT_STATUS=$?
 
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Executor.java b/tools/dexfuzz/src/dexfuzz/executors/Executor.java
index 2bcf3a1..074672d 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/Executor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/Executor.java
@@ -117,7 +117,7 @@
     commandBuilder.append("--runtime-arg -classpath ");
     commandBuilder.append("--runtime-arg ").append(programName).append(" ");
     commandBuilder.append("--dex-file=").append(programName).append(" ");
-    commandBuilder.append("--compiler-filter=interpret-only --runtime-arg -Xnorelocate ");
+    commandBuilder.append("--compiler-filter=quicken --runtime-arg -Xnorelocate ");
 
     ExecutionResult verificationResult = device.executeCommand(commandBuilder.toString(), true,
         outputConsumer, errorConsumer);
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 07c300e..d48d857 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -132,8 +132,8 @@
   vm_args="--vm-arg $image"
 fi
 if $use_jit; then
-  vm_args="$vm_args --vm-arg -Xcompiler-option --vm-arg --compiler-filter=interpret-only"
-  debuggee_args="$debuggee_args -Xcompiler-option --compiler-filter=interpret-only"
+  vm_args="$vm_args --vm-arg -Xcompiler-option --vm-arg --compiler-filter=quicken"
+  debuggee_args="$debuggee_args -Xcompiler-option --compiler-filter=quicken"
 fi
 vm_args="$vm_args --vm-arg -Xusejit:$use_jit"
 debuggee_args="$debuggee_args -Xusejit:$use_jit"
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 729a3e5..b860a62 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -127,7 +127,7 @@
 
 # JIT settings.
 if $use_jit; then
-  vogar_args="$vogar_args --vm-arg -Xcompiler-option --vm-arg --compiler-filter=interpret-only"
+  vogar_args="$vogar_args --vm-arg -Xcompiler-option --vm-arg --compiler-filter=quicken"
 fi
 vogar_args="$vogar_args --vm-arg -Xusejit:$use_jit"