Clean-up sharpening and compiler driver.

Remove dependency on compiler driver for sharpening
and dex2dex (the methods called on the compiler driver were
doing unnecessary work), and remove the now unused methods
in compiler driver.

Also remove test that is now invalid, as sharpening always
succeeds.

test: m test-art-host m test-art-target
Change-Id: I54e91c6839bd5b0b86182f2f43ba5d2c112ef908
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/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 {
-}