summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2012-03-04 21:51:51 -0800
committerIan Rogers <irogers@google.com>2012-03-05 08:56:55 -0800
commitfb6adba0d5d5505610fbd325e7911db700a2f1e8 (patch)
tree84ad8f9cc55a2ae87f80c05927126af7e75604d7 /src
parent123e8a7fdf69b40603f7df95f08d62c69ee1c07e (diff)
downloadart-fb6adba0d5d5505610fbd325e7911db700a2f1e8.zip
art-fb6adba0d5d5505610fbd325e7911db700a2f1e8.tar.gz
art-fb6adba0d5d5505610fbd325e7911db700a2f1e8.tar.bz2
Sharpen virtual calls to final methods.
Also remove unused instance resolution stub. Change-Id: I2abb988d107e98ac0148fb81464b22622a468382
Diffstat (limited to 'src')
-rw-r--r--src/class_linker.cc41
-rw-r--r--src/compiler.cc23
-rw-r--r--src/compiler.h2
-rw-r--r--src/image.h1
-rw-r--r--src/image_writer.cc2
-rw-r--r--src/oatdump.cc4
-rw-r--r--src/object.cc3
-rw-r--r--src/runtime.cc2
-rw-r--r--src/runtime.h1
-rw-r--r--src/runtime_support.cc12
-rw-r--r--src/space.cc6
11 files changed, 65 insertions, 32 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 700174e..ecf33ac 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1339,12 +1339,30 @@ const void* ClassLinker::GetOatCodeFor(const Method* method) {
// Special case to get oat code without overwriting a trampoline.
CHECK(method->GetDeclaringClass()->IsInitializing());
// Although we overwrite the trampoline of non-static methods, we may get here via the resolution
- // method for direct methods.
- CHECK(method->IsStatic() || method->IsDirect());
- ClassHelper kh(method->GetDeclaringClass());
+ // method for direct methods (or virtual methods made direct).
+ Class* declaring_class = method->GetDeclaringClass();
+ size_t oat_method_index;
+ if (method->IsStatic() || method->IsDirect()) {
+ // Simple case where the oat method index was stashed at load time.
+ oat_method_index = method->GetMethodIndex();
+ } else {
+ // We're invoking a virtual method directly (thanks to sharpening), compute the oat_method_index
+ // by search for its position in the declared virtual methods.
+ oat_method_index = declaring_class->NumDirectMethods();
+ size_t end = declaring_class->NumVirtualMethods();
+ bool found = false;
+ for (size_t i = 0; i < end; i++) {
+ oat_method_index++;
+ if (declaring_class->GetVirtualMethod(i) == method) {
+ found = true;
+ break;
+ }
+ }
+ CHECK(found) << "Didn't find oat method index for virtual method: " << PrettyMethod(method);
+ }
+ ClassHelper kh(declaring_class);
UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor()));
- size_t method_index = method->GetMethodIndex();
- return oat_class->GetOatMethod(method_index).GetCode();
+ return oat_class->GetOatMethod(oat_method_index).GetCode();
}
void ClassLinker::FixupStaticTrampolines(Class* klass) {
@@ -1470,25 +1488,26 @@ void ClassLinker::LoadClass(const DexFile& dex_file,
// TODO: append direct methods to class object
klass->SetVirtualMethods(AllocObjectArray<Method>(it.NumVirtualMethods()));
}
- size_t method_index = 0;
+ size_t class_def_method_index = 0;
for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
SirtRef<Method> method(AllocMethod());
klass->SetDirectMethod(i, method.get());
LoadMethod(dex_file, it, klass, method);
if (oat_class.get() != NULL) {
- LinkCode(method, oat_class.get(), method_index);
+ LinkCode(method, oat_class.get(), class_def_method_index);
}
- method->SetMethodIndex(method_index);
- method_index++;
+ method->SetMethodIndex(class_def_method_index);
+ class_def_method_index++;
}
for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
SirtRef<Method> method(AllocMethod());
klass->SetVirtualMethod(i, method.get());
LoadMethod(dex_file, it, klass, method);
+ DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
if (oat_class.get() != NULL) {
- LinkCode(method, oat_class.get(), method_index);
+ LinkCode(method, oat_class.get(), class_def_method_index);
}
- method_index++;
+ class_def_method_index++;
}
DCHECK(!it.HasNext());
}
diff --git a/src/compiler.cc b/src/compiler.cc
index 51354aa..98d8fac 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -86,7 +86,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),
+ virtual_made_direct_(0) {
for (size_t i = 0; i < kMaxInvokeType; i++) {
resolved_methods_[i] = 0;
unresolved_methods_[i] = 0;
@@ -108,6 +109,8 @@ class AOTCompilationStats {
oss << "resolved " << static_cast<InvokeType>(i) << " methods";
DumpStat(resolved_methods_[i], unresolved_methods_[i], oss.str().c_str());
}
+ DumpStat(virtual_made_direct_, resolved_methods_[kVirtual] + unresolved_methods_[kVirtual],
+ "made direct from virtual");
}
// Allow lossy statistics in non-debug builds
@@ -184,6 +187,10 @@ class AOTCompilationStats {
unresolved_methods_[type]++;
}
+ void VirtualMadeDirect() {
+ STATS_LOCK();
+ virtual_made_direct_++;
+ }
private:
Mutex stats_lock_;
@@ -205,6 +212,7 @@ class AOTCompilationStats {
size_t resolved_methods_[kMaxInvokeType + 1];
size_t unresolved_methods_[kMaxInvokeType + 1];
+ size_t virtual_made_direct_;
DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);;
};
@@ -566,7 +574,7 @@ bool Compiler::ComputeStaticFieldInfo(uint32_t field_idx, OatCompilationUnit* mU
return false; // Incomplete knowledge needs slow path.
}
-bool Compiler::ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType type,
+bool Compiler::ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType& type,
int& vtable_idx) {
vtable_idx = -1;
Method* resolved_method = ComputeReferrerMethod(mUnit, method_idx);
@@ -591,7 +599,16 @@ bool Compiler::ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit,
referrer_class->CanAccessMember(methods_class,
resolved_method->GetAccessFlags())) {
vtable_idx = resolved_method->GetMethodIndex();
- if (type != kSuper) {
+ if (type == kVirtual && (resolved_method->IsFinal() || methods_class->IsFinal())) {
+ stats_->ResolvedMethod(kVirtual);
+ // 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;
diff --git a/src/compiler.h b/src/compiler.h
index 2ff3b90..476a744 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -120,7 +120,7 @@ class Compiler {
bool& is_referrers_class, bool& is_volatile, bool is_put);
// Can we fastpath a interface, super class or virtual method call? Computes method's vtable index
- bool ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType type,
+ bool ComputeInvokeInfo(uint32_t method_idx, OatCompilationUnit* mUnit, InvokeType& type,
int& vtable_idx);
#if defined(ART_USE_LLVM_COMPILER)
diff --git a/src/image.h b/src/image.h
index 0a83c39..6286411 100644
--- a/src/image.h
+++ b/src/image.h
@@ -82,7 +82,6 @@ class PACKED ImageHeader {
enum ImageRoot {
kJniStubArray,
kAbstractMethodErrorStubArray,
- kInstanceResolutionStubArray,
kStaticResolutionStubArray,
kUnknownMethodResolutionStubArray,
kResolutionMethod,
diff --git a/src/image_writer.cc b/src/image_writer.cc
index d0e3579..23c2029 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -302,8 +302,6 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots() const {
image_roots->Set(ImageHeader::kJniStubArray, runtime->GetJniDlsymLookupStub());
image_roots->Set(ImageHeader::kAbstractMethodErrorStubArray,
runtime->GetAbstractMethodErrorStubArray());
- image_roots->Set(ImageHeader::kInstanceResolutionStubArray,
- runtime->GetResolutionStubArray(Runtime::kInstanceMethod));
image_roots->Set(ImageHeader::kStaticResolutionStubArray,
runtime->GetResolutionStubArray(Runtime::kStaticMethod));
image_roots->Set(ImageHeader::kUnknownMethodResolutionStubArray,
diff --git a/src/oatdump.cc b/src/oatdump.cc
index cf4dc2d..c7b8151 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -72,7 +72,6 @@ static void usage() {
const char* image_roots_descriptions_[] = {
"kJniStubArray",
"kAbstractMethodErrorStubArray",
- "kInstanceResolutionStubArray",
"kStaticResolutionStubArray",
"kUnknownMethodResolutionStubArray",
"kResolutionMethod",
@@ -618,8 +617,7 @@ class ImageDumper {
const void* GetOatCode(Method* m) {
Runtime* runtime = Runtime::Current();
const void* code = m->GetCode();
- if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData() ||
- code == runtime->GetResolutionStubArray(Runtime::kInstanceMethod)->GetData()) {
+ if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()) {
code = oat_dumper_->GetOatCode(m);
}
return code;
diff --git a/src/object.cc b/src/object.cc
index 85a2d0a..c91a371 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -481,8 +481,7 @@ static const void* GetOatCode(const Method* m) {
code = runtime->GetTracer()->GetSavedCodeFromMap(m);
}
// Peel off any resolution stub.
- if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData() ||
- code == runtime->GetResolutionStubArray(Runtime::kInstanceMethod)->GetData()) {
+ if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()) {
code = runtime->GetClassLinker()->GetOatCodeFor(m);
}
return code;
diff --git a/src/runtime.cc b/src/runtime.cc
index f0a6bbc..22f4329 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -847,7 +847,7 @@ Runtime::TrampolineType Runtime::GetTrampolineType(Method* method) {
} else if (method->IsStatic()) {
return Runtime::kStaticMethod;
} else {
- return Runtime::kInstanceMethod;
+ return Runtime::kUnknownMethod;
}
}
diff --git a/src/runtime.h b/src/runtime.h
index fb1cd03..36f0084 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -183,7 +183,6 @@ class Runtime {
void SetAbstractMethodErrorStubArray(ByteArray* abstract_method_error_stub_array);
enum TrampolineType {
- kInstanceMethod,
kStaticMethod,
kUnknownMethod,
kLastTrampolineMethodType // Value used for iteration
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 607542e..c4771b0 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -463,6 +463,7 @@ const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp
ClassLinker* linker = Runtime::Current()->GetClassLinker();
Method* caller = *caller_sp;
bool is_static;
+ bool is_virtual;
uint32_t dex_method_idx;
const char* shorty;
uint32_t shorty_len;
@@ -476,14 +477,19 @@ const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp
Instruction::Code instr_code = instr->Opcode();
is_static = (instr_code == Instruction::INVOKE_STATIC) ||
(instr_code == Instruction::INVOKE_STATIC_RANGE);
+ is_virtual = (instr_code == Instruction::INVOKE_VIRTUAL) ||
+ (instr_code == Instruction::INVOKE_VIRTUAL_RANGE);
DCHECK(is_static || (instr_code == Instruction::INVOKE_DIRECT) ||
- (instr_code == Instruction::INVOKE_DIRECT_RANGE));
+ (instr_code == Instruction::INVOKE_DIRECT_RANGE) ||
+ (instr_code == Instruction::INVOKE_VIRTUAL) ||
+ (instr_code == Instruction::INVOKE_VIRTUAL_RANGE));
Instruction::DecodedInstruction dec_insn(instr);
dex_method_idx = dec_insn.vB_;
shorty = linker->MethodShorty(dex_method_idx, caller, &shorty_len);
} else {
DCHECK(!called->IsRuntimeMethod());
is_static = type == Runtime::kStaticMethod;
+ is_virtual = false;
dex_method_idx = called->GetDexMethodIndex();
MethodHelper mh(called);
shorty = mh.GetShorty();
@@ -535,11 +541,11 @@ const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp
}
// Resolve method filling in dex cache
if (type == Runtime::kUnknownMethod) {
- called = linker->ResolveMethod(dex_method_idx, caller, true);
+ called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
}
const void* code = NULL;
if (LIKELY(!thread->IsExceptionPending())) {
- if (LIKELY(called->IsDirect())) {
+ if (LIKELY(called->IsDirect() == !is_virtual)) {
// Ensure that the called method's class is initialized.
Class* called_class = called->GetDeclaringClass();
linker->EnsureInitialized(called_class, true);
diff --git a/src/space.cc b/src/space.cc
index 32d3f3e..6d5a31a 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -319,10 +319,8 @@ ImageSpace* Space::CreateImageSpace(const std::string& image_file_name) {
Object* ame_stub_array = image_header.GetImageRoot(ImageHeader::kAbstractMethodErrorStubArray);
runtime->SetAbstractMethodErrorStubArray(down_cast<ByteArray*>(ame_stub_array));
- Object* resolution_stub_array = image_header.GetImageRoot(ImageHeader::kInstanceResolutionStubArray);
- runtime->SetResolutionStubArray(
- down_cast<ByteArray*>(resolution_stub_array), Runtime::kInstanceMethod);
- resolution_stub_array = image_header.GetImageRoot(ImageHeader::kStaticResolutionStubArray);
+ Object* resolution_stub_array =
+ image_header.GetImageRoot(ImageHeader::kStaticResolutionStubArray);
runtime->SetResolutionStubArray(
down_cast<ByteArray*>(resolution_stub_array), Runtime::kStaticMethod);
resolution_stub_array = image_header.GetImageRoot(ImageHeader::kUnknownMethodResolutionStubArray);