Implement direct apk -> boot calling
Also sharpen super calls.
Change-Id: Ie4d3ab2cbf2961a06ec86762a53132f49a4ed922
diff --git a/src/compiler.cc b/src/compiler.cc
index f64b1cb..5156122 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -71,12 +71,14 @@
strings_in_dex_cache_(0), strings_not_in_dex_cache_(0),
resolved_types_(0), unresolved_types_(0),
resolved_instance_fields_(0), unresolved_instance_fields_(0),
- resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0),
- virtual_made_direct_(0) {
- for (size_t i = 0; i < kMaxInvokeType; i++) {
+ resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0) {
+ for (size_t i = 0; i <= kMaxInvokeType; i++) {
resolved_methods_[i] = 0;
unresolved_methods_[i] = 0;
- }
+ virtual_made_direct_[i] = 0;
+ direct_calls_to_boot_[i] = 0;
+ direct_methods_to_boot_[i] = 0;
+ }
}
void Dump() {
@@ -89,13 +91,32 @@
DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
"static fields local to a class");
- for (size_t i = 0; i < kMaxInvokeType; i++) {
+ for (size_t i = 0; i <= kMaxInvokeType; i++) {
std::ostringstream oss;
- oss << "resolved " << static_cast<InvokeType>(i) << " methods";
+ oss << static_cast<InvokeType>(i) << " methods were AOT resolved";
DumpStat(resolved_methods_[i], unresolved_methods_[i], oss.str().c_str());
+ if (virtual_made_direct_[i] > 0) {
+ std::ostringstream oss2;
+ oss2 << static_cast<InvokeType>(i) << " methods made direct";
+ DumpStat(virtual_made_direct_[i],
+ resolved_methods_[i] + unresolved_methods_[i] - virtual_made_direct_[i],
+ oss2.str().c_str());
+ }
+ if (direct_calls_to_boot_[i] > 0) {
+ std::ostringstream oss2;
+ oss2 << static_cast<InvokeType>(i) << " method calls are direct into boot";
+ DumpStat(direct_calls_to_boot_[i],
+ resolved_methods_[i] + unresolved_methods_[i] - direct_calls_to_boot_[i],
+ oss2.str().c_str());
+ }
+ if (direct_methods_to_boot_[i] > 0) {
+ std::ostringstream oss2;
+ oss2 << static_cast<InvokeType>(i) << " method calls have methods in boot";
+ DumpStat(direct_methods_to_boot_[i],
+ resolved_methods_[i] + unresolved_methods_[i] - direct_methods_to_boot_[i],
+ oss2.str().c_str());
+ }
}
- DumpStat(virtual_made_direct_, resolved_methods_[kVirtual] + unresolved_methods_[kVirtual],
- "made direct from virtual");
}
// Allow lossy statistics in non-debug builds
@@ -172,10 +193,24 @@
unresolved_methods_[type]++;
}
- void VirtualMadeDirect() {
+ void VirtualMadeDirect(InvokeType type) {
+ DCHECK_LE(type, kMaxInvokeType);
STATS_LOCK();
- virtual_made_direct_++;
+ virtual_made_direct_[type]++;
}
+
+ void DirectCallsToBoot(InvokeType type) {
+ DCHECK_LE(type, kMaxInvokeType);
+ STATS_LOCK();
+ direct_calls_to_boot_[type]++;
+ }
+
+ void DirectMethodsToBoot(InvokeType type) {
+ DCHECK_LE(type, kMaxInvokeType);
+ STATS_LOCK();
+ direct_methods_to_boot_[type]++;
+ }
+
private:
Mutex stats_lock_;
@@ -197,7 +232,9 @@
size_t resolved_methods_[kMaxInvokeType + 1];
size_t unresolved_methods_[kMaxInvokeType + 1];
- size_t virtual_made_direct_;
+ size_t virtual_made_direct_[kMaxInvokeType + 1];
+ size_t direct_calls_to_boot_[kMaxInvokeType + 1];
+ size_t direct_methods_to_boot_[kMaxInvokeType + 1];
DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);;
};
@@ -652,9 +689,39 @@
return false; // Incomplete knowledge needs slow path.
}
+void Compiler::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, Method* method,
+ uintptr_t& direct_code, uintptr_t& direct_method) {
+ direct_code = 0;
+ direct_method = 0;
+ if (sharp_type != kStatic && sharp_type != kDirect) {
+ return;
+ }
+ bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
+ if (compiling_boot) {
+ return;
+ }
+ bool method_code_in_boot = method->GetDeclaringClass()->GetClassLoader() == NULL;
+ if (!method_code_in_boot) {
+ return;
+ }
+ bool has_clinit_trampoline = method->IsStatic() && !method->GetDeclaringClass()->IsInitialized();
+ if (has_clinit_trampoline) {
+ return;
+ }
+ stats_->DirectCallsToBoot(type);
+ stats_->DirectMethodsToBoot(type);
+ if (Runtime::Current()->GetHeap()->GetImageSpace()->Contains(method)) {
+ direct_method = reinterpret_cast<uintptr_t>(method);
+ }
+ direct_code = reinterpret_cast<uintptr_t>(method->GetCode());
+}
+
bool Compiler::ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType& type,
- int& vtable_idx) {
+ int& vtable_idx, uintptr_t& direct_code,
+ uintptr_t& direct_method) {
vtable_idx = -1;
+ direct_code = 0;
+ direct_method = 0;
Method* resolved_method = ComputeReferrerMethod(mUnit, method_idx);
if (resolved_method != NULL) {
Class* referrer_class = ComputeReferrerClass(mUnit);
@@ -678,27 +745,33 @@
resolved_method->GetAccessFlags())) {
vtable_idx = resolved_method->GetMethodIndex();
const bool kEnableSharpening = true;
- if (kEnableSharpening && type == kVirtual &&
- (resolved_method->IsFinal() || methods_class->IsFinal())) {
- stats_->ResolvedMethod(kVirtual);
+ // Sharpen a virtual call into a direct call when the target is known.
+ bool can_sharpen = type == kVirtual && (resolved_method->IsFinal() ||
+ methods_class->IsFinal());
+ // ensure the vtable index will be correct to dispatch in the vtable of the super class
+ can_sharpen = can_sharpen || (type == kSuper &&
+ referrer_class->IsSubClass(methods_class) &&
+ vtable_idx < methods_class->GetVTable()->GetLength());
+ if (kEnableSharpening && can_sharpen) {
+ stats_->ResolvedMethod(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(referrer_class->GetDexCache()->GetResolvedMethod(method_idx) == resolved_method)
<< PrettyMethod(resolved_method);
- type = kDirect;
- stats_->VirtualMadeDirect();
- return true;
- } else if (type != kSuper) {
- // nothing left to do for static/direct/virtual/interface dispatch
- stats_->ResolvedMethod(type);
- return true;
- } else {
- // ensure the vtable index will be correct to dispatch in the vtable of the super class
- if (referrer_class->IsSubClass(methods_class) &&
- vtable_idx < methods_class->GetVTable()->GetLength()) {
- stats_->ResolvedMethod(type);
- return true;
+ if (type == kSuper) {
+ CHECK(methods_class->GetVTable()->Get(vtable_idx) == resolved_method)
+ << PrettyMethod(resolved_method);
}
+ stats_->VirtualMadeDirect(type);
+ GetCodeAndMethodForDirectCall(type, kDirect, resolved_method, direct_code, direct_method);
+ type = kDirect;
+ return true;
+ } else if (type == kSuper) {
+ // Unsharpened super calls are suspicious so go slowpath.
+ } else {
+ stats_->ResolvedMethod(type);
+ GetCodeAndMethodForDirectCall(type, type, resolved_method, direct_code, direct_method);
+ return true;
}
}
}