Merge "Minor jfuzz improvements."
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index c902d28..e0abf19 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -277,39 +277,44 @@
     return;
   }
   uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
-  MethodReference target_method(&GetDexFile(), method_idx);
-  InvokeType invoke_type = kVirtual;
-  InvokeType original_invoke_type = invoke_type;
-  int vtable_idx;
-  uintptr_t direct_code;
-  uintptr_t direct_method;
-  // TODO: support devirtualization.
-  const bool kEnableDevirtualization = false;
-  bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc,
-                                             false, kEnableDevirtualization,
-                                             &invoke_type,
-                                             &target_method, &vtable_idx,
-                                             &direct_code, &direct_method);
-  if (fast_path && original_invoke_type == invoke_type) {
-    if (vtable_idx >= 0 && IsUint<16>(vtable_idx)) {
-      VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
-                     << "(" << PrettyMethod(method_idx, GetDexFile(), true) << ")"
-                     << " to " << Instruction::Name(new_opcode)
-                     << " by replacing method index " << method_idx
-                     << " by vtable index " << vtable_idx
-                     << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
-                     << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
-      // We are modifying 4 consecutive bytes.
-      inst->SetOpcode(new_opcode);
-      // Replace method index by vtable index.
-      if (is_range) {
-        inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
-      } else {
-        inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
-      }
-      quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
-    }
+  ScopedObjectAccess soa(Thread::Current());
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+      soa.Decode<mirror::ClassLoader*>(unit_.GetClassLoader())));
+
+  ClassLinker* class_linker = unit_.GetClassLinker();
+  ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(
+      GetDexFile(),
+      method_idx,
+      unit_.GetDexCache(),
+      class_loader,
+      /* referrer */ nullptr,
+      kVirtual);
+
+  if (UNLIKELY(resolved_method == nullptr)) {
+    // Clean up any exception left by type resolution.
+    soa.Self()->ClearException();
+    return;
   }
+
+  uint32_t vtable_idx = resolved_method->GetMethodIndex();
+  DCHECK(IsUint<16>(vtable_idx));
+  VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
+                 << "(" << PrettyMethod(method_idx, GetDexFile(), true) << ")"
+                 << " to " << Instruction::Name(new_opcode)
+                 << " by replacing method index " << method_idx
+                 << " by vtable index " << vtable_idx
+                 << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
+                 << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
+  // We are modifying 4 consecutive bytes.
+  inst->SetOpcode(new_opcode);
+  // Replace method index by vtable index.
+  if (is_range) {
+    inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
+  } else {
+    inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
+  }
+  quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
 }
 
 CompiledMethod* ArtCompileDEX(
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 3a260f5..4b913f4 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -293,146 +293,6 @@
   }
 }
 
-inline int CompilerDriver::IsFastInvoke(
-    ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-    Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
-    mirror::Class* referrer_class, ArtMethod* resolved_method, InvokeType* invoke_type,
-    MethodReference* target_method, const MethodReference* devirt_target,
-    uintptr_t* direct_code, uintptr_t* direct_method) {
-  // Don't try to fast-path if we don't understand the caller's class.
-  // Referrer_class is the class that this invoke is contained in.
-  if (UNLIKELY(referrer_class == nullptr)) {
-    return 0;
-  }
-  StackHandleScope<2> hs(soa.Self());
-  // Methods_class is the class refered to by the class_idx field of the methodId the method_idx is
-  // pointing to.
-  // For example in
-  //   .class LABC;
-  //   .super LDEF;
-  //   .method hi()V
-  //     ...
-  //     invoke-super {p0}, LDEF;->hi()V
-  //     ...
-  //   .end method
-  // the referrer_class is 'ABC' and the methods_class is DEF. Note that the methods class is 'DEF'
-  // even if 'DEF' inherits the method from it's superclass.
-  Handle<mirror::Class> methods_class(hs.NewHandle(mUnit->GetClassLinker()->ResolveType(
-      *target_method->dex_file,
-      target_method->dex_file->GetMethodId(target_method->dex_method_index).class_idx_,
-      dex_cache,
-      class_loader)));
-  DCHECK(methods_class.Get() != nullptr);
-  mirror::Class* methods_declaring_class = resolved_method->GetDeclaringClass();
-  if (UNLIKELY(!referrer_class->CanAccessResolvedMethod(methods_declaring_class, resolved_method,
-                                                        dex_cache.Get(),
-                                                        target_method->dex_method_index))) {
-    return 0;
-  }
-  // Sharpen a virtual call into a direct call when the target is known not to have been
-  // overridden (ie is final).
-  const bool same_dex_file = target_method->dex_file == mUnit->GetDexFile();
-  bool can_sharpen_virtual_based_on_type = same_dex_file &&
-      (*invoke_type == kVirtual) && (resolved_method->IsFinal() ||
-                                     methods_declaring_class->IsFinal());
-  // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
-  // the super class.
-  const PointerSize pointer_size = InstructionSetPointerSize(GetInstructionSet());
-  // TODO We should be able to sharpen if we are going into the boot image as well.
-  bool can_sharpen_super_based_on_type = same_dex_file &&
-      (*invoke_type == kSuper) &&
-      !methods_class->IsInterface() &&
-      (referrer_class != methods_declaring_class) &&
-      referrer_class->IsSubClass(methods_declaring_class) &&
-      resolved_method->GetMethodIndex() < methods_declaring_class->GetVTableLength() &&
-      (methods_declaring_class->GetVTableEntry(
-          resolved_method->GetMethodIndex(), pointer_size) == resolved_method) &&
-      resolved_method->IsInvokable();
-  // TODO We should be able to sharpen if we are going into the boot image as well.
-  bool can_sharpen_interface_super_based_on_type = same_dex_file &&
-      (*invoke_type == kSuper) &&
-      methods_class->IsInterface() &&
-      methods_class->IsAssignableFrom(referrer_class) &&
-      resolved_method->IsInvokable();
-
-  if (can_sharpen_virtual_based_on_type ||
-      can_sharpen_super_based_on_type ||
-      can_sharpen_interface_super_based_on_type) {
-    // Sharpen a virtual call into a direct call. The method_idx is into referrer's
-    // dex cache, check that this resolved method is where we expect it.
-    CHECK_EQ(target_method->dex_file, mUnit->GetDexFile());
-    DCHECK_EQ(dex_cache.Get(), mUnit->GetClassLinker()->FindDexCache(
-        soa.Self(), *mUnit->GetDexFile(), false));
-    CHECK_EQ(referrer_class->GetDexCache()->GetResolvedMethod(
-        target_method->dex_method_index, pointer_size),
-             resolved_method) << PrettyMethod(resolved_method);
-    int stats_flags = kFlagMethodResolved;
-    GetCodeAndMethodForDirectCall(/*out*/invoke_type,
-                                  kDirect,  // Sharp type
-                                  false,    // The dex cache is guaranteed to be available
-                                  referrer_class, resolved_method,
-                                  /*out*/&stats_flags,
-                                  target_method,
-                                  /*out*/direct_code,
-                                  /*out*/direct_method);
-    DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method);
-    if (*invoke_type == kDirect) {
-      stats_flags |= kFlagsMethodResolvedVirtualMadeDirect;
-    }
-    return stats_flags;
-  }
-
-  if ((*invoke_type == kVirtual || *invoke_type == kInterface) && devirt_target != nullptr) {
-    // Post-verification callback recorded a more precise invoke target based on its type info.
-    ArtMethod* called_method;
-    ClassLinker* class_linker = mUnit->GetClassLinker();
-    if (LIKELY(devirt_target->dex_file == mUnit->GetDexFile())) {
-      called_method = class_linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
-          *devirt_target->dex_file, devirt_target->dex_method_index, dex_cache, class_loader,
-          nullptr, kVirtual);
-    } else {
-      auto target_dex_cache(hs.NewHandle(class_linker->RegisterDexFile(*devirt_target->dex_file,
-                                                                       class_loader.Get())));
-      called_method = class_linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
-          *devirt_target->dex_file, devirt_target->dex_method_index, target_dex_cache,
-          class_loader, nullptr, kVirtual);
-    }
-    CHECK(called_method != nullptr);
-    CHECK(called_method->IsInvokable());
-    int stats_flags = kFlagMethodResolved;
-    GetCodeAndMethodForDirectCall(/*out*/invoke_type,
-                                  kDirect,  // Sharp type
-                                  true,     // The dex cache may not be available
-                                  referrer_class, called_method,
-                                  /*out*/&stats_flags,
-                                  target_method,
-                                  /*out*/direct_code,
-                                  /*out*/direct_method);
-    DCHECK_NE(*invoke_type, kSuper);
-    if (*invoke_type == kDirect) {
-      stats_flags |= kFlagsMethodResolvedPreciseTypeDevirtualization;
-    }
-    return stats_flags;
-  }
-
-  if (UNLIKELY(*invoke_type == kSuper)) {
-    // Unsharpened super calls are suspicious so go slow-path.
-    return 0;
-  }
-
-  // Sharpening failed so generate a regular resolved method dispatch.
-  int stats_flags = kFlagMethodResolved;
-  GetCodeAndMethodForDirectCall(/*out*/invoke_type,
-                                *invoke_type,  // Sharp type
-                                false,         // The dex cache is guaranteed to be available
-                                referrer_class, resolved_method,
-                                /*out*/&stats_flags,
-                                target_method,
-                                /*out*/direct_code,
-                                /*out*/direct_method);
-  return stats_flags;
-}
-
 inline bool CompilerDriver::IsMethodsClassInitialized(mirror::Class* referrer_class,
                                                       ArtMethod* resolved_method) {
   if (!resolved_method->IsStatic()) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index a149c07..adbf9fd 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1654,12 +1654,8 @@
   }
 }
 
-void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type,
-                                                   bool no_guarantee_of_dex_cache_entry,
-                                                   const mirror::Class* referrer_class,
+void CompilerDriver::GetCodeAndMethodForDirectCall(const mirror::Class* referrer_class,
                                                    ArtMethod* method,
-                                                   int* stats_flags,
-                                                   MethodReference* target_method,
                                                    uintptr_t* direct_code,
                                                    uintptr_t* direct_method) {
   // For direct and static methods compute possible direct_code and direct_method values, ie
@@ -1671,15 +1667,11 @@
   Runtime* const runtime = Runtime::Current();
   gc::Heap* const heap = runtime->GetHeap();
   auto* cl = runtime->GetClassLinker();
-  const auto pointer_size = cl->GetImagePointerSize();
   bool use_dex_cache = GetCompilerOptions().GetCompilePic();  // Off by default
   const bool compiling_boot = heap->IsCompilingBoot();
   // TODO This is somewhat hacky. We should refactor all of this invoke codepath.
   const bool force_relocations = (compiling_boot ||
                                   GetCompilerOptions().GetIncludePatchInformation());
-  if (sharp_type != kStatic && sharp_type != kDirect) {
-    return;
-  }
   // TODO: support patching on all architectures.
   use_dex_cache = use_dex_cache || (force_relocations && !support_boot_image_fixup_);
   mirror::Class* declaring_class = method->GetDeclaringClass();
@@ -1687,14 +1679,12 @@
   if (!use_dex_cache) {
     if (!method_code_in_boot) {
       use_dex_cache = true;
-    } else {
-      bool has_clinit_trampoline =
-          method->IsStatic() && !declaring_class->IsInitialized();
-      if (has_clinit_trampoline && declaring_class != referrer_class) {
-        // Ensure we run the clinit trampoline unless we are invoking a static method in the same
-        // class.
-        use_dex_cache = true;
-      }
+    } else if (method->IsStatic() &&
+               declaring_class != referrer_class &&
+               !declaring_class->IsInitialized()) {
+      // Ensure we run the clinit trampoline unless we are invoking a static method in the same
+      // class.
+      use_dex_cache = true;
     }
   }
   if (runtime->UseJitCompilation()) {
@@ -1705,9 +1695,7 @@
       use_dex_cache = true;
     }
   }
-  if (method_code_in_boot) {
-    *stats_flags |= kFlagDirectCallToBoot | kFlagDirectMethodToBoot;
-  }
+
   if (!use_dex_cache && force_relocations) {
     bool is_in_image;
     if (IsBootImage()) {
@@ -1724,39 +1712,8 @@
       use_dex_cache = true;
     }
   }
-  // The method is defined not within this dex file. We need a dex cache slot within the current
-  // dex file or direct pointers.
-  bool must_use_direct_pointers = false;
-  mirror::DexCache* dex_cache = declaring_class->GetDexCache();
-  if (target_method->dex_file == dex_cache->GetDexFile() &&
-    !(runtime->UseJitCompilation() && dex_cache->GetResolvedMethod(
-        method->GetDexMethodIndex(), pointer_size) == nullptr)) {
-    target_method->dex_method_index = method->GetDexMethodIndex();
-  } else {
-    if (no_guarantee_of_dex_cache_entry) {
-      // See if the method is also declared in this dex cache.
-      uint32_t dex_method_idx = method->FindDexMethodIndexInOtherDexFile(
-          *target_method->dex_file, target_method->dex_method_index);
-      if (dex_method_idx != DexFile::kDexNoIndex) {
-        target_method->dex_method_index = dex_method_idx;
-      } else {
-        if (force_relocations && !use_dex_cache) {
-          target_method->dex_method_index = method->GetDexMethodIndex();
-          target_method->dex_file = dex_cache->GetDexFile();
-        }
-        must_use_direct_pointers = true;
-      }
-    }
-  }
-  if (use_dex_cache) {
-    if (must_use_direct_pointers) {
-      // Fail. Test above showed the only safe dispatch was via the dex cache, however, the direct
-      // pointers are required as the dex cache lacks an appropriate entry.
-      VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method);
-    } else {
-      *type = sharp_type;
-    }
-  } else {
+
+  if (!use_dex_cache) {
     bool method_in_image = false;
     const std::vector<gc::space::ImageSpace*> image_spaces = heap->GetBootImageSpaces();
     for (gc::space::ImageSpace* image_space : image_spaces) {
@@ -1772,87 +1729,15 @@
       // the method and its code are / will be. We don't sharpen to interpreter bridge since we
       // check IsQuickToInterpreterBridge above.
       CHECK(!method->IsAbstract());
-      *type = sharp_type;
       *direct_method = force_relocations ? -1 : reinterpret_cast<uintptr_t>(method);
       *direct_code = force_relocations ? -1 : compiler_->GetEntryPointOf(method);
-      target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
-      target_method->dex_method_index = method->GetDexMethodIndex();
-    } else if (!must_use_direct_pointers) {
+    } else {
       // Set the code and rely on the dex cache for the method.
-      *type = sharp_type;
-      if (force_relocations) {
-        *direct_code = -1;
-        target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
-        target_method->dex_method_index = method->GetDexMethodIndex();
-      } else {
-        *direct_code = compiler_->GetEntryPointOf(method);
-      }
-    } else {
-      // Direct pointers were required but none were available.
-      VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method);
+      *direct_code = force_relocations ? -1 : compiler_->GetEntryPointOf(method);
     }
   }
 }
 
-bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
-                                       bool update_stats, bool enable_devirtualization,
-                                       InvokeType* invoke_type, MethodReference* target_method,
-                                       int* vtable_idx, uintptr_t* direct_code,
-                                       uintptr_t* direct_method) {
-  InvokeType orig_invoke_type = *invoke_type;
-  int stats_flags = 0;
-  ScopedObjectAccess soa(Thread::Current());
-  // Try to resolve the method and compiling method's class.
-  StackHandleScope<2> hs(soa.Self());
-  Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache());
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
-      soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
-  uint32_t method_idx = target_method->dex_method_index;
-  ArtMethod* resolved_method = ResolveMethod(
-      soa, dex_cache, class_loader, mUnit, method_idx, orig_invoke_type);
-  auto h_referrer_class = hs.NewHandle(resolved_method != nullptr ?
-      ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit) : nullptr);
-  bool result = false;
-  if (resolved_method != nullptr) {
-    *vtable_idx = GetResolvedMethodVTableIndex(resolved_method, orig_invoke_type);
-
-    if (enable_devirtualization && mUnit->GetVerifiedMethod() != nullptr) {
-      const MethodReference* devirt_target = mUnit->GetVerifiedMethod()->GetDevirtTarget(dex_pc);
-
-      stats_flags = IsFastInvoke(
-          soa, dex_cache, class_loader, mUnit, h_referrer_class.Get(), resolved_method,
-          invoke_type, target_method, devirt_target, direct_code, direct_method);
-      result = stats_flags != 0;
-    } else {
-      // Devirtualization not enabled. Inline IsFastInvoke(), dropping the devirtualization parts.
-      if (UNLIKELY(h_referrer_class.Get() == nullptr) ||
-          UNLIKELY(!h_referrer_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(),
-                                                            resolved_method, dex_cache.Get(),
-                                                            target_method->dex_method_index)) ||
-          *invoke_type == kSuper) {
-        // Slow path. (Without devirtualization, all super calls go slow path as well.)
-      } else {
-        // Sharpening failed so generate a regular resolved method dispatch.
-        stats_flags = kFlagMethodResolved;
-        GetCodeAndMethodForDirectCall(
-            invoke_type, *invoke_type, false, h_referrer_class.Get(), resolved_method, &stats_flags,
-            target_method, direct_code, direct_method);
-        result = true;
-      }
-    }
-  }
-  if (!result) {
-    // Conservative defaults.
-    *vtable_idx = -1;
-    *direct_code = 0u;
-    *direct_method = 0u;
-  }
-  if (update_stats) {
-    ProcessedInvoke(orig_invoke_type, stats_flags);
-  }
-  return result;
-}
-
 const VerifiedMethod* CompilerDriver::GetVerifiedMethod(const DexFile* dex_file,
                                                         uint32_t method_idx) const {
   MethodReference ref(dex_file, method_idx);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ee21efa..1f4c3ac 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -328,16 +328,6 @@
       ArtMethod* resolved_method, InvokeType type)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // Can we fast-path an INVOKE? If no, returns 0. If yes, returns a non-zero opaque flags value
-  // for ProcessedInvoke() and computes the necessary lowering info.
-  int IsFastInvoke(
-      ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-      Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
-      mirror::Class* referrer_class, ArtMethod* resolved_method, InvokeType* invoke_type,
-      MethodReference* target_method, const MethodReference* devirt_target,
-      uintptr_t* direct_code, uintptr_t* direct_method)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   // Is method's class initialized for an invoke?
   // For static invokes to determine whether we need to consider potential call to <clinit>().
   // For non-static invokes, assuming a non-null reference, the class is always initialized.
@@ -371,14 +361,6 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
 
-  // Can we fastpath a interface, super class or virtual method call? Computes method's vtable
-  // index.
-  bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
-                         bool update_stats, bool enable_devirtualization,
-                         InvokeType* type, MethodReference* target_method, int* vtable_idx,
-                         uintptr_t* direct_code, uintptr_t* direct_method)
-      REQUIRES(!Locks::mutator_lock_);
-
   const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
   bool IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc);
 
@@ -538,14 +520,10 @@
 
  public:  // TODO make private or eliminate.
   // Compute constant code and method pointers when possible.
-  void GetCodeAndMethodForDirectCall(/*out*/InvokeType* type,
-                                     InvokeType sharp_type,
-                                     bool no_guarantee_of_dex_cache_entry,
-                                     const mirror::Class* referrer_class,
+  void GetCodeAndMethodForDirectCall(const mirror::Class* referrer_class,
                                      ArtMethod* method,
-                                     /*out*/int* stats_flags,
-                                     MethodReference* target_method,
-                                     uintptr_t* direct_code, uintptr_t* direct_method)
+                                     /* out */ uintptr_t* direct_code,
+                                     /* out */ uintptr_t* direct_method)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index cf633df..0f8cdbb 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -346,7 +346,7 @@
 
   // Initialize to anything to silent compiler warnings.
   QuickEntrypointEnum entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck;
-  switch (invoke->GetOriginalInvokeType()) {
+  switch (invoke->GetInvokeType()) {
     case kStatic:
       entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck;
       break;
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index c0c798d..8500204 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -515,7 +515,7 @@
   // otherwise return a fall-back info that should be used instead.
   virtual HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) = 0;
+      HInvokeStaticOrDirect* invoke) = 0;
 
   // Generate a call to a static or direct method.
   virtual void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) = 0;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index a052873..6be458c 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -6672,7 +6672,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) {
+      HInvokeStaticOrDirect* invoke) {
   HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
   // We disable pc-relative load when there is an irreducible loop, as the optimization
   // is incompatible with it.
@@ -6686,7 +6686,7 @@
 
   if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
     const DexFile& outer_dex_file = GetGraph()->GetDexFile();
-    if (&outer_dex_file != target_method.dex_file) {
+    if (&outer_dex_file != invoke->GetTargetMethod().dex_file) {
       // Calls across dex files are more likely to exceed the available BL range,
       // so use absolute patch with fixup if available and kCallArtMethod otherwise.
       HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 424a1a1..6416d40 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -454,7 +454,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) OVERRIDE;
+      HInvokeStaticOrDirect* invoke) OVERRIDE;
 
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
   void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a29e9f3..7160607 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -3544,7 +3544,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM64::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method ATTRIBUTE_UNUSED) {
+      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
   // On ARM64 we support all dispatch types.
   return desired_dispatch_info;
 }
@@ -3588,7 +3588,7 @@
       break;
     case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
       // Add ADRP with its PC-relative DexCache access patch.
-      const DexFile& dex_file = *invoke->GetTargetMethod().dex_file;
+      const DexFile& dex_file = invoke->GetDexFile();
       uint32_t element_offset = invoke->GetDexCacheArrayOffset();
       vixl::aarch64::Label* adrp_label = NewPcRelativeDexCacheArrayPatch(dex_file, element_offset);
       {
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index f1dc7ee..a152245 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -522,7 +522,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) OVERRIDE;
+      HInvokeStaticOrDirect* invoke) OVERRIDE;
 
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
   void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index b06c84d..226f109 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -432,7 +432,7 @@
 // otherwise return a fall-back info that should be used instead.
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARMVIXL::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) {
+      HInvokeStaticOrDirect* invoke) {
   TODO_VIXL32(FATAL);
   return desired_dispatch_info;
 }
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index d0c2c85..7b7118c 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -363,7 +363,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) OVERRIDE;
+      HInvokeStaticOrDirect* invoke) OVERRIDE;
 
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
   void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 2211ea3..f560207 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -4327,7 +4327,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method ATTRIBUTE_UNUSED) {
+      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
   HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
   // We disable PC-relative load when there is an irreducible loop, as the optimization
   // is incompatible with it.
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 553a7e6..f943978 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -395,7 +395,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) OVERRIDE;
+      HInvokeStaticOrDirect* invoke) OVERRIDE;
 
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
   void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 5039fad..a5e2351 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -2972,7 +2972,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS64::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method ATTRIBUTE_UNUSED) {
+      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
   switch (desired_dispatch_info.method_load_kind) {
     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
     case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 2dd409a..690eccb 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -343,7 +343,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) OVERRIDE;
+      HInvokeStaticOrDirect* invoke) OVERRIDE;
 
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
   void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index cc9fe83..47dfb2e 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4217,7 +4217,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method ATTRIBUTE_UNUSED) {
+      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
   HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
 
   // We disable pc-relative load when there is an irreducible loop, as the optimization
@@ -4297,7 +4297,7 @@
       __ movl(temp.AsRegister<Register>(), Address(base_reg, kDummy32BitOffset));
       // Bind a new fixup label at the end of the "movl" insn.
       uint32_t offset = invoke->GetDexCacheArrayOffset();
-      __ Bind(NewPcRelativeDexCacheArrayPatch(*invoke->GetTargetMethod().dex_file, offset));
+      __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset));
       break;
     }
     case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 5866e65..1ae9af3 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -402,7 +402,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) OVERRIDE;
+      HInvokeStaticOrDirect* invoke) OVERRIDE;
 
   // Generate a call to a static or direct method.
   Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 1d87bf6..59c0ca4 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -733,7 +733,7 @@
 
 HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method ATTRIBUTE_UNUSED) {
+      HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
   switch (desired_dispatch_info.code_ptr_location) {
     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
     case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
@@ -775,7 +775,7 @@
               Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
       // Bind a new fixup label at the end of the "movl" insn.
       uint32_t offset = invoke->GetDexCacheArrayOffset();
-      __ Bind(NewPcRelativeDexCacheArrayPatch(*invoke->GetTargetMethod().dex_file, offset));
+      __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset));
       break;
     }
     case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 7108676..594f051 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -399,7 +399,7 @@
   // otherwise return a fall-back info that should be used instead.
   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
-      MethodReference target_method) OVERRIDE;
+      HInvokeStaticOrDirect* invoke) OVERRIDE;
 
   Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.cc b/compiler/optimizing/dex_cache_array_fixups_arm.cc
index 6ad9b07..7010171 100644
--- a/compiler/optimizing/dex_cache_array_fixups_arm.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_arm.cc
@@ -82,12 +82,10 @@
     // we need to add the dex cache arrays base as the special input.
     if (invoke->HasPcRelativeDexCache() &&
         !IsCallFreeIntrinsic<IntrinsicLocationsBuilderARM>(invoke, codegen_)) {
-      // Initialize base for target method dex file if needed.
-      MethodReference target_method = invoke->GetTargetMethod();
-      HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(*target_method.dex_file);
+      HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(invoke->GetDexFile());
       // Update the element offset in base.
-      DexCacheArraysLayout layout(kArmPointerSize, target_method.dex_file);
-      base->UpdateElementOffset(layout.MethodOffset(target_method.dex_method_index));
+      DexCacheArraysLayout layout(kArmPointerSize, &invoke->GetDexFile());
+      base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex()));
       // Add the special argument base to the method.
       DCHECK(!invoke->HasCurrentMethodInput());
       invoke->AddSpecialInput(base);
diff --git a/compiler/optimizing/dex_cache_array_fixups_mips.cc b/compiler/optimizing/dex_cache_array_fixups_mips.cc
index 300284d..4456b49 100644
--- a/compiler/optimizing/dex_cache_array_fixups_mips.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_mips.cc
@@ -89,11 +89,10 @@
     if (invoke->HasPcRelativeDexCache() &&
         !IsCallFreeIntrinsic<IntrinsicLocationsBuilderMIPS>(invoke, codegen_)) {
       // Initialize base for target method dex file if needed.
-      MethodReference target_method = invoke->GetTargetMethod();
-      HMipsDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(*target_method.dex_file);
+      HMipsDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(invoke->GetDexFile());
       // Update the element offset in base.
-      DexCacheArraysLayout layout(kMipsPointerSize, target_method.dex_file);
-      base->UpdateElementOffset(layout.MethodOffset(target_method.dex_method_index));
+      DexCacheArraysLayout layout(kMipsPointerSize, &invoke->GetDexFile());
+      base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex()));
       // Add the special argument base to the method.
       DCHECK(!invoke->HasCurrentMethodInput());
       invoke->AddSpecialInput(base);
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index b3d5341..912ee29 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -447,7 +447,7 @@
 
   void VisitInvokeUnresolved(HInvokeUnresolved* invoke) OVERRIDE {
     VisitInvoke(invoke);
-    StartAttributeStream("invoke_type") << invoke->GetOriginalInvokeType();
+    StartAttributeStream("invoke_type") << invoke->GetInvokeType();
   }
 
   void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index ce53134..f21dc0e 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -263,42 +263,24 @@
     return false;  // Don't bother to move further if we know the method is unresolved.
   }
 
-  uint32_t method_index = invoke_instruction->GetDexMethodIndex();
   ScopedObjectAccess soa(Thread::Current());
+  uint32_t method_index = invoke_instruction->GetDexMethodIndex();
   const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
   VLOG(compiler) << "Try inlining " << PrettyMethod(method_index, caller_dex_file);
 
-  ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
   // We can query the dex cache directly. The verifier has populated it already.
-  ArtMethod* resolved_method;
+  ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod();
   ArtMethod* actual_method = nullptr;
-  if (invoke_instruction->IsInvokeStaticOrDirect()) {
-    if (invoke_instruction->AsInvokeStaticOrDirect()->IsStringInit()) {
-      VLOG(compiler) << "Not inlining a String.<init> method";
-      return false;
-    }
-    MethodReference ref = invoke_instruction->AsInvokeStaticOrDirect()->GetTargetMethod();
-    mirror::DexCache* const dex_cache = IsSameDexFile(caller_dex_file, *ref.dex_file)
-        ? caller_compilation_unit_.GetDexCache().Get()
-        : class_linker->FindDexCache(soa.Self(), *ref.dex_file);
-    resolved_method = dex_cache->GetResolvedMethod(
-        ref.dex_method_index, class_linker->GetImagePointerSize());
-    // actual_method == resolved_method for direct or static calls.
+  if (resolved_method == nullptr) {
+    DCHECK(invoke_instruction->IsInvokeStaticOrDirect());
+    DCHECK(invoke_instruction->AsInvokeStaticOrDirect()->IsStringInit());
+    VLOG(compiler) << "Not inlining a String.<init> method";
+    return false;
+  } else if (invoke_instruction->IsInvokeStaticOrDirect()) {
     actual_method = resolved_method;
   } else {
-    resolved_method = caller_compilation_unit_.GetDexCache().Get()->GetResolvedMethod(
-        method_index, class_linker->GetImagePointerSize());
-    if (resolved_method != nullptr) {
-      // Check if we can statically find the method.
-      actual_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method);
-    }
-  }
-
-  if (resolved_method == nullptr) {
-    // TODO: Can this still happen?
-    // Method cannot be resolved if it is in another dex file we do not have access to.
-    VLOG(compiler) << "Method cannot be resolved " << PrettyMethod(method_index, caller_dex_file);
-    return false;
+    // Check if we can statically find the method.
+    actual_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method);
   }
 
   if (actual_method != nullptr) {
@@ -763,9 +745,9 @@
       // 2) We will not go to the conflict trampoline with an invoke-virtual.
       // TODO: Consider sharpening once it is not dependent on the compiler driver.
       const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
-      uint32_t method_index = FindMethodIndexIn(
+      uint32_t dex_method_index = FindMethodIndexIn(
           method, caller_dex_file, invoke_instruction->GetDexMethodIndex());
-      if (method_index == DexFile::kDexNoIndex) {
+      if (dex_method_index == DexFile::kDexNoIndex) {
         return false;
       }
       HInvokeVirtual* new_invoke = new (graph_->GetArena()) HInvokeVirtual(
@@ -773,7 +755,8 @@
           invoke_instruction->GetNumberOfArguments(),
           invoke_instruction->GetType(),
           invoke_instruction->GetDexPc(),
-          method_index,
+          dex_method_index,
+          method,
           method->GetMethodIndex());
       HInputsRef inputs = invoke_instruction->GetInputs();
       for (size_t index = 0; index != inputs.size(); ++index) {
@@ -1122,7 +1105,7 @@
     }
   }
 
-  InvokeType invoke_type = invoke_instruction->GetOriginalInvokeType();
+  InvokeType invoke_type = invoke_instruction->GetInvokeType();
   if (invoke_type == kInterface) {
     // We have statically resolved the dispatch. To please the class linker
     // at runtime, we change this call as if it was a virtual call.
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index d7e4c53..5a6a212 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -785,8 +785,6 @@
     number_of_arguments++;
   }
 
-  MethodReference target_method(dex_file_, method_idx);
-
   // Special handling for string init.
   int32_t string_init_offset = 0;
   bool is_string_init = compiler_driver_->IsStringInit(method_idx,
@@ -800,16 +798,17 @@
         dchecked_integral_cast<uint64_t>(string_init_offset),
         0U
     };
+    MethodReference target_method(dex_file_, method_idx);
     HInvoke* invoke = new (arena_) HInvokeStaticOrDirect(
         arena_,
         number_of_arguments - 1,
         Primitive::kPrimNot /*return_type */,
         dex_pc,
         method_idx,
-        target_method,
+        nullptr,
         dispatch_info,
         invoke_type,
-        kStatic /* optimized_invoke_type */,
+        target_method,
         HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
     return HandleStringInit(invoke,
                             number_of_vreg_arguments,
@@ -853,10 +852,9 @@
           dex_pc, resolved_method, method_idx, &clinit_check_requirement);
     } else if (invoke_type == kSuper) {
       if (IsSameDexFile(*resolved_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) {
-        // Update the target method to the one resolved. Note that this may be a no-op if
+        // Update the method index to the one resolved. Note that this may be a no-op if
         // we resolved to the method referenced by the instruction.
         method_idx = resolved_method->GetDexMethodIndex();
-        target_method = MethodReference(dex_file_, method_idx);
       }
     }
 
@@ -866,15 +864,17 @@
         0u,
         0U
     };
+    MethodReference target_method(resolved_method->GetDexFile(),
+                                  resolved_method->GetDexMethodIndex());
     invoke = new (arena_) HInvokeStaticOrDirect(arena_,
                                                 number_of_arguments,
                                                 return_type,
                                                 dex_pc,
                                                 method_idx,
-                                                target_method,
+                                                resolved_method,
                                                 dispatch_info,
                                                 invoke_type,
-                                                invoke_type,
+                                                target_method,
                                                 clinit_check_requirement);
   } else if (invoke_type == kVirtual) {
     ScopedObjectAccess soa(Thread::Current());  // Needed for the method index
@@ -883,15 +883,17 @@
                                          return_type,
                                          dex_pc,
                                          method_idx,
+                                         resolved_method,
                                          resolved_method->GetMethodIndex());
   } else {
     DCHECK_EQ(invoke_type, kInterface);
-    ScopedObjectAccess soa(Thread::Current());  // Needed for the method index
+    ScopedObjectAccess soa(Thread::Current());  // Needed for the IMT index.
     invoke = new (arena_) HInvokeInterface(arena_,
                                            number_of_arguments,
                                            return_type,
                                            dex_pc,
                                            method_idx,
+                                           resolved_method,
                                            resolved_method->GetImtIndex());
   }
 
@@ -1103,7 +1105,7 @@
 
   size_t start_index = 0;
   size_t argument_index = 0;
-  if (invoke->GetOriginalInvokeType() != InvokeType::kStatic) {  // Instance call.
+  if (invoke->GetInvokeType() != InvokeType::kStatic) {  // Instance call.
     uint32_t obj_reg = is_range ? register_index : args[0];
     HInstruction* arg = is_unresolved
         ? LoadLocal(obj_reg, Primitive::kPrimNot)
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index b787888..ff829af 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -1657,7 +1657,7 @@
                                                   bool is_left,
                                                   Primitive::Type type) {
   DCHECK(invoke->IsInvokeStaticOrDirect());
-  DCHECK_EQ(invoke->GetOriginalInvokeType(), InvokeType::kStatic);
+  DCHECK_EQ(invoke->GetInvokeType(), InvokeType::kStatic);
   HInstruction* value = invoke->InputAt(0);
   HInstruction* distance = invoke->InputAt(1);
   // Replace the invoke with an HRor.
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 418d59c..4d4bbcf 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -532,9 +532,7 @@
   // inline. If the precise type is known, however, the instruction will be sharpened to an
   // InvokeStaticOrDirect.
   InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
-  InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
-      invoke->AsInvokeStaticOrDirect()->GetOptimizedInvokeType() :
-      invoke->IsInvokeVirtual() ? kVirtual : kSuper;
+  InvokeType invoke_type = invoke->GetInvokeType();
   switch (intrinsic_type) {
     case kStatic:
       return (invoke_type == kStatic);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 6d207765..57ae555 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -3742,8 +3742,8 @@
   uint32_t GetDexMethodIndex() const { return dex_method_index_; }
   const DexFile& GetDexFile() const { return GetEnvironment()->GetDexFile(); }
 
-  InvokeType GetOriginalInvokeType() const {
-    return GetPackedField<OriginalInvokeTypeField>();
+  InvokeType GetInvokeType() const {
+    return GetPackedField<InvokeTypeField>();
   }
 
   Intrinsics GetIntrinsic() const {
@@ -3777,21 +3777,22 @@
 
   bool IsIntrinsic() const { return intrinsic_ != Intrinsics::kNone; }
 
+  ArtMethod* GetResolvedMethod() const { return resolved_method_; }
+
   DECLARE_ABSTRACT_INSTRUCTION(Invoke);
 
  protected:
-  static constexpr size_t kFieldOriginalInvokeType = kNumberOfGenericPackedBits;
-  static constexpr size_t kFieldOriginalInvokeTypeSize =
+  static constexpr size_t kFieldInvokeType = kNumberOfGenericPackedBits;
+  static constexpr size_t kFieldInvokeTypeSize =
       MinimumBitsToStore(static_cast<size_t>(kMaxInvokeType));
   static constexpr size_t kFieldReturnType =
-      kFieldOriginalInvokeType + kFieldOriginalInvokeTypeSize;
+      kFieldInvokeType + kFieldInvokeTypeSize;
   static constexpr size_t kFieldReturnTypeSize =
       MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
   static constexpr size_t kFlagCanThrow = kFieldReturnType + kFieldReturnTypeSize;
   static constexpr size_t kNumberOfInvokePackedBits = kFlagCanThrow + 1;
   static_assert(kNumberOfInvokePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
-  using OriginalInvokeTypeField =
-      BitField<InvokeType, kFieldOriginalInvokeType, kFieldOriginalInvokeTypeSize>;
+  using InvokeTypeField = BitField<InvokeType, kFieldInvokeType, kFieldInvokeTypeSize>;
   using ReturnTypeField = BitField<Primitive::Type, kFieldReturnType, kFieldReturnTypeSize>;
 
   HInvoke(ArenaAllocator* arena,
@@ -3800,23 +3801,26 @@
           Primitive::Type return_type,
           uint32_t dex_pc,
           uint32_t dex_method_index,
-          InvokeType original_invoke_type)
+          ArtMethod* resolved_method,
+          InvokeType invoke_type)
     : HInstruction(
           SideEffects::AllExceptGCDependency(), dex_pc),  // Assume write/read on all fields/arrays.
       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) {
     SetPackedField<ReturnTypeField>(return_type);
-    SetPackedField<OriginalInvokeTypeField>(original_invoke_type);
+    SetPackedField<InvokeTypeField>(invoke_type);
     SetPackedFlag<kFlagCanThrow>(true);
   }
 
   void SetCanThrow(bool can_throw) { SetPackedFlag<kFlagCanThrow>(can_throw); }
 
   uint32_t number_of_arguments_;
+  ArtMethod* const resolved_method_;
   ArenaVector<HUserRecord<HInstruction*>> inputs_;
   const uint32_t dex_method_index_;
   Intrinsics intrinsic_;
@@ -3842,6 +3846,7 @@
                 return_type,
                 dex_pc,
                 dex_method_index,
+                nullptr,
                 invoke_type) {
   }
 
@@ -3935,10 +3940,10 @@
                         Primitive::Type return_type,
                         uint32_t dex_pc,
                         uint32_t method_index,
-                        MethodReference target_method,
+                        ArtMethod* resolved_method,
                         DispatchInfo dispatch_info,
-                        InvokeType original_invoke_type,
-                        InvokeType optimized_invoke_type,
+                        InvokeType invoke_type,
+                        MethodReference target_method,
                         ClinitCheckRequirement clinit_check_requirement)
       : HInvoke(arena,
                 number_of_arguments,
@@ -3950,10 +3955,10 @@
                 return_type,
                 dex_pc,
                 method_index,
-                original_invoke_type),
+                resolved_method,
+                invoke_type),
         target_method_(target_method),
         dispatch_info_(dispatch_info) {
-    SetPackedField<OptimizedInvokeTypeField>(optimized_invoke_type);
     SetPackedField<ClinitCheckRequirementField>(clinit_check_requirement);
   }
 
@@ -4017,14 +4022,6 @@
   uint32_t GetSpecialInputIndex() const { return GetNumberOfArguments(); }
   bool HasSpecialInput() const { return GetNumberOfArguments() != InputCount(); }
 
-  InvokeType GetOptimizedInvokeType() const {
-    return GetPackedField<OptimizedInvokeTypeField>();
-  }
-
-  void SetOptimizedInvokeType(InvokeType invoke_type) {
-    SetPackedField<OptimizedInvokeTypeField>(invoke_type);
-  }
-
   MethodLoadKind GetMethodLoadKind() const { return dispatch_info_.method_load_kind; }
   CodePtrLocation GetCodePtrLocation() const { return dispatch_info_.code_ptr_location; }
   bool IsRecursive() const { return GetMethodLoadKind() == MethodLoadKind::kRecursive; }
@@ -4046,8 +4043,6 @@
     }
   }
   bool HasDirectCodePtr() const { return GetCodePtrLocation() == CodePtrLocation::kCallDirect; }
-  MethodReference GetTargetMethod() const { return target_method_; }
-  void SetTargetMethod(MethodReference method) { target_method_ = method; }
 
   int32_t GetStringInitOffset() const {
     DCHECK(IsStringInit());
@@ -4075,7 +4070,11 @@
 
   // Is this instruction a call to a static method?
   bool IsStatic() const {
-    return GetOriginalInvokeType() == kStatic;
+    return GetInvokeType() == kStatic;
+  }
+
+  MethodReference GetTargetMethod() const {
+    return target_method_;
   }
 
   // Remove the HClinitCheck or the replacement HLoadClass (set as last input by
@@ -4117,26 +4116,18 @@
   void RemoveInputAt(size_t index);
 
  private:
-  static constexpr size_t kFieldOptimizedInvokeType = kNumberOfInvokePackedBits;
-  static constexpr size_t kFieldOptimizedInvokeTypeSize =
-      MinimumBitsToStore(static_cast<size_t>(kMaxInvokeType));
-  static constexpr size_t kFieldClinitCheckRequirement =
-      kFieldOptimizedInvokeType + kFieldOptimizedInvokeTypeSize;
+  static constexpr size_t kFieldClinitCheckRequirement = kNumberOfInvokePackedBits;
   static constexpr size_t kFieldClinitCheckRequirementSize =
       MinimumBitsToStore(static_cast<size_t>(ClinitCheckRequirement::kLast));
   static constexpr size_t kNumberOfInvokeStaticOrDirectPackedBits =
       kFieldClinitCheckRequirement + kFieldClinitCheckRequirementSize;
   static_assert(kNumberOfInvokeStaticOrDirectPackedBits <= kMaxNumberOfPackedBits,
                 "Too many packed fields.");
-  using OptimizedInvokeTypeField =
-      BitField<InvokeType, kFieldOptimizedInvokeType, kFieldOptimizedInvokeTypeSize>;
   using ClinitCheckRequirementField = BitField<ClinitCheckRequirement,
                                                kFieldClinitCheckRequirement,
                                                kFieldClinitCheckRequirementSize>;
 
-  // The target method may refer to different dex file or method index than the original
-  // invoke. This happens for sharpened calls and for calls where a method was redeclared
-  // in derived class to increase visibility.
+  // Cached values of the resolved method, to avoid needing the mutator lock.
   MethodReference target_method_;
   DispatchInfo dispatch_info_;
 
@@ -4152,8 +4143,16 @@
                  Primitive::Type return_type,
                  uint32_t dex_pc,
                  uint32_t dex_method_index,
+                 ArtMethod* resolved_method,
                  uint32_t vtable_index)
-      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kVirtual),
+      : HInvoke(arena,
+                number_of_arguments,
+                0u,
+                return_type,
+                dex_pc,
+                dex_method_index,
+                resolved_method,
+                kVirtual),
         vtable_index_(vtable_index) {}
 
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
@@ -4166,6 +4165,7 @@
   DECLARE_INSTRUCTION(InvokeVirtual);
 
  private:
+  // Cached value of the resolved method, to avoid needing the mutator lock.
   const uint32_t vtable_index_;
 
   DISALLOW_COPY_AND_ASSIGN(HInvokeVirtual);
@@ -4178,8 +4178,16 @@
                    Primitive::Type return_type,
                    uint32_t dex_pc,
                    uint32_t dex_method_index,
+                   ArtMethod* resolved_method,
                    uint32_t imt_index)
-      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kInterface),
+      : HInvoke(arena,
+                number_of_arguments,
+                0u,
+                return_type,
+                dex_pc,
+                dex_method_index,
+                resolved_method,
+                kInterface),
         imt_index_(imt_index) {}
 
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
@@ -4193,6 +4201,7 @@
   DECLARE_INSTRUCTION(InvokeInterface);
 
  private:
+  // Cached value of the resolved method, to avoid needing the mutator lock.
   const uint32_t imt_index_;
 
   DISALLOW_COPY_AND_ASSIGN(HInvokeInterface);
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index e64c005..abec55f 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -61,44 +61,28 @@
     return;
   }
 
-  // TODO: Avoid CompilerDriver.
-  InvokeType original_invoke_type = invoke->GetOriginalInvokeType();
-  InvokeType optimized_invoke_type = original_invoke_type;
-  MethodReference target_method(&graph_->GetDexFile(), invoke->GetDexMethodIndex());
-  int vtable_idx;
-  uintptr_t direct_code, direct_method;
-  bool success = compiler_driver_->ComputeInvokeInfo(
-      &compilation_unit_,
-      invoke->GetDexPc(),
-      false /* update_stats: already updated in builder */,
-      true /* enable_devirtualization */,
-      &optimized_invoke_type,
-      &target_method,
-      &vtable_idx,
-      &direct_code,
-      &direct_method);
-  if (!success) {
-    // TODO: try using kDexCachePcRelative. It's always a valid method load
-    // kind as long as it's supported by the codegen
-    return;
-  }
-  invoke->SetOptimizedInvokeType(optimized_invoke_type);
-  invoke->SetTargetMethod(target_method);
+  HGraph* outer_graph = codegen_->GetGraph();
+  ArtMethod* compiling_method = graph_->GetArtMethod();
 
   HInvokeStaticOrDirect::MethodLoadKind method_load_kind;
   HInvokeStaticOrDirect::CodePtrLocation code_ptr_location;
   uint64_t method_load_data = 0u;
   uint64_t direct_code_ptr = 0u;
 
-  HGraph* outer_graph = codegen_->GetGraph();
-  if (target_method.dex_file == &outer_graph->GetDexFile() &&
-      target_method.dex_method_index == outer_graph->GetMethodIdx()) {
+  if (invoke->GetResolvedMethod() == outer_graph->GetArtMethod()) {
+    DCHECK(outer_graph->GetArtMethod() != nullptr);
     method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRecursive;
     code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallSelf;
   } else {
-    bool use_pc_relative_instructions =
-        ((direct_method == 0u || direct_code == static_cast<uintptr_t>(-1))) &&
-        ContainsElement(compiler_driver_->GetDexFilesForOatFile(), target_method.dex_file);
+    uintptr_t direct_code, direct_method;
+    {
+      ScopedObjectAccess soa(Thread::Current());
+      compiler_driver_->GetCodeAndMethodForDirectCall(
+          (compiling_method == nullptr) ? nullptr : compiling_method->GetDeclaringClass(),
+          invoke->GetResolvedMethod(),
+          &direct_code,
+          &direct_method);
+    }
     if (direct_method != 0u) {  // Should we use a direct pointer to the method?
       // Note: For JIT, kDirectAddressWithFixup doesn't make sense at all and while
       // kDirectAddress would be fine for image methods, we don't support it at the moment.
@@ -110,13 +94,12 @@
         method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup;
       }
     } else {  // Use dex cache.
-      DCHECK_EQ(target_method.dex_file, &graph_->GetDexFile());
-      if (use_pc_relative_instructions) {  // Can we use PC-relative access to the dex cache arrays?
-        DCHECK(!Runtime::Current()->UseJitCompilation());
+      if (!Runtime::Current()->UseJitCompilation()) {
+        // Use PC-relative access to the dex cache arrays.
         method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative;
         DexCacheArraysLayout layout(GetInstructionSetPointerSize(codegen_->GetInstructionSet()),
                                     &graph_->GetDexFile());
-        method_load_data = layout.MethodOffset(target_method.dex_method_index);
+        method_load_data = layout.MethodOffset(invoke->GetDexMethodIndex());
       } else {  // We must go through the ArtMethod's pointer to resolved methods.
         method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
       }
@@ -125,10 +108,11 @@
       // Note: For JIT, kCallPCRelative and kCallDirectWithFixup don't make sense at all and
       // while kCallDirect would be fine for image methods, we don't support it at the moment.
       DCHECK(!Runtime::Current()->UseJitCompilation());
+      const DexFile* dex_file_of_callee = invoke->GetTargetMethod().dex_file;
       if (direct_code != static_cast<uintptr_t>(-1)) {  // Is the code pointer known now?
         code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallDirect;
         direct_code_ptr = direct_code;
-      } else if (use_pc_relative_instructions) {
+      } else if (ContainsElement(compiler_driver_->GetDexFilesForOatFile(), dex_file_of_callee)) {
         // Use PC-relative calls for invokes within a multi-dex oat file.
         code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative;
       } else {  // The direct pointer will be known at link time.
@@ -151,8 +135,7 @@
       method_load_kind, code_ptr_location, method_load_data, direct_code_ptr
   };
   HInvokeStaticOrDirect::DispatchInfo dispatch_info =
-      codegen_->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info,
-                                                         invoke->GetTargetMethod());
+      codegen_->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, invoke);
   invoke->SetDispatchInfo(dispatch_info);
 }
 
diff --git a/test/555-checker-regression-x86const/build b/test/555-checker-regression-x86const/build
deleted file mode 100644
index 92ddfc9..0000000
--- a/test/555-checker-regression-x86const/build
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2015 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.
-
-# Stop if something fails.
-set -e
-
-# We can't use src-ex testing infrastructure because src and src-ex are compiled
-# with javac independetely and can't share code (without reflection).
-
-mkdir classes
-${JAVAC} -d classes `find src -name '*.java'`
-
-mkdir classes-ex
-mv classes/UnresolvedClass.class classes-ex
-
-if [ ${USE_JACK} = "true" ]; then
-  jar cf classes.jill.jar -C classes .
-  jar cf classes-ex.jill.jar -C classes-ex .
-
-  ${JACK} --import classes.jill.jar --output-dex .
-  zip $TEST_NAME.jar classes.dex
-  ${JACK} --import classes-ex.jill.jar --output-dex .
-  zip ${TEST_NAME}-ex.jar classes.dex
-else
-  if [ ${NEED_DEX} = "true" ]; then
-    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
-    zip $TEST_NAME.jar classes.dex
-    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
-    zip ${TEST_NAME}-ex.jar classes.dex
-  fi
-fi
diff --git a/test/555-checker-regression-x86const/expected.txt b/test/555-checker-regression-x86const/expected.txt
deleted file mode 100644
index e69de29..0000000
--- a/test/555-checker-regression-x86const/expected.txt
+++ /dev/null
diff --git a/test/555-checker-regression-x86const/info.txt b/test/555-checker-regression-x86const/info.txt
deleted file mode 100644
index c4037fa..0000000
--- a/test/555-checker-regression-x86const/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Check that X86 FP constant-area handling handles intrinsics with CurrentMethod
-on the call.
diff --git a/test/555-checker-regression-x86const/run b/test/555-checker-regression-x86const/run
deleted file mode 100644
index 63fdb8c..0000000
--- a/test/555-checker-regression-x86const/run
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2015 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.
-
-# Use secondary switch to add secondary dex file to class path.
-exec ${RUN} "${@}" --secondary
diff --git a/test/555-checker-regression-x86const/src/Main.java b/test/555-checker-regression-x86const/src/Main.java
deleted file mode 100644
index 914cfde..0000000
--- a/test/555-checker-regression-x86const/src/Main.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Main extends UnresolvedClass {
-
-  /// CHECK-START: float Main.callAbs(float) register (before)
-  /// CHECK:       <<CurrentMethod:[ij]\d+>> CurrentMethod
-  /// CHECK:       <<ParamValue:f\d+>> ParameterValue
-  /// CHECK:       InvokeStaticOrDirect [<<ParamValue>>,<<CurrentMethod>>] method_name:java.lang.Math.abs
-  static public float callAbs(float f) {
-    // An intrinsic invoke in a method that has unresolved references will still
-    // have a CurrentMethod as an argument.  The X86 pc_relative_fixups_x86 pass
-    // must be able to handle Math.abs invokes that have a CurrentMethod, as both
-    // the CurrentMethod and the HX86LoadFromConstantTable (for the bitmask)
-    // expect to be in the 'SpecialInputIndex' input index.
-    return Math.abs(f);
-  }
-
-  static public void main(String[] args) {
-    expectEquals(callAbs(-6.5f), 6.5f);
-  }
-
-  public static void expectEquals(float expected, float result) {
-    if (expected != result) {
-      throw new Error("Expected: " + expected + ", found: " + result);
-    }
-  }
-}
diff --git a/test/555-checker-regression-x86const/src/Unresolved.java b/test/555-checker-regression-x86const/src/Unresolved.java
deleted file mode 100644
index e98bdbf..0000000
--- a/test/555-checker-regression-x86const/src/Unresolved.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-class UnresolvedClass {
-}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 0497735..211a69f 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -263,9 +263,12 @@
 # 147-stripped-dex-fallback isn't supported on device because --strip-dex
 # requires the zip command.
 # 569-checker-pattern-replacement tests behaviour present only on host.
+# 902-hello-transformation isn't supported in current form due to linker
+# restrictions. See b/31681198
 TEST_ART_BROKEN_TARGET_TESTS := \
   147-stripped-dex-fallback \
-  569-checker-pattern-replacement
+  569-checker-pattern-replacement \
+  902-hello-transformation
 
 ifneq (,$(filter target,$(TARGET_TYPES)))
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
diff --git a/test/run-test b/test/run-test
index 250263a..c50a9ca 100755
--- a/test/run-test
+++ b/test/run-test
@@ -476,7 +476,7 @@
         run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}:${ANDROID_HOST_OUT}/nativetest${suffix64}"
     else
         guess_target_arch_name
-        run_args="${run_args} --runtime-option -Djava.library.path=/data/nativetest${suffix64}/art/${target_arch_name}:/system/lib${suffix64}"
+        run_args="${run_args} --runtime-option -Djava.library.path=/data/nativetest${suffix64}/art/${target_arch_name}:${android_root}/lib${suffix64}"
         run_args="${run_args} --boot /data/art-test/core${image_suffix}${pic_image_suffix}${multi_image_suffix}.art"
     fi
     if [ "$relocate" = "yes" ]; then
diff --git a/tools/jfuzz/README.md b/tools/jfuzz/README.md
index 48ce295..3eb41cf 100644
--- a/tools/jfuzz/README.md
+++ b/tools/jfuzz/README.md
@@ -14,7 +14,7 @@
 ================
 
     jfuzz [-s seed] [-d expr-depth] [-l stmt-length]
-             [-i if-nest] [-n loop-nest]
+             [-i if-nest] [-n loop-nest] [-v] [-h]
 
 where
 
@@ -28,6 +28,8 @@
          (higher values yield deeper nested conditionals)
     -n : defines a fuzzing nest for for/while/do-while loops
          (higher values yield deeper nested loops)
+    -v : prints version number and exits
+    -h : prints help and exits
 
 The current version of JFuzz sends all output to stdout, and uses
 a fixed testing class named Test. So a typical test run looks as follows.
@@ -43,18 +45,22 @@
                           [--num_tests=NUM_TESTS]
                           [--device=DEVICE]
                           [--mode1=MODE] [--mode2=MODE]
+                          [--report_script=SCRIPT]
+                          [--jfuzz_arg=ARG]
 
 where
 
-    --num_tests : number of tests to run (10000 by default)
-    --device    : target device serial number (passed to adb -s)
-    --mode1     : m1
-    --mode2     : m2, with m1 != m2, and values one of
+    --num_tests     : number of tests to run (10000 by default)
+    --device        : target device serial number (passed to adb -s)
+    --mode1         : m1
+    --mode2         : m2, with m1 != m2, and values one of
       ri   = reference implementation on host (default for m1)
       hint = Art interpreter on host
       hopt = Art optimizing on host (default for m2)
       tint = Art interpreter on target
       topt = Art optimizing on target
+    --report_script : path to script called for each divergence
+    --jfuzz_arg     : argument for jfuzz
 
 How to start J/DexFuzz testing (multi-layered)
 ==============================================
diff --git a/tools/jfuzz/jfuzz.cc b/tools/jfuzz/jfuzz.cc
index fabfc69..82683f2 100644
--- a/tools/jfuzz/jfuzz.cc
+++ b/tools/jfuzz/jfuzz.cc
@@ -1145,7 +1145,7 @@
 
   // Parse options.
   while (1) {
-    int32_t option = getopt(argc, argv, "s:d:l:i:n:h");
+    int32_t option = getopt(argc, argv, "s:d:l:i:n:vh");
     if (option < 0) {
       break;  // done
     }
@@ -1165,12 +1165,15 @@
       case 'n':
         loop_nest = strtoul(optarg, nullptr, 0);
         break;
+      case 'v':
+        fprintf(stderr, "jfuzz version %s\n", VERSION);
+        return 0;
       case 'h':
       default:
         fprintf(stderr,
                 "usage: %s [-s seed] "
                 "[-d expr-depth] [-l stmt-length] "
-                "[-i if-nest] [-n loop-nest] [-h]\n",
+                "[-i if-nest] [-n loop-nest] [-v] [-h]\n",
                 argv[0]);
         return 1;
     }
diff --git a/tools/jfuzz/run_jfuzz_test.py b/tools/jfuzz/run_jfuzz_test.py
index cf2364b..05e8daf 100755
--- a/tools/jfuzz/run_jfuzz_test.py
+++ b/tools/jfuzz/run_jfuzz_test.py
@@ -20,9 +20,11 @@
 import os
 import shlex
 import shutil
+import subprocess
 import sys
 
 from glob import glob
+from subprocess import DEVNULL
 from tempfile import mkdtemp
 
 sys.path.append(os.path.dirname(os.path.dirname(
@@ -34,6 +36,7 @@
 from common.common import GetJackClassPath
 from common.common import GetEnvVariableOrError
 from common.common import RunCommand
+from common.common import RunCommandForOutput
 from common.common import DeviceTestEnv
 
 # Return codes supported by bisection bug search.
@@ -302,7 +305,8 @@
 class JFuzzTester(object):
   """Tester that runs JFuzz many times and report divergences."""
 
-  def  __init__(self, num_tests, device, mode1, mode2):
+  def  __init__(self, num_tests, device, mode1, mode2, jfuzz_args,
+                report_script):
     """Constructor for the tester.
 
     Args:
@@ -310,11 +314,15 @@
       device: string, target device serial number (or None)
       mode1: string, execution mode for first runner
       mode2: string, execution mode for second runner
+      jfuzz_args: list of strings, additional arguments for jfuzz
+      report_script: string, path to script called for each divergence
     """
     self._num_tests = num_tests
     self._device = device
     self._runner1 = GetExecutionModeRunner(device, mode1)
     self._runner2 = GetExecutionModeRunner(device, mode2)
+    self._jfuzz_args = jfuzz_args
+    self._report_script = report_script
     self._save_dir = None
     self._results_dir = None
     self._jfuzz_dir = None
@@ -392,7 +400,8 @@
     Raises:
       FatalError: error when jfuzz fails
     """
-    if RunCommand(['jfuzz'], out='Test.java', err=None) != RetCode.SUCCESS:
+    if (RunCommand(['jfuzz'] + self._jfuzz_args, out='Test.java', err=None)
+          != RetCode.SUCCESS):
       raise FatalError('Unexpected error while running JFuzz')
 
   def CheckForDivergence(self, retc1, retc2):
@@ -442,6 +451,44 @@
     # 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."""
+    try:
+      title = "Divergence between {0} and {1} (found with fuzz testing)".format(
+          self._runner1.description, self._runner2.description)
+      # Prepare divergence comment.
+      jfuzz_cmd_and_version = subprocess.check_output(
+          ['grep', '-o', 'jfuzz.*', 'Test.java'], universal_newlines=True)
+      (jfuzz_cmd_str, jfuzz_ver) = jfuzz_cmd_and_version.split('(')
+      # Strip right parenthesis and new line.
+      jfuzz_ver = jfuzz_ver[:-2]
+      jfuzz_args = ['\'-{0}\''.format(arg)
+                    for arg in jfuzz_cmd_str.strip().split(' -')][1:]
+      wrapped_args = ['--jfuzz_arg={0}'.format(opt) for opt in jfuzz_args]
+      repro_cmd_str = (os.path.basename(__file__) + ' --num_tests 1 ' +
+                       ' '.join(wrapped_args))
+      comment = 'jfuzz {0}\nReproduce test:\n{1}\nReproduce divergence:\n{2}\n'.format(
+          jfuzz_ver, jfuzz_cmd_str, repro_cmd_str)
+      if is_output_divergence:
+        (output, _, _) = RunCommandForOutput(
+            ['diff', self._runner1.output_file, self._runner2.output_file],
+            None, subprocess.PIPE, subprocess.STDOUT)
+        comment += 'Diff:\n' + output
+      else:
+        comment += '{0} vs {1}\n'.format(retc1, retc2)
+      # Prepare report script command.
+      script_cmd = [self._report_script, title, comment]
+      ddir = self.GetCurrentDivergenceDir()
+      bisection_out_files = glob(ddir + '/*_bisection_out.txt')
+      if bisection_out_files:
+        script_cmd += ['--bisection_out', bisection_out_files[0]]
+      subprocess.check_call(script_cmd, stdout=DEVNULL, stderr=DEVNULL)
+    except subprocess.CalledProcessError as err:
+      print('Failed to run report script.\n', err)
 
   def RunBisectionSearch(self, args, expected_retcode, expected_output,
                          runner_id):
@@ -495,12 +542,16 @@
                       help='execution mode 1 (default: ri)')
   parser.add_argument('--mode2', default='hopt',
                       help='execution mode 2 (default: hopt)')
+  parser.add_argument('--report_script', help='script called for each'
+                                              'divergence')
+  parser.add_argument('--jfuzz_arg', default=[], dest='jfuzz_args',
+                      action='append', help='argument for jfuzz')
   args = parser.parse_args()
   if args.mode1 == args.mode2:
     raise FatalError('Identical execution modes given')
   # Run the JFuzz tester.
-  with JFuzzTester(args.num_tests, args.device,
-                      args.mode1, args.mode2) as fuzzer:
+  with JFuzzTester(args.num_tests, args.device, args.mode1, args.mode2,
+                   args.jfuzz_args, args.report_script) as fuzzer:
     fuzzer.Run()
 
 if __name__ == '__main__':