Cache method lowering info in mir graph.
This should enable easy inlining checks. It should also
improve compilation time of methods that call the same
methods over and over - it is exactly such methods that
tend to exceed our 100ms time limit.
Change-Id: If01cd18e039071a74a1444570283c153429c9cd4
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 1499ae4..664f809 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -21,8 +21,11 @@
#include "dex/compiler_ir.h"
#include "mirror/art_field.h"
#include "mirror/art_field-inl.h"
+#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
#include "mirror/class_loader.h"
#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
#include "mirror/art_field-inl.h"
#include "scoped_thread_state_change.h"
#include "sirt_ref-inl.h"
@@ -161,6 +164,131 @@
return std::make_pair(false, false);
}
+inline mirror::ArtMethod* CompilerDriver::ResolveMethod(
+ ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ uint32_t method_idx, InvokeType invoke_type) {
+ DCHECK(dex_cache->GetDexFile() == mUnit->GetDexFile());
+ DCHECK(class_loader.get() == soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ mirror::ArtMethod* resolved_method = mUnit->GetClassLinker()->ResolveMethod(
+ *mUnit->GetDexFile(), method_idx, dex_cache, class_loader, nullptr, invoke_type);
+ DCHECK_EQ(resolved_method == nullptr, soa.Self()->IsExceptionPending());
+ if (UNLIKELY(resolved_method == nullptr)) {
+ // Clean up any exception left by type resolution.
+ soa.Self()->ClearException();
+ return nullptr;
+ }
+ if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(invoke_type))) {
+ // Silently return nullptr on incompatible class change.
+ return nullptr;
+ }
+ return resolved_method;
+}
+
+inline void CompilerDriver::GetResolvedMethodDexFileLocation(
+ mirror::ArtMethod* resolved_method, const DexFile** declaring_dex_file,
+ uint16_t* declaring_class_idx, uint16_t* declaring_method_idx) {
+ mirror::Class* declaring_class = resolved_method->GetDeclaringClass();
+ *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile();
+ *declaring_class_idx = declaring_class->GetDexTypeIndex();
+ *declaring_method_idx = resolved_method->GetDexMethodIndex();
+}
+
+inline uint16_t CompilerDriver::GetResolvedMethodVTableIndex(
+ mirror::ArtMethod* resolved_method, InvokeType type) {
+ if (type == kVirtual || type == kSuper) {
+ return resolved_method->GetMethodIndex();
+ } else if (type == kInterface) {
+ return resolved_method->GetDexMethodIndex();
+ } else {
+ return DexFile::kDexNoIndex16;
+ }
+}
+
+inline int CompilerDriver::IsFastInvoke(
+ ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ mirror::Class* referrer_class, mirror::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.
+ if (UNLIKELY(referrer_class == nullptr)) {
+ return 0;
+ }
+ mirror::Class* methods_class = resolved_method->GetDeclaringClass();
+ if (UNLIKELY(!referrer_class->CanAccessResolvedMethod(methods_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).
+ bool can_sharpen_virtual_based_on_type =
+ (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal());
+ // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
+ // the super class.
+ bool can_sharpen_super_based_on_type = (*invoke_type == kSuper) &&
+ (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) &&
+ resolved_method->GetMethodIndex() < methods_class->GetVTable()->GetLength() &&
+ (methods_class->GetVTable()->Get(resolved_method->GetMethodIndex()) == resolved_method);
+
+ if (can_sharpen_virtual_based_on_type || can_sharpen_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(target_method->dex_file == mUnit->GetDexFile());
+ DCHECK(dex_cache.get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
+ CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) ==
+ resolved_method) << PrettyMethod(resolved_method);
+ int stats_flags = kFlagMethodResolved;
+ GetCodeAndMethodForDirectCall(invoke_type, kDirect, false, referrer_class, resolved_method,
+ &stats_flags, target_method, direct_code, 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.
+ mirror::ArtMethod* called_method;
+ ClassLinker* class_linker = mUnit->GetClassLinker();
+ if (LIKELY(devirt_target->dex_file == mUnit->GetDexFile())) {
+ called_method = class_linker->ResolveMethod(*devirt_target->dex_file,
+ devirt_target->dex_method_index,
+ dex_cache, class_loader, NULL, kVirtual);
+ } else {
+ SirtRef<mirror::DexCache> target_dex_cache(soa.Self(),
+ class_linker->FindDexCache(*devirt_target->dex_file));
+ called_method = class_linker->ResolveMethod(*devirt_target->dex_file,
+ devirt_target->dex_method_index,
+ target_dex_cache, class_loader, NULL, kVirtual);
+ }
+ CHECK(called_method != NULL);
+ CHECK(!called_method->IsAbstract());
+ int stats_flags = kFlagMethodResolved;
+ GetCodeAndMethodForDirectCall(invoke_type, kDirect, true, referrer_class, called_method,
+ &stats_flags, target_method, direct_code, 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(invoke_type, *invoke_type, false, referrer_class, resolved_method,
+ &stats_flags, target_method, direct_code, direct_method);
+ return stats_flags;
+}
+
} // namespace art
#endif // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index a46015d..7c4a6f7 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -71,7 +71,7 @@
LOG(INFO) << Percentage(x, y) << "% of " << str << " for " << (x + y) << " cases";
}
-class AOTCompilationStats {
+class CompilerDriver::AOTCompilationStats {
public:
AOTCompilationStats()
: stats_lock_("AOT compilation statistics lock"),
@@ -242,6 +242,30 @@
direct_methods_to_boot_[type]++;
}
+ void ProcessedInvoke(InvokeType type, int flags) {
+ STATS_LOCK();
+ if (flags == 0) {
+ unresolved_methods_[type]++;
+ } else {
+ DCHECK_NE((flags & kFlagMethodResolved), 0);
+ resolved_methods_[type]++;
+ if ((flags & kFlagVirtualMadeDirect) != 0) {
+ virtual_made_direct_[type]++;
+ if ((flags & kFlagPreciseTypeDevirtualization) != 0) {
+ type_based_devirtualization_++;
+ }
+ } else {
+ DCHECK_EQ((flags & kFlagPreciseTypeDevirtualization), 0);
+ }
+ if ((flags & kFlagDirectCallToBoot) != 0) {
+ direct_calls_to_boot_[type]++;
+ }
+ if ((flags & kFlagDirectMethodToBoot) != 0) {
+ direct_methods_to_boot_[type]++;
+ }
+ }
+ }
+
// A check-cast could be eliminated due to verifier type analysis.
void SafeCast() {
STATS_LOCK();
@@ -933,32 +957,8 @@
}
}
-static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa,
- SirtRef<mirror::DexCache>& dex_cache,
- const DexCompilationUnit* mUnit)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // The passed dex_cache is a hint, sanity check before asking the class linker that will take a
- // lock.
- if (dex_cache->GetDexFile() != mUnit->GetDexFile()) {
- dex_cache.reset(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
- }
- SirtRef<mirror::ClassLoader>
- class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
- const DexFile::MethodId& referrer_method_id =
- mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
- return mUnit->GetClassLinker()->ResolveType(*mUnit->GetDexFile(), referrer_method_id.class_idx_,
- dex_cache, class_loader);
-}
-
-static mirror::ArtMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjectAccess& soa,
- const DexCompilationUnit* mUnit,
- uint32_t method_idx,
- InvokeType type)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SirtRef<mirror::DexCache> dex_cache(soa.Self(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
- SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
- return mUnit->GetClassLinker()->ResolveMethod(*mUnit->GetDexFile(), method_idx, dex_cache,
- class_loader, NULL, type);
+void CompilerDriver::ProcessedInvoke(InvokeType invoke_type, int flags) {
+ stats_->ProcessedInvoke(invoke_type, flags);
}
bool CompilerDriver::ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
@@ -1065,7 +1065,7 @@
bool no_guarantee_of_dex_cache_entry,
mirror::Class* referrer_class,
mirror::ArtMethod* method,
- bool update_stats,
+ int* stats_flags,
MethodReference* target_method,
uintptr_t* direct_code,
uintptr_t* direct_method) {
@@ -1103,9 +1103,8 @@
}
}
}
- if (update_stats && method_code_in_boot) {
- stats_->DirectCallsToBoot(*type);
- stats_->DirectMethodsToBoot(*type);
+ if (method_code_in_boot) {
+ *stats_flags |= kFlagDirectCallToBoot | kFlagDirectMethodToBoot;
}
if (!use_dex_cache && compiling_boot) {
MethodHelper mh(method);
@@ -1174,110 +1173,63 @@
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());
- *vtable_idx = -1;
- *direct_code = 0;
- *direct_method = 0;
- mirror::ArtMethod* resolved_method =
- ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method->dex_method_index,
- *invoke_type);
- if (resolved_method != NULL) {
- if (*invoke_type == kVirtual || *invoke_type == kSuper) {
- *vtable_idx = resolved_method->GetMethodIndex();
- } else if (*invoke_type == kInterface) {
- *vtable_idx = resolved_method->GetDexMethodIndex();
- }
- // Don't try to fast-path if we don't understand the caller's class or this appears to be an
- // Incompatible Class Change Error.
- SirtRef<mirror::DexCache> dex_cache(soa.Self(), resolved_method->GetDeclaringClass()->GetDexCache());
- mirror::Class* referrer_class =
- ComputeCompilingMethodsClass(soa, dex_cache, mUnit);
- bool icce = resolved_method->CheckIncompatibleClassChange(*invoke_type);
- if (referrer_class != NULL && !icce) {
- mirror::Class* methods_class = resolved_method->GetDeclaringClass();
- if (referrer_class->CanAccessResolvedMethod(methods_class, resolved_method, dex_cache.get(),
- target_method->dex_method_index)) {
- const bool enableFinalBasedSharpening = enable_devirtualization;
- // Sharpen a virtual call into a direct call when the target is known not to have been
- // overridden (ie is final).
- bool can_sharpen_virtual_based_on_type =
- (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal());
- // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
- // the super class.
- bool can_sharpen_super_based_on_type = (*invoke_type == kSuper) &&
- (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) &&
- resolved_method->GetMethodIndex() < methods_class->GetVTable()->GetLength() &&
- (methods_class->GetVTable()->Get(resolved_method->GetMethodIndex()) == resolved_method);
+ // Try to resolve the method and compiling method's class.
+ mirror::ArtMethod* resolved_method;
+ mirror::Class* referrer_class;
+ SirtRef<mirror::DexCache> dex_cache(soa.Self(),
+ mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
+ SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+ soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ {
+ uint32_t method_idx = target_method->dex_method_index;
+ SirtRef<mirror::ArtMethod> resolved_method_sirt(soa.Self(),
+ ResolveMethod(soa, dex_cache, class_loader, mUnit, method_idx, orig_invoke_type));
+ referrer_class = (resolved_method_sirt.get() != nullptr)
+ ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit) : nullptr;
+ resolved_method = resolved_method_sirt.get();
+ }
+ bool result = false;
+ if (resolved_method != nullptr) {
+ *vtable_idx = GetResolvedMethodVTableIndex(resolved_method, orig_invoke_type);
- if (enableFinalBasedSharpening && (can_sharpen_virtual_based_on_type ||
- can_sharpen_super_based_on_type)) {
- // Sharpen a virtual call into a direct call. The method_idx is into the DexCache
- // associated with target_method->dex_file.
- CHECK(target_method->dex_file == mUnit->GetDexFile());
- DCHECK(dex_cache.get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
- CHECK(dex_cache->GetResolvedMethod(target_method->dex_method_index) ==
- resolved_method) << PrettyMethod(resolved_method);
- InvokeType orig_invoke_type = *invoke_type;
- GetCodeAndMethodForDirectCall(invoke_type, kDirect, false, referrer_class, resolved_method,
- update_stats, target_method, direct_code, direct_method);
- if (update_stats && (*invoke_type == kDirect)) {
- stats_->ResolvedMethod(orig_invoke_type);
- stats_->VirtualMadeDirect(orig_invoke_type);
- }
- DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method);
- return true;
- }
- const bool enableVerifierBasedSharpening = enable_devirtualization;
- if (enableVerifierBasedSharpening && (*invoke_type == kVirtual ||
- *invoke_type == kInterface)) {
- // Did the verifier record a more precise invoke target based on its type information?
- DCHECK(mUnit->GetVerifiedMethod() != nullptr);
- const MethodReference* devirt_map_target =
- mUnit->GetVerifiedMethod()->GetDevirtTarget(dex_pc);
- if (devirt_map_target != NULL) {
- SirtRef<mirror::DexCache> target_dex_cache(soa.Self(), mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file));
- SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
- mirror::ArtMethod* called_method =
- mUnit->GetClassLinker()->ResolveMethod(*devirt_map_target->dex_file,
- devirt_map_target->dex_method_index,
- target_dex_cache, class_loader, NULL,
- kVirtual);
- CHECK(called_method != NULL);
- CHECK(!called_method->IsAbstract());
- InvokeType orig_invoke_type = *invoke_type;
- GetCodeAndMethodForDirectCall(invoke_type, kDirect, true, referrer_class, called_method,
- update_stats, target_method, direct_code, direct_method);
- if (update_stats && (*invoke_type == kDirect)) {
- stats_->ResolvedMethod(orig_invoke_type);
- stats_->VirtualMadeDirect(orig_invoke_type);
- stats_->PreciseTypeDevirtualization();
- }
- DCHECK_NE(*invoke_type, kSuper);
- return true;
- }
- }
- if (*invoke_type == kSuper) {
- // Unsharpened super calls are suspicious so go slow-path.
- } else {
- // Sharpening failed so generate a regular resolved method dispatch.
- if (update_stats) {
- stats_->ResolvedMethod(*invoke_type);
- }
- GetCodeAndMethodForDirectCall(invoke_type, *invoke_type, false, referrer_class, resolved_method,
- update_stats, target_method, direct_code, direct_method);
- return true;
- }
+ if (enable_devirtualization) {
+ DCHECK(mUnit->GetVerifiedMethod() != nullptr);
+ const MethodReference* devirt_target = mUnit->GetVerifiedMethod()->GetDevirtTarget(dex_pc);
+
+ stats_flags = IsFastInvoke(
+ soa, dex_cache, class_loader, mUnit, referrer_class, 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(referrer_class == nullptr) ||
+ UNLIKELY(!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, referrer_class, resolved_method,
+ &stats_flags, target_method, direct_code, direct_method);
+ result = true;
}
}
}
- // Clean up any exception left by method/invoke_type resolution
- if (soa.Self()->IsExceptionPending()) {
- soa.Self()->ClearException();
+ if (!result) {
+ // Conservative defaults.
+ *vtable_idx = -1;
+ *direct_code = 0u;
+ *direct_method = 0u;
}
if (update_stats) {
- stats_->UnresolvedMethod(*invoke_type);
+ ProcessedInvoke(orig_invoke_type, stats_flags);
}
- return false; // Incomplete knowledge needs slow path.
+ return result;
}
const VerifiedMethod* CompilerDriver::GetVerifiedMethod(const DexFile* dex_file,
@@ -1297,7 +1249,6 @@
return result;
}
-
void CompilerDriver::AddCodePatch(const DexFile* dex_file,
uint16_t referrer_class_def_idx,
uint32_t referrer_method_idx,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 817da17..26210c9 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -44,7 +44,6 @@
class MethodVerifier;
} // namespace verifier
-class AOTCompilationStats;
class CompilerOptions;
class DexCompilationUnit;
class DexFileToMethodInlinerMap;
@@ -256,8 +255,37 @@
uint32_t* storage_index, bool* is_referrers_class, bool* is_initialized)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Resolve a method. Returns nullptr on failure, including incompatible class change.
+ mirror::ArtMethod* ResolveMethod(
+ ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ uint32_t method_idx, InvokeType invoke_type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Get declaration location of a resolved field.
+ void GetResolvedMethodDexFileLocation(
+ mirror::ArtMethod* resolved_method, const DexFile** declaring_dex_file,
+ uint16_t* declaring_class_idx, uint16_t* declaring_method_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Get declaration location of a resolved field.
+ uint16_t GetResolvedMethodVTableIndex(
+ mirror::ArtMethod* resolved_method, InvokeType type)
+ SHARED_LOCKS_REQUIRED(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, const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ mirror::Class* referrer_class, mirror::ArtMethod* resolved_method, InvokeType* invoke_type,
+ MethodReference* target_method, const MethodReference* devirt_target,
+ uintptr_t* direct_code, uintptr_t* direct_method)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void ProcessedInstanceField(bool resolved);
void ProcessedStaticField(bool resolved, bool local);
+ void ProcessedInvoke(InvokeType invoke_type, int flags);
// Can we fast path instance field access in a verified accessor?
// If yes, computes field's offset and volatility and whether the method is static or not.
@@ -594,16 +622,37 @@
bool SkipCompilation(const std::string& method_name);
private:
- // Compute constant code and method pointers when possible
+ // These flags are internal to CompilerDriver for collecting INVOKE resolution statistics.
+ // The only external contract is that unresolved method has flags 0 and resolved non-0.
+ enum {
+ kBitMethodResolved = 0,
+ kBitVirtualMadeDirect,
+ kBitPreciseTypeDevirtualization,
+ kBitDirectCallToBoot,
+ kBitDirectMethodToBoot
+ };
+ static constexpr int kFlagMethodResolved = 1 << kBitMethodResolved;
+ static constexpr int kFlagVirtualMadeDirect = 1 << kBitVirtualMadeDirect;
+ static constexpr int kFlagPreciseTypeDevirtualization = 1 << kBitPreciseTypeDevirtualization;
+ static constexpr int kFlagDirectCallToBoot = 1 << kBitDirectCallToBoot;
+ static constexpr int kFlagDirectMethodToBoot = 1 << kBitDirectMethodToBoot;
+ static constexpr int kFlagsMethodResolvedVirtualMadeDirect =
+ kFlagMethodResolved | kFlagVirtualMadeDirect;
+ static constexpr int kFlagsMethodResolvedPreciseTypeDevirtualization =
+ kFlagsMethodResolvedVirtualMadeDirect | kFlagPreciseTypeDevirtualization;
+
+ public: // TODO make private or eliminate.
+ // Compute constant code and method pointers when possible.
void GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type,
bool no_guarantee_of_dex_cache_entry,
mirror::Class* referrer_class,
mirror::ArtMethod* method,
- bool update_stats,
+ int* stats_flags,
MethodReference* target_method,
uintptr_t* direct_code, uintptr_t* direct_method)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
@@ -688,6 +737,7 @@
size_t thread_count_;
uint64_t start_ns_;
+ class AOTCompilationStats;
UniquePtr<AOTCompilationStats> stats_;
bool dump_stats_;