diff options
author | Ian Rogers <irogers@google.com> | 2012-03-04 21:51:51 -0800 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2012-03-05 08:56:55 -0800 |
commit | fb6adba0d5d5505610fbd325e7911db700a2f1e8 (patch) | |
tree | 84ad8f9cc55a2ae87f80c05927126af7e75604d7 /src | |
parent | 123e8a7fdf69b40603f7df95f08d62c69ee1c07e (diff) | |
download | art-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.cc | 41 | ||||
-rw-r--r-- | src/compiler.cc | 23 | ||||
-rw-r--r-- | src/compiler.h | 2 | ||||
-rw-r--r-- | src/image.h | 1 | ||||
-rw-r--r-- | src/image_writer.cc | 2 | ||||
-rw-r--r-- | src/oatdump.cc | 4 | ||||
-rw-r--r-- | src/object.cc | 3 | ||||
-rw-r--r-- | src/runtime.cc | 2 | ||||
-rw-r--r-- | src/runtime.h | 1 | ||||
-rw-r--r-- | src/runtime_support.cc | 12 | ||||
-rw-r--r-- | src/space.cc | 6 |
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); |