Merge "Allow redefined methods/classes to access fields"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index d59d8f6..bd7f900 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -26,6 +26,8 @@
   AbstractMethod \
   AllFields \
   DexToDexDecompiler \
+  ErroneousA \
+  ErroneousB \
   ExceptionHandle \
   GetMethodSignature \
   ImageLayoutA \
@@ -85,7 +87,7 @@
 ART_GTEST_dex2oat_environment_tests_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested
 
 ART_GTEST_atomic_method_ref_map_test_DEX_DEPS := Interfaces
-ART_GTEST_class_linker_test_DEX_DEPS := Interfaces MethodTypes MultiDex MyClass Nested Statics StaticsFromCode
+ART_GTEST_class_linker_test_DEX_DEPS := ErroneousA ErroneousB Interfaces MethodTypes MultiDex MyClass Nested Statics StaticsFromCode
 ART_GTEST_class_table_test_DEX_DEPS := XandY
 ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex
 ART_GTEST_dex_cache_test_DEX_DEPS := Main Packages MethodTypes
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
index 6e042c3..f4540ff 100644
--- a/cmdline/cmdline.h
+++ b/cmdline/cmdline.h
@@ -24,10 +24,12 @@
 #include <iostream>
 #include <string>
 
-#include "runtime.h"
+#include "android-base/stringprintf.h"
+
+#include "base/logging.h"
 #include "base/stringpiece.h"
 #include "noop_compiler_callbacks.h"
-#include "base/logging.h"
+#include "runtime.h"
 
 #if !defined(NDEBUG)
 #define DBG_LOG LOG(INFO)
@@ -197,7 +199,7 @@
         "      Example: --boot-image=/system/framework/boot.art\n"
         "               (specifies /system/framework/<arch>/boot.art as the image file)\n"
         "\n";
-    usage += StringPrintf(  // Optional.
+    usage += android::base::StringPrintf(  // Optional.
         "  --instruction-set=(arm|arm64|mips|mips64|x86|x86_64): for locating the image\n"
         "      file based on the image location set.\n"
         "      Example: --instruction-set=x86\n"
@@ -264,8 +266,8 @@
       // Check that the boot image location points to a valid file name.
       std::string file_name;
       if (!LocationToFilename(boot_image_location, instruction_set_, &file_name)) {
-        *error_msg = StringPrintf("No corresponding file for location '%s' exists",
-                                  file_name.c_str());
+        *error_msg = android::base::StringPrintf("No corresponding file for location '%s' exists",
+                                                 file_name.c_str());
         return false;
       }
 
diff --git a/compiler/compiled_class.h b/compiler/compiled_class.h
index b88d613..06ce946 100644
--- a/compiler/compiled_class.h
+++ b/compiler/compiled_class.h
@@ -28,8 +28,11 @@
   mirror::Class::Status GetStatus() const {
     return status_;
   }
+  void SetStatus(mirror::Class::Status status) {
+    status_ = status;
+  }
  private:
-  const mirror::Class::Status status_;
+  mirror::Class::Status status_;
 };
 
 }  // namespace art
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index cf69f46..d4f6545 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -16,6 +16,8 @@
 
 #include "dex_to_dex_compiler.h"
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/logging.h"
@@ -32,6 +34,8 @@
 namespace art {
 namespace optimizer {
 
+using android::base::StringPrintf;
+
 // Controls quickening activation.
 const bool kEnableQuickening = true;
 // Control check-cast elision.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 1b1de78..d1a5c4d 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -423,7 +423,7 @@
   // Compile:
   // 1) Compile all classes and methods enabled for compilation. May fall back to dex-to-dex
   //    compilation.
-  if (!GetCompilerOptions().VerifyAtRuntime()) {
+  if (!GetCompilerOptions().VerifyAtRuntime() && !GetCompilerOptions().VerifyOnlyProfile()) {
     Compile(class_loader, dex_files, timings);
   }
   if (dump_stats_) {
@@ -492,6 +492,7 @@
     // TODO: we unquicken unconditionnally, as we don't know
     // if the boot image has changed. How exactly we'll know is under
     // experimentation.
+    TimingLogger::ScopedTiming t("Unquicken", timings);
     Unquicken(dex_files, vdex_file->GetQuickeningInfo());
     Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
         new verifier::VerifierDeps(dex_files, vdex_file->GetVerifierDepsData()));
@@ -983,8 +984,10 @@
                << "situations. Please check the log.";
   }
 
-  InitializeClasses(class_loader, dex_files, timings);
-  VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
+  if (!verify_only_profile) {
+    InitializeClasses(class_loader, dex_files, timings);
+    VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
+  }
 
   UpdateImageClasses(timings);
   VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString(false);
@@ -2060,21 +2063,32 @@
         std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
         for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
           const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
-          const char* descriptor = dex_file->GetClassDescriptor(class_def);
-          cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader));
-          if (cls.Get() == nullptr) {
-            CHECK(soa.Self()->IsExceptionPending());
-            soa.Self()->ClearException();
-          } else if (set.find(class_def.class_idx_) == set.end()) {
-            ObjectLock<mirror::Class> lock(soa.Self(), cls);
-            mirror::Class::SetStatus(cls, mirror::Class::kStatusVerified, soa.Self());
-            // Create `VerifiedMethod`s for each methods, the compiler expects one for
-            // quickening or compiling.
-            // Note that this means:
-            // - We're only going to compile methods that did verify.
-            // - Quickening will not do checkcast ellision.
-            // TODO(ngeoffray): Reconsider this once we refactor compiler filters.
-            PopulateVerifiedMethods(*dex_file, i, verification_results_);
+          if (set.find(class_def.class_idx_) == set.end()) {
+            if (GetCompilerOptions().VerifyOnlyProfile()) {
+              // Just update the compiled_classes_ map. The compiler doesn't need to resolve
+              // the type.
+              compiled_classes_.Overwrite(
+                  ClassReference(dex_file, i), new CompiledClass(mirror::Class::kStatusVerified));
+            } else {
+              // Resolve the type, so later compilation stages know they don't need to verify
+              // the class.
+              const char* descriptor = dex_file->GetClassDescriptor(class_def);
+              cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader));
+              if (cls.Get() != nullptr) {
+                ObjectLock<mirror::Class> lock(soa.Self(), cls);
+                mirror::Class::SetStatus(cls, mirror::Class::kStatusVerified, soa.Self());
+              } else {
+                DCHECK(soa.Self()->IsExceptionPending());
+                soa.Self()->ClearException();
+              }
+              // Create `VerifiedMethod`s for each methods, the compiler expects one for
+              // quickening or compiling.
+              // Note that this means:
+              // - We're only going to compile methods that did verify.
+              // - Quickening will not do checkcast ellision.
+              // TODO(ngeoffray): Reconsider this once we refactor compiler filters.
+              PopulateVerifiedMethods(*dex_file, i, verification_results_);
+            }
           }
         }
       }
@@ -2675,29 +2689,29 @@
 }
 
 void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status status) {
+  switch (status) {
+    case mirror::Class::kStatusNotReady:
+    case mirror::Class::kStatusError:
+    case mirror::Class::kStatusRetryVerificationAtRuntime:
+    case mirror::Class::kStatusVerified:
+    case mirror::Class::kStatusInitialized:
+    case mirror::Class::kStatusResolved:
+      break;  // Expected states.
+    default:
+      LOG(FATAL) << "Unexpected class status for class "
+          << PrettyDescriptor(ref.first->GetClassDescriptor(ref.first->GetClassDef(ref.second)))
+          << " of " << status;
+  }
+
   MutexLock mu(Thread::Current(), compiled_classes_lock_);
   auto it = compiled_classes_.find(ref);
-  if (it == compiled_classes_.end() || it->second->GetStatus() != status) {
-    // An entry doesn't exist or the status is lower than the new status.
-    if (it != compiled_classes_.end()) {
-      CHECK_GT(status, it->second->GetStatus());
-      delete it->second;
-    }
-    switch (status) {
-      case mirror::Class::kStatusNotReady:
-      case mirror::Class::kStatusError:
-      case mirror::Class::kStatusRetryVerificationAtRuntime:
-      case mirror::Class::kStatusVerified:
-      case mirror::Class::kStatusInitialized:
-      case mirror::Class::kStatusResolved:
-        break;  // Expected states.
-      default:
-        LOG(FATAL) << "Unexpected class status for class "
-            << PrettyDescriptor(ref.first->GetClassDescriptor(ref.first->GetClassDef(ref.second)))
-            << " of " << status;
-    }
+  if (it == compiled_classes_.end()) {
     CompiledClass* compiled_class = new CompiledClass(status);
     compiled_classes_.Overwrite(ref, compiled_class);
+  } else if (status > it->second->GetStatus()) {
+    // Update the status if we now have a greater one. This happens with vdex,
+    // which records a class is verified, but does not resolve it.
+    it->second->SetStatus(status);
   }
 }
 
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index cc50197..eb69931 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -440,9 +440,12 @@
                       TimingLogger* timings)
       REQUIRES(!Locks::mutator_lock_);
 
+  // NO_THREAD_SAFETY_ANALYSIS as the method accesses a guarded value in a
+  // single-threaded way.
   void Verify(jobject class_loader,
               const std::vector<const DexFile*>& dex_files,
-              TimingLogger* timings);
+              TimingLogger* timings)
+    NO_THREAD_SAFETY_ANALYSIS;
 
   void VerifyDexFile(jobject class_loader,
                      const DexFile& dex_file,
diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc
index 64fd9e7..47b1929 100644
--- a/compiler/driver/dex_compilation_unit.cc
+++ b/compiler/driver/dex_compilation_unit.cc
@@ -16,7 +16,6 @@
 
 #include "dex_compilation_unit.h"
 
-#include "base/stringprintf.h"
 #include "mirror/dex_cache.h"
 #include "utils.h"
 
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index 6f48779..9669c4a 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -16,7 +16,6 @@
 
 #include "elf_file.h"
 
-#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 #include "common_compiler_test.h"
 #include "elf_file.h"
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 9bbe595..1290379 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -20,6 +20,8 @@
 #include <string>
 #include <vector>
 
+#include "android-base/stringprintf.h"
+
 #include "base/unix_file/fd_file.h"
 #include "class_linker-inl.h"
 #include "common_compiler_test.h"
@@ -134,7 +136,8 @@
     // Create a generic tmp file, to be the base of the .art and .oat temporary files.
     ScratchFile location;
     for (int i = 0; i < static_cast<int>(class_path.size()); ++i) {
-      std::string cur_location(StringPrintf("%s-%d.art", location.GetFilename().c_str(), i));
+      std::string cur_location =
+          android::base::StringPrintf("%s-%d.art", location.GetFilename().c_str(), i);
       image_locations.push_back(ScratchFile(cur_location));
     }
   }
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 9dfb434..148ce4f 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -16,6 +16,8 @@
 
 #include "jit_compiler.h"
 
+#include "android-base/stringprintf.h"
+
 #include "arch/instruction_set.h"
 #include "arch/instruction_set_features.h"
 #include "art_method-inl.h"
@@ -81,7 +83,7 @@
   va_list ap;
   va_start(ap, fmt);
   std::string error;
-  StringAppendV(&error, fmt, ap);
+  android::base::StringAppendV(&error, fmt, ap);
   LOG(FATAL) << error;
   va_end(ap);
   exit(EXIT_FAILURE);
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 0a778b0..edc93ab 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "android-base/stringprintf.h"
+
 #include "arch/instruction_set_features.h"
 #include "art_method-inl.h"
 #include "base/enums.h"
@@ -48,7 +50,7 @@
   va_list ap;
   va_start(ap, fmt);
   std::string error;
-  StringAppendV(&error, fmt, ap);
+  android::base::StringAppendV(&error, fmt, ap);
   LOG(FATAL) << error;
   va_end(ap);
   UNREACHABLE();
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 55f3c3c..1c5aec0 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -46,8 +46,10 @@
 using helpers::InputRegister;
 using helpers::InputRegisterAt;
 using helpers::InputSRegisterAt;
+using helpers::InputVRegister;
 using helpers::InputVRegisterAt;
 using helpers::Int32ConstantFrom;
+using helpers::Int64ConstantFrom;
 using helpers::LocationFrom;
 using helpers::LowRegisterFrom;
 using helpers::LowSRegisterFrom;
@@ -56,6 +58,7 @@
 using helpers::OutputVRegister;
 using helpers::RegisterFrom;
 using helpers::SRegisterFrom;
+using helpers::Uint64ConstantFrom;
 
 using vixl::ExactAssemblyScope;
 using vixl::CodeBufferCheckScope;
@@ -1378,7 +1381,7 @@
   if (!skip_overflow_check) {
     UseScratchRegisterScope temps(GetVIXLAssembler());
     vixl32::Register temp = temps.Acquire();
-    __ Sub(temp, sp, static_cast<int32_t>(GetStackOverflowReservedBytes(kArm)));
+    __ Sub(temp, sp, Operand::From(GetStackOverflowReservedBytes(kArm)));
     // The load must immediately precede RecordPcInfo.
     ExactAssemblyScope aas(GetVIXLAssembler(),
                            vixl32::kMaxInstructionSizeInBytes,
@@ -1795,7 +1798,7 @@
       break;
   }
   if (right.IsConstant()) {
-    int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
+    int64_t value = Int64ConstantFrom(right);
     int32_t val_low = Low32Bits(value);
     int32_t val_high = High32Bits(value);
 
@@ -1880,7 +1883,7 @@
         __ B(true_target);
       }
     } else {
-      DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
+      DCHECK(cond->AsIntConstant()->IsFalse()) << Int32ConstantFrom(cond);
       if (false_target != nullptr) {
         __ B(false_target);
       }
@@ -2482,9 +2485,7 @@
 
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
-      // TODO(VIXL): Consider introducing an InputVRegister()
-      // helper function (equivalent to InputRegister()).
-      __ Vneg(OutputVRegister(neg), InputVRegisterAt(neg, 0));
+      __ Vneg(OutputVRegister(neg), InputVRegister(neg));
       break;
 
     default:
@@ -2774,8 +2775,8 @@
           } else {
             DCHECK(in.IsConstant());
             DCHECK(in.GetConstant()->IsLongConstant());
-            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
-            __ Mov(OutputRegister(conversion), static_cast<int32_t>(value));
+            int32_t value = Int32ConstantFrom(in);
+            __ Mov(OutputRegister(conversion), value);
           }
           break;
 
@@ -3114,8 +3115,8 @@
       // Extra checks to protect caused by the existence of R1_R2.
       // The algorithm is wrong if out.hi is either in1.lo or in2.lo:
       // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2);
-      DCHECK_NE(out_hi.GetCode(), in1_lo.GetCode());
-      DCHECK_NE(out_hi.GetCode(), in2_lo.GetCode());
+      DCHECK(!out_hi.Is(in1_lo));
+      DCHECK(!out_hi.Is(in2_lo));
 
       // input: in1 - 64 bits, in2 - 64 bits
       // output: out
@@ -3155,7 +3156,7 @@
 
   vixl32::Register out = OutputRegister(instruction);
   vixl32::Register dividend = InputRegisterAt(instruction, 0);
-  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+  int32_t imm = Int32ConstantFrom(second);
   DCHECK(imm == 1 || imm == -1);
 
   if (instruction->IsRem()) {
@@ -3180,7 +3181,7 @@
   vixl32::Register out = OutputRegister(instruction);
   vixl32::Register dividend = InputRegisterAt(instruction, 0);
   vixl32::Register temp = RegisterFrom(locations->GetTemp(0));
-  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+  int32_t imm = Int32ConstantFrom(second);
   uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
   int ctz_imm = CTZ(abs_imm);
 
@@ -3253,7 +3254,7 @@
   Location second = instruction->GetLocations()->InAt(1);
   DCHECK(second.IsConstant());
 
-  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+  int32_t imm = Int32ConstantFrom(second);
   if (imm == 0) {
     // Do not generate anything. DivZeroCheck would prevent any code to be executed.
   } else if (imm == 1 || imm == -1) {
@@ -3287,7 +3288,7 @@
         locations->SetInAt(0, Location::RequiresRegister());
         locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
-        int32_t value = div->InputAt(1)->AsIntConstant()->GetValue();
+        int32_t value = Int32ConstantFrom(div->InputAt(1));
         if (value == 1 || value == 0 || value == -1) {
           // No temp register required.
         } else {
@@ -3400,7 +3401,7 @@
         locations->SetInAt(0, Location::RequiresRegister());
         locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
-        int32_t value = rem->InputAt(1)->AsIntConstant()->GetValue();
+        int32_t value = Int32ConstantFrom(rem->InputAt(1));
         if (value == 1 || value == 0 || value == -1) {
           // No temp register required.
         } else {
@@ -3535,7 +3536,7 @@
         __ CompareAndBranchIfZero(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
       } else {
         DCHECK(value.IsConstant()) << value;
-        if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
+        if (Int32ConstantFrom(value) == 0) {
           __ B(slow_path->GetEntryLabel());
         }
       }
@@ -3549,7 +3550,7 @@
         __ B(eq, slow_path->GetEntryLabel());
       } else {
         DCHECK(value.IsConstant()) << value;
-        if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
+        if (Int64ConstantFrom(value) == 0) {
           __ B(slow_path->GetEntryLabel());
         }
       }
@@ -3759,7 +3760,7 @@
           __ Lsr(out_reg, first_reg, out_reg);
         }
       } else {
-        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
+        int32_t cst = Int32ConstantFrom(second);
         uint32_t shift_value = cst & kMaxIntShiftDistance;
         if (shift_value == 0) {  // ARM does not support shifting with 0 immediate.
           __ Mov(out_reg, first_reg);
@@ -3844,7 +3845,7 @@
         // Register allocator doesn't create partial overlap.
         DCHECK(!o_l.Is(high));
         DCHECK(!o_h.Is(low));
-        int32_t cst = second.GetConstant()->AsIntConstant()->GetValue();
+        int32_t cst = Int32ConstantFrom(second);
         uint32_t shift_value = cst & kMaxLongShiftDistance;
         if (shift_value > 32) {
           if (op->IsShl()) {
@@ -4911,7 +4912,7 @@
         codegen_->MaybeRecordImplicitNullCheck(instruction);
       }
       if (index.IsConstant()) {
-        int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
+        int32_t const_index = Int32ConstantFrom(index);
         if (maybe_compressed_char_at) {
           vixl32::Label uncompressed_load, done;
           __ Lsrs(length, length, 1u);  // LSRS has a 16-bit encoding, TST (immediate) does not.
@@ -4945,7 +4946,7 @@
           // `TryExtractArrayAccessAddress()`.
           if (kIsDebugBuild) {
             HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
-            DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
+            DCHECK_EQ(Uint64ConstantFrom(tmp->GetOffset()), data_offset);
           }
           temp = obj;
         } else {
@@ -4990,7 +4991,7 @@
         vixl32::Register out = OutputRegister(instruction);
         if (index.IsConstant()) {
           size_t offset =
-              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+              (Int32ConstantFrom(index) << TIMES_4) + data_offset;
           GetAssembler()->LoadFromOffset(kLoadWord, out, obj, offset);
           // TODO(VIXL): Here and for other calls to `MaybeRecordImplicitNullCheck` in this method,
           // we should use a scope and the assembler to emit the load instruction to guarantee that
@@ -5012,7 +5013,7 @@
             // `TryExtractArrayAccessAddress()`.
             if (kIsDebugBuild) {
               HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
-              DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
+              DCHECK_EQ(Uint64ConstantFrom(tmp->GetOffset()), data_offset);
             }
             temp = obj;
           } else {
@@ -5037,7 +5038,7 @@
     case Primitive::kPrimLong: {
       if (index.IsConstant()) {
         size_t offset =
-            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+            (Int32ConstantFrom(index) << TIMES_8) + data_offset;
         GetAssembler()->LoadFromOffset(kLoadWordPair, LowRegisterFrom(out_loc), obj, offset);
       } else {
         UseScratchRegisterScope temps(GetVIXLAssembler());
@@ -5051,7 +5052,7 @@
     case Primitive::kPrimFloat: {
       vixl32::SRegister out = SRegisterFrom(out_loc);
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+        size_t offset = (Int32ConstantFrom(index) << TIMES_4) + data_offset;
         GetAssembler()->LoadSFromOffset(out, obj, offset);
       } else {
         UseScratchRegisterScope temps(GetVIXLAssembler());
@@ -5064,7 +5065,7 @@
 
     case Primitive::kPrimDouble: {
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+        size_t offset = (Int32ConstantFrom(index) << TIMES_8) + data_offset;
         GetAssembler()->LoadDFromOffset(DRegisterFrom(out_loc), obj, offset);
       } else {
         UseScratchRegisterScope temps(GetVIXLAssembler());
@@ -5138,7 +5139,7 @@
     case Primitive::kPrimChar:
     case Primitive::kPrimInt: {
       if (index.IsConstant()) {
-        int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
+        int32_t const_index = Int32ConstantFrom(index);
         uint32_t full_offset =
             data_offset + (const_index << Primitive::ComponentSizeShift(value_type));
         StoreOperandType store_type = GetStoreOperandType(value_type);
@@ -5153,7 +5154,7 @@
           // `TryExtractArrayAccessAddress()`.
           if (kIsDebugBuild) {
             HIntermediateAddress* tmp = array_instr->AsIntermediateAddress();
-            DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == data_offset);
+            DCHECK_EQ(Uint64ConstantFrom(tmp->GetOffset()), data_offset);
           }
           temp = array;
         } else {
@@ -5174,7 +5175,7 @@
         // Just setting null.
         if (index.IsConstant()) {
           size_t offset =
-              (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+              (Int32ConstantFrom(index) << TIMES_4) + data_offset;
           GetAssembler()->StoreToOffset(kStoreWord, value, array, offset);
         } else {
           DCHECK(index.IsRegister()) << index;
@@ -5210,7 +5211,7 @@
           __ CompareAndBranchIfNonZero(value, &non_zero);
           if (index.IsConstant()) {
             size_t offset =
-               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+               (Int32ConstantFrom(index) << TIMES_4) + data_offset;
             GetAssembler()->StoreToOffset(kStoreWord, value, array, offset);
           } else {
             DCHECK(index.IsRegister()) << index;
@@ -5284,7 +5285,7 @@
 
       if (index.IsConstant()) {
         size_t offset =
-            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+            (Int32ConstantFrom(index) << TIMES_4) + data_offset;
         GetAssembler()->StoreToOffset(kStoreWord, source, array, offset);
       } else {
         DCHECK(index.IsRegister()) << index;
@@ -5321,7 +5322,7 @@
       Location value = locations->InAt(2);
       if (index.IsConstant()) {
         size_t offset =
-            (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+            (Int32ConstantFrom(index) << TIMES_8) + data_offset;
         GetAssembler()->StoreToOffset(kStoreWordPair, LowRegisterFrom(value), array, offset);
       } else {
         UseScratchRegisterScope temps(GetVIXLAssembler());
@@ -5336,7 +5337,7 @@
       Location value = locations->InAt(2);
       DCHECK(value.IsFpuRegister());
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
+        size_t offset = (Int32ConstantFrom(index) << TIMES_4) + data_offset;
         GetAssembler()->StoreSToOffset(SRegisterFrom(value), array, offset);
       } else {
         UseScratchRegisterScope temps(GetVIXLAssembler());
@@ -5351,7 +5352,7 @@
       Location value = locations->InAt(2);
       DCHECK(value.IsFpuRegisterPair());
       if (index.IsConstant()) {
-        size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
+        size_t offset = (Int32ConstantFrom(index) << TIMES_8) + data_offset;
         GetAssembler()->StoreDToOffset(DRegisterFrom(value), array, offset);
       } else {
         UseScratchRegisterScope temps(GetVIXLAssembler());
@@ -5416,7 +5417,7 @@
   if (second.IsRegister()) {
     __ Add(out, first, RegisterFrom(second));
   } else {
-    __ Add(out, first, second.GetConstant()->AsIntConstant()->GetValue());
+    __ Add(out, first, Int32ConstantFrom(second));
   }
 }
 
@@ -5612,7 +5613,7 @@
         GetAssembler()->StoreToOffset(kStoreWord, temp, sp, destination.GetStackIndex());
       }
     } else if (constant->IsLongConstant()) {
-      int64_t value = constant->AsLongConstant()->GetValue();
+      int64_t value = Int64ConstantFrom(source);
       if (destination.IsRegisterPair()) {
         __ Mov(LowRegisterFrom(destination), Low32Bits(value));
         __ Mov(HighRegisterFrom(destination), High32Bits(value));
diff --git a/compiler/optimizing/common_arm.h b/compiler/optimizing/common_arm.h
index eabdbad..21c3ae6 100644
--- a/compiler/optimizing/common_arm.h
+++ b/compiler/optimizing/common_arm.h
@@ -122,10 +122,16 @@
   if (type == Primitive::kPrimFloat) {
     return InputSRegisterAt(instr, input_index);
   } else {
+    DCHECK_EQ(type, Primitive::kPrimDouble);
     return InputDRegisterAt(instr, input_index);
   }
 }
 
+inline vixl::aarch32::VRegister InputVRegister(HInstruction* instr) {
+  DCHECK_EQ(instr->InputCount(), 1u);
+  return InputVRegisterAt(instr, 0);
+}
+
 inline vixl::aarch32::Register OutputRegister(HInstruction* instr) {
   return RegisterFrom(instr->GetLocations()->Out(), instr->GetType());
 }
@@ -140,8 +146,7 @@
   return InputRegisterAt(instr, 0);
 }
 
-inline int32_t Int32ConstantFrom(Location location) {
-  HConstant* instr = location.GetConstant();
+inline int32_t Int32ConstantFrom(HInstruction* instr) {
   if (instr->IsIntConstant()) {
     return instr->AsIntConstant()->GetValue();
   } else if (instr->IsNullConstant()) {
@@ -155,6 +160,10 @@
   }
 }
 
+inline int32_t Int32ConstantFrom(Location location) {
+  return Int32ConstantFrom(location.GetConstant());
+}
+
 inline int64_t Int64ConstantFrom(Location location) {
   HConstant* instr = location.GetConstant();
   if (instr->IsIntConstant()) {
@@ -167,6 +176,11 @@
   }
 }
 
+inline uint64_t Uint64ConstantFrom(HInstruction* instr) {
+  DCHECK(instr->IsConstant()) << instr->DebugName();
+  return instr->AsConstant()->GetValueAsUint64();
+}
+
 inline vixl::aarch32::Operand OperandFrom(Location location, Primitive::Type type) {
   if (location.IsRegister()) {
     return vixl::aarch32::Operand(RegisterFrom(location, type));
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 188ee3a..34b52a8 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -20,12 +20,15 @@
 #include <string>
 #include <sstream>
 
+#include "android-base/stringprintf.h"
+
 #include "base/arena_containers.h"
 #include "base/bit_vector-inl.h"
-#include "base/stringprintf.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static bool IsAllowedToJumpToExitBlock(HInstruction* instruction) {
   return instruction->IsThrow() || instruction->IsReturn() || instruction->IsReturnVoid();
 }
diff --git a/compiler/optimizing/graph_test.cc b/compiler/optimizing/graph_test.cc
index d530564..28ee3a5 100644
--- a/compiler/optimizing/graph_test.cc
+++ b/compiler/optimizing/graph_test.cc
@@ -15,7 +15,6 @@
  */
 
 #include "base/arena_allocator.h"
-#include "base/stringprintf.h"
 #include "builder.h"
 #include "nodes.h"
 #include "optimizing_unit_test.h"
diff --git a/compiler/optimizing/induction_var_analysis.cc b/compiler/optimizing/induction_var_analysis.cc
index c240c67..b21bc09 100644
--- a/compiler/optimizing/induction_var_analysis.cc
+++ b/compiler/optimizing/induction_var_analysis.cc
@@ -211,7 +211,7 @@
 void HInductionVarAnalysis::ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction) {
   InductionInfo* info = nullptr;
   if (instruction->IsPhi()) {
-    info = TransferPhi(loop, instruction, /* input_index */ 0);
+    info = TransferPhi(loop, instruction, /*input_index*/ 0, /*adjust_input_size*/ 0);
   } else if (instruction->IsAdd()) {
     info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
                           LookupInfo(loop, instruction->InputAt(1)), kAdd);
@@ -224,11 +224,13 @@
     info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
                        LookupInfo(loop, instruction->InputAt(1)));
   } else if (instruction->IsShl()) {
-    HInstruction* mulc = GetMultConstantForShift(loop, instruction);
+    HInstruction* mulc = GetShiftConstant(loop, instruction, /*initial*/ nullptr);
     if (mulc != nullptr) {
       info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
                          LookupInfo(loop, mulc));
     }
+  } else if (instruction->IsSelect()) {
+    info = TransferPhi(loop, instruction, /*input_index*/ 0, /*adjust_input_size*/ 1);
   } else if (instruction->IsTypeConversion()) {
     info = TransferCnv(LookupInfo(loop, instruction->InputAt(0)),
                        instruction->AsTypeConversion()->GetInputType(),
@@ -270,7 +272,7 @@
 
   // Singleton is wrap-around induction if all internal links have the same meaning.
   if (size == 1) {
-    InductionInfo* update = TransferPhi(loop, phi, /* input_index */ 1);
+    InductionInfo* update = TransferPhi(loop, phi, /*input_index*/ 1, /*adjust_input_size*/ 0);
     if (update != nullptr) {
       AssignInfo(loop, phi, CreateInduction(kWrapAround,
                                             kNop,
@@ -305,10 +307,15 @@
       update = SolveOp(
           loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kRem);
     } else if (instruction->IsShl()) {
-      HInstruction* mulc = GetMultConstantForShift(loop, instruction);
+      HInstruction* mulc = GetShiftConstant(loop, instruction, /*initial*/ nullptr);
       if (mulc != nullptr) {
         update = SolveOp(loop, phi, instruction, instruction->InputAt(0), mulc, kMul);
       }
+    } else if (instruction->IsShr() || instruction->IsUShr()) {
+      HInstruction* divc = GetShiftConstant(loop, instruction, initial);
+      if (divc != nullptr) {
+        update = SolveOp(loop, phi, instruction, instruction->InputAt(0), divc, kDiv);
+      }
     } else if (instruction->IsXor()) {
       update = SolveOp(
           loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kXor);
@@ -316,6 +323,8 @@
       update = SolveTest(loop, phi, instruction, 0);
     } else if (instruction->IsNotEqual()) {
       update = SolveTest(loop, phi, instruction, 1);
+    } else if (instruction->IsSelect()) {
+      update = SolvePhi(instruction, /*input_index*/ 0, /*adjust_input_size*/ 1);  // acts like Phi
     } else if (instruction->IsTypeConversion()) {
       update = SolveCnv(instruction->AsTypeConversion());
     }
@@ -326,7 +335,7 @@
   }
 
   // Success if all internal links received the same temporary meaning.
-  InductionInfo* induction = SolvePhi(phi, /* input_index */ 1);
+  InductionInfo* induction = SolvePhi(phi, /*input_index*/ 1, /*adjust_input_size*/ 0);
   if (induction != nullptr) {
     switch (induction->induction_class) {
       case kInvariant:
@@ -385,12 +394,13 @@
 
 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(HLoopInformation* loop,
                                                                          HInstruction* phi,
-                                                                         size_t input_index) {
+                                                                         size_t input_index,
+                                                                         size_t adjust_input_size) {
   // Match all phi inputs from input_index onwards exactly.
   HInputsRef inputs = phi->GetInputs();
   DCHECK_LT(input_index, inputs.size());
   InductionInfo* a = LookupInfo(loop, inputs[input_index]);
-  for (size_t i = input_index + 1; i < inputs.size(); i++) {
+  for (size_t i = input_index + 1, n = inputs.size() - adjust_input_size; i < n; i++) {
     InductionInfo* b = LookupInfo(loop, inputs[i]);
     if (!InductionEqual(a, b)) {
       return nullptr;
@@ -504,13 +514,14 @@
 }
 
 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HInstruction* phi,
-                                                                      size_t input_index) {
+                                                                      size_t input_index,
+                                                                      size_t adjust_input_size) {
   // Match all phi inputs from input_index onwards exactly.
   HInputsRef inputs = phi->GetInputs();
   DCHECK_LT(input_index, inputs.size());
   auto ita = cycle_.find(inputs[input_index]);
   if (ita != cycle_.end()) {
-    for (size_t i = input_index + 1; i < inputs.size(); i++) {
+    for (size_t i = input_index + 1, n = inputs.size() - adjust_input_size; i < n; i++) {
       auto itb = cycle_.find(inputs[i]);
       if (itb == cycle_.end() ||
           !HInductionVarAnalysis::InductionEqual(ita->second, itb->second)) {
@@ -527,7 +538,7 @@
     HInstruction* entry_phi,
     HInstruction* phi) {
   // Match all phi inputs.
-  InductionInfo* match = SolvePhi(phi, /* input_index */ 0);
+  InductionInfo* match = SolvePhi(phi, /*input_index*/ 0, /*adjust_input_size*/ 0);
   if (match != nullptr) {
     return match;
   }
@@ -542,7 +553,7 @@
         InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
         return CreateInduction(kPeriodic, kNop, a, initial, /*fetch*/ nullptr, type_);
       }
-      InductionInfo* b = SolvePhi(phi, /* input_index */ 1);
+      InductionInfo* b = SolvePhi(phi, /*input_index*/ 1, /*adjust_input_size*/ 0);
       if (b != nullptr && b->induction_class == kPeriodic) {
         return CreateInduction(kPeriodic, kNop, a, b, /*fetch*/ nullptr, type_);
       }
@@ -574,14 +585,14 @@
           return CreateInvariantOp(op, a, b);
         }
       }
-    } else if (op == kAdd && b->induction_class == kLinear) {
+    } else if (b->induction_class == kLinear) {
       // Solve within a tight cycle that adds a term that is already classified as a linear
       // induction for a polynomial induction k = k + i (represented as sum over linear terms).
       if (x == entry_phi && entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
         InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
         return CreateInduction(kPolynomial,
                                kNop,
-                               b,
+                               op == kAdd ? b : TransferNeg(b),
                                initial,
                                /*fetch*/ nullptr,
                                type_);
@@ -1038,13 +1049,23 @@
   return new (graph_->GetArena()) InductionInfo(kInvariant, op, a, b, nullptr, b->type);
 }
 
-HInstruction* HInductionVarAnalysis::GetMultConstantForShift(HLoopInformation* loop,
-                                                             HInstruction* instruction) {
-  // Obtain the constant needed to treat shift as equivalent multiplication. This yields an
-  // existing instruction if the constant is already there. Otherwise, this has a side effect
-  // on the HIR. The restriction on the shift factor avoids generating a negative constant
-  // (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that generalization for
-  // shift factors outside [0,32) and [0,64) ranges is done by earlier simplification.
+HInstruction* HInductionVarAnalysis::GetShiftConstant(HLoopInformation* loop,
+                                                      HInstruction* instruction,
+                                                      InductionInfo* initial) {
+  DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
+  // Shift-rights are only the same as division for non-negative initial inputs.
+  // Otherwise we would round incorrectly.
+  if (initial != nullptr) {
+    int64_t value = -1;
+    if (!IsAtLeast(initial, &value) || value < 0) {
+      return nullptr;
+    }
+  }
+  // Obtain the constant needed to treat shift as equivalent multiplication or division.
+  // This yields an existing instruction if the constant is already there. Otherwise, this
+  // has a side effect on the HIR. The restriction on the shift factor avoids generating a
+  // negative constant (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that
+  // generalization for shift factors outside [0,32) and [0,64) ranges is done earlier.
   InductionInfo* b = LookupInfo(loop, instruction->InputAt(1));
   int64_t value = -1;
   if (IsExact(b, &value)) {
diff --git a/compiler/optimizing/induction_var_analysis.h b/compiler/optimizing/induction_var_analysis.h
index 4720f2d..293aa70 100644
--- a/compiler/optimizing/induction_var_analysis.h
+++ b/compiler/optimizing/induction_var_analysis.h
@@ -115,7 +115,7 @@
     InductionInfo* op_a;
     InductionInfo* op_b;
     HInstruction* fetch;
-    Primitive::Type type;  // precision of induction
+    Primitive::Type type;  // precision of operation
   };
 
   bool IsVisitedNode(HInstruction* instruction) const {
@@ -160,14 +160,17 @@
   InductionInfo* RotatePeriodicInduction(InductionInfo* induction, InductionInfo* last);
 
   // Transfer operations.
-  InductionInfo* TransferPhi(HLoopInformation* loop, HInstruction* phi, size_t input_index);
+  InductionInfo* TransferPhi(HLoopInformation* loop,
+                             HInstruction* phi,
+                             size_t input_index,
+                             size_t adjust_input_size);
   InductionInfo* TransferAddSub(InductionInfo* a, InductionInfo* b, InductionOp op);
   InductionInfo* TransferNeg(InductionInfo* a);
   InductionInfo* TransferMul(InductionInfo* a, InductionInfo* b);
   InductionInfo* TransferCnv(InductionInfo* a, Primitive::Type from, Primitive::Type to);
 
   // Solvers.
-  InductionInfo* SolvePhi(HInstruction* phi, size_t input_index);
+  InductionInfo* SolvePhi(HInstruction* phi, size_t input_index, size_t adjust_input_size);
   InductionInfo* SolvePhiAllInputs(HLoopInformation* loop,
                                    HInstruction* entry_phi,
                                    HInstruction* phi);
@@ -220,7 +223,9 @@
   InductionInfo* LookupInfo(HLoopInformation* loop, HInstruction* instruction);
   InductionInfo* CreateConstant(int64_t value, Primitive::Type type);
   InductionInfo* CreateSimplifiedInvariant(InductionOp op, InductionInfo* a, InductionInfo* b);
-  HInstruction* GetMultConstantForShift(HLoopInformation* loop, HInstruction* instruction);
+  HInstruction* GetShiftConstant(HLoopInformation* loop,
+                                 HInstruction* instruction,
+                                 InductionInfo* initial);
   void AssignCycle(HPhi* phi);
   ArenaSet<HInstruction*>* LookupCycle(HPhi* phi);
 
diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc
index 2d182f6..f52a1aa 100644
--- a/compiler/optimizing/induction_var_analysis_test.cc
+++ b/compiler/optimizing/induction_var_analysis_test.cc
@@ -87,6 +87,7 @@
     constant2_ = graph_->GetIntConstant(2);
     constant7_ = graph_->GetIntConstant(7);
     constant100_ = graph_->GetIntConstant(100);
+    constantm1_ = graph_->GetIntConstant(-1);
     float_constant0_ = graph_->GetFloatConstant(0.0f);
     return_->AddInstruction(new (&allocator_) HReturnVoid());
     exit_->AddInstruction(new (&allocator_) HExit());
@@ -196,6 +197,7 @@
   HInstruction* constant2_;
   HInstruction* constant7_;
   HInstruction* constant100_;
+  HInstruction* constantm1_;
   HInstruction* float_constant0_;
 
   // Loop specifics.
@@ -612,6 +614,45 @@
   EXPECT_STREQ("", GetInductionInfo(div, 0).c_str());
 }
 
+TEST_F(InductionVarAnalysisTest, FindGeometricShrInduction) {
+  // Setup:
+  // k = 100;
+  // for (int i = 0; i < 100; i++) {
+  //   k = k >> 1;  // geometric (/ 2)
+  // }
+  BuildLoopNest(1);
+  HPhi* k_header = InsertLoopPhi(0, 0);
+  k_header->AddInput(constant100_);
+
+  HInstruction* shr = InsertInstruction(
+      new (&allocator_) HShr(Primitive::kPrimInt, k_header, constant1_), 0);
+  k_header->AddInput(shr);
+  PerformInductionVarAnalysis();
+
+  // Note, only the phi in the cycle is classified.
+  EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
+}
+
+TEST_F(InductionVarAnalysisTest, FindNotGeometricShrInduction) {
+  // Setup:
+  // k = -1;
+  // for (int i = 0; i < 100; i++) {
+  //   k = k >> 1;  // initial value is negative
+  // }
+  BuildLoopNest(1);
+  HPhi* k_header = InsertLoopPhi(0, 0);
+  k_header->AddInput(constantm1_);
+
+  HInstruction* shr = InsertInstruction(
+      new (&allocator_) HShr(Primitive::kPrimInt, k_header, constant1_), 0);
+  k_header->AddInput(shr);
+  PerformInductionVarAnalysis();
+
+  EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
+  EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
+}
+
 TEST_F(InductionVarAnalysisTest, FindRemWrapAroundInductionAndDerived) {
   // Setup:
   // k = 100;
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index e665551..7bcc384 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -983,10 +983,10 @@
   int64_t a = 0;
   int64_t b = 0;
   int64_t m = 0;
-  if (IsConstant(info->op_a->op_a, kExact, &a) && a >= 0 &&
-      IsConstant(info->op_a->op_b, kExact, &b) && b >= 0 &&
+  if (IsConstant(info->op_a->op_a, kExact, &a) &&
+      IsConstant(info->op_a->op_b, kExact, &b) &&
       IsConstant(trip->op_a, kExact, &m) && m >= 1) {
-    // Evaluate bounds on sum_i=0^m-1(a * i + b) + c with a,b >= 0 for known
+    // Evaluate bounds on sum_i=0^m-1(a * i + b) + c for known
     // maximum index value m as a * (m * (m-1)) / 2 + b * m + c.
     // TODO: generalize
     HInstruction* c_instr = nullptr;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index c615df1..439e3b6 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -1897,7 +1897,8 @@
 static bool NoEscapeForStringBufferReference(HInstruction* reference, HInstruction* user) {
   if (user->IsInvokeStaticOrDirect()) {
     // Any constructor on StringBuffer is okay.
-    return user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
+    return user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
+           user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
            user->InputAt(0) == reference;
   } else if (user->IsInvokeVirtual()) {
     switch (user->AsInvokeVirtual()->GetIntrinsic()) {
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 95551c8..641a5c9 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -1509,7 +1509,7 @@
   SlowPathCodeARMVIXL* slow_path = nullptr;
   HInstruction* code_point = invoke->InputAt(1);
   if (code_point->IsIntConstant()) {
-    if (static_cast<uint32_t>(code_point->AsIntConstant()->GetValue()) >
+    if (static_cast<uint32_t>(Int32ConstantFrom(code_point)) >
         std::numeric_limits<uint16_t>::max()) {
       // Always needs the slow-path. We could directly dispatch to it, but this case should be
       // rare, so for simplicity just put the full slow-path down and branch unconditionally.
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index 13e14c5..3831aa6 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -18,7 +18,6 @@
 
 #include "arch/x86/instruction_set_features_x86.h"
 #include "base/arena_allocator.h"
-#include "base/stringprintf.h"
 #include "builder.h"
 #include "code_generator.h"
 #include "code_generator_x86.h"
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 1e946d6..cabc078 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1108,13 +1108,23 @@
   return HasEnvironment() ? environment_->Size() : 0;
 }
 
-void HPhi::AddInput(HInstruction* input) {
+void HVariableInputSizeInstruction::AddInput(HInstruction* input) {
   DCHECK(input->GetBlock() != nullptr);
   inputs_.push_back(HUserRecord<HInstruction*>(input));
   input->AddUseAt(this, inputs_.size() - 1);
 }
 
-void HPhi::RemoveInputAt(size_t index) {
+void HVariableInputSizeInstruction::InsertInputAt(size_t index, HInstruction* input) {
+  inputs_.insert(inputs_.begin() + index, HUserRecord<HInstruction*>(input));
+  input->AddUseAt(this, index);
+  // Update indexes in use nodes of inputs that have been pushed further back by the insert().
+  for (size_t i = index + 1u, e = inputs_.size(); i < e; ++i) {
+    DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i - 1u);
+    inputs_[i].GetUseNode()->SetIndex(i);
+  }
+}
+
+void HVariableInputSizeInstruction::RemoveInputAt(size_t index) {
   RemoveAsUserOfInput(index);
   inputs_.erase(inputs_.begin() + index);
   // Update indexes in use nodes of inputs that have been pulled forward by the erase().
@@ -2386,26 +2396,6 @@
   return !opt.GetDoesNotNeedDexCache();
 }
 
-void HInvokeStaticOrDirect::InsertInputAt(size_t index, HInstruction* input) {
-  inputs_.insert(inputs_.begin() + index, HUserRecord<HInstruction*>(input));
-  input->AddUseAt(this, index);
-  // Update indexes in use nodes of inputs that have been pushed further back by the insert().
-  for (size_t i = index + 1u, e = inputs_.size(); i < e; ++i) {
-    DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i - 1u);
-    inputs_[i].GetUseNode()->SetIndex(i);
-  }
-}
-
-void HInvokeStaticOrDirect::RemoveInputAt(size_t index) {
-  RemoveAsUserOfInput(index);
-  inputs_.erase(inputs_.begin() + index);
-  // Update indexes in use nodes of inputs that have been pulled forward by the erase().
-  for (size_t i = index, e = inputs_.size(); i < e; ++i) {
-    DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i + 1u);
-    inputs_[i].GetUseNode()->SetIndex(i);
-  }
-}
-
 std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind rhs) {
   switch (rhs) {
     case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 4a8cfcb..4a77bed 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2347,6 +2347,27 @@
   DISALLOW_COPY_AND_ASSIGN(HBackwardInstructionIterator);
 };
 
+class HVariableInputSizeInstruction : public HInstruction {
+ public:
+  void AddInput(HInstruction* input);
+  void InsertInputAt(size_t index, HInstruction* input);
+  void RemoveInputAt(size_t index);
+
+ protected:
+  HVariableInputSizeInstruction(SideEffects side_effects,
+                                uint32_t dex_pc,
+                                ArenaAllocator* arena,
+                                size_t number_of_inputs,
+                                ArenaAllocKind kind)
+      : HInstruction(side_effects, dex_pc),
+        inputs_(number_of_inputs, arena->Adapter(kind)) {}
+
+  ArenaVector<HUserRecord<HInstruction*>> inputs_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HVariableInputSizeInstruction);
+};
+
 template<size_t N>
 class HTemplateInstruction: public HInstruction {
  public:
@@ -2438,15 +2459,19 @@
   DISALLOW_COPY_AND_ASSIGN(HReturn);
 };
 
-class HPhi FINAL : public HInstruction {
+class HPhi FINAL : public HVariableInputSizeInstruction {
  public:
   HPhi(ArenaAllocator* arena,
        uint32_t reg_number,
        size_t number_of_inputs,
        Primitive::Type type,
        uint32_t dex_pc = kNoDexPc)
-      : HInstruction(SideEffects::None(), dex_pc),
-        inputs_(number_of_inputs, arena->Adapter(kArenaAllocPhiInputs)),
+      : HVariableInputSizeInstruction(
+            SideEffects::None(),
+            dex_pc,
+            arena,
+            number_of_inputs,
+            kArenaAllocPhiInputs),
         reg_number_(reg_number) {
     SetPackedField<TypeField>(ToPhiType(type));
     DCHECK_NE(GetType(), Primitive::kPrimVoid);
@@ -2469,9 +2494,6 @@
     return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
   }
 
-  void AddInput(HInstruction* input);
-  void RemoveInputAt(size_t index);
-
   Primitive::Type GetType() const OVERRIDE { return GetPackedField<TypeField>(); }
   void SetType(Primitive::Type new_type) {
     // Make sure that only valid type changes occur. The following are allowed:
@@ -2527,7 +2549,6 @@
   static_assert(kNumberOfPhiPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
   using TypeField = BitField<Primitive::Type, kFieldType, kFieldTypeSize>;
 
-  ArenaVector<HUserRecord<HInstruction*>> inputs_;
   const uint32_t reg_number_;
 
   DISALLOW_COPY_AND_ASSIGN(HPhi);
@@ -3791,7 +3812,7 @@
   kCanThrow  // Intrinsic may throw exceptions.
 };
 
-class HInvoke : public HInstruction {
+class HInvoke : public HVariableInputSizeInstruction {
  public:
   bool NeedsEnvironment() const OVERRIDE;
 
@@ -3878,12 +3899,14 @@
           uint32_t dex_method_index,
           ArtMethod* resolved_method,
           InvokeType invoke_type)
-    : HInstruction(
-          SideEffects::AllExceptGCDependency(), dex_pc),  // Assume write/read on all fields/arrays.
+    : HVariableInputSizeInstruction(
+          SideEffects::AllExceptGCDependency(),  // Assume write/read on all fields/arrays.
+          dex_pc,
+          arena,
+          number_of_arguments + number_of_other_inputs,
+          kArenaAllocInvokeInputs),
       number_of_arguments_(number_of_arguments),
       resolved_method_(resolved_method),
-      inputs_(number_of_arguments + number_of_other_inputs,
-              arena->Adapter(kArenaAllocInvokeInputs)),
       dex_method_index_(dex_method_index),
       intrinsic_(Intrinsics::kNone),
       intrinsic_optimizations_(0) {
@@ -3894,7 +3917,6 @@
 
   uint32_t number_of_arguments_;
   ArtMethod* const resolved_method_;
-  ArenaVector<HUserRecord<HInstruction*>> inputs_;
   const uint32_t dex_method_index_;
   Intrinsics intrinsic_;
 
@@ -4184,10 +4206,6 @@
 
   DECLARE_INSTRUCTION(InvokeStaticOrDirect);
 
- protected:
-  void InsertInputAt(size_t index, HInstruction* input);
-  void RemoveInputAt(size_t index);
-
  private:
   static constexpr size_t kFieldClinitCheckRequirement = kNumberOfInvokePackedBits;
   static constexpr size_t kFieldClinitCheckRequirementSize =
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index ba7012a..0d0f62a 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1193,7 +1193,7 @@
   }
   uint8_t* stack_map_data = nullptr;
   uint8_t* roots_data = nullptr;
-  code_cache->ReserveData(
+  uint32_t data_size = code_cache->ReserveData(
       self, stack_map_size, number_of_roots, method, &stack_map_data, &roots_data);
   if (stack_map_data == nullptr || roots_data == nullptr) {
     return false;
@@ -1212,6 +1212,7 @@
       codegen->GetFpuSpillMask(),
       code_allocator.GetMemory().data(),
       code_allocator.GetSize(),
+      data_size,
       osr,
       roots,
       codegen->GetGraph()->HasShouldDeoptimizeFlag(),
diff --git a/compiler/optimizing/pretty_printer.h b/compiler/optimizing/pretty_printer.h
index 5891350..c6579dc 100644
--- a/compiler/optimizing/pretty_printer.h
+++ b/compiler/optimizing/pretty_printer.h
@@ -17,7 +17,8 @@
 #ifndef ART_COMPILER_OPTIMIZING_PRETTY_PRINTER_H_
 #define ART_COMPILER_OPTIMIZING_PRETTY_PRINTER_H_
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
 #include "nodes.h"
 
 namespace art {
@@ -108,7 +109,7 @@
       : HPrettyPrinter(graph), str_(""), current_block_(nullptr) { }
 
   void PrintInt(int value) OVERRIDE {
-    str_ += StringPrintf("%d", value);
+    str_ += android::base::StringPrintf("%d", value);
   }
 
   void PrintString(const char* value) OVERRIDE {
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index 951cdfb..1af94f3 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -15,7 +15,6 @@
  */
 
 #include "base/arena_allocator.h"
-#include "base/stringprintf.h"
 #include "builder.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index 4297634..f69f417 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
+#include "android-base/stringprintf.h"
+
 #include "base/arena_allocator.h"
-#include "base/stringprintf.h"
 #include "builder.h"
 #include "dex_file.h"
 #include "dex_instruction.h"
@@ -35,7 +36,7 @@
   explicit SsaPrettyPrinter(HGraph* graph) : HPrettyPrinter(graph), str_("") {}
 
   void PrintInt(int value) OVERRIDE {
-    str_ += StringPrintf("%d", value);
+    str_ += android::base::StringPrintf("%d", value);
   }
 
   void PrintString(const char* value) OVERRIDE {
diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc
index 30e8f4e..0147a76 100644
--- a/compiler/utils/arm/assembler_thumb2_test.cc
+++ b/compiler/utils/arm/assembler_thumb2_test.cc
@@ -16,12 +16,15 @@
 
 #include "assembler_thumb2.h"
 
+#include "android-base/stringprintf.h"
+
 #include "base/stl_util.h"
-#include "base/stringprintf.h"
 #include "utils/assembler_test.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 class AssemblerThumb2Test : public AssemblerTest<arm::Thumb2Assembler,
                                                  arm::Register, arm::SRegister,
                                                  uint32_t> {
diff --git a/compiler/utils/dedupe_set-inl.h b/compiler/utils/dedupe_set-inl.h
index ac54813..c06e9ca 100644
--- a/compiler/utils/dedupe_set-inl.h
+++ b/compiler/utils/dedupe_set-inl.h
@@ -23,10 +23,11 @@
 #include <inttypes.h>
 #include <unordered_map>
 
+#include "android-base/stringprintf.h"
+
 #include "base/mutex.h"
 #include "base/hash_set.h"
 #include "base/stl_util.h"
-#include "base/stringprintf.h"
 #include "base/time_utils.h"
 
 namespace art {
@@ -238,13 +239,13 @@
   for (HashType shard = 0; shard < kShard; ++shard) {
     shards_[shard]->UpdateStats(self, &stats);
   }
-  return StringPrintf("%zu collisions, %zu max hash collisions, "
-                      "%zu/%zu probe distance, %" PRIu64 " ns hash time",
-                      stats.collision_sum,
-                      stats.collision_max,
-                      stats.total_probe_distance,
-                      stats.total_size,
-                      hash_time_);
+  return android::base::StringPrintf("%zu collisions, %zu max hash collisions, "
+                                     "%zu/%zu probe distance, %" PRIu64 " ns hash time",
+                                     stats.collision_sum,
+                                     stats.collision_max,
+                                     stats.total_probe_distance,
+                                     stats.total_size,
+                                     hash_time_);
 }
 
 
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 5a0f0c6..2346635 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -33,6 +33,7 @@
 #include <sys/utsname.h>
 #endif
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
 #include "arch/instruction_set_features.h"
@@ -87,6 +88,9 @@
 
 namespace art {
 
+using android::base::StringAppendV;
+using android::base::StringPrintf;
+
 static constexpr size_t kDefaultMinDexFilesForSwap = 2;
 static constexpr size_t kDefaultMinDexFileCumulativeSizeForSwap = 20 * MB;
 
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index b6b62a8..cdb3b9f 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -19,11 +19,15 @@
 #include <string>
 #include <vector>
 
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "android-base/stringprintf.h"
+
 #include "common_runtime_test.h"
 
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/stringprintf.h"
 #include "dex_file-inl.h"
 #include "dex2oat_environment_test.h"
 #include "jit/offline_profiling_info.h"
@@ -31,9 +35,6 @@
 #include "oat_file.h"
 #include "utils.h"
 
-#include <sys/wait.h>
-#include <unistd.h>
-
 namespace art {
 
 class Dex2oatTest : public Dex2oatEnvironmentTest {
@@ -217,7 +218,7 @@
     std::unique_ptr<ScratchFile> sf;
     if (use_fd) {
       sf.reset(new ScratchFile());
-      copy.push_back(StringPrintf("--swap-fd=%d", sf->GetFd()));
+      copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd()));
     } else {
       std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
       copy.push_back("--swap-file=" + swap_location);
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 916984c..d5776fa 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -42,7 +42,8 @@
 #include <sstream>
 #include <vector>
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
 #include "dexdump_cfg.h"
 #include "dex_file-inl.h"
 #include "dex_file_types.h"
@@ -887,8 +888,10 @@
           const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
           const Signature signature = pDexFile->GetMethodSignature(pMethodId);
           const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
-          method = StringPrintf("%s.%s:%s",
-                                backDescriptor, name, signature.ToString().c_str());
+          method = android::base::StringPrintf("%s.%s:%s",
+                                               backDescriptor,
+                                               name,
+                                               signature.ToString().c_str());
         }
         if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
           const DexFile::ProtoId& protoId = pDexFile->GetProtoId(secondary_index);
diff --git a/dexdump/dexdump_test.cc b/dexdump/dexdump_test.cc
index d28ca28..53dda6a 100644
--- a/dexdump/dexdump_test.cc
+++ b/dexdump/dexdump_test.cc
@@ -21,7 +21,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "base/stringprintf.h"
 #include "common_runtime_test.h"
 #include "runtime/arch/instruction_set.h"
 #include "runtime/os.h"
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index cfe4837..cac6090 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -30,7 +30,8 @@
 #include <sstream>
 #include <vector>
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
 #include "dex_ir_builder.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
@@ -43,6 +44,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 /*
  * Flags for use with createAccessFlagStr().
  */
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 665baa6..46a1c43 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -21,7 +21,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 #include "common_runtime_test.h"
 #include "utils.h"
diff --git a/dexlist/dexlist_test.cc b/dexlist/dexlist_test.cc
index da1dd7f..1320942 100644
--- a/dexlist/dexlist_test.cc
+++ b/dexlist/dexlist_test.cc
@@ -21,7 +21,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "base/stringprintf.h"
 #include "common_runtime_test.h"
 #include "runtime/arch/instruction_set.h"
 #include "runtime/gc/heap.h"
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index a374686..f307cbc 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -26,9 +26,10 @@
 #include <map>
 #include <unordered_set>
 
+#include "android-base/stringprintf.h"
+
 #include "art_method-inl.h"
 #include "base/unix_file/fd_file.h"
-#include "base/stringprintf.h"
 #include "gc/space/image_space.h"
 #include "gc/heap.h"
 #include "mirror/class-inl.h"
@@ -46,6 +47,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 class ImgDiagDumper {
  public:
   explicit ImgDiagDumper(std::ostream* os,
diff --git a/imgdiag/imgdiag_test.cc b/imgdiag/imgdiag_test.cc
index 9f771ba..3f2afc0 100644
--- a/imgdiag/imgdiag_test.cc
+++ b/imgdiag/imgdiag_test.cc
@@ -20,12 +20,13 @@
 
 #include "common_runtime_test.h"
 
+#include "android-base/stringprintf.h"
+
 #include "runtime/os.h"
 #include "runtime/arch/instruction_set.h"
 #include "runtime/utils.h"
 #include "runtime/gc/space/image_space.h"
 #include "runtime/gc/heap.h"
-#include "base/stringprintf.h"
 
 #include <sys/types.h>
 #include <unistd.h>
@@ -57,7 +58,7 @@
 
   virtual void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE {
     // Needs to live until CommonRuntimeTest::SetUp finishes, since we pass it a cstring.
-    runtime_args_image_ = StringPrintf("-Ximage:%s", GetCoreArtLocation().c_str());
+    runtime_args_image_ = android::base::StringPrintf("-Ximage:%s", GetCoreArtLocation().c_str());
     options->push_back(std::make_pair(runtime_args_image_, nullptr));
   }
 
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 17b47a4..148ee88 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -26,6 +26,7 @@
 #include <unordered_set>
 #include <vector>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
 #include "arch/instruction_set_features.h"
@@ -76,6 +77,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 const char* image_methods_descriptions_[] = {
   "kResolutionMethod",
   "kImtConflictMethod",
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index a2eba45..e77d03b 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -22,7 +22,6 @@
 
 #include "common_runtime_test.h"
 
-#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 #include "runtime/arch/instruction_set.h"
 #include "runtime/gc/heap.h"
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 62d1ddf..7ae13a5 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
 #include "art_field-inl.h"
@@ -31,7 +32,6 @@
 #include "base/dumpable.h"
 #include "base/scoped_flock.h"
 #include "base/stringpiece.h"
-#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 #include "base/unix_file/random_access_file_utils.h"
 #include "elf_utils.h"
@@ -939,7 +939,7 @@
 
 static void UsageErrorV(const char* fmt, va_list ap) {
   std::string error;
-  StringAppendV(&error, fmt, ap);
+  android::base::StringAppendV(&error, fmt, ap);
   LOG(ERROR) << error;
 }
 
diff --git a/profman/profman.cc b/profman/profman.cc
index 0b2d172..e538407 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -25,12 +25,12 @@
 #include <string>
 #include <vector>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
 #include "base/dumpable.h"
 #include "base/scoped_flock.h"
 #include "base/stringpiece.h"
-#include "base/stringprintf.h"
 #include "base/time_utils.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file.h"
@@ -61,7 +61,7 @@
 
 static void UsageErrorV(const char* fmt, va_list ap) {
   std::string error;
-  StringAppendV(&error, fmt, ap);
+  android::base::StringAppendV(&error, fmt, ap);
   LOG(ERROR) << error;
 }
 
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 32ebee2..86019bf 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -40,7 +40,6 @@
         "base/scoped_arena_allocator.cc",
         "base/scoped_flock.cc",
         "base/stringpiece.cc",
-        "base/stringprintf.cc",
         "base/time_utils.cc",
         "base/timing_logger.cc",
         "base/unix_file/fd_file.cc",
@@ -508,7 +507,6 @@
         "base/histogram_test.cc",
         "base/mutex_test.cc",
         "base/scoped_flock_test.cc",
-        "base/stringprintf_test.cc",
         "base/time_utils_test.cc",
         "base/timing_logger_test.cc",
         "base/transform_array_ref_test.cc",
diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc
index f264b82..181b2ed 100644
--- a/runtime/arch/arm/instruction_set_features_arm.cc
+++ b/runtime/arch/arm/instruction_set_features_arm.cc
@@ -24,10 +24,10 @@
 #include "signal.h"
 #include <fstream>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
-#include "base/stringprintf.h"
-#include "utils.h"  // For Trim.
+#include "base/logging.h"
 
 #if defined(__arm__)
 extern "C" bool artCheckForArmSdivInstruction();
@@ -35,6 +35,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromVariant(
     const std::string& variant, std::string* error_msg) {
   // Assume all ARM processors are SMP.
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc
index f7b5a76..52d8b3e 100644
--- a/runtime/arch/arm64/instruction_set_features_arm64.cc
+++ b/runtime/arch/arm64/instruction_set_features_arm64.cc
@@ -19,14 +19,16 @@
 #include <fstream>
 #include <sstream>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
+#include "base/logging.h"
 #include "base/stl_util.h"
-#include "base/stringprintf.h"
-#include "utils.h"  // For Trim.
 
 namespace art {
 
+using android::base::StringPrintf;
+
 Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant(
     const std::string& variant, std::string* error_msg) {
   const bool smp = true;  // Conservative default.
diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc
index 0b8e531..d489392 100644
--- a/runtime/arch/instruction_set_features_test.cc
+++ b/runtime/arch/instruction_set_features_test.cc
@@ -22,11 +22,14 @@
 #include "android-base/properties.h"
 #endif
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
-#include "base/stringprintf.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 #ifdef ART_TARGET_ANDROID
 #if defined(__aarch64__)
 TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromSystemPropertyVariant) {
diff --git a/runtime/arch/instruction_set_test.cc b/runtime/arch/instruction_set_test.cc
index 5dfc4b4..5aae93a 100644
--- a/runtime/arch/instruction_set_test.cc
+++ b/runtime/arch/instruction_set_test.cc
@@ -19,7 +19,6 @@
 #include <gtest/gtest.h>
 
 #include "base/enums.h"
-#include "base/stringprintf.h"
 
 namespace art {
 
diff --git a/runtime/arch/mips/instruction_set_features_mips.cc b/runtime/arch/mips/instruction_set_features_mips.cc
index a65c967..5b50573 100644
--- a/runtime/arch/mips/instruction_set_features_mips.cc
+++ b/runtime/arch/mips/instruction_set_features_mips.cc
@@ -19,14 +19,16 @@
 #include <fstream>
 #include <sstream>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
+#include "base/logging.h"
 #include "base/stl_util.h"
-#include "base/stringprintf.h"
-#include "utils.h"  // For Trim.
 
 namespace art {
 
+using android::base::StringPrintf;
+
 // An enum for the Mips revision.
 enum class MipsLevel {
   kBase,
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.cc b/runtime/arch/mips64/instruction_set_features_mips64.cc
index e564d1e..92c44e8 100644
--- a/runtime/arch/mips64/instruction_set_features_mips64.cc
+++ b/runtime/arch/mips64/instruction_set_features_mips64.cc
@@ -19,13 +19,15 @@
 #include <fstream>
 #include <sstream>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
-#include "base/stringprintf.h"
-#include "utils.h"  // For Trim.
+#include "base/logging.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 Mips64FeaturesUniquePtr Mips64InstructionSetFeatures::FromVariant(
     const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED) {
   if (variant != "default" && variant != "mips64r6") {
diff --git a/runtime/arch/x86/instruction_set_features_x86.cc b/runtime/arch/x86/instruction_set_features_x86.cc
index cc102ec..c520d63 100644
--- a/runtime/arch/x86/instruction_set_features_x86.cc
+++ b/runtime/arch/x86/instruction_set_features_x86.cc
@@ -19,14 +19,16 @@
 #include <fstream>
 #include <sstream>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
 #include "arch/x86_64/instruction_set_features_x86_64.h"
-#include "base/stringprintf.h"
-#include "utils.h"  // For Trim.
+#include "base/logging.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 // Feature-support arrays.
 
 static constexpr const char* x86_known_variants[] = {
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 96b6f18..dfc7837 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -18,6 +18,8 @@
 
 #include <cstddef>
 
+#include "android-base/stringprintf.h"
+
 #include "arch/context.h"
 #include "art_field-inl.h"
 #include "art_method-inl.h"
@@ -46,6 +48,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
                                       const char*);
 extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 5ef1f06..e4972da 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -175,19 +175,19 @@
 #define MIRROR_CLASS_IF_TABLE_OFFSET (16 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_IF_TABLE_OFFSET,
             art::mirror::Class::IfTableOffset().Int32Value())
-#define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (64 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (56 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET,
             art::mirror::Class::AccessFlagsOffset().Int32Value())
-#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (96 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (88 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET,
             art::mirror::Class::ObjectSizeOffset().Int32Value())
-#define MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET (100 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET (92 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET,
             art::mirror::Class::ObjectSizeAllocFastPathOffset().Int32Value())
-#define MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET (104 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET (96 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET,
             art::mirror::Class::PrimitiveTypeOffset().Int32Value())
-#define MIRROR_CLASS_STATUS_OFFSET (112 + MIRROR_OBJECT_HEADER_SIZE)
+#define MIRROR_CLASS_STATUS_OFFSET (104 + MIRROR_OBJECT_HEADER_SIZE)
 ADD_TEST_EQ(MIRROR_CLASS_STATUS_OFFSET,
             art::mirror::Class::StatusOffset().Int32Value())
 
diff --git a/runtime/base/file_magic.cc b/runtime/base/file_magic.cc
index de6f423..568a7ae 100644
--- a/runtime/base/file_magic.cc
+++ b/runtime/base/file_magic.cc
@@ -20,13 +20,16 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file.h"
-#include "stringprintf.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 File OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg) {
   CHECK(magic != nullptr);
   File fd(filename, O_RDONLY, /* check_usage */ false);
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index 92b7c65..44a84c8 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -21,7 +21,6 @@
 
 #include "mutex.h"
 
-#include "base/stringprintf.h"
 #include "base/value_object.h"
 #include "thread.h"
 #include "utils.h"
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index ce452cb..9116097 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -19,6 +19,8 @@
 #include <errno.h>
 #include <sys/time.h>
 
+#include "android-base/stringprintf.h"
+
 #include "atomic.h"
 #include "base/logging.h"
 #include "base/time_utils.h"
@@ -30,6 +32,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static Atomic<Locks::ClientCallback*> safe_to_call_abort_callback(nullptr);
 
 Mutex* Locks::abort_lock_ = nullptr;
diff --git a/runtime/base/scoped_flock.cc b/runtime/base/scoped_flock.cc
index 0e8031f..d4bb56b 100644
--- a/runtime/base/scoped_flock.cc
+++ b/runtime/base/scoped_flock.cc
@@ -19,12 +19,15 @@
 #include <sys/file.h>
 #include <sys/stat.h>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
-#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 bool ScopedFlock::Init(const char* filename, std::string* error_msg) {
   return Init(filename, O_CREAT | O_RDWR, true, error_msg);
 }
diff --git a/runtime/base/stringprintf.cc b/runtime/base/stringprintf.cc
deleted file mode 100644
index 8fd9257..0000000
--- a/runtime/base/stringprintf.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "stringprintf.h"
-
-#include <stdio.h>
-
-namespace art {
-
-void StringAppendV(std::string* dst, const char* format, va_list ap) {
-  // First try with a small fixed size buffer
-  char space[1024];
-
-  // It's possible for methods that use a va_list to invalidate
-  // the data in it upon use.  The fix is to make a copy
-  // of the structure before using it and use that copy instead.
-  va_list backup_ap;
-  va_copy(backup_ap, ap);
-  int result = vsnprintf(space, sizeof(space), format, backup_ap);
-  va_end(backup_ap);
-
-  if (result < static_cast<int>(sizeof(space))) {
-    if (result >= 0) {
-      // Normal case -- everything fit.
-      dst->append(space, result);
-      return;
-    }
-
-    if (result < 0) {
-      // Just an error.
-      return;
-    }
-  }
-
-  // Increase the buffer size to the size requested by vsnprintf,
-  // plus one for the closing \0.
-  int length = result+1;
-  char* buf = new char[length];
-
-  // Restore the va_list before we use it again
-  va_copy(backup_ap, ap);
-  result = vsnprintf(buf, length, format, backup_ap);
-  va_end(backup_ap);
-
-  if (result >= 0 && result < length) {
-    // It fit
-    dst->append(buf, result);
-  }
-  delete[] buf;
-}
-
-std::string StringPrintf(const char* fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  std::string result;
-  StringAppendV(&result, fmt, ap);
-  va_end(ap);
-  return result;
-}
-
-void StringAppendF(std::string* dst, const char* format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  StringAppendV(dst, format, ap);
-  va_end(ap);
-}
-
-}  // namespace art
diff --git a/runtime/base/stringprintf.h b/runtime/base/stringprintf.h
deleted file mode 100644
index 4767a75..0000000
--- a/runtime/base/stringprintf.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_BASE_STRINGPRINTF_H_
-#define ART_RUNTIME_BASE_STRINGPRINTF_H_
-
-#include <stdarg.h>
-#include <string>
-
-namespace art {
-
-// Returns a string corresponding to printf-like formatting of the arguments.
-std::string StringPrintf(const char* fmt, ...)
-        __attribute__((__format__(__printf__, 1, 2)));
-
-// Appends a printf-like formatting of the arguments to 'dst'.
-void StringAppendF(std::string* dst, const char* fmt, ...)
-        __attribute__((__format__(__printf__, 2, 3)));
-
-// Appends a printf-like formatting of the arguments to 'dst'.
-void StringAppendV(std::string* dst, const char* format, va_list ap);
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_BASE_STRINGPRINTF_H_
diff --git a/runtime/base/time_utils.cc b/runtime/base/time_utils.cc
index 57f198d..3c09d5a 100644
--- a/runtime/base/time_utils.cc
+++ b/runtime/base/time_utils.cc
@@ -20,8 +20,9 @@
 
 #include "time_utils.h"
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
-#include "base/stringprintf.h"
 
 #if defined(__APPLE__)
 #include <sys/time.h>
@@ -29,6 +30,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits) {
   if (nano_duration == 0) {
     return "0";
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 6c27bc6..1c3328e 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -20,6 +20,8 @@
 #include <sys/mman.h>
 #include <zlib.h>
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/logging.h"
@@ -42,6 +44,9 @@
 
 namespace art {
 
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+
 /*
  * ===========================================================================
  *      JNI function helpers
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 213986a..a11257f 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -73,7 +73,7 @@
   // MethodVerifier refuses methods with string_idx out of bounds.
   DCHECK_LT(string_idx.index_, declaring_class->GetDexFile().NumStringIds());
   ObjPtr<mirror::String> string =
-        mirror::StringDexCachePair::Lookup(declaring_class->GetDexCacheStrings(),
+        mirror::StringDexCachePair::Lookup(declaring_class->GetDexCache()->GetStrings(),
                                            string_idx.index_,
                                            mirror::DexCache::kDexCacheStringCacheSize).Read();
   if (UNLIKELY(string == nullptr)) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 6565f6b..20aaa42 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -28,6 +28,8 @@
 #include <utility>
 #include <vector>
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/arena_allocator.h"
@@ -106,6 +108,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static constexpr bool kSanityCheckObjects = kIsDebugBuild;
 static constexpr bool kVerifyArtMethodDeclaringClasses = kIsDebugBuild;
 
@@ -1401,39 +1405,20 @@
   return true;
 }
 
-// Update the class loader and resolved string dex cache array of classes. Should only be used on
-// classes in the image space.
-class UpdateClassLoaderAndResolvedStringsVisitor {
+// Update the class loader. Should only be used on classes in the image space.
+class UpdateClassLoaderVisitor {
  public:
-  UpdateClassLoaderAndResolvedStringsVisitor(gc::space::ImageSpace* space,
-                                             ObjPtr<mirror::ClassLoader> class_loader,
-                                             bool forward_strings)
+  UpdateClassLoaderVisitor(gc::space::ImageSpace* space, ObjPtr<mirror::ClassLoader> class_loader)
       : space_(space),
-        class_loader_(class_loader),
-        forward_strings_(forward_strings) {}
+        class_loader_(class_loader) {}
 
   bool operator()(ObjPtr<mirror::Class> klass) const REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (forward_strings_) {
-      mirror::StringDexCacheType* strings = klass->GetDexCacheStrings();
-      if (strings != nullptr) {
-        DCHECK(
-            space_->GetImageHeader().GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains(
-                reinterpret_cast<uint8_t*>(strings) - space_->Begin()))
-            << "String dex cache array for " << klass->PrettyClass() << " is not in app image";
-        // Dex caches have already been updated, so take the strings pointer from there.
-        mirror::StringDexCacheType* new_strings = klass->GetDexCache()->GetStrings();
-        DCHECK_NE(strings, new_strings);
-        klass->SetDexCacheStrings(new_strings);
-      }
-    }
-    // Finally, update class loader.
     klass->SetClassLoader(class_loader_);
     return true;
   }
 
   gc::space::ImageSpace* const space_;
   ObjPtr<mirror::ClassLoader> const class_loader_;
-  const bool forward_strings_;
 };
 
 static std::unique_ptr<const DexFile> OpenOatDexFile(const OatFile* oat_file,
@@ -1860,10 +1845,8 @@
     }
     // Update class loader and resolved strings. If added_class_table is false, the resolved
     // strings were forwarded UpdateAppImageClassLoadersAndDexCaches.
-    UpdateClassLoaderAndResolvedStringsVisitor visitor(space,
-                                                       class_loader.Get(),
-                                                       forward_dex_cache_arrays);
-    for (ClassTable::TableSlot& root : temp_set) {
+    UpdateClassLoaderVisitor visitor(space, class_loader.Get());
+    for (const ClassTable::TableSlot& root : temp_set) {
       visitor(root.Read());
     }
     // forward_dex_cache_arrays is true iff we copied all of the dex cache arrays into the .bss.
@@ -2663,6 +2646,8 @@
 
   ObjectLock<mirror::Class> lock(self, klass);
   klass->SetClinitThreadId(self->GetTid());
+  // Make sure we have a valid empty iftable even if there are errors.
+  klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
 
   // Add the newly loaded class to the loaded classes table.
   ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash);
@@ -3014,7 +2999,6 @@
 
   klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
   klass->SetDexTypeIndex(dex_class_def.class_idx_);
-  CHECK(klass->GetDexCacheStrings() != nullptr);
 }
 
 void ClassLinker::LoadClass(Thread* self,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 685677b..42108d8 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -278,8 +278,6 @@
     EXPECT_FALSE(klass->IsArrayClass());
     EXPECT_TRUE(klass->GetComponentType() == nullptr);
     EXPECT_TRUE(klass->IsInSamePackage(klass.Get()));
-    EXPECT_TRUE(klass->GetDexCacheStrings() != nullptr);
-    EXPECT_EQ(klass->GetDexCacheStrings(), klass->GetDexCache()->GetStrings());
     std::string temp2;
     EXPECT_TRUE(mirror::Class::IsInSamePackage(klass->GetDescriptor(&temp),
                                                klass->GetDescriptor(&temp2)));
@@ -590,7 +588,6 @@
     addOffset(OFFSETOF_MEMBER(mirror::Class, component_type_), "componentType");
     addOffset(OFFSETOF_MEMBER(mirror::Class, copied_methods_offset_), "copiedMethodsOffset");
     addOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_), "dexCache");
-    addOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_strings_), "dexCacheStrings");
     addOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex");
     addOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex");
     addOffset(OFFSETOF_MEMBER(mirror::Class, ext_data_), "extData");
@@ -1175,6 +1172,24 @@
   EXPECT_TRUE(init->IsInitialized());
 }
 
+TEST_F(ClassLinkerTest, ErroneousClass) {
+  ScopedObjectAccess soa(Thread::Current());
+  jobject jclass_loader = LoadMultiDex("ErroneousA", "ErroneousB");
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
+  hs.Self()->AssertNoPendingException();
+  const char* descriptor = "LErroneous;";
+  ObjPtr<mirror::Class> klass = class_linker_->FindClass(soa.Self(), descriptor, class_loader);
+  // Erronenous since we are extending final class.
+  hs.Self()->AssertPendingException();
+  EXPECT_TRUE(klass == nullptr);
+  klass = class_linker_->LookupClass(soa.Self(), descriptor, class_loader.Get());
+  EXPECT_FALSE(klass == nullptr);
+  EXPECT_TRUE(klass->IsErroneous());
+  EXPECT_TRUE(klass->GetIfTable() != nullptr);
+}
+
 TEST_F(ClassLinkerTest, FinalizableBit) {
   ScopedObjectAccess soa(Thread::Current());
   mirror::Class* c;
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 8226e60..743fcc8 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -24,11 +24,12 @@
 #include <stdlib.h>
 
 #include "../../external/icu/icu4c/source/common/unicode/uvernum.h"
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "base/macros.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
-#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "compiler_callbacks.h"
@@ -65,6 +66,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 ScratchFile::ScratchFile() {
   // ANDROID_DATA needs to be set
   CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 9f0dbbb..c30272e 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -18,6 +18,7 @@
 
 #include <sstream>
 
+#include "android-base/stringprintf.h"
 #include "ScopedLocalRef.h"
 
 #include "art_field-inl.h"
@@ -37,6 +38,9 @@
 
 namespace art {
 
+using android::base::StringAppendV;
+using android::base::StringPrintf;
+
 static void AddReferrerLocation(std::ostream& os, ObjPtr<mirror::Class> referrer)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (referrer != nullptr) {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index e339666..df4413d 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -20,6 +20,8 @@
 
 #include <set>
 
+#include "android-base/stringprintf.h"
+
 #include "arch/context.h"
 #include "art_field-inl.h"
 #include "art_method-inl.h"
@@ -61,6 +63,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 // The key identifying the debugger to update instrumentation.
 static constexpr const char* kDbgInstrumentationKey = "Debugger";
 
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index aa8fb38..7d704ad 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -28,10 +28,11 @@
 #include <sstream>
 #include <type_traits>
 
+#include "android-base/stringprintf.h"
+
 #include "base/enums.h"
 #include "base/file_magic.h"
 #include "base/logging.h"
-#include "base/stringprintf.h"
 #include "base/systrace.h"
 #include "base/unix_file/fd_file.h"
 #include "dex_file-inl.h"
@@ -45,6 +46,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static_assert(sizeof(dex::StringIndex) == sizeof(uint32_t), "StringIndex size is wrong");
 static_assert(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex not trivial");
 static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 52b9f11..9504e8b 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -18,6 +18,8 @@
 
 #include <stdlib.h>
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "class_linker-inl.h"
@@ -31,6 +33,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 struct DexFile::AnnotationValue {
   JValue value_;
   uint8_t type_;
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 07f0fca..a3ab9fa 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -22,7 +22,8 @@
 #include <limits>
 #include <memory>
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
 #include "dex_file-inl.h"
 #include "experimental_flags.h"
 #include "leb128.h"
@@ -32,6 +33,9 @@
 
 namespace art {
 
+using android::base::StringAppendV;
+using android::base::StringPrintf;
+
 static constexpr uint32_t kTypeIdLimit = std::numeric_limits<uint16_t>::max();
 
 static bool IsValidOrNoTypeId(uint16_t low, uint16_t high) {
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index 9902389..7b8974f 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -21,12 +21,15 @@
 #include <iomanip>
 #include <sstream>
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
 #include "dex_file-inl.h"
 #include "utils.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 const char* const Instruction::kInstructionNames[] = {
 #define INSTRUCTION_NAME(o, c, pname, f, i, a, v) pname,
 #include "dex_instruction_list.h"
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index ee0f340..59b734f 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -20,11 +20,11 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
 #include "arch/instruction_set.h"
 #include "base/logging.h"
-#include "base/stringprintf.h"
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "elf_file_impl.h"
@@ -34,6 +34,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 template <typename ElfTypes>
 ElfFileImpl<ElfTypes>::ElfFileImpl(File* file, bool writable,
                                    bool program_header_only,
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index f4d0bc7..eb9f039 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -16,8 +16,9 @@
 
 #include "space_bitmap-inl.h"
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
-#include "base/stringprintf.h"
 #include "dex_file-inl.h"
 #include "mem_map.h"
 #include "mirror/object-inl.h"
@@ -28,6 +29,8 @@
 namespace gc {
 namespace accounting {
 
+using android::base::StringPrintf;
+
 template<size_t kAlignment>
 size_t SpaceBitmap<kAlignment>::ComputeBitmapSize(uint64_t capacity) {
   const uint64_t kBytesCoveredPerWord = kAlignment * kBitsPerIntPtrT;
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 2e4475f..35a251f 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -16,6 +16,13 @@
 
 #include "rosalloc.h"
 
+#include <map>
+#include <list>
+#include <sstream>
+#include <vector>
+
+#include "android-base/stringprintf.h"
+
 #include "base/memory_tool.h"
 #include "base/mutex-inl.h"
 #include "gc/space/memory_tool_settings.h"
@@ -26,15 +33,12 @@
 #include "thread-inl.h"
 #include "thread_list.h"
 
-#include <map>
-#include <list>
-#include <sstream>
-#include <vector>
-
 namespace art {
 namespace gc {
 namespace allocator {
 
+using android::base::StringPrintf;
+
 static constexpr bool kUsePrefetchDuringAllocRun = false;
 static constexpr bool kPrefetchNewRunDataByZeroing = false;
 static constexpr size_t kPrefetchStride = 64;
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index ed16854..01bcb7d 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -18,6 +18,8 @@
 
 #include "garbage_collector.h"
 
+#include "android-base/stringprintf.h"
+
 #include "base/dumpable.h"
 #include "base/histogram-inl.h"
 #include "base/logging.h"
@@ -81,7 +83,7 @@
 }
 
 void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) {
-  ScopedTrace trace(StringPrintf("%s %s GC", PrettyCause(gc_cause), GetName()));
+  ScopedTrace trace(android::base::StringPrintf("%s %s GC", PrettyCause(gc_cause), GetName()));
   Thread* self = Thread::Current();
   uint64_t start_time = NanoTime();
   Iteration* current_iteration = GetCurrentIteration();
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 3ed138c..34d8284 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -21,6 +21,8 @@
 #include <unwind.h>  // For GC verification.
 #include <vector>
 
+#include "android-base/stringprintf.h"
+
 #include "allocation_listener.h"
 #include "art_field-inl.h"
 #include "base/allocator.h"
@@ -82,6 +84,8 @@
 
 namespace gc {
 
+using android::base::StringPrintf;
+
 static constexpr size_t kCollectorTransitionStressIterations = 0;
 static constexpr size_t kCollectorTransitionStressWait = 10 * 1000;  // Microseconds
 // Minimum amount of remaining bytes before a concurrent GC is triggered.
@@ -3919,7 +3923,7 @@
       ScopedObjectAccess soa(env);
       env->ThrowNew(WellKnownClasses::java_lang_RuntimeException,
                     StringPrintf("Attempted to free %zd native bytes with only %zd native bytes "
-                                 "registered as allocated", bytes, expected_size).c_str());
+                    "registered as allocated", bytes, expected_size).c_str());
       break;
     }
   } while (!native_bytes_allocated_.CompareExchangeWeakRelaxed(expected_size,
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 76f3692..e03958d 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
 #include "art_method.h"
@@ -45,6 +46,9 @@
 namespace gc {
 namespace space {
 
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+
 Atomic<uint32_t> ImageSpace::bitmap_index_(0);
 
 ImageSpace::ImageSpace(const std::string& image_filename,
diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h
index fa941c0..5999548 100644
--- a/runtime/gc/space/image_space_fs.h
+++ b/runtime/gc/space/image_space_fs.h
@@ -20,9 +20,10 @@
 #include <dirent.h>
 #include <dlfcn.h>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 #include "globals.h"
 #include "os.h"
@@ -56,7 +57,7 @@
       continue;
     }
     // We only want to delete regular files and symbolic links.
-    std::string file = StringPrintf("%s/%s", dir.c_str(), name);
+    std::string file = android::base::StringPrintf("%s/%s", dir.c_str(), name);
     if (de->d_type != DT_REG && de->d_type != DT_LNK) {
       if (de->d_type == DT_DIR) {
         if (recurse) {
diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc
index b1572cc..a186f4c 100644
--- a/runtime/gc/space/malloc_space.cc
+++ b/runtime/gc/space/malloc_space.cc
@@ -16,6 +16,8 @@
 
 #include "malloc_space.h"
 
+#include "android-base/stringprintf.h"
+
 #include "gc/accounting/card_table-inl.h"
 #include "gc/accounting/space_bitmap-inl.h"
 #include "gc/heap.h"
@@ -33,6 +35,8 @@
 namespace gc {
 namespace space {
 
+using android::base::StringPrintf;
+
 size_t MallocSpace::bitmap_index_ = 0;
 
 MallocSpace::MallocSpace(const std::string& name, MemMap* mem_map,
diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h
index f13ff8c..bebcd71 100644
--- a/runtime/generated/asm_support_gen.h
+++ b/runtime/generated/asm_support_gen.h
@@ -74,8 +74,6 @@
 DEFINE_CHECK_EQ(static_cast<int32_t>(ART_METHOD_QUICK_CODE_OFFSET_64), (static_cast<int32_t>(art::ArtMethod:: EntryPointFromQuickCompiledCodeOffset(art::PointerSize::k64).Int32Value())))
 #define ART_METHOD_DECLARING_CLASS_OFFSET 0
 DEFINE_CHECK_EQ(static_cast<int32_t>(ART_METHOD_DECLARING_CLASS_OFFSET), (static_cast<int32_t>(art::ArtMethod:: DeclaringClassOffset().Int32Value())))
-#define DECLARING_CLASS_DEX_CACHE_STRINGS_OFFSET 40
-DEFINE_CHECK_EQ(static_cast<int32_t>(DECLARING_CLASS_DEX_CACHE_STRINGS_OFFSET), (static_cast<int32_t>(art::mirror::Class:: DexCacheStringsOffset().Int32Value())))
 #define STRING_DEX_CACHE_ELEMENT_SIZE_SHIFT 3
 DEFINE_CHECK_EQ(static_cast<int32_t>(STRING_DEX_CACHE_ELEMENT_SIZE_SHIFT), (static_cast<int32_t>(art::WhichPowerOf2(sizeof(art::mirror::StringDexCachePair)))))
 #define STRING_DEX_CACHE_SIZE_MINUS_ONE 1023
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 8cbe491..fe6a6e9 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -37,9 +37,10 @@
 
 #include <set>
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "base/logging.h"
-#include "base/stringprintf.h"
 #include "base/time_utils.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
@@ -797,8 +798,9 @@
       file->Erase();
     }
     if (!okay) {
-      std::string msg(StringPrintf("Couldn't dump heap; writing \"%s\" failed: %s",
-                                   filename_.c_str(), strerror(errno)));
+      std::string msg(android::base::StringPrintf("Couldn't dump heap; writing \"%s\" failed: %s",
+                                                  filename_.c_str(),
+                                                  strerror(errno)));
       ThrowRuntimeException("%s", msg.c_str());
       LOG(ERROR) << msg;
     }
diff --git a/runtime/image.cc b/runtime/image.cc
index 52c9f4e..2ef60c3 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -25,7 +25,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '3', '3', '\0' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '3', '4', '\0' };  // mirror::Class update
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h
index 9c634fa..0e66ae9 100644
--- a/runtime/indirect_reference_table-inl.h
+++ b/runtime/indirect_reference_table-inl.h
@@ -19,6 +19,8 @@
 
 #include "indirect_reference_table.h"
 
+#include "android-base/stringprintf.h"
+
 #include "base/dumpable.h"
 #include "gc_root-inl.h"
 #include "obj_ptr-inl.h"
@@ -38,15 +40,15 @@
     return false;
   }
   if (UNLIKELY(GetIndirectRefKind(iref) == kHandleScopeOrInvalid)) {
-    AbortIfNoCheckJNI(StringPrintf("JNI ERROR (app bug): invalid %s %p",
-                                   GetIndirectRefKindString(kind_),
-                                   iref));
+    AbortIfNoCheckJNI(android::base::StringPrintf("JNI ERROR (app bug): invalid %s %p",
+                                                  GetIndirectRefKindString(kind_),
+                                                  iref));
     return false;
   }
   const uint32_t top_index = segment_state_.top_index;
   uint32_t idx = ExtractIndex(iref);
   if (UNLIKELY(idx >= top_index)) {
-    std::string msg = StringPrintf(
+    std::string msg = android::base::StringPrintf(
         "JNI ERROR (app bug): accessed stale %s %p  (index %d in a table of size %d)",
         GetIndirectRefKindString(kind_),
         iref,
@@ -56,9 +58,9 @@
     return false;
   }
   if (UNLIKELY(table_[idx].GetReference()->IsNull())) {
-    AbortIfNoCheckJNI(StringPrintf("JNI ERROR (app bug): accessed deleted %s %p",
-                                   GetIndirectRefKindString(kind_),
-                                   iref));
+    AbortIfNoCheckJNI(android::base::StringPrintf("JNI ERROR (app bug): accessed deleted %s %p",
+                                                  GetIndirectRefKindString(kind_),
+                                                  iref));
     return false;
   }
   if (UNLIKELY(!CheckEntry("use", iref, idx))) {
@@ -73,7 +75,7 @@
                                                uint32_t idx) const {
   IndirectRef checkRef = ToIndirectRef(idx);
   if (UNLIKELY(checkRef != iref)) {
-    std::string msg = StringPrintf(
+    std::string msg = android::base::StringPrintf(
         "JNI ERROR (app bug): attempt to %s stale %s %p (should be %p)",
         what,
         GetIndirectRefKindString(kind_),
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 722b411..bf4cab2 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -16,6 +16,8 @@
 
 #include "indirect_reference_table-inl.h"
 
+#include "android-base/stringprintf.h"
+
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "mirror/object-inl.h"
@@ -23,6 +25,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 class IndirectReferenceTableTest : public CommonRuntimeTest {};
 
 static void CheckDump(IndirectReferenceTable* irt, size_t num_objects, size_t num_unique)
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 870d1ae..03ef962 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -1098,10 +1098,14 @@
                     Dbg::IsForcedInterpreterNeededForUpcall(self, visitor.caller));
   if (deoptimize && Runtime::Current()->IsDeoptimizeable(*return_pc)) {
     if (kVerboseInstrumentation) {
-      LOG(INFO) << StringPrintf("Deoptimizing %s by returning from %s with result %#" PRIx64 " in ",
-                                visitor.caller->PrettyMethod().c_str(),
-                                method->PrettyMethod().c_str(),
-                                return_value.GetJ()) << *self;
+      LOG(INFO) << "Deoptimizing "
+                << visitor.caller->PrettyMethod()
+                << " by returning from "
+                << method->PrettyMethod()
+                << " with result "
+                << std::hex << return_value.GetJ() << std::dec
+                << " in "
+                << *self;
     }
     self->PushDeoptimizationContext(return_value,
                                     return_shorty == 'L',
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 22da07d..a09e71b 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -676,7 +676,7 @@
   CHECK(Runtime::Current()->IsActiveTransaction());
   // Constructs abort message.
   std::string abort_msg;
-  StringAppendV(&abort_msg, fmt, args);
+  android::base::StringAppendV(&abort_msg, fmt, args);
   // Throws an exception so we can abort the transaction and rollback every change.
   Runtime::Current()->AbortTransactionAndThrowAbortError(self, abort_msg);
 }
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index c9a5b44..423f054 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -25,6 +25,8 @@
 #include <sstream>
 #include <atomic>
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/enums.h"
@@ -254,7 +256,7 @@
   DCHECK_LT(string_idx.index_ % mirror::DexCache::kDexCacheStringCacheSize,
             declaring_class->GetDexFile().NumStringIds());
   ObjPtr<mirror::String> string_ptr =
-      mirror::StringDexCachePair::Lookup(declaring_class->GetDexCacheStrings(),
+      mirror::StringDexCachePair::Lookup(declaring_class->GetDexCache()->GetStrings(),
                                          string_idx.index_,
                                          mirror::DexCache::kDexCacheStringCacheSize).Read();
   if (UNLIKELY(string_ptr == nullptr)) {
@@ -430,12 +432,12 @@
 #define TRACE_LOG std::cerr
     std::ostringstream oss;
     oss << shadow_frame.GetMethod()->PrettyMethod()
-        << StringPrintf("\n0x%x: ", dex_pc)
+        << android::base::StringPrintf("\n0x%x: ", dex_pc)
         << inst->DumpString(shadow_frame.GetMethod()->GetDexFile()) << "\n";
     for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
       uint32_t raw_value = shadow_frame.GetVReg(i);
       ObjPtr<mirror::Object> ref_value = shadow_frame.GetVRegReference(i);
-      oss << StringPrintf(" vreg%u=0x%08X", i, raw_value);
+      oss << android::base::StringPrintf(" vreg%u=0x%08X", i, raw_value);
       if (ref_value != nullptr) {
         if (ref_value->GetClass()->IsStringClass() &&
             !ref_value->AsString()->IsValueNull()) {
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index a5b1038..7dd3d3d 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -25,6 +25,7 @@
 #include <locale>
 #include <unordered_map>
 
+#include "android-base/stringprintf.h"
 #include "ScopedLocalRef.h"
 
 #include "art_method-inl.h"
@@ -56,6 +57,9 @@
 namespace art {
 namespace interpreter {
 
+using android::base::StringAppendV;
+using android::base::StringPrintf;
+
 static void AbortTransactionOrFail(Thread* self, const char* fmt, ...)
     __attribute__((__format__(__printf__, 2, 3)))
     REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index caf705a..f80c43d 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -18,6 +18,8 @@
 
 #include <dlfcn.h>
 
+#include "android-base/stringprintf.h"
+
 #include "art_method.h"
 #include "base/dumpable.h"
 #include "base/mutex.h"
@@ -42,6 +44,9 @@
 
 namespace art {
 
+using android::base::StringAppendF;
+using android::base::StringAppendV;
+
 static constexpr size_t kGlobalsMax = 51200;  // Arbitrary sanity check. (Must fit in 16 bits.)
 
 static constexpr size_t kWeakGlobalsMax = 51200;  // Arbitrary sanity check. (Must fit in 16 bits.)
diff --git a/runtime/jdwp/jdwp_adb.cc b/runtime/jdwp/jdwp_adb.cc
index e9d6d07..0eff2ab 100644
--- a/runtime/jdwp/jdwp_adb.cc
+++ b/runtime/jdwp/jdwp_adb.cc
@@ -20,8 +20,9 @@
 #include <sys/un.h>
 #include <unistd.h>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
-#include "base/stringprintf.h"
 #include "jdwp/jdwp_priv.h"
 
 #ifdef ART_TARGET_ANDROID
@@ -52,6 +53,8 @@
 
 namespace JDWP {
 
+using android::base::StringPrintf;
+
 struct JdwpAdbState : public JdwpNetStateBase {
  public:
   explicit JdwpAdbState(JdwpState* state) : JdwpNetStateBase(state) {
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index 5574a11..172f52a 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -21,10 +21,11 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/logging.h"
-#include "base/stringprintf.h"
 #include "debugger.h"
 #include "jdwp/jdwp_constants.h"
 #include "jdwp/jdwp_expand_buf.h"
@@ -103,6 +104,8 @@
 
 namespace JDWP {
 
+using android::base::StringPrintf;
+
 /*
  * Stuff to compare against when deciding if a mod matches.  Only the
  * values for mods valid for the event being evaluated will be filled in.
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index 0f2d188..964c567 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -20,11 +20,12 @@
 #include <memory>
 #include <string>
 
+#include "android-base/stringprintf.h"
+
 #include "atomic.h"
 #include "base/hex_dump.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/stringprintf.h"
 #include "debugger.h"
 #include "jdwp/jdwp_constants.h"
 #include "jdwp/jdwp_event.h"
@@ -39,6 +40,8 @@
 
 namespace JDWP {
 
+using android::base::StringPrintf;
+
 std::string DescribeField(const FieldId& field_id) {
   return StringPrintf("%#" PRIx64 " (%s)", field_id, Dbg::GetFieldName(field_id).c_str());
 }
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index e3bf3e5..7707ba4 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -20,6 +20,8 @@
 #include <time.h>
 #include <unistd.h>
 
+#include "android-base/stringprintf.h"
+
 #include "atomic.h"
 #include "base/logging.h"
 #include "base/time_utils.h"
@@ -31,6 +33,8 @@
 
 namespace JDWP {
 
+using android::base::StringPrintf;
+
 static void* StartJdwpThread(void* arg);
 
 /*
diff --git a/runtime/jdwp/jdwp_request.cc b/runtime/jdwp/jdwp_request.cc
index 18f40a1..6af267e 100644
--- a/runtime/jdwp/jdwp_request.cc
+++ b/runtime/jdwp/jdwp_request.cc
@@ -18,7 +18,8 @@
 
 #include <inttypes.h>
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
 #include "jdwp/jdwp_priv.h"
 
 namespace art {
@@ -100,7 +101,7 @@
 
 ObjectId Request::ReadObjectId(const char* specific_kind) {
   ObjectId id = Read8BE();
-  VLOG(jdwp) << StringPrintf("    %s id %#" PRIx64, specific_kind, id);
+  VLOG(jdwp) << android::base::StringPrintf("    %s id %#" PRIx64, specific_kind, id);
   return id;
 }
 
diff --git a/runtime/jdwp/jdwp_socket.cc b/runtime/jdwp/jdwp_socket.cc
index 3be7fd6..97662f0 100644
--- a/runtime/jdwp/jdwp_socket.cc
+++ b/runtime/jdwp/jdwp_socket.cc
@@ -26,8 +26,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
-#include "base/stringprintf.h"
 #include "jdwp/jdwp_priv.h"
 
 namespace art {
@@ -500,7 +501,7 @@
    */
   if (IsAwaitingHandshake()) {
     if (memcmp(input_buffer_, kMagicHandshake, kMagicHandshakeLen) != 0) {
-      LOG(ERROR) << StringPrintf("ERROR: bad handshake '%.14s'", input_buffer_);
+      LOG(ERROR) << android::base::StringPrintf("ERROR: bad handshake '%.14s'", input_buffer_);
       goto fail;
     }
 
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 1b0ad83..f43e30d 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -217,6 +217,7 @@
                                   size_t fp_spill_mask,
                                   const uint8_t* code,
                                   size_t code_size,
+                                  size_t data_size,
                                   bool osr,
                                   Handle<mirror::ObjectArray<mirror::Object>> roots,
                                   bool has_should_deoptimize_flag,
@@ -230,6 +231,7 @@
                                        fp_spill_mask,
                                        code,
                                        code_size,
+                                       data_size,
                                        osr,
                                        roots,
                                        has_should_deoptimize_flag,
@@ -246,6 +248,7 @@
                                 fp_spill_mask,
                                 code,
                                 code_size,
+                                data_size,
                                 osr,
                                 roots,
                                 has_should_deoptimize_flag,
@@ -513,6 +516,7 @@
                                           size_t fp_spill_mask,
                                           const uint8_t* code,
                                           size_t code_size,
+                                          size_t data_size,
                                           bool osr,
                                           Handle<mirror::ObjectArray<mirror::Object>> roots,
                                           bool has_should_deoptimize_flag,
@@ -547,6 +551,11 @@
           core_spill_mask,
           fp_spill_mask,
           code_size);
+      DCHECK_EQ(FromStackMapToRoots(stack_map), roots_data);
+      DCHECK_LE(roots_data, stack_map);
+      // Flush data cache, as compiled code references literals in it.
+      FlushDataCache(reinterpret_cast<char*>(roots_data),
+                     reinterpret_cast<char*>(roots_data + data_size));
       // Flush caches before we remove write permission because on some ARMv8 hardware,
       // flushing caches require write permissions.
       //
@@ -657,12 +666,12 @@
   FreeData(reinterpret_cast<uint8_t*>(roots_data));
 }
 
-void JitCodeCache::ReserveData(Thread* self,
-                               size_t stack_map_size,
-                               size_t number_of_roots,
-                               ArtMethod* method,
-                               uint8_t** stack_map_data,
-                               uint8_t** roots_data) {
+size_t JitCodeCache::ReserveData(Thread* self,
+                                 size_t stack_map_size,
+                                 size_t number_of_roots,
+                                 ArtMethod* method,
+                                 uint8_t** stack_map_data,
+                                 uint8_t** roots_data) {
   size_t table_size = ComputeRootTableSize(number_of_roots);
   size_t size = RoundUp(stack_map_size + table_size, sizeof(void*));
   uint8_t* result = nullptr;
@@ -695,9 +704,11 @@
     *roots_data = result;
     *stack_map_data = result + table_size;
     FillRootTableLength(*roots_data, number_of_roots);
+    return size;
   } else {
     *roots_data = nullptr;
     *stack_map_data = nullptr;
+    return 0;
   }
 }
 
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 30e2efb..d97742d 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -106,6 +106,7 @@
                       size_t fp_spill_mask,
                       const uint8_t* code,
                       size_t code_size,
+                      size_t data_size,
                       bool osr,
                       Handle<mirror::ObjectArray<mirror::Object>> roots,
                       bool has_should_deoptimize_flag,
@@ -121,12 +122,13 @@
 
   // Allocate a region of data that contain `size` bytes, and potentially space
   // for storing `number_of_roots` roots. Returns null if there is no more room.
-  void ReserveData(Thread* self,
-                   size_t size,
-                   size_t number_of_roots,
-                   ArtMethod* method,
-                   uint8_t** stack_map_data,
-                   uint8_t** roots_data)
+  // Return the number of bytes allocated.
+  size_t ReserveData(Thread* self,
+                     size_t size,
+                     size_t number_of_roots,
+                     ArtMethod* method,
+                     uint8_t** stack_map_data,
+                     uint8_t** roots_data)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!lock_);
 
@@ -237,6 +239,7 @@
                               size_t fp_spill_mask,
                               const uint8_t* code,
                               size_t code_size,
+                              size_t data_size,
                               bool osr,
                               Handle<mirror::ObjectArray<mirror::Object>> roots,
                               bool has_should_deoptimize_flag,
diff --git a/runtime/jni_env_ext.cc b/runtime/jni_env_ext.cc
index 342e0d2..5a3fafa 100644
--- a/runtime/jni_env_ext.cc
+++ b/runtime/jni_env_ext.cc
@@ -19,6 +19,8 @@
 #include <algorithm>
 #include <vector>
 
+#include "android-base/stringprintf.h"
+
 #include "check_jni.h"
 #include "indirect_reference_table.h"
 #include "java_vm_ext.h"
@@ -30,6 +32,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static constexpr size_t kMonitorsInitial = 32;  // Arbitrary.
 static constexpr size_t kMonitorsMax = 4096;  // Arbitrary sanity check.
 
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index a421c34..4da5e23 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -16,6 +16,8 @@
 
 #include "jni_internal.h"
 
+#include "android-base/stringprintf.h"
+
 #include "art_method-inl.h"
 #include "common_compiler_test.h"
 #include "indirect_reference_table.h"
@@ -27,6 +29,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 // TODO: Convert to CommonRuntimeTest. Currently MakeExecutable is used.
 class JniInternalTest : public CommonCompilerTest {
  protected:
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 6da72e4..19a65bb 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -24,7 +24,8 @@
 #include <memory>
 #include <sstream>
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
 #include "base/unix_file/fd_file.h"
 #include "os.h"
 #include "thread-inl.h"
@@ -42,6 +43,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static std::ostream& operator<<(
     std::ostream& os,
     std::pair<BacktraceMap::const_iterator, BacktraceMap::const_iterator> iters) {
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 3c22d7f..da510ce 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-#include "method_handles.h"
-
 #include "method_handles-inl.h"
+
+#include "android-base/stringprintf.h"
+
 #include "jvalue.h"
 #include "jvalue-inl.h"
 #include "reflection.h"
@@ -25,6 +26,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 namespace {
 
 #define PRIMITIVES_LIST(V) \
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 7d7c1d7..a5db0c0 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -19,10 +19,11 @@
 
 #include "array.h"
 
+#include "android-base/stringprintf.h"
+
 #include "base/bit_utils.h"
 #include "base/casts.h"
 #include "base/logging.h"
-#include "base/stringprintf.h"
 #include "class-inl.h"
 #include "gc/heap-inl.h"
 #include "obj_ptr-inl.h"
@@ -167,9 +168,9 @@
 #else
   // 32-bit.
   if (UNLIKELY(size == 0)) {
-    self->ThrowOutOfMemoryError(StringPrintf("%s of length %d would overflow",
-                                             array_class->PrettyDescriptor().c_str(),
-                                             component_count).c_str());
+    self->ThrowOutOfMemoryError(android::base::StringPrintf("%s of length %d would overflow",
+                                                            array_class->PrettyDescriptor().c_str(),
+                                                            component_count).c_str());
     return nullptr;
   }
 #endif
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index 8afa4aa..cc548b9 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "array.h"
+#include "array-inl.h"
 
 #include "class.h"
 #include "class-inl.h"
@@ -23,7 +23,6 @@
 #include "dex_file-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "object-inl.h"
-#include "object_array.h"
 #include "object_array-inl.h"
 #include "handle_scope-inl.h"
 #include "thread.h"
@@ -32,6 +31,8 @@
 namespace art {
 namespace mirror {
 
+using android::base::StringPrintf;
+
 // Create a multi-dimensional array of Objects or primitive types.
 //
 // We have to generate the names for X[], X[][], X[][][], and so on.  The
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 5fdf8f3..2fb8d28 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -937,14 +937,6 @@
   }
 }
 
-inline void Class::SetDexCacheStrings(StringDexCacheType* new_dex_cache_strings) {
-  SetFieldPtr<false>(DexCacheStringsOffset(), new_dex_cache_strings);
-}
-
-inline StringDexCacheType* Class::GetDexCacheStrings() {
-  return GetFieldPtr64<StringDexCacheType*>(DexCacheStringsOffset());
-}
-
 template<ReadBarrierOption kReadBarrierOption, class Visitor>
 void Class::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) {
   for (ArtField& field : GetSFieldsUnchecked()) {
@@ -1095,12 +1087,6 @@
   if (methods != new_methods) {
     dest->SetMethodsPtrInternal(new_methods);
   }
-  // Update dex cache strings.
-  StringDexCacheType* strings = GetDexCacheStrings();
-  StringDexCacheType* new_strings = visitor(strings);
-  if (strings != new_strings) {
-    dest->SetDexCacheStrings(new_strings);
-  }
   // Fix up embedded tables.
   if (!IsTemp() && ShouldHaveEmbeddedVTable<kVerifyNone, kReadBarrierOption>()) {
     for (int32_t i = 0, count = GetEmbeddedVTableLength(); i < count; ++i) {
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index a862c97..9964b73 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -16,6 +16,8 @@
 
 #include "class.h"
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "class_ext.h"
@@ -40,6 +42,8 @@
 namespace art {
 namespace mirror {
 
+using android::base::StringPrintf;
+
 GcRoot<Class> Class::java_lang_Class_;
 
 void Class::SetClassClass(ObjPtr<Class> java_lang_Class) {
@@ -187,7 +191,6 @@
 
 void Class::SetDexCache(ObjPtr<DexCache> new_dex_cache) {
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), new_dex_cache);
-  SetDexCacheStrings(new_dex_cache != nullptr ? new_dex_cache->GetStrings() : nullptr);
 }
 
 void Class::SetClassSize(uint32_t new_class_size) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index d7449c8..fb2792a 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1247,13 +1247,6 @@
   bool GetSlowPathEnabled() REQUIRES_SHARED(Locks::mutator_lock_);
   void SetSlowPath(bool enabled) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  StringDexCacheType* GetDexCacheStrings() REQUIRES_SHARED(Locks::mutator_lock_);
-  void SetDexCacheStrings(StringDexCacheType* new_dex_cache_strings)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static MemberOffset DexCacheStringsOffset() {
-    return OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_strings_);
-  }
-
   // May cause thread suspension due to EqualParameters.
   ArtMethod* GetDeclaredConstructor(Thread* self,
                                     Handle<ObjectArray<Class>> args,
@@ -1438,9 +1431,6 @@
   // virtual_ methods_ for miranda methods.
   HeapReference<PointerArray> vtable_;
 
-  // Short cuts to dex_cache_ member for fast compiled code access.
-  uint64_t dex_cache_strings_;
-
   // instance fields
   //
   // These describe the layout of the contents of an Object.
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index 0fdf132..3e04bf6 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -17,12 +17,13 @@
 #ifndef ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_
 #define ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_
 
-#include <string>
-
 #include "object_array.h"
 
+#include <string>
+
+#include "android-base/stringprintf.h"
+
 #include "array-inl.h"
-#include "base/stringprintf.h"
 #include "gc/heap.h"
 #include "mirror/class.h"
 #include "obj_ptr-inl.h"
@@ -330,13 +331,15 @@
     std::string actualSrcType(mirror::Object::PrettyTypeOf(o));
     std::string dstType(PrettyTypeOf());
     Thread* self = Thread::Current();
+    std::string msg = android::base::StringPrintf(
+        "source[%d] of type %s cannot be stored in destination array of type %s",
+        src_pos + i,
+        actualSrcType.c_str(),
+        dstType.c_str());
     if (throw_exception) {
-      self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
-                               "source[%d] of type %s cannot be stored in destination array of type %s",
-                               src_pos + i, actualSrcType.c_str(), dstType.c_str());
+      self->ThrowNewException("Ljava/lang/ArrayStoreException;", msg.c_str());
     } else {
-      LOG(FATAL) << StringPrintf("source[%d] of type %s cannot be stored in destination array of type %s",
-                                 src_pos + i, actualSrcType.c_str(), dstType.c_str());
+      LOG(FATAL) << msg;
     }
   }
 }
diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h
index 95516ac..9b8445d 100644
--- a/runtime/mirror/string-inl.h
+++ b/runtime/mirror/string-inl.h
@@ -16,6 +16,10 @@
 #ifndef ART_RUNTIME_MIRROR_STRING_INL_H_
 #define ART_RUNTIME_MIRROR_STRING_INL_H_
 
+#include "string.h"
+
+#include "android-base/stringprintf.h"
+
 #include "array.h"
 #include "base/bit_utils.h"
 #include "class.h"
@@ -24,7 +28,6 @@
 #include "globals.h"
 #include "intern_table.h"
 #include "runtime.h"
-#include "string.h"
 #include "thread.h"
 #include "utf.h"
 #include "utils.h"
@@ -228,9 +231,10 @@
                 "kObjectAlignment must be at least as big as Java char alignment");
   const size_t max_length = RoundDown(max_alloc_length, kObjectAlignment / block_size);
   if (UNLIKELY(length > max_length)) {
-    self->ThrowOutOfMemoryError(StringPrintf("%s of length %d would overflow",
-                                             Class::PrettyDescriptor(string_class).c_str(),
-                                             static_cast<int>(length)).c_str());
+    self->ThrowOutOfMemoryError(
+        android::base::StringPrintf("%s of length %d would overflow",
+                                    Class::PrettyDescriptor(string_class).c_str(),
+                                    static_cast<int>(length)).c_str());
     return nullptr;
   }
 
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index ade4e87..e50409f 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -16,6 +16,8 @@
 
 #include "throwable.h"
 
+#include "android-base/stringprintf.h"
+
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "class-inl.h"
@@ -31,6 +33,8 @@
 namespace art {
 namespace mirror {
 
+using android::base::StringPrintf;
+
 GcRoot<Class> Throwable::java_lang_Throwable_;
 
 void Throwable::SetDetailMessage(ObjPtr<String> new_detail_message) {
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index e7de7e6..222eb5c 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -18,6 +18,8 @@
 
 #include <vector>
 
+#include "android-base/stringprintf.h"
+
 #include "art_method-inl.h"
 #include "base/mutex.h"
 #include "base/stl_util.h"
@@ -38,6 +40,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static constexpr uint64_t kLongWaitMs = 100;
 
 /*
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 1a77072..cd0e55f 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -18,9 +18,10 @@
 
 #include <sstream>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
 #include "base/stl_util.h"
-#include "base/stringprintf.h"
 #include "class_linker.h"
 #include "common_throws.h"
 #include "compiler_filter.h"
@@ -43,6 +44,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static bool ConvertJavaArrayToDexFiles(
     JNIEnv* env,
     jobject arrayObject,
diff --git a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
index db245aa..981be68 100644
--- a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
+++ b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
@@ -16,6 +16,8 @@
 
 #include "dalvik_system_InMemoryDexClassLoader_DexData.h"
 
+#include "android-base/stringprintf.h"
+
 #include "class_linker.h"
 #include "common_throws.h"
 #include "dex_file.h"
@@ -29,6 +31,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static std::unique_ptr<MemMap> AllocateDexMemoryMap(JNIEnv* env, jint start, jint end) {
   if (end <= start) {
     ScopedObjectAccess soa(env);
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 3058df4..1af8619 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -27,6 +27,8 @@
 #include "toStringArray.h"
 #pragma GCC diagnostic pop
 
+#include "android-base/stringprintf.h"
+
 #include "art_method-inl.h"
 #include "arch/instruction_set.h"
 #include "base/enums.h"
@@ -54,6 +56,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static jfloat VMRuntime_getTargetHeapUtilization(JNIEnv*, jobject) {
   return Runtime::Current()->GetHeap()->GetTargetHeapUtilization();
 }
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index a78909b..10fc90b 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -18,6 +18,8 @@
 
 #include <stdlib.h>
 
+#include "android-base/stringprintf.h"
+
 #include "arch/instruction_set.h"
 #include "debugger.h"
 #include "java_vm_ext.h"
@@ -37,6 +39,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static void EnableDebugger() {
 #if defined(__linux__)
   // To let a non-privileged gdbserver attach to this
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index 73b81a7..ee59c4a 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_reflect_Executable.h"
 
+#include "android-base/stringprintf.h"
+
 #include "art_method-inl.h"
 #include "dex_file_annotations.h"
 #include "handle.h"
@@ -30,6 +32,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static jobjectArray Executable_getDeclaredAnnotationsNative(JNIEnv* env, jobject javaMethod) {
   ScopedFastNativeObjectAccess soa(env);
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 6206948..374eeb5 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_reflect_Field.h"
 
+#include "android-base/stringprintf.h"
+
 #include "class_linker.h"
 #include "class_linker-inl.h"
 #include "common_throws.h"
@@ -30,6 +32,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 template<bool kIsSet>
 ALWAYS_INLINE inline static bool VerifyFieldAccess(Thread* self,
                                                    ObjPtr<mirror::Field> field,
diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
index 16164d2..0bb9e38 100644
--- a/runtime/native/java_lang_reflect_Parameter.cc
+++ b/runtime/native/java_lang_reflect_Parameter.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_reflect_Parameter.h"
 
+#include "android-base/stringprintf.h"
+
 #include "art_method-inl.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
@@ -26,6 +28,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static jobject Parameter_getAnnotationNative(JNIEnv* env,
                                              jclass,
                                              jobject javaMethod,
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index 5565565..7460d62 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -37,10 +37,11 @@
 #include <sys/time.h>
 #include <sys/types.h>
 
+#include "android-base/stringprintf.h"
+
 #include "arch/instruction_set.h"
 #include "base/memory_tool.h"
 #include "base/mutex.h"
-#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 #include "oat_quick_method_header.h"
 #include "os.h"
@@ -53,6 +54,8 @@
 
 #if defined(__linux__)
 
+using android::base::StringPrintf;
+
 static constexpr bool kUseAddr2line = !kIsTargetBuild;
 
 ALWAYS_INLINE
diff --git a/runtime/oat.cc b/runtime/oat.cc
index aab0e81..cebe765 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -19,12 +19,15 @@
 #include <string.h>
 #include <zlib.h>
 
+#include "android-base/stringprintf.h"
+
 #include "arch/instruction_set_features.h"
 #include "base/bit_utils.h"
-#include "base/stringprintf.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 constexpr uint8_t OatHeader::kOatMagic[4];
 constexpr uint8_t OatHeader::kOatVersion[4];
 constexpr const char OatHeader::kTrueValue[];
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index bdf8b0e..0bf7136 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -32,6 +32,8 @@
 #include "android/dlext.h"
 #endif
 
+#include "android-base/stringprintf.h"
+
 #include "art_method-inl.h"
 #include "base/bit_vector.h"
 #include "base/enums.h"
@@ -58,6 +60,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 // Whether OatFile::Open will try dlopen. Fallback is our own ELF loader.
 static constexpr bool kUseDlopen = true;
 
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 7f7b1b5..ee7cf9d 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -23,7 +23,6 @@
 #include "android-base/strings.h"
 
 #include "base/logging.h"
-#include "base/stringprintf.h"
 #include "compiler_filter.h"
 #include "class_linker.h"
 #include "gc/heap.h"
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 5641459..33bd0f3 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -20,6 +20,8 @@
 #include <queue>
 #include <vector>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/systrace.h"
@@ -38,6 +40,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 // If true, then we attempt to load the application image if it exists.
 static constexpr bool kEnableAppImage = true;
 
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 98c2c5f..68815e7 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -33,6 +33,8 @@
 
 #include <limits>
 
+#include "android-base/stringprintf.h"
+
 #include "art_jvmti.h"
 #include "base/logging.h"
 #include "events-inl.h"
@@ -49,13 +51,15 @@
 
 namespace openjdkjvmti {
 
+using android::base::StringPrintf;
+
 // Moves dex data to an anonymous, read-only mmap'd region.
 std::unique_ptr<art::MemMap> Redefiner::MoveDataToMemMap(const std::string& original_location,
                                                          jint data_len,
                                                          unsigned char* dex_data,
                                                          std::string* error_msg) {
   std::unique_ptr<art::MemMap> map(art::MemMap::MapAnonymous(
-      art::StringPrintf("%s-transformed", original_location.c_str()).c_str(),
+      StringPrintf("%s-transformed", original_location.c_str()).c_str(),
       nullptr,
       data_len,
       PROT_READ|PROT_WRITE,
@@ -246,9 +250,9 @@
 }
 
 void Redefiner::RecordFailure(jvmtiError result, const std::string& error_msg) {
-  *error_msg_ = art::StringPrintf("Unable to perform redefinition of '%s': %s",
-                                  class_sig_,
-                                  error_msg.c_str());
+  *error_msg_ = StringPrintf("Unable to perform redefinition of '%s': %s",
+                             class_sig_,
+                             error_msg.c_str());
   result_ = result;
 }
 
@@ -478,7 +482,6 @@
   // Need to update class last since the ArtMethod gets its DexFile from the class (which is needed
   // to call GetReturnTypeDescriptor and GetParameterTypeList above).
   mclass->SetDexCache(new_dex_cache.Ptr());
-  mclass->SetDexCacheStrings(new_dex_cache->GetStrings());
   mclass->SetDexClassDefIndex(dex_file_->GetIndexForClassDef(*class_def));
   mclass->SetDexTypeIndex(dex_file_->GetIndexForTypeId(*dex_file_->FindTypeId(class_sig_)));
   return true;
diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc
index 5b90c6a..8948c71 100644
--- a/runtime/parsed_options_test.cc
+++ b/runtime/parsed_options_test.cc
@@ -19,7 +19,6 @@
 #include <memory>
 
 #include "arch/instruction_set.h"
-#include "base/stringprintf.h"
 #include "common_runtime_test.h"
 
 namespace art {
diff --git a/runtime/plugin.cc b/runtime/plugin.cc
index 481b1ca..731967c 100644
--- a/runtime/plugin.cc
+++ b/runtime/plugin.cc
@@ -17,11 +17,15 @@
 #include "plugin.h"
 
 #include <dlfcn.h>
-#include "base/stringprintf.h"
+
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
 
 namespace art {
 
+using android::base::StringPrintf;
+
 const char* PLUGIN_INITIALIZATION_FUNCTION_NAME = "ArtPlugin_Initialize";
 const char* PLUGIN_DEINITIALIZATION_FUNCTION_NAME = "ArtPlugin_Deinitialize";
 
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index 1c975a4..d8b9dcc 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -16,6 +16,8 @@
 
 #include "reference_table.h"
 
+#include "android-base/stringprintf.h"
+
 #include "base/mutex.h"
 #include "indirect_reference_table.h"
 #include "mirror/array.h"
@@ -30,6 +32,9 @@
 
 namespace art {
 
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+
 ReferenceTable::ReferenceTable(const char* name, size_t initial_size, size_t max_size)
     : name_(name), max_size_(max_size) {
   CHECK_LE(initial_size, max_size);
diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc
index d80a9b3..9523e92 100644
--- a/runtime/reference_table_test.cc
+++ b/runtime/reference_table_test.cc
@@ -16,6 +16,8 @@
 
 #include "reference_table.h"
 
+#include "android-base/stringprintf.h"
+
 #include "class_linker.h"
 #include "common_runtime_test.h"
 #include "handle_scope-inl.h"
@@ -30,6 +32,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 class ReferenceTableTest : public CommonRuntimeTest {};
 
 static mirror::Object* CreateWeakReference(mirror::Object* referent)
diff --git a/runtime/reflection-inl.h b/runtime/reflection-inl.h
index 68e7a10..62ce9e9 100644
--- a/runtime/reflection-inl.h
+++ b/runtime/reflection-inl.h
@@ -19,7 +19,8 @@
 
 #include "reflection.h"
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
 #include "common_throws.h"
 #include "jvalue-inl.h"
 #include "mirror/object-inl.h"
@@ -103,13 +104,14 @@
   }
 
   if (!unbox_for_result) {
-    ThrowIllegalArgumentException(StringPrintf("Invalid primitive conversion from %s to %s",
-                                               PrettyDescriptor(srcType).c_str(),
-                                               PrettyDescriptor(dstType).c_str()).c_str());
+    ThrowIllegalArgumentException(
+        android::base::StringPrintf("Invalid primitive conversion from %s to %s",
+                                    PrettyDescriptor(srcType).c_str(),
+                                    PrettyDescriptor(dstType).c_str()).c_str());
   } else {
-    ThrowClassCastException(StringPrintf("Couldn't convert result of type %s to %s",
-                                         PrettyDescriptor(srcType).c_str(),
-                                         PrettyDescriptor(dstType).c_str()).c_str());
+    ThrowClassCastException(android::base::StringPrintf("Couldn't convert result of type %s to %s",
+                                                        PrettyDescriptor(srcType).c_str(),
+                                                        PrettyDescriptor(dstType).c_str()).c_str());
   }
   return false;
 }
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 8446b52..4d24501 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -34,6 +34,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 class ArgArray {
  public:
   ArgArray(const char* shorty, uint32_t shorty_len)
diff --git a/runtime/runtime_android.cc b/runtime/runtime_android.cc
index be97860..0a996a9 100644
--- a/runtime/runtime_android.cc
+++ b/runtime/runtime_android.cc
@@ -21,7 +21,6 @@
 
 #include "base/logging.h"
 #include "base/mutex.h"
-#include "base/stringprintf.h"
 #include "thread-inl.h"
 #include "utils.h"
 
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index 93704a9..b8894d2 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -24,11 +24,12 @@
 #include <iostream>
 #include <sstream>
 
+#include "android-base/stringprintf.h"
+
 #include "base/dumpable.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "base/stringprintf.h"
 #include "native_stack_dump.h"
 #include "thread-inl.h"
 #include "thread_list.h"
@@ -36,6 +37,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static constexpr bool kUseSigRTTimeout = true;
 static constexpr bool kDumpNativeStackOnTimeout = true;
 
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 792da88..3fed7c9 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -16,6 +16,8 @@
 
 #include "stack.h"
 
+#include "android-base/stringprintf.h"
+
 #include "arch/context.h"
 #include "art_method-inl.h"
 #include "base/enums.h"
@@ -39,6 +41,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static constexpr bool kDebugStackWalk = false;
 
 mirror::Object* ShadowFrame::GetThisObject() const {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index d79bf36..9c93a5f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -28,6 +28,8 @@
 #include <list>
 #include <sstream>
 
+#include "android-base/stringprintf.h"
+
 #include "arch/context.h"
 #include "art_field-inl.h"
 #include "art_method-inl.h"
@@ -88,6 +90,9 @@
 
 namespace art {
 
+using android::base::StringAppendV;
+using android::base::StringPrintf;
+
 extern "C" NO_RETURN void artDeoptimize(Thread* self);
 
 bool Thread::is_started_ = false;
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 664eeb4..bf9eef8 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -25,6 +25,8 @@
 
 #include <sstream>
 
+#include "android-base/stringprintf.h"
+
 #include "base/histogram-inl.h"
 #include "base/mutex-inl.h"
 #include "base/systrace.h"
@@ -52,6 +54,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static constexpr uint64_t kLongThreadSuspendThreshold = MsToNs(5);
 static constexpr uint64_t kThreadSuspendTimeoutMs = 30 * 1000;  // 30s.
 // Use 0 since we want to yield to prevent blocking for an unpredictable amount of time.
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index d9d2ea3..6abdca1 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -21,6 +21,8 @@
 #include <sys/time.h>
 #include <sys/resource.h>
 
+#include "android-base/stringprintf.h"
+
 #include "base/bit_utils.h"
 #include "base/casts.h"
 #include "base/logging.h"
@@ -31,6 +33,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static constexpr bool kMeasureWaitTime = false;
 
 ThreadPoolWorker::ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name,
diff --git a/runtime/ti/agent.cc b/runtime/ti/agent.cc
index d21ff77..0bba44c 100644
--- a/runtime/ti/agent.cc
+++ b/runtime/ti/agent.cc
@@ -15,12 +15,17 @@
  */
 
 #include "agent.h"
+
+#include "android-base/stringprintf.h"
+
 #include "java_vm_ext.h"
 #include "runtime.h"
 
 namespace art {
 namespace ti {
 
+using android::base::StringPrintf;
+
 const char* AGENT_ON_LOAD_FUNCTION_NAME = "Agent_OnLoad";
 const char* AGENT_ON_ATTACH_FUNCTION_NAME = "Agent_OnAttach";
 const char* AGENT_ON_UNLOAD_FUNCTION_NAME = "Agent_OnUnload";
diff --git a/runtime/ti/agent.h b/runtime/ti/agent.h
index 6561756..7408aee 100644
--- a/runtime/ti/agent.h
+++ b/runtime/ti/agent.h
@@ -20,7 +20,6 @@
 #include <dlfcn.h>
 #include <jni.h>  // for jint, JavaVM* etc declarations
 
-#include "base/stringprintf.h"
 #include "runtime.h"
 #include "utils.h"
 
diff --git a/runtime/trace.cc b/runtime/trace.cc
index f564de4..9d9360e 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -19,6 +19,8 @@
 #include <sys/uio.h>
 #include <unistd.h>
 
+#include "android-base/stringprintf.h"
+
 #include "art_method-inl.h"
 #include "base/casts.h"
 #include "base/enums.h"
@@ -46,6 +48,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 static constexpr size_t TraceActionBits = MinimumBitsToStore(
     static_cast<size_t>(kTraceMethodActionMask));
 static constexpr uint8_t kOpNewMethod = 1U;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 4732f59..8867743 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <memory>
 
+#include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
 #include "base/stl_util.h"
@@ -48,6 +49,9 @@
 
 namespace art {
 
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+
 static const uint8_t kBase64Map[256] = {
   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
diff --git a/runtime/utils.h b/runtime/utils.h
index 04e0dde..16ef706 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -284,6 +284,12 @@
   __builtin___clear_cache(begin, end);
 }
 
+inline void FlushDataCache(char* begin, char* end) {
+  // Same as FlushInstructionCache for lack of other builtin. __builtin___clear_cache
+  // flushes both caches.
+  __builtin___clear_cache(begin, end);
+}
+
 template <typename T>
 constexpr PointerSize ConvertToPointerSize(T any) {
   if (any == 4 || any == 8) {
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index ebecc85..7e23c8b 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -18,6 +18,8 @@
 
 #include <iostream>
 
+#include "android-base/stringprintf.h"
+
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/enums.h"
@@ -55,6 +57,8 @@
 namespace art {
 namespace verifier {
 
+using android::base::StringPrintf;
+
 static constexpr bool kTimeVerifyMethod = !kIsDebugBuild;
 static constexpr bool kDebugVerify = false;
 // TODO: Add a constant to method_verifier to turn on verbose logging?
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index ab23773..52f7e34 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -16,6 +16,8 @@
 
 #include "reg_type-inl.h"
 
+#include "android-base/stringprintf.h"
+
 #include "base/arena_bit_vector.h"
 #include "base/bit_vector-inl.h"
 #include "base/casts.h"
@@ -35,6 +37,8 @@
 namespace art {
 namespace verifier {
 
+using android::base::StringPrintf;
+
 const UndefinedType* UndefinedType::instance_ = nullptr;
 const ConflictType* ConflictType::instance_ = nullptr;
 const BooleanType* BooleanType::instance_ = nullptr;
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index a6088aa..383d890 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -16,7 +16,8 @@
 
 #include "register_line.h"
 
-#include "base/stringprintf.h"
+#include "android-base/stringprintf.h"
+
 #include "dex_instruction-inl.h"
 #include "method_verifier-inl.h"
 #include "register_line-inl.h"
@@ -25,6 +26,8 @@
 namespace art {
 namespace verifier {
 
+using android::base::StringPrintf;
+
 bool RegisterLine::CheckConstructorReturn(MethodVerifier* verifier) const {
   if (kIsDebugBuild && this_initialized_) {
     // Ensure that there is no UninitializedThisReference type anymore if this_initialized_ is true.
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 3549586..009170c 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -20,6 +20,8 @@
 
 #include <sstream>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
 #include "jni_internal.h"
@@ -189,7 +191,7 @@
 static jmethodID CachePrimitiveBoxingMethod(JNIEnv* env, char prim_name, const char* boxed_name) {
   ScopedLocalRef<jclass> boxed_class(env, env->FindClass(boxed_name));
   return CacheMethod(env, boxed_class.get(), true, "valueOf",
-                     StringPrintf("(%c)L%s;", prim_name, boxed_name).c_str());
+                     android::base::StringPrintf("(%c)L%s;", prim_name, boxed_name).c_str());
 }
 
 #define STRING_INIT_LIST(V) \
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index d96fb42..cd79bb6 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -23,7 +23,6 @@
 #include <unistd.h>
 #include <vector>
 
-#include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
 
 namespace art {
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 113b35f..3b237f4 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -25,11 +25,11 @@
 
 #include "jni.h"
 
+#include "android-base/stringprintf.h"
 #include <backtrace/Backtrace.h>
 
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/stringprintf.h"
 #include "gc/heap.h"
 #include "gc/space/image_space.h"
 #include "oat_file.h"
@@ -91,7 +91,7 @@
 static void MoreErrorInfo(pid_t pid, bool sig_quit_on_fail) {
   printf("Secondary pid is %d\n", pid);
 
-  PrintFileToLog(StringPrintf("/proc/%d/maps", pid), ::android::base::ERROR);
+  PrintFileToLog(android::base::StringPrintf("/proc/%d/maps", pid), ::android::base::ERROR);
 
   if (sig_quit_on_fail) {
     int res = kill(pid, SIGQUIT);
diff --git a/test/530-checker-loops4/src/Main.java b/test/530-checker-loops4/src/Main.java
index 7d3d7d9..91af1f4 100644
--- a/test/530-checker-loops4/src/Main.java
+++ b/test/530-checker-loops4/src/Main.java
@@ -96,7 +96,29 @@
   /// CHECK-NOT: Phi
   public static int geo4(int a) {
     for (int i = 0; i < 10; i++) {
-      a %= 7;
+      a %= 7;  // a wrap-around induction
+    }
+    return a;
+  }
+
+  /// CHECK-START: int Main.geo5() loop_optimization (before)
+  /// CHECK-DAG: Phi loop:<<Loop:B\d+>>
+  /// CHECK-DAG: Shr loop:<<Loop>>
+  //
+  /// CHECK-START: int Main.geo5() loop_optimization (after)
+  /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0          loop:none
+  /// CHECK-DAG: <<Int1:i\d+>> IntConstant 2147483647 loop:none
+  /// CHECK-DAG: <<Int2:i\d+>> IntConstant 1024       loop:none
+  /// CHECK-DAG: <<Div:i\d+>>  Div [<<Int1>>,<<Int2>>] loop:none
+  /// CHECK-DAG: <<Add:i\d+>>  Add [<<Div>>,<<Zero>>]  loop:none
+  /// CHECK-DAG:               Return [<<Add>>]        loop:none
+  //
+  /// CHECK-START: int Main.geo5() loop_optimization (after)
+  /// CHECK-NOT: Phi
+  public static int geo5() {
+    int a = 0x7fffffff;
+    for (int i = 0; i < 10; i++) {
+      a >>= 1;
     }
     return a;
   }
@@ -186,7 +208,7 @@
     int r = 0;
     for (int i = 0; i < 100; i++) {  // a converges to 0
       r += x[a];
-      a %= 5;
+      a %= 5;  // a wrap-around induction
     }
     return r;
   }
@@ -305,6 +327,8 @@
       expectEquals(i % 7, geo4(i));
     }
 
+    expectEquals(0x1fffff, geo5());
+
     expectEquals(34,  geo1BCE());
     expectEquals(36,  geo2BCE());
     expectEquals(131, geo3BCE());
diff --git a/test/618-checker-induction/src/Main.java b/test/618-checker-induction/src/Main.java
index 87a69b2..ecc129a 100644
--- a/test/618-checker-induction/src/Main.java
+++ b/test/618-checker-induction/src/Main.java
@@ -248,6 +248,33 @@
     return closed;  // only needs last value
   }
 
+  /// CHECK-START: int Main.closedFormInductionTrivialIf() loop_optimization (before)
+  /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               Select            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               Return [<<Phi1>>] loop:none
+  //
+  /// CHECK-START: int Main.closedFormInductionTrivialIf() loop_optimization (after)
+  /// CHECK-NOT:               Phi
+  /// CHECK-NOT:               Select
+  //
+  /// CHECK-START: int Main.closedFormInductionTrivialIf() instruction_simplifier$after_bce (after)
+  /// CHECK-DAG: <<Int:i\d+>>  IntConstant 81    loop:none
+  /// CHECK-DAG:               Return [<<Int>>]  loop:none
+  static int closedFormInductionTrivialIf() {
+    int closed = 11;
+    for (int i = 0; i < 10; i++) {
+      // Trivial if becomes trivial select at HIR level.
+      // Make sure this is still recognized as induction.
+      if (i < 5) {
+        closed += 7;
+      } else {
+        closed += 7;
+      }
+    }
+    return closed;  // only needs last value
+  }
+
   /// CHECK-START: int Main.closedFormNested() loop_optimization (before)
   /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop1:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop1>>      outer_loop:none
@@ -732,6 +759,7 @@
 
     expectEquals(12395, closedFormInductionUp());
     expectEquals(12295, closedFormInductionInAndDown(12345));
+    expectEquals(81, closedFormInductionTrivialIf());
     expectEquals(10 * 10, closedFormNested());
     expectEquals(12345 + 17 * 23 * 7, closedFormNestedAlt());
     for (int n = -4; n < 10; n++) {
diff --git a/test/624-checker-stringops/src/Main.java b/test/624-checker-stringops/src/Main.java
index d965e3f..75b782e 100644
--- a/test/624-checker-stringops/src/Main.java
+++ b/test/624-checker-stringops/src/Main.java
@@ -258,6 +258,20 @@
     return b.length();
   }
 
+  // Regression b/33656359: StringBuffer x is passed to constructor of String
+  // (this caused old code to crash due to missing nullptr check).
+  //
+  /// CHECK-START: void Main.doesNothing() instruction_simplifier (before)
+  /// CHECK-DAG: InvokeVirtual intrinsic:StringBufferToString
+  //
+  /// CHECK-START: void Main.doesNothing() instruction_simplifier (after)
+  /// CHECK-DAG: InvokeVirtual intrinsic:StringBufferToString
+  static void doesNothing() {
+    StringBuffer x = new StringBuffer();
+    String y = new String(x);
+    x.toString();
+  }
+
   public static void main(String[] args) {
     expectEquals(1865, liveIndexOf());
     expectEquals(29, deadIndexOf());
@@ -281,6 +295,8 @@
     expectEquals(0, bufferDeadLoop());
     expectEquals(0, builderDeadLoop());
 
+    doesNothing();
+
     System.out.println("passed");
   }
 
diff --git a/test/911-get-stack-trace/stack_trace.cc b/test/911-get-stack-trace/stack_trace.cc
index 9092f2f..57f6a92 100644
--- a/test/911-get-stack-trace/stack_trace.cc
+++ b/test/911-get-stack-trace/stack_trace.cc
@@ -20,9 +20,10 @@
 #include <memory>
 #include <stdio.h>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/stringprintf.h"
 #include "jni.h"
 #include "openjdkjvmti/jvmti.h"
 #include "ScopedLocalRef.h"
@@ -32,6 +33,8 @@
 namespace art {
 namespace Test911GetStackTrace {
 
+using android::base::StringPrintf;
+
 static jint FindLineNumber(jint line_number_count,
                            jvmtiLineNumberEntry* line_number_table,
                            jlocation location) {
diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt
index e5fa53f..7522a65 100644
--- a/test/913-heaps/expected.txt
+++ b/test/913-heaps/expected.txt
@@ -5,12 +5,12 @@
 root@root --(thread)--> 3000@0 [size=132, length=-1]
 0@0 --(array-element@0)--> 1@1000 [size=16, length=-1]
 1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
-1002@0 --(interface)--> 2001@0 [size=132, length=-1]
+1002@0 --(interface)--> 2001@0 [size=124, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
 1@1000 --(class)--> 1000@0 [size=123, length=-1]
 1@1000 --(field@12)--> 3@1001 [size=24, length=-1]
 1@1000 --(field@8)--> 2@1000 [size=16, length=-1]
-2001@0 --(interface)--> 2000@0 [size=132, length=-1]
+2001@0 --(interface)--> 2000@0 [size=124, length=-1]
 2@1000 --(class)--> 1000@0 [size=123, length=-1]
 3@1001 --(class)--> 1001@0 [size=123, length=-1]
 3@1001 --(field@16)--> 4@1000 [size=16, length=-1]
@@ -22,12 +22,12 @@
 6@1000 --(class)--> 1000@0 [size=123, length=-1]
 ---
 1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
-1002@0 --(interface)--> 2001@0 [size=132, length=-1]
+1002@0 --(interface)--> 2001@0 [size=124, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
 1@1000 --(class)--> 1000@0 [size=123, length=-1]
 1@1000 --(field@12)--> 3@1001 [size=24, length=-1]
 1@1000 --(field@8)--> 2@1000 [size=16, length=-1]
-2001@0 --(interface)--> 2000@0 [size=132, length=-1]
+2001@0 --(interface)--> 2000@0 [size=124, length=-1]
 2@1000 --(class)--> 1000@0 [size=123, length=-1]
 3@1001 --(class)--> 1001@0 [size=123, length=-1]
 3@1001 --(field@16)--> 4@1000 [size=16, length=-1]
@@ -46,12 +46,12 @@
 root@root --(thread)--> 1@1000 [size=16, length=-1]
 root@root --(thread)--> 3000@0 [size=132, length=-1]
 1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
-1002@0 --(interface)--> 2001@0 [size=132, length=-1]
+1002@0 --(interface)--> 2001@0 [size=124, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
 1@1000 --(class)--> 1000@0 [size=123, length=-1]
 1@1000 --(field@12)--> 3@1001 [size=24, length=-1]
 1@1000 --(field@8)--> 2@1000 [size=16, length=-1]
-2001@0 --(interface)--> 2000@0 [size=132, length=-1]
+2001@0 --(interface)--> 2000@0 [size=124, length=-1]
 2@1000 --(class)--> 1000@0 [size=123, length=-1]
 3@1001 --(class)--> 1001@0 [size=123, length=-1]
 3@1001 --(field@16)--> 4@1000 [size=16, length=-1]
@@ -63,12 +63,12 @@
 6@1000 --(class)--> 1000@0 [size=123, length=-1]
 ---
 1001@0 --(superclass)--> 1000@0 [size=123, length=-1]
-1002@0 --(interface)--> 2001@0 [size=132, length=-1]
+1002@0 --(interface)--> 2001@0 [size=124, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123, length=-1]
 1@1000 --(class)--> 1000@0 [size=123, length=-1]
 1@1000 --(field@12)--> 3@1001 [size=24, length=-1]
 1@1000 --(field@8)--> 2@1000 [size=16, length=-1]
-2001@0 --(interface)--> 2000@0 [size=132, length=-1]
+2001@0 --(interface)--> 2000@0 [size=124, length=-1]
 2@1000 --(class)--> 1000@0 [size=123, length=-1]
 3@1001 --(class)--> 1001@0 [size=123, length=-1]
 3@1001 --(field@16)--> 4@1000 [size=16, length=-1]
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 7b00fcd..49ab7dd 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -22,9 +22,10 @@
 
 #include <vector>
 
+#include "android-base/stringprintf.h"
+
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/stringprintf.h"
 #include "jit/jit.h"
 #include "jni.h"
 #include "native_stack_dump.h"
@@ -39,6 +40,8 @@
 namespace art {
 namespace Test913Heaps {
 
+using android::base::StringPrintf;
+
 extern "C" JNIEXPORT void JNICALL Java_Main_forceGarbageCollection(JNIEnv* env ATTRIBUTE_UNUSED,
                                                                    jclass klass ATTRIBUTE_UNUSED) {
   jvmtiError ret = jvmti_env->ForceGarbageCollection();
@@ -180,7 +183,7 @@
       if (*tag_ptr >= 1000) {
         // This is a class or interface, the size of which will be dependent on the architecture.
         // Do not print the size, but detect known values and "normalize" for the golden file.
-        if ((sizeof(void*) == 4 && size == 180) || (sizeof(void*) == 8 && size == 232)) {
+        if ((sizeof(void*) == 4 && size == 172) || (sizeof(void*) == 8 && size == 224)) {
           adapted_size = 123;
         }
       }
diff --git a/runtime/base/stringprintf_test.cc b/test/ErroneousA/ErroneousA.java
similarity index 61%
copy from runtime/base/stringprintf_test.cc
copy to test/ErroneousA/ErroneousA.java
index 0bfde33..49da544 100644
--- a/runtime/base/stringprintf_test.cc
+++ b/test/ErroneousA/ErroneousA.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,16 +14,4 @@
  * limitations under the License.
  */
 
-#include "stringprintf.h"
-
-#include "gtest/gtest.h"
-
-namespace art {
-
-TEST(StringPrintfTest, HexSizeT) {
-  size_t size = 0x00107e59;
-  EXPECT_STREQ("00107e59", StringPrintf("%08zx", size).c_str());
-  EXPECT_STREQ("0x00107e59", StringPrintf("0x%08zx", size).c_str());
-}
-
-}  // namespace art
+final class FinalSuper {}
diff --git a/runtime/base/stringprintf_test.cc b/test/ErroneousB/ErroneousB.java
similarity index 61%
rename from runtime/base/stringprintf_test.cc
rename to test/ErroneousB/ErroneousB.java
index 0bfde33..6c2902a 100644
--- a/runtime/base/stringprintf_test.cc
+++ b/test/ErroneousB/ErroneousB.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,16 +14,7 @@
  * limitations under the License.
  */
 
-#include "stringprintf.h"
+// Only final in first dex.
+class FinalSuper {}
 
-#include "gtest/gtest.h"
-
-namespace art {
-
-TEST(StringPrintfTest, HexSizeT) {
-  size_t size = 0x00107e59;
-  EXPECT_STREQ("00107e59", StringPrintf("%08zx", size).c_str());
-  EXPECT_STREQ("0x00107e59", StringPrintf("0x%08zx", size).c_str());
-}
-
-}  // namespace art
+class Erroneous extends FinalSuper {}
diff --git a/tools/cpp-define-generator/offset_dexcache.def b/tools/cpp-define-generator/offset_dexcache.def
index 4b9d481..abb5e1e 100644
--- a/tools/cpp-define-generator/offset_dexcache.def
+++ b/tools/cpp-define-generator/offset_dexcache.def
@@ -38,7 +38,6 @@
 DEFINE_ART_METHOD_OFFSET_SIZED(JNI,                  EntryPointFromJni)
 DEFINE_ART_METHOD_OFFSET_SIZED(QUICK_CODE,           EntryPointFromQuickCompiledCode)
 DEFINE_ART_METHOD_OFFSET(DECLARING_CLASS,            DeclaringClass)
-DEFINE_DECLARING_CLASS_OFFSET(DEX_CACHE_STRINGS,     DexCacheStrings)
 
 #undef DEFINE_ART_METHOD_OFFSET
 #undef DEFINE_ART_METHOD_OFFSET_32
diff --git a/tools/jfuzz/run_jfuzz_test.py b/tools/jfuzz/run_jfuzz_test.py
index fd8415d..42745d2 100755
--- a/tools/jfuzz/run_jfuzz_test.py
+++ b/tools/jfuzz/run_jfuzz_test.py
@@ -414,14 +414,16 @@
       retc2: int, normalized return code of second runner
     """
     if retc1 == retc2:
-      # Non-divergent in return code.
+      # No divergence in return code.
       if retc1 == RetCode.SUCCESS:
         # Both compilations and runs were successful, inspect generated output.
         runner1_out = self._runner1.output_file
         runner2_out = self._runner2.output_file
         if not filecmp.cmp(runner1_out, runner2_out, shallow=False):
+          # Divergence in output.
           self.ReportDivergence(retc1, retc2, is_output_divergence=True)
         else:
+          # No divergence in output.
           self._num_success += 1
       elif retc1 == RetCode.TIMEOUT:
         self._num_timed_out += 1
@@ -429,8 +431,12 @@
         self._num_not_compiled += 1
       else:
         self._num_not_run += 1
+    elif self._true_divergence_only and RetCode.TIMEOUT in (retc1, retc2):
+      # When only true divergences are requested, any divergence in return
+      # code where one is a time out is treated as a regular time out.
+      self._num_timed_out += 1
     else:
-      # Divergent in return code.
+      # Divergence in return code.
       self.ReportDivergence(retc1, retc2, is_output_divergence=False)
 
   def GetCurrentDivergenceDir(self):
@@ -450,13 +456,12 @@
     os.mkdir(ddir)
     for f in glob('*.txt') + ['Test.java']:
       shutil.copy(f, ddir)
-    if not (self._true_divergence_only and RetCode.TIMEOUT in (retc1, retc2)):
-      # Maybe run bisection bug search.
-      if retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES:
-        self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
-      # Call reporting script.
-      if self._report_script:
-        self.RunReportScript(retc1, retc2, is_output_divergence)
+    # Maybe run bisection bug search.
+    if retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES:
+      self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
+    # Call reporting script.
+    if self._report_script:
+      self.RunReportScript(retc1, retc2, is_output_divergence)
 
   def RunReportScript(self, retc1, retc2, is_output_divergence):
     """Runs report script."""