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/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: