summaryrefslogtreecommitdiffstats
path: root/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/dex/mir_dataflow.cc10
-rw-r--r--src/compiler/dex/quick/gen_invoke.cc2
-rw-r--r--src/compiler/driver/compiler_driver.cc51
-rw-r--r--src/compiler/driver/compiler_driver.h7
-rw-r--r--src/compiler/llvm/gbc_expander.cc4
5 files changed, 62 insertions, 12 deletions
diff --git a/src/compiler/dex/mir_dataflow.cc b/src/compiler/dex/mir_dataflow.cc
index 23bf24889..444874dce 100644
--- a/src/compiler/dex/mir_dataflow.cc
+++ b/src/compiler/dex/mir_dataflow.cc
@@ -1249,11 +1249,13 @@ bool MIRGraph::InvokeUsesMethodStar(MIR* mir)
int vtable_idx;
uintptr_t direct_code;
uintptr_t direct_method;
+ uint32_t current_offset = static_cast<uint32_t>(current_offset_);
bool fast_path =
- cu_->compiler_driver->ComputeInvokeInfo(dex_method_idx, &m_unit, type,
- vtable_idx, direct_code,
- direct_method) &&
- !(cu_->enable_debug & (1 << kDebugSlowInvokePath));
+ cu_->compiler_driver->ComputeInvokeInfo(dex_method_idx, current_offset,
+ &m_unit, type,
+ vtable_idx, direct_code,
+ direct_method) &&
+ !(cu_->enable_debug & (1 << kDebugSlowInvokePath));
return (((type == kDirect) || (type == kStatic)) &&
fast_path && ((direct_code == 0) || (direct_method == 0)));
}
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
index 2eab673e2..efacff0ab 100644
--- a/src/compiler/dex/quick/gen_invoke.cc
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -1329,7 +1329,7 @@ void Mir2Lir::GenInvoke(CallInfo* info)
uintptr_t direct_method;
bool skip_this;
bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(
- dex_method_idx, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
+ dex_method_idx, current_dalvik_offset_, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
direct_code, direct_method) && !SLOW_INVOKE_PATH;
if (info->type == kInterface) {
if (fast_path) {
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 1660914ce..bed9ac141 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -71,7 +71,8 @@ class AOTCompilationStats {
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) {
+ resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0),
+ type_based_devirtualization_(0) {
for (size_t i = 0; i <= kMaxInvokeType; i++) {
resolved_methods_[i] = 0;
unresolved_methods_[i] = 0;
@@ -90,6 +91,8 @@ class AOTCompilationStats {
"static fields resolved");
DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
"static fields local to a class");
+ DumpStat(type_based_devirtualization_,virtual_made_direct_[kInterface] + virtual_made_direct_[kVirtual]
+ - type_based_devirtualization_, "sharpened calls based on type information");
for (size_t i = 0; i <= kMaxInvokeType; i++) {
std::ostringstream oss;
@@ -181,6 +184,11 @@ class AOTCompilationStats {
unresolved_static_fields_++;
}
+ void PreciseTypeDevirtualization() {
+ STATS_LOCK();
+ type_based_devirtualization_++;
+ }
+
void ResolvedMethod(InvokeType type) {
DCHECK_LE(type, kMaxInvokeType);
STATS_LOCK();
@@ -229,6 +237,8 @@ class AOTCompilationStats {
size_t resolved_local_static_fields_;
size_t resolved_static_fields_;
size_t unresolved_static_fields_;
+ // Type based devirtualization for invoke interface and virtual.
+ size_t type_based_devirtualization_;
size_t resolved_methods_[kMaxInvokeType + 1];
size_t unresolved_methods_[kMaxInvokeType + 1];
@@ -805,15 +815,24 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s
}
}
-bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx, const DexCompilationUnit* mUnit,
- InvokeType& type, int& vtable_idx, uintptr_t& direct_code,
+bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx,const uint32_t dex_pc,
+ const DexCompilationUnit* mUnit, InvokeType& type,
+ int& vtable_idx, uintptr_t& direct_code,
uintptr_t& direct_method) {
ScopedObjectAccess soa(Thread::Current());
+
+ const bool kEnableVerifierBasedSharpening = true;
+ const CompilerDriver::MethodReference ref_caller(mUnit->GetDexFile(), mUnit->GetDexMethodIndex());
+ const CompilerDriver::MethodReference* ref_sharpen = verifier::MethodVerifier::GetDevirtMap(ref_caller, dex_pc);
+ bool can_devirtualize = (dex_pc != art::kDexPCNotReady) && (ref_sharpen != NULL);
+
vtable_idx = -1;
direct_code = 0;
direct_method = 0;
mirror::AbstractMethod* resolved_method =
ComputeMethodReferencedFromCompilingMethod(soa, mUnit, method_idx, type);
+
+
if (resolved_method != NULL) {
// 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.
@@ -836,8 +855,10 @@ bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx, const DexCompilation
}
if (referrer_class->CanAccess(methods_class) &&
referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) {
+
vtable_idx = resolved_method->GetMethodIndex();
const bool kEnableSharpening = true;
+
// Sharpen a virtual call into a direct call when the target is known.
bool can_sharpen = type == kVirtual && (resolved_method->IsFinal() ||
methods_class->IsFinal());
@@ -846,6 +867,7 @@ bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx, const DexCompilation
referrer_class->IsSubClass(methods_class) &&
vtable_idx < methods_class->GetVTable()->GetLength() &&
methods_class->GetVTable()->Get(vtable_idx) == resolved_method);
+
if (kEnableSharpening && can_sharpen) {
stats_->ResolvedMethod(type);
// Sharpen a virtual call into a direct call. The method_idx is into referrer's
@@ -857,7 +879,28 @@ bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx, const DexCompilation
direct_code, direct_method);
type = kDirect;
return true;
- } else if (type == kSuper) {
+
+ } else if(can_devirtualize && kEnableSharpening && kEnableVerifierBasedSharpening) {
+ // If traditional sharpening fails, try the sharpening based on type information (Devirtualization)
+ mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*ref_sharpen->first);
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+ mirror::AbstractMethod* concrete_method = mUnit->GetClassLinker()->ResolveMethod(
+ *ref_sharpen->first, ref_sharpen->second, dex_cache, class_loader, NULL, kVirtual);
+ CHECK(concrete_method != NULL);
+ CHECK(!concrete_method->IsAbstract());
+ // TODO: fix breakage in image patching to be able to devirtualize cases with different
+ // resolved and concrete methods.
+ if(resolved_method == concrete_method) {
+ GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, concrete_method, direct_code, direct_method);
+ type = kDirect;
+ stats_->VirtualMadeDirect(type);
+ stats_->PreciseTypeDevirtualization();
+ }
+ stats_->ResolvedMethod(type);
+
+ return true;
+ }
+ else if (type == kSuper) {
// Unsharpened super calls are suspicious so go slow-path.
} else {
stats_->ResolvedMethod(type);
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index a20e5ef58..e28955827 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -39,6 +39,8 @@ class ParallelCompilationManager;
class DexCompilationUnit;
class TimingLogger;
+const uint32_t kDexPCNotReady = 0xFFFFFF;
+
enum CompilerBackend {
kQuick,
kPortable,
@@ -149,8 +151,9 @@ class CompilerDriver {
// Can we fastpath a interface, super class or virtual method call? Computes method's vtable
// index.
- bool ComputeInvokeInfo(uint32_t method_idx, const DexCompilationUnit* mUnit, InvokeType& type,
- int& vtable_idx, uintptr_t& direct_code, uintptr_t& direct_method)
+ bool ComputeInvokeInfo(uint32_t method_idx, uint32_t dex_pc,
+ const DexCompilationUnit* mUnit, InvokeType& type, int& vtable_idx,
+ uintptr_t& direct_code, uintptr_t& direct_method)
LOCKS_EXCLUDED(Locks::mutator_lock_);
// Record patch information for later fix up.
diff --git a/src/compiler/llvm/gbc_expander.cc b/src/compiler/llvm/gbc_expander.cc
index 94eb74103..c1e35a69a 100644
--- a/src/compiler/llvm/gbc_expander.cc
+++ b/src/compiler/llvm/gbc_expander.cc
@@ -785,8 +785,10 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) {
int vtable_idx = -1;
uintptr_t direct_code = 0;
uintptr_t direct_method = 0;
+ // TODO: pass actual value of dex PC (instead of kDexPCNotready) needed by verifier based
+ // sharpening after LLVM re-factoring is finished.
bool is_fast_path = driver_->
- ComputeInvokeInfo(callee_method_idx, dex_compilation_unit_,
+ ComputeInvokeInfo(callee_method_idx, art::kDexPCNotReady, dex_compilation_unit_,
invoke_type, vtable_idx, direct_code, direct_method);
// Load the method object