From e3cd2f0e3c3d976ae9c65c8a731003a5aaf71986 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 24 May 2013 15:32:56 -0700 Subject: Enable devirtualization for abstract and sub-class methods. If we know the type of a receiver in the verifier we record devirtualization data. Currently we only use this data to avoid virtual method dispatch when we know the receiver of a method isn't a sub-class. This change allows devirtualization of virtual and interface methods when we know the receiver's type and the method the we'd find via dispatch is either known within boot or has a reference from the current dex file. Pass the receiver through to the method resolution trampoline as devirtualization may mean the dex method index needs to be made more accurate for the receiver. Tidy up method devirtualization and related statistics. Push the devirtualization map lookup into a less common case to avoid taking its lock. Make MethodReference a struct rather than a typedef of a pair, so the members can have more meaningful names than first and second. Rough statistics show that we devirtualize using this change around 2.5% of the time, whilst some apps like GMS core devirtualize over 3.4% of the time. Change-Id: Ieed3471dbedfc4cc881d652631b67176bb37d394 --- src/compiler/driver/compiler_driver.cc | 217 +++++++++++++++++++++++---------- 1 file changed, 154 insertions(+), 63 deletions(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 698517277f..bf8bb8acb2 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -184,34 +184,43 @@ class AOTCompilationStats { unresolved_static_fields_++; } + // Indicate that type information from the verifier led to devirtualization. void PreciseTypeDevirtualization() { STATS_LOCK(); type_based_devirtualization_++; } + + // Indicate that a method of the given type was resolved at compile time. void ResolvedMethod(InvokeType type) { DCHECK_LE(type, kMaxInvokeType); STATS_LOCK(); resolved_methods_[type]++; } + // Indicate that a method of the given type was unresolved at compile time as it was in an + // unknown dex file. void UnresolvedMethod(InvokeType type) { DCHECK_LE(type, kMaxInvokeType); STATS_LOCK(); unresolved_methods_[type]++; } + // Indicate that a type of virtual method dispatch has been converted into a direct method + // dispatch. void VirtualMadeDirect(InvokeType type) { - DCHECK_LE(type, kMaxInvokeType); + DCHECK(type == kVirtual || type == kInterface || type == kSuper); STATS_LOCK(); virtual_made_direct_[type]++; } + // Indicate that a method of the given type was able to call directly into boot. void DirectCallsToBoot(InvokeType type) { DCHECK_LE(type, kMaxInvokeType); STATS_LOCK(); direct_calls_to_boot_[type]++; } + // Indicate that a method of the given type was able to be resolved directly from boot. void DirectMethodsToBoot(InvokeType type) { DCHECK_LE(type, kMaxInvokeType); STATS_LOCK(); @@ -312,6 +321,7 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet compiler_(NULL), compiler_context_(NULL), jni_compiler_(NULL), + compiler_enable_auto_elf_loading_(NULL), compiler_get_method_code_addr_(NULL) { std::string compiler_so_name(MakeCompilerSoName(compiler_backend_)); @@ -764,7 +774,8 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s mirror::Class* referrer_class, mirror::AbstractMethod* method, uintptr_t& direct_code, - uintptr_t& direct_method) { + uintptr_t& direct_method, + bool update_stats) { // For direct and static methods compute possible direct_code and direct_method values, ie // an address for the Method* being invoked and an address of the code for that Method*. // For interface calls compute a value for direct_method that is the interface method being @@ -789,10 +800,12 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s // Ensure we run the clinit trampoline unless we are invoking a static method in the same class. return; } - if (sharp_type != kInterface) { // Interfaces always go via a trampoline. - stats_->DirectCallsToBoot(type); + if (update_stats) { + if (sharp_type != kInterface) { // Interfaces always go via a trampoline. + stats_->DirectCallsToBoot(type); + } + stats_->DirectMethodsToBoot(type); } - stats_->DirectMethodsToBoot(type); bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1; if (compiling_boot) { const bool kSupportBootImageFixup = true; @@ -813,26 +826,24 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s } } -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) { +bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc, + InvokeType& invoke_type, + MethodReference& target_method, + int& vtable_idx, + uintptr_t& direct_code, uintptr_t& direct_method, + bool update_stats) { 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); + ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method.dex_method_index, + invoke_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. mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit); - bool icce = resolved_method->CheckIncompatibleClassChange(type); + bool icce = resolved_method->CheckIncompatibleClassChange(invoke_type); if (referrer_class != NULL && !icce) { mirror::Class* methods_class = resolved_method->GetDeclaringClass(); if (!referrer_class->CanAccess(methods_class) || @@ -842,71 +853,151 @@ bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx,const uint32_t dex_pc // protected method being made public by implementing an interface that re-declares the // method public. Resort to the dex file to determine the correct class for the access // check. - const DexFile& dex_file = *referrer_class->GetDexCache()->GetDexFile(); - methods_class = - mUnit->GetClassLinker()->ResolveType(dex_file, - dex_file.GetMethodId(method_idx).class_idx_, - referrer_class); + uint16_t class_idx = + target_method.dex_file->GetMethodId(target_method.dex_method_index).class_idx_; + methods_class = mUnit->GetClassLinker()->ResolveType(*target_method.dex_file, + class_idx, referrer_class); } 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()); - // Ensure the vtable index will be correct to dispatch in the vtable of the super class. - can_sharpen = can_sharpen || (type == kSuper && referrer_class != methods_class && - 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); + const bool kEnableFinalBasedSharpening = true; + // 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 (kEnableFinalBasedSharpening && (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(referrer_class->GetDexCache()->GetResolvedMethod(method_idx) == resolved_method) - << PrettyMethod(resolved_method); - stats_->VirtualMadeDirect(type); - GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, resolved_method, - direct_code, direct_method); - type = kDirect; + CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method.dex_method_index) == + resolved_method) << PrettyMethod(resolved_method); + if (update_stats) { + stats_->ResolvedMethod(invoke_type); + stats_->VirtualMadeDirect(invoke_type); + } + GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, resolved_method, + direct_code, direct_method, update_stats); + invoke_type = kDirect; return true; - } 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(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); - stats_->VirtualMadeDirect(type); - type = kDirect; - stats_->PreciseTypeDevirtualization(); + } + const bool kEnableVerifierBasedSharpening = true; + if (kEnableVerifierBasedSharpening && (invoke_type == kVirtual || + invoke_type == kInterface)) { + // Did the verifier record a more precise invoke target based on its type information? + const CompilerDriver::MethodReference caller_method(mUnit->GetDexFile(), + mUnit->GetDexMethodIndex()); + const CompilerDriver::MethodReference* devirt_map_target = + verifier::MethodVerifier::GetDevirtMap(caller_method, dex_pc); + if (devirt_map_target != NULL) { + mirror::DexCache* target_dex_cache = + mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file); + mirror::ClassLoader* class_loader = + soa.Decode(mUnit->GetClassLoader()); + mirror::AbstractMethod* 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()); + GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, called_method, + direct_code, direct_method, update_stats); + bool compiler_needs_dex_cache = + (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) || + (direct_code == 0) || (direct_code == static_cast(-1)) || + (direct_method == 0) || (direct_method == static_cast(-1)); + if ((devirt_map_target->dex_file != target_method.dex_file) && + compiler_needs_dex_cache) { + // We need to use the dex cache to find either the method or code, and the dex file + // containing the method isn't the one expected for the target method. Try to find + // the method within the expected target dex file. + // TODO: the -1 could be handled as direct code if the patching new the target dex + // file. + // TODO: quick only supports direct pointers with Thumb2. + // TODO: the following should be factored into a common helper routine to find + // one dex file's method within another. + const DexFile* dexfile = target_method.dex_file; + const DexFile* cm_dexfile = + called_method->GetDeclaringClass()->GetDexCache()->GetDexFile(); + const DexFile::MethodId& cm_method_id = + cm_dexfile->GetMethodId(called_method->GetDexMethodIndex()); + const char* cm_descriptor = cm_dexfile->StringByTypeIdx(cm_method_id.class_idx_); + const DexFile::StringId* descriptor = dexfile->FindStringId(cm_descriptor); + if (descriptor != NULL) { + const DexFile::TypeId* type_id = + dexfile->FindTypeId(dexfile->GetIndexForStringId(*descriptor)); + if (type_id != NULL) { + const char* cm_name = cm_dexfile->GetMethodName(cm_method_id); + const DexFile::StringId* name = dexfile->FindStringId(cm_name); + if (name != NULL) { + uint16_t return_type_idx; + std::vector param_type_idxs; + bool success = dexfile->CreateTypeList(&return_type_idx, ¶m_type_idxs, + cm_dexfile->GetMethodSignature(cm_method_id)); + if (success) { + const DexFile::ProtoId* sig = + dexfile->FindProtoId(return_type_idx, param_type_idxs); + if (sig != NULL) { + const DexFile::MethodId* method_id = dexfile->FindMethodId(*type_id, + *name, *sig); + if (method_id != NULL) { + if (update_stats) { + stats_->ResolvedMethod(invoke_type); + stats_->VirtualMadeDirect(invoke_type); + stats_->PreciseTypeDevirtualization(); + } + target_method.dex_method_index = dexfile->GetIndexForMethodId(*method_id); + invoke_type = kDirect; + return true; + } + } + } + } + } + } + } else { + if (update_stats) { + stats_->ResolvedMethod(invoke_type); + stats_->VirtualMadeDirect(invoke_type); + stats_->PreciseTypeDevirtualization(); + } + target_method = *devirt_map_target; + invoke_type = kDirect; + return true; } - stats_->ResolvedMethod(type); - return true; + } } - else if (type == kSuper) { + if (invoke_type == kSuper) { // Unsharpened super calls are suspicious so go slow-path. } else { - stats_->ResolvedMethod(type); - GetCodeAndMethodForDirectCall(type, type, referrer_class, resolved_method, - direct_code, direct_method); + // Sharpening failed so generate a regular resolved method dispatch. + if (update_stats) { + stats_->ResolvedMethod(invoke_type); + } + if (invoke_type == kVirtual || invoke_type == kSuper) { + vtable_idx = resolved_method->GetMethodIndex(); + } + GetCodeAndMethodForDirectCall(invoke_type, invoke_type, referrer_class, resolved_method, + direct_code, direct_method, update_stats); return true; } } } } - // Clean up any exception left by method/type resolution + // Clean up any exception left by method/invoke_type resolution if (soa.Self()->IsExceptionPending()) { soa.Self()->ClearException(); } - stats_->UnresolvedMethod(type); + if (update_stats) { + stats_->UnresolvedMethod(invoke_type); + } return false; // Incomplete knowledge needs slow path. } -- cgit v1.2.3 From f8582c3b87efa0245d176f768fd373e5b4289da4 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 29 May 2013 16:33:03 -0700 Subject: Build fix. MIPS build exposed a latest bug in DexFile's binary search code. Portable build always requires a dex cache when using verifier based sharpening. Change-Id: I235c033d7eba0272b264f5dbda209ff5cd7cce93 --- src/compiler/driver/compiler_driver.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index bf8bb8acb2..85dcdf671b 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -910,6 +910,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, called_method, direct_code, direct_method, update_stats); bool compiler_needs_dex_cache = + (GetCompilerBackend() == kPortable) || (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) || (direct_code == 0) || (direct_code == static_cast(-1)) || (direct_method == 0) || (direct_method == static_cast(-1)); -- cgit v1.2.3 From 1bf8d4dbe5cb9891e8a1125ff1928b544efc243a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 30 May 2013 00:18:49 -0700 Subject: Profiler directed clean-up of dex2oat. Fix bad usage of std::string in: the verifier and compiler driver method arguments, causing unnecessary boxing and allocations; in creating a symbol for the dex compilation unit, that is only used in portable builds; in pattern matching for intrinsics by name. Make class linker dex and classes locks reader/writer to allow concurrent dex cache or class querying. Refactor ComputeCompilingMethodsClass to pass in a dex cache hint, to avoid taking any locks when the dex file of the compiling method matches that of the field or method being resolved. Make the RegType's HasClass method virtual to avoid frequent virtual method dispatch. Make RegTypeCache GetFromId inlinable. Various other bits of whitespace and formatting clean-up. Change-Id: Id152e1e5a6fed2961dad0b612b7aa0c48001ef94 --- src/compiler/driver/compiler_driver.cc | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 85dcdf671b..cc65cbee67 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -500,7 +500,7 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vectorGetClassLinker()->FindDexCache(*mUnit->GetDexFile()); + // 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 = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()); + } mirror::ClassLoader* class_loader = soa.Decode(mUnit->GetClassLoader()); const DexFile::MethodId& referrer_method_id = mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex()); return mUnit->GetClassLinker()->ResolveType(*mUnit->GetDexFile(), referrer_method_id.class_idx_, @@ -649,7 +654,9 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi // Try to resolve field and ignore if an Incompatible Class Change Error (ie is static). mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && !resolved_field->IsStatic()) { - mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit); + mirror::Class* referrer_class = + ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(), + mUnit); if (referrer_class != NULL) { mirror::Class* fields_class = resolved_field->GetDeclaringClass(); bool access_ok = referrer_class->CanAccess(fields_class) && @@ -698,7 +705,9 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila // Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static). mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && resolved_field->IsStatic()) { - mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit); + mirror::Class* referrer_class = + ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(), + mUnit); if (referrer_class != NULL) { mirror::Class* fields_class = resolved_field->GetDeclaringClass(); if (fields_class == referrer_class) { @@ -842,7 +851,9 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui 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. - mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit); + mirror::Class* referrer_class = + ComputeCompilingMethodsClass(soa, resolved_method->GetDeclaringClass()->GetDexCache(), + mUnit); bool icce = resolved_method->CheckIncompatibleClassChange(invoke_type); if (referrer_class != NULL && !icce) { mirror::Class* methods_class = resolved_method->GetDeclaringClass(); -- cgit v1.2.3 From 39ebcb800aabedd0ffa6aa4aeac8aa4194c66e61 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 30 May 2013 16:57:23 -0700 Subject: More profiler driven tweaks. Make more code inlinable by moving to header files. Use reserve on std::vectors to avoid reallocation. Change-Id: I1bf67d32dd58ff5c06dec73a247fadc3de593e91 --- src/compiler/driver/compiler_driver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index cc65cbee67..6feda1714d 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -34,7 +34,7 @@ #include "gc/space.h" #include "mirror/class_loader.h" #include "mirror/class-inl.h" -#include "mirror/dex_cache.h" +#include "mirror/dex_cache-inl.h" #include "mirror/field-inl.h" #include "mirror/abstract_method-inl.h" #include "mirror/object-inl.h" -- cgit v1.2.3 From 637c65b1e431fd90195b71c141b3590bd81cc91a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 31 May 2013 11:46:00 -0700 Subject: Verifier improvements. Make type hierarchy for unresolved and unitialized types explicit. Tidy and comment code. Add DexFile::FindStringId that takes UTF-16 to avoid unnecessary UTF-8 conversions during image writing. Explicitly disable RTTI that causes problems in debug builds. Change-Id: I701f1c3be8be5854fcabf5ec39e9f9c5d388aab0 --- src/compiler/driver/compiler_driver.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 6feda1714d..aad77adb72 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -752,9 +752,8 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila } // Search dex file for localized ssb index, may fail if field's class is a parent // of the class mentioned in the dex file and there is no dex cache entry. - std::string descriptor(FieldHelper(resolved_field).GetDeclaringClassDescriptor()); const DexFile::StringId* string_id = - mUnit->GetDexFile()->FindStringId(descriptor); + mUnit->GetDexFile()->FindStringId(FieldHelper(resolved_field).GetDeclaringClassDescriptor()); if (string_id != NULL) { const DexFile::TypeId* type_id = mUnit->GetDexFile()->FindTypeId(mUnit->GetDexFile()->GetIndexForStringId(*string_id)); -- cgit v1.2.3 From d0583802482a7b2f54749edc4faa00303459f9a8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sat, 1 Jun 2013 10:51:46 -0700 Subject: Allow type based sharpening for imprecise references. When a reference is imprecise we may still be able to devirtualize if the method that is dispatched upon may not be overridden (ie final). Some other tidying of the devirtualization code. For boot this increases the frequency of type based devirtualization by a little more than 0.01%. Change-Id: I050efbcc78c6b89135a6432bd7c2e946d8efbab4 --- src/compiler/driver/compiler_driver.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index aad77adb72..2783e2e13e 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -973,6 +973,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui } } } + // TODO: the stats for direct code and method are off as we failed to find the direct + // method in the referring method's dex cache/file. } else { if (update_stats) { stats_->ResolvedMethod(invoke_type); -- cgit v1.2.3 From fae370a044f5817f69937cccfd2d12a16b374266 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 5 Jun 2013 08:33:27 -0700 Subject: Don't apply instance-of peephole when vDest == vSrc. Bug: 9284898. Also statistic to show check-cast ellision use. Fix bug where the check-cast ellision was using wrong dex pc. Avoid a use of DecodedInstruction. Other formatting clean-up. Change-Id: Ibf67941a24148b615896d0be6f2f29ce5034e53a --- src/compiler/driver/compiler_driver.cc | 39 +++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 2783e2e13e..3dddc751be 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -72,7 +72,8 @@ class AOTCompilationStats { 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), - type_based_devirtualization_(0) { + type_based_devirtualization_(0), + safe_casts_(0), not_safe_casts_(0) { for (size_t i = 0; i <= kMaxInvokeType; i++) { resolved_methods_[i] = 0; unresolved_methods_[i] = 0; @@ -91,8 +92,14 @@ 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"); + DumpStat(safe_casts_, not_safe_casts_, "check-casts removed based on type information"); + // Note, the code below subtracts the stat value so that when added to the stat value we have + // 100% of samples. TODO: clean this up. + DumpStat(type_based_devirtualization_, + resolved_methods_[kVirtual] + unresolved_methods_[kVirtual] + + resolved_methods_[kInterface] + unresolved_methods_[kInterface] - + type_based_devirtualization_, + "virtual/interface calls made direct based on type information"); for (size_t i = 0; i <= kMaxInvokeType; i++) { std::ostringstream oss; @@ -227,6 +234,18 @@ class AOTCompilationStats { direct_methods_to_boot_[type]++; } + // A check-cast could be eliminated due to verifier type analysis. + void SafeCast() { + STATS_LOCK(); + safe_casts_++; + } + + // A check-cast couldn't be eliminated due to verifier type analysis. + void NotASafeCast() { + STATS_LOCK(); + not_safe_casts_++; + } + private: Mutex stats_lock_; @@ -254,6 +273,9 @@ class AOTCompilationStats { size_t direct_calls_to_boot_[kMaxInvokeType + 1]; size_t direct_methods_to_boot_[kMaxInvokeType + 1]; + size_t safe_casts_; + size_t not_safe_casts_; + DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats); }; @@ -1014,6 +1036,17 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui return false; // Incomplete knowledge needs slow path. } +bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) { + bool result = verifier::MethodVerifier::IsSafeCast(mr, dex_pc); + if (result) { + stats_->SafeCast(); + } else { + stats_->NotASafeCast(); + } + return result; +} + + void CompilerDriver::AddCodePatch(const DexFile* dex_file, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, -- cgit v1.2.3 From c9e463c8aa083a5ed20293f42363ebff93de5f84 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 5 Jun 2013 16:52:26 -0700 Subject: Faster instance-of for final classes. If a class is final and not and array we can generate a 1/0 based on class equality. Use a method's declaring class if it matches the instance-of class (common in Java equals methods). Don't do a class pointer comparison in the case of an abstract or interface class, just go straight into the slow-path. Fix performance bug where peep-hole verifier pass didn't merge into the fall-through line if the next instruction wasn't interesting. Change-Id: Idb47ec6acebfd25a344ed74adaacba02fafc7df2 --- src/compiler/driver/compiler_driver.cc | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 3dddc751be..1b8f87d51f 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -577,7 +577,18 @@ bool CompilerDriver::CanAssumeStringIsPresentInDexCache(const DexFile& dex_file, } bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexFile& dex_file, - uint32_t type_idx) { + uint32_t type_idx, + bool* type_known_final, bool* type_known_abstract, + bool* equals_referrers_class) { + if (type_known_final != NULL) { + *type_known_final = false; + } + if (type_known_abstract != NULL) { + *type_known_abstract = false; + } + if (equals_referrers_class != NULL) { + *equals_referrers_class = false; + } ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); // Get type from dex cache assuming it was populated by the verifier @@ -587,6 +598,9 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const Dex return false; // Unknown class needs access checks. } const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx); + if (equals_referrers_class != NULL) { + *equals_referrers_class = (method_id.class_idx_ == type_idx); + } mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_); if (referrer_class == NULL) { stats_->TypeNeedsAccessCheck(); @@ -597,6 +611,12 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const Dex bool result = referrer_class->CanAccess(resolved_class); if (result) { stats_->TypeDoesntNeedAccessCheck(); + if (type_known_final != NULL) { + *type_known_final = resolved_class->IsFinal() && !resolved_class->IsArrayClass(); + } + if (type_known_abstract != NULL) { + *type_known_abstract = resolved_class->IsAbstract(); + } } else { stats_->TypeNeedsAccessCheck(); } -- cgit v1.2.3 From 0aba0ba155bef7346bde19e53581200b89ae8a7a Mon Sep 17 00:00:00 2001 From: Jeff Hao Date: Mon, 3 Jun 2013 14:49:28 -0700 Subject: Created compiled stubs in image. Saves class linker from having to set code pointers when loading from an image. Added stubs for quick and portable resolution trampolines, and interpreter-to-interpreter and interpreter-to-quick entry points. Also added sizing stats output for oat writer. Change-Id: I3905fae81047742c23d1cf0ca001db798db971b1 --- src/compiler/driver/compiler_driver.cc | 61 ++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 1b8f87d51f..834be64d74 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -24,6 +24,7 @@ #include "base/stl_util.h" #include "base/timing_logger.h" #include "class_linker.h" +#include "compiler/stubs/stubs.h" #include "dex_compilation_unit.h" #include "dex_file-inl.h" #include "jni_internal.h" @@ -448,6 +449,66 @@ CompilerTls* CompilerDriver::GetTls() { return res; } +const std::vector* CompilerDriver::CreatePortableResolutionTrampoline() const { + switch (instruction_set_) { + case kArm: + case kThumb2: + return arm::CreatePortableResolutionTrampoline(); + case kMips: + return mips::CreatePortableResolutionTrampoline(); + case kX86: + return x86::CreatePortableResolutionTrampoline(); + default: + LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_; + return NULL; + } +} + +const std::vector* CompilerDriver::CreateQuickResolutionTrampoline() const { + switch (instruction_set_) { + case kArm: + case kThumb2: + return arm::CreateQuickResolutionTrampoline(); + case kMips: + return mips::CreateQuickResolutionTrampoline(); + case kX86: + return x86::CreateQuickResolutionTrampoline(); + default: + LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_; + return NULL; + } +} + +const std::vector* CompilerDriver::CreateInterpreterToInterpreterEntry() const { + switch (instruction_set_) { + case kArm: + case kThumb2: + return arm::CreateInterpreterToInterpreterEntry(); + case kMips: + return mips::CreateInterpreterToInterpreterEntry(); + case kX86: + return x86::CreateInterpreterToInterpreterEntry(); + default: + LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_; + return NULL; + } +} + +const std::vector* CompilerDriver::CreateInterpreterToQuickEntry() const { + switch (instruction_set_) { + case kArm: + case kThumb2: + return arm::CreateInterpreterToQuickEntry(); + case kMips: + return mips::CreateInterpreterToQuickEntry(); + case kX86: + return x86::CreateInterpreterToQuickEntry(); + default: + LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_; + return NULL; + } +} + void CompilerDriver::CompileAll(jobject class_loader, const std::vector& dex_files) { DCHECK(!Runtime::Current()->IsStarted()); -- cgit v1.2.3 From 6fe568e16cea80dfe9ccb856c138a75da5f2a90d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 7 Jun 2013 15:16:10 -0700 Subject: Simplify CanAssumeTypeIsPresentInDexCache. Only use ScopedObjectAccess to check correct dex cache semantics. Change-Id: Ia4d3475368f92736c8a705b1b9a13175fc0af413 --- src/compiler/driver/compiler_driver.cc | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 1b8f87d51f..3917295fe1 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -536,24 +536,19 @@ void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compil bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file, uint32_t type_idx) { - ScopedObjectAccess soa(Thread::Current()); - mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); - if (!IsImage()) { - stats_->TypeNotInDexCache(); - return false; - } - mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); - if (resolved_class == NULL) { - stats_->TypeNotInDexCache(); - return false; - } - bool result = IsImageClass(ClassHelper(resolved_class).GetDescriptor()); - if (result) { + if (IsImage() && IsImageClass(dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)))) { + if (kIsDebugBuild) { + ScopedObjectAccess soa(Thread::Current()); + mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); + mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); + CHECK(resolved_class != NULL); + } stats_->TypeInDexCache(); + return true; } else { stats_->TypeNotInDexCache(); + return false; } - return result; } bool CompilerDriver::CanAssumeStringIsPresentInDexCache(const DexFile& dex_file, -- cgit v1.2.3 From 96391606d8adfc661e1c21703ded1e7a39377a76 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Thu, 13 Jun 2013 19:49:50 -0700 Subject: Move image class computation to the CompilerDriver Change-Id: Ia51cdc199cdeaf409755ab8da23323e204ce041e --- src/compiler/driver/compiler_driver.cc | 267 +++++++++++++++++++++++++++++++-- 1 file changed, 255 insertions(+), 12 deletions(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 40cc4830d4..186cf0d4d3 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -324,8 +324,8 @@ static Fn FindFunction(const std::string& compiler_so_name, void* library, const } CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set, - bool image, size_t thread_count, bool support_debugging, - const std::set* image_classes, + bool image, DescriptorSet* image_classes, + size_t thread_count, bool support_debugging, bool dump_stats, bool dump_timings) : compiler_backend_(compiler_backend), instruction_set_(instruction_set), @@ -333,19 +333,20 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet compiled_classes_lock_("compiled classes lock"), compiled_methods_lock_("compiled method lock"), image_(image), + image_classes_(image_classes), thread_count_(thread_count), support_debugging_(support_debugging), start_ns_(0), stats_(new AOTCompilationStats), dump_stats_(dump_stats), dump_timings_(dump_timings), - image_classes_(image_classes), compiler_library_(NULL), compiler_(NULL), compiler_context_(NULL), jni_compiler_(NULL), compiler_enable_auto_elf_loading_(NULL), - compiler_get_method_code_addr_(NULL) + compiler_get_method_code_addr_(NULL), + support_boot_image_fixup_(true) { std::string compiler_so_name(MakeCompilerSoName(compiler_backend_)); compiler_library_ = dlopen(compiler_so_name.c_str(), RTLD_LAZY); @@ -380,7 +381,7 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet CHECK(!Runtime::Current()->IsStarted()); if (!image_) { - CHECK(image_classes_ == NULL); + CHECK(image_classes_.get() == NULL); } } @@ -576,20 +577,199 @@ void CompilerDriver::Resolve(jobject class_loader, const std::vector& dex_files, ThreadPool& thread_pool, TimingLogger& timings) { + LoadImageClasses(timings); + Resolve(class_loader, dex_files, thread_pool, timings); Verify(class_loader, dex_files, thread_pool, timings); InitializeClasses(class_loader, dex_files, thread_pool, timings); + + UpdateImageClasses(timings); } bool CompilerDriver::IsImageClass(const char* descriptor) const { - if (image_classes_ == NULL) { - return false; + DCHECK(descriptor != NULL); + if (image_classes_.get() == NULL) { + return true; } return image_classes_->find(descriptor) != image_classes_->end(); } +static void ResolveExceptionsForMethod(MethodHelper* mh, + std::set >& exceptions_to_resolve) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::CodeItem* code_item = mh->GetCodeItem(); + if (code_item == NULL) { + return; // native or abstract method + } + if (code_item->tries_size_ == 0) { + return; // nothing to process + } + const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0); + size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list); + for (size_t i = 0; i < num_encoded_catch_handlers; i++) { + int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list); + bool has_catch_all = false; + if (encoded_catch_handler_size <= 0) { + encoded_catch_handler_size = -encoded_catch_handler_size; + has_catch_all = true; + } + for (int32_t j = 0; j < encoded_catch_handler_size; j++) { + uint16_t encoded_catch_handler_handlers_type_idx = + DecodeUnsignedLeb128(&encoded_catch_handler_list); + // Add to set of types to resolve if not already in the dex cache resolved types + if (!mh->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) { + exceptions_to_resolve.insert( + std::pair(encoded_catch_handler_handlers_type_idx, + &mh->GetDexFile())); + } + // ignore address associated with catch handler + DecodeUnsignedLeb128(&encoded_catch_handler_list); + } + if (has_catch_all) { + // ignore catch all address + DecodeUnsignedLeb128(&encoded_catch_handler_list); + } + } +} + +static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + std::set >* exceptions_to_resolve = + reinterpret_cast >*>(arg); + MethodHelper mh; + for (size_t i = 0; i < c->NumVirtualMethods(); ++i) { + mirror::AbstractMethod* m = c->GetVirtualMethod(i); + mh.ChangeMethod(m); + ResolveExceptionsForMethod(&mh, *exceptions_to_resolve); + } + for (size_t i = 0; i < c->NumDirectMethods(); ++i) { + mirror::AbstractMethod* m = c->GetDirectMethod(i); + mh.ChangeMethod(m); + ResolveExceptionsForMethod(&mh, *exceptions_to_resolve); + } + return true; +} + +static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CompilerDriver::DescriptorSet* image_classes = + reinterpret_cast(arg); + image_classes->insert(ClassHelper(klass).GetDescriptor()); + return true; +} + +// Make a list of descriptors for classes to include in the image +void CompilerDriver::LoadImageClasses(TimingLogger& timings) + LOCKS_EXCLUDED(Locks::mutator_lock_) { + if (image_classes_.get() == NULL) { + return; + } + + // Make a first class to load all classes explicitly listed in the file + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + typedef DescriptorSet::iterator It; // TODO: C++0x auto + for (It it = image_classes_->begin(), end = image_classes_->end(); it != end;) { + std::string descriptor(*it); + SirtRef klass(self, class_linker->FindSystemClass(descriptor.c_str())); + if (klass.get() == NULL) { + image_classes_->erase(it++); + LOG(WARNING) << "Failed to find class " << descriptor; + Thread::Current()->ClearException(); + } else { + ++it; + } + } + + // Resolve exception classes referenced by the loaded classes. The catch logic assumes + // exceptions are resolved by the verifier when there is a catch block in an interested method. + // Do this here so that exception classes appear to have been specified image classes. + std::set > unresolved_exception_types; + SirtRef java_lang_Throwable(self, + class_linker->FindSystemClass("Ljava/lang/Throwable;")); + do { + unresolved_exception_types.clear(); + class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor, + &unresolved_exception_types); + typedef std::set >::const_iterator It; // TODO: C++0x auto + for (It it = unresolved_exception_types.begin(), + end = unresolved_exception_types.end(); + it != end; ++it) { + uint16_t exception_type_idx = it->first; + const DexFile* dex_file = it->second; + mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file); + mirror:: ClassLoader* class_loader = NULL; + SirtRef klass(self, class_linker->ResolveType(*dex_file, exception_type_idx, + dex_cache, class_loader)); + if (klass.get() == NULL) { + const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx); + const char* descriptor = dex_file->GetTypeDescriptor(type_id); + LOG(FATAL) << "Failed to resolve class " << descriptor; + } + DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get())); + } + // Resolving exceptions may load classes that reference more exceptions, iterate until no + // more are found + } while (!unresolved_exception_types.empty()); + + // We walk the roots looking for classes so that we'll pick up the + // above classes plus any classes them depend on such super + // classes, interfaces, and the required ClassLinker roots. + class_linker->VisitClasses(RecordImageClassesVisitor, image_classes_.get()); + + CHECK_NE(image_classes_->size(), 0U); + timings.AddSplit("LoadImageClasses"); +} + +static void MaybeAddToImageClasses(mirror::Class* klass, CompilerDriver::DescriptorSet* image_classes) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + while (!klass->IsObjectClass()) { + ClassHelper kh(klass); + const char* descriptor = kh.GetDescriptor(); + std::pair result = + image_classes->insert(descriptor); + if (result.second) { + LOG(INFO) << "Adding " << descriptor << " to image classes"; + } else { + return; + } + for (size_t i = 0; i < kh.NumDirectInterfaces(); ++i) { + MaybeAddToImageClasses(kh.GetDirectInterface(i), image_classes); + } + if (klass->IsArrayClass()) { + MaybeAddToImageClasses(klass->GetComponentType(), image_classes); + } + klass = klass->GetSuperClass(); + } +} + +void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) { + DCHECK(object != NULL); + DCHECK(arg != NULL); + CompilerDriver* compiler_driver = reinterpret_cast(arg); + MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get()); +} + +void CompilerDriver::UpdateImageClasses(TimingLogger& timings) { + if (image_classes_.get() == NULL) { + return; + } + + // Update image_classes_ with classes for objects created by methods. + Thread* self = Thread::Current(); + const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); + Heap* heap = Runtime::Current()->GetHeap(); + // TODO: Image spaces only? + WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); + heap->FlushAllocStack(); + heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this); + self->EndAssertNoThreadSuspension(old_cause); + timings.AddSplit("UpdateImageClasses"); +} + void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) { MutexLock mu(Thread::Current(), CompilerDriver::compiled_classes_lock_); compiled_classes_.Put(ref, compiled_class); @@ -914,8 +1094,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s } bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1; if (compiling_boot) { - const bool kSupportBootImageFixup = true; - if (kSupportBootImageFixup) { + if (support_boot_image_fixup_) { MethodHelper mh(method); if (IsImageClass(mh.GetDeclaringClassDescriptor())) { // We can only branch directly to Methods that are resolved in the DexCache. @@ -1617,10 +1796,13 @@ static const char* class_initializer_black_list[] = { "Ljava/io/ObjectStreamClass;", // Calls to Class.forName -> java.io.FileDescriptor. "Ljava/io/ObjectStreamConstants;", // Instance of non-image class SerializablePermission. "Ljava/lang/ClassLoader$SystemClassLoader;", // Calls System.getProperty -> OsConstants.initConstants. + "Ljava/lang/HexStringParser;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl. + "Ljava/lang/ProcessManager;", // Calls Thread.currentThread. "Ljava/lang/Runtime;", // Calls System.getProperty -> OsConstants.initConstants. "Ljava/lang/System;", // Calls OsConstants.initConstants. "Ljava/math/BigDecimal;", // Calls native ... -> java.math.NativeBN.BN_new(). "Ljava/math/BigInteger;", // Calls native ... -> java.math.NativeBN.BN_new(). + "Ljava/math/Primality;", // Calls native ... -> java.math.NativeBN.BN_new(). "Ljava/math/Multiplication;", // Calls native ... -> java.math.NativeBN.BN_new(). "Ljava/net/InetAddress;", // Requires libcore.io.OsConstants. "Ljava/net/Inet4Address;", // Sub-class of InetAddress. @@ -1629,23 +1811,57 @@ static const char* class_initializer_black_list[] = { "Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants. "Ljava/nio/charset/CharsetICU;", // Sub-class of Charset. "Ljava/nio/charset/Charsets;", // Calls Charset.forName. + "Ljava/security/AlgorithmParameterGenerator;", // Calls OsConstants.initConstants. + "Ljava/security/KeyPairGenerator$KeyPairGeneratorImpl;", // Calls OsConstants.initConstants. "Ljava/security/KeyPairGenerator;", // Calls OsConstants.initConstants. "Ljava/security/Security;", // Tries to do disk IO for "security.properties". + "Ljava/security/spec/RSAKeyGenParameterSpec;", // java.math.NativeBN.BN_new() "Ljava/sql/Date;", // Calls OsConstants.initConstants. + "Ljava/sql/DriverManager;", // Calls OsConstants.initConstants. + "Ljava/sql/Time;", // Calls OsConstants.initConstants. + "Ljava/sql/Timestamp;", // Calls OsConstants.initConstants. "Ljava/util/Date;", // Calls Date. -> System.currentTimeMillis -> OsConstants.initConstants. + "Ljava/util/ListResourceBundle;", // Calls OsConstants.initConstants. "Ljava/util/Locale;", // Calls System.getProperty -> OsConstants.initConstants. + "Ljava/util/PropertyResourceBundle;", // Calls OsConstants.initConstants. + "Ljava/util/ResourceBundle;", // Calls OsConstants.initConstants. + "Ljava/util/ResourceBundle$MissingBundle;", // Calls OsConstants.initConstants. + "Ljava/util/Scanner;", // regex.Pattern.compileImpl. "Ljava/util/SimpleTimeZone;", // Sub-class of TimeZone. "Ljava/util/TimeZone;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl. "Ljava/util/concurrent/ConcurrentHashMap$Segment;", // Calls Runtime.getRuntime().availableProcessors(). + "Ljava/util/concurrent/ConcurrentSkipListMap;", // Calls OsConstants.initConstants. + "Ljava/util/concurrent/Exchanger;", // Calls OsConstants.initConstants. + "Ljava/util/concurrent/ForkJoinPool;", // Calls OsConstants.initConstants. + "Ljava/util/concurrent/LinkedTransferQueue;", // Calls OsConstants.initConstants. + "Ljava/util/concurrent/Phaser;", // Calls OsConstants.initConstants. + "Ljava/util/concurrent/ScheduledThreadPoolExecutor;", // Calls AtomicLong.VMSupportsCS8() + "Ljava/util/concurrent/SynchronousQueue;", // Calls OsConstants.initConstants. + "Ljava/util/concurrent/atomic/AtomicLong;", // Calls AtomicLong.VMSupportsCS8() "Ljava/util/logging/LogManager;", // Calls System.getProperty -> OsConstants.initConstants. + "Ljava/util/prefs/AbstractPreferences;", // Calls OsConstants.initConstants. + "Ljava/util/prefs/FilePreferencesImpl;", // Calls OsConstants.initConstants. + "Ljava/util/prefs/FilePreferencesFactoryImpl;", // Calls OsConstants.initConstants. + "Ljava/util/prefs/Preferences;", // Calls OsConstants.initConstants. + "Ljavax/crypto/KeyAgreement;", // Calls OsConstants.initConstants. + "Ljavax/crypto/KeyGenerator;", // Calls OsConstants.initConstants. + "Ljavax/security/cert/X509Certificate;", // Calls VMClassLoader.getBootClassPathSize. + "Ljavax/security/cert/X509Certificate$1;", // Calls VMClassLoader.getBootClassPathSize. "Ljavax/microedition/khronos/egl/EGL10;", // Requires EGLContext. "Ljavax/microedition/khronos/egl/EGLContext;", // Requires com.google.android.gles_jni.EGLImpl. "Ljavax/net/ssl/HttpsURLConnection;", // Calls SSLSocketFactory.getDefault -> java.security.Security.getProperty. + "Ljavax/xml/datatype/DatatypeConstants;", // Calls OsConstants.initConstants. + "Ljavax/xml/datatype/FactoryFinder;", // Calls OsConstants.initConstants. + "Ljavax/xml/namespace/QName;", // Calls OsConstants.initConstants. + "Ljavax/xml/validation/SchemaFactoryFinder;", // Calls OsConstants.initConstants. + "Ljavax/xml/xpath/XPathConstants;", // Calls OsConstants.initConstants. + "Ljavax/xml/xpath/XPathFactoryFinder;", // Calls OsConstants.initConstants. "Llibcore/icu/LocaleData;", // Requires java.util.Locale. "Llibcore/icu/TimeZoneNames;", // Requires java.util.TimeZone. "Llibcore/io/IoUtils;", // Calls Random. -> System.currentTimeMillis -> FileDescriptor -> OsConstants.initConstants. "Llibcore/io/OsConstants;", // Platform specific. "Llibcore/net/MimeUtils;", // Calls libcore.net.MimeUtils.getContentTypesPropertiesStream -> System.getProperty. + "Llibcore/reflect/Types;", // Calls OsConstants.initConstants. "Llibcore/util/ZoneInfo;", // Sub-class of TimeZone. "Llibcore/util/ZoneInfoDB;", // Calls System.getenv -> OsConstants.initConstants. "Lorg/apache/commons/logging/LogFactory;", // Calls System.getProperty. @@ -1653,17 +1869,40 @@ static const char* class_initializer_black_list[] = { "Lorg/apache/harmony/security/provider/cert/X509CertFactoryImpl;", // Requires java.nio.charsets.Charsets. "Lorg/apache/harmony/security/provider/crypto/RandomBitsSupplier;", // Requires java.io.File. "Lorg/apache/harmony/security/utils/AlgNameMapper;", // Requires java.util.Locale. + "Lorg/apache/harmony/security/pkcs10/CertificationRequest;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/pkcs10/CertificationRequestInfo;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/pkcs7/AuthenticatedAttributes;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/pkcs7/SignedData;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/pkcs7/SignerInfo;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/pkcs8/PrivateKeyInfo;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl;", // Calls OsConstants.initConstants. "Lorg/apache/harmony/security/x501/AttributeTypeAndValue;", // Calls IntegralToString.convertInt -> Thread.currentThread. "Lorg/apache/harmony/security/x501/DirectoryString;", // Requires BigInteger. "Lorg/apache/harmony/security/x501/Name;", // Requires org.apache.harmony.security.x501.AttributeTypeAndValue. + "Lorg/apache/harmony/security/x509/AccessDescription;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/AuthorityKeyIdentifier;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/CRLDistributionPoints;", // Calls Thread.currentThread. "Lorg/apache/harmony/security/x509/Certificate;", // Requires org.apache.harmony.security.x509.TBSCertificate. - "Lorg/apache/harmony/security/x509/TBSCertificate;", // Requires org.apache.harmony.security.x501.Name. + "Lorg/apache/harmony/security/x509/CertificateIssuer;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/CertificateList;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/DistributionPoint;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/DistributionPointName;", // Calls Thread.currentThread. "Lorg/apache/harmony/security/x509/EDIPartyName;", // Calls native ... -> java.math.NativeBN.BN_new(). "Lorg/apache/harmony/security/x509/GeneralName;", // Requires org.apache.harmony.security.x501.Name. "Lorg/apache/harmony/security/x509/GeneralNames;", // Requires GeneralName. + "Lorg/apache/harmony/security/x509/GeneralSubtree;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/GeneralSubtrees;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/InfoAccessSyntax;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/IssuingDistributionPoint;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/NameConstraints;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/TBSCertList$RevokedCertificate;", // Calls NativeBN.BN_new(). + "Lorg/apache/harmony/security/x509/TBSCertList;", // Calls Thread.currentThread. + "Lorg/apache/harmony/security/x509/TBSCertificate;", // Requires org.apache.harmony.security.x501.Name. "Lorg/apache/harmony/security/x509/Time;", // Calls native ... -> java.math.NativeBN.BN_new(). "Lorg/apache/harmony/security/x509/Validity;", // Requires x509.Time. + "Lorg/apache/harmony/security/x509/tsp/TSTInfo;", // Calls Thread.currentThread. "Lorg/apache/harmony/xml/ExpatParser;", // Calls native ExpatParser.staticInitialize. + "Lorg/apache/harmony/xml/ExpatParser$EntityParser;", // Calls ExpatParser.staticInitialize. "Lorg/apache/http/conn/params/ConnRouteParams;", // Requires java.util.Locale. "Lorg/apache/http/conn/ssl/SSLSocketFactory;", // Calls java.security.Security.getProperty. "Lorg/apache/http/conn/util/InetAddressUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl. @@ -1693,6 +1932,9 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl // Only try to initialize classes that were successfully verified. if (klass->IsVerified()) { manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields); + if (soa.Self()->IsExceptionPending()) { + soa.Self()->GetException(NULL)->Dump(); + } if (!klass->IsInitialized()) { if (can_init_static_fields) { bool is_black_listed = false; @@ -1730,7 +1972,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl compiled_class = new CompiledClass(status); manager->GetCompiler()->RecordClassStatus(ref, compiled_class); } else { - DCHECK_EQ(status, compiled_class->GetStatus()); + DCHECK_GE(status, compiled_class->GetStatus()) << descriptor; } } // Clear any class not found or verification exceptions. @@ -1854,7 +2096,8 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t } else if ((access_flags & kAccAbstract) != 0) { } else { // In small mode we only compile image classes. - bool dont_compile = Runtime::Current()->IsSmallMode() && ((image_classes_ == NULL) || (image_classes_->size() == 0)); + bool dont_compile = (Runtime::Current()->IsSmallMode() && + ((image_classes_.get() == NULL) || (image_classes_->size() == 0))); // Don't compile class initializers, ever. if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) { -- cgit v1.2.3 From b19fa800aab1c2731b12ff24696feca13901db3f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 20 Jun 2013 11:17:03 -0700 Subject: Don't always slow-path array casts/instance-of. Recent changes to IsAbstract for arrays pushed us in to always generating slow-paths. Change-Id: I52fb50953949f337243961a308eabf0d684eacf3 --- src/compiler/driver/compiler_driver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 186cf0d4d3..b04e5b1f3d 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -851,7 +851,7 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const Dex *type_known_final = resolved_class->IsFinal() && !resolved_class->IsArrayClass(); } if (type_known_abstract != NULL) { - *type_known_abstract = resolved_class->IsAbstract(); + *type_known_abstract = resolved_class->IsAbstract() && !resolved_class->IsArrayClass(); } } else { stats_->TypeNeedsAccessCheck(); -- cgit v1.2.3 From 1d54e73444e017d3a65234e0f193846f3e27472b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 2 May 2013 21:10:01 -0700 Subject: GC clean up. Greater use of directories and namespaces. Fix bugs that cause verify options to fail. Address numerous other issues: GC barrier wait occurring holding locks: GC barrier waits occur when we wait for threads to run the check point function on themselves. This is happening with the heap bitmap and mutator lock held meaning that a thread that tries to take either lock exclusively will block waiting on a thread that is waiting. If this thread is the thread we're waiting to run the check point then the VM will deadlock. This deadlock occurred unnoticed as the call to check for wait safety was removed in: https://googleplex-android-review.googlesource.com/#/c/249423/1. NewTimingLogger: Existing timing log states when a split ends but not when it begins. This isn't good for systrace, in the context of GC it means that races between mutators and the GC are hard to discover what phase the GC is in, we know what phase it just finished and derive but that's not ideal. Support for only 1 discontinuous space: Code special cases continuous and large object space, rather than assuming we can have a collection of both. Sorted atomic stacks: Used to improve verification performance. Simplify their use and add extra checks. Simplify mod-union table abstractions. Reduce use of std::strings and their associated overhead in hot code. Make time units of fields explicit. Reduce confusion that IsAllocSpace is really IsDlMallocSpace. Make GetTotalMemory (exposed via System) equal to the footprint (as in Dalvik) rather than the max memory footprint. Change-Id: Ie87067140fa4499b15edab691fe6565d79599812 --- src/compiler/driver/compiler_driver.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index b04e5b1f3d..6050108d48 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -31,8 +31,9 @@ #include "oat_file.h" #include "object_utils.h" #include "runtime.h" -#include "gc/card_table-inl.h" -#include "gc/space.h" +#include "gc/accounting/card_table-inl.h" +#include "gc/accounting/heap_bitmap.h" +#include "gc/space/space.h" #include "mirror/class_loader.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" @@ -761,7 +762,7 @@ void CompilerDriver::UpdateImageClasses(TimingLogger& timings) { // Update image_classes_ with classes for objects created by methods. Thread* self = Thread::Current(); const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter"); - Heap* heap = Runtime::Current()->GetHeap(); + gc::Heap* heap = Runtime::Current()->GetHeap(); // TODO: Image spaces only? WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); heap->FlushAllocStack(); @@ -1092,7 +1093,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s } stats_->DirectMethodsToBoot(type); } - bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1; + bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1; if (compiling_boot) { if (support_boot_image_fixup_) { MethodHelper mh(method); @@ -1104,7 +1105,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s } } } else { - if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method)->IsImageSpace()) { + if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace()) { direct_method = reinterpret_cast(method); } direct_code = reinterpret_cast(method->GetEntryPointFromCompiledCode()); @@ -1382,7 +1383,7 @@ class ParallelCompilationManager { CHECK_NE(self->GetState(), kRunnable); // Wait for all the worker threads to finish. - thread_pool_->Wait(self); + thread_pool_->Wait(self, true, false); } private: @@ -1915,7 +1916,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl mirror::ClassLoader* class_loader = soa.Decode(manager->GetClassLoader()); const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def); mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader); - bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1; + bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1; bool can_init_static_fields = compiling_boot && manager->GetCompiler()->IsImageClass(descriptor); if (klass != NULL) { @@ -1925,8 +1926,9 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl // on a second thread the sub-class is initialized (holding its lock) after first initializing // its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent // lock ordering and consequent potential deadlock. - static Mutex lock1("Initializer lock", kMonitorLock); - MutexLock mu(soa.Self(), lock1); + // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather + // than use a special Object for the purpose we use the Class of java.lang.Class. + ObjectLock lock1(soa.Self(), klass->GetClass()); // The lock required to initialize the class. ObjectLock lock2(soa.Self(), klass); // Only try to initialize classes that were successfully verified. -- cgit v1.2.3 From 2d6ba5158d7fd459db2870df47300b517dc4d08c Mon Sep 17 00:00:00 2001 From: Sebastien Hertz Date: Fri, 17 May 2013 11:31:37 +0200 Subject: Quickening support. This CL adds quickening support for methods which are interpreted at runtime. This CL introduces a DEX-to-DEX compiler. A method is now compiled in one of the two following modes: - Native compilation: the method is compiled by the Quick or Portable backends. At runtime, the generated native target-dependent code is executed. - DEX-to-DEX compilation: the method is executed by the interpreter at runtime. Its DEX code is compiled so some instructions can be replaced by special instructions only valid at runtime. No native code is generated. The quickening adds special instructions to improve runtime performance. They are "-quick" versions of the following instructions: - iget/iput - iget-wide/iput-wide - iget-object/iput-object - invoke-virtual/range. These special instructions cannot be treated by the verifier since they lose the field/method index referencing the field/method being accessed/invoked. To prevent this, the DEX-to-DEX compiler is run only on methods of preverified classes (without verification error at compilation time). The DEX-to-DEX compiler implements quickening support using the CompilerDriver interface like the native compiler does (Quick or Portable backends). To replace instructions, the DEX-to-DEX compiler must be able to modify the mmapped DEX file. Since it can be read-only protected, the DEX-to-DEX compiler must be able to temporarily change its protection to read-write mmapped file. To achieve this, this CL adds support for changing DEX file protection with DexFile::EnableWrite and DexFile::DisableWrite methods. Besides, it also adds a dedicated lock (DexFile::modification_lock) to ensure thread-safety and avoid concurrent DEX file protection change (from a parallel DEX-to-DEX compiler on the same DEX file). Change-Id: Iaafd103b9766810d7fc94a2c424a8fafba66e26a --- src/compiler/driver/compiler_driver.cc | 68 +++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 10 deletions(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 6050108d48..4a6eb962e3 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -372,6 +372,8 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet compiler_ = FindFunction(compiler_so_name, compiler_library_, "ArtQuickCompileMethod"); } + dex_to_dex_compiler_ = FindFunction(compiler_so_name, compiler_library_, "ArtCompileDEX"); + init_compiler_context(*this); if (compiler_backend_ == kPortable) { @@ -531,10 +533,33 @@ void CompilerDriver::CompileAll(jobject class_loader, } } +static bool IsDexToDexCompilationAllowed(mirror::ClassLoader* class_loader, + const DexFile& dex_file, + const DexFile::ClassDef& class_def) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Do not allow DEX-to-DEX compilation of image classes. This is to prevent the + // verifier from passing on "quick" instruction at compilation time. It must + // only pass on quick instructions at runtime. + if (class_loader == NULL) { + return false; + } + const char* descriptor = dex_file.GetClassDescriptor(class_def); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + mirror::Class* klass = class_linker->FindClass(descriptor, class_loader); + if (klass == NULL) { + Thread* self = Thread::Current(); + CHECK(self->IsExceptionPending()); + self->ClearException(); + return false; + } + // DEX-to-DEX compilation is only allowed on preverified classes. + return klass->IsVerified(); +} + void CompilerDriver::CompileOne(const mirror::AbstractMethod* method) { DCHECK(!Runtime::Current()->IsStarted()); Thread* self = Thread::Current(); - jobject class_loader; + jobject jclass_loader; const DexFile* dex_file; uint32_t class_def_idx; { @@ -542,7 +567,7 @@ void CompilerDriver::CompileOne(const mirror::AbstractMethod* method) { ScopedLocalRef local_class_loader(soa.Env(), soa.AddLocalReference(method->GetDeclaringClass()->GetClassLoader())); - class_loader = soa.Env()->NewGlobalRef(local_class_loader.get()); + jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get()); // Find the dex_file MethodHelper mh(method); dex_file = &mh.GetDexFile(); @@ -555,14 +580,22 @@ void CompilerDriver::CompileOne(const mirror::AbstractMethod* method) { UniquePtr thread_pool(new ThreadPool(1U)); TimingLogger timings("CompileOne", false); - PreCompile(class_loader, dex_files, *thread_pool.get(), timings); + PreCompile(jclass_loader, dex_files, *thread_pool.get(), timings); uint32_t method_idx = method->GetDexMethodIndex(); const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); + // Can we run DEX-to-DEX compiler on this class ? + bool allow_dex_compilation; + { + ScopedObjectAccess soa(Thread::Current()); + const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); + mirror::ClassLoader* class_loader = soa.Decode(jclass_loader); + allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, *dex_file, class_def); + } CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(), - class_def_idx, method_idx, class_loader, *dex_file); + class_def_idx, method_idx, jclass_loader, *dex_file, allow_dex_compilation); - self->GetJniEnv()->DeleteGlobalRef(class_loader); + self->GetJniEnv()->DeleteGlobalRef(jclass_loader); self->TransitionFromSuspendedToRunnable(); } @@ -2015,12 +2048,12 @@ void CompilerDriver::Compile(jobject class_loader, const std::vectorGetClassLoader(); + jobject jclass_loader = manager->GetClassLoader(); const DexFile& dex_file = *manager->GetDexFile(); const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); { ScopedObjectAccess soa(Thread::Current()); - mirror::ClassLoader* class_loader = soa.Decode(manager->GetClassLoader()); + mirror::ClassLoader* class_loader = soa.Decode(jclass_loader); if (SkipClass(class_loader, dex_file, class_def)) { return; } @@ -2035,6 +2068,13 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz // empty class, probably a marker interface return; } + // Can we run DEX-to-DEX compiler on this class ? + bool allow_dex_compilation; + { + ScopedObjectAccess soa(Thread::Current()); + mirror::ClassLoader* class_loader = soa.Decode(jclass_loader); + allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, dex_file, class_def); + } ClassDataItemIterator it(dex_file, class_data); // Skip fields while (it.HasNextStaticField()) { @@ -2056,7 +2096,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz previous_direct_method_idx = method_idx; manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(), it.GetMethodInvokeType(class_def), class_def_index, - method_idx, class_loader, dex_file); + method_idx, jclass_loader, dex_file, allow_dex_compilation); it.Next(); } // Compile virtual methods @@ -2072,7 +2112,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz previous_virtual_method_idx = method_idx; manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(), it.GetMethodInvokeType(class_def), class_def_index, - method_idx, class_loader, dex_file); + method_idx, jclass_loader, dex_file, allow_dex_compilation); it.Next(); } DCHECK(!it.HasNext()); @@ -2088,7 +2128,8 @@ void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_fil void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, - const DexFile& dex_file) { + const DexFile& dex_file, + bool allow_dex_to_dex_compilation) { CompiledMethod* compiled_method = NULL; uint64_t start_ns = NanoTime(); @@ -2113,6 +2154,13 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file); CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file); + } else if (allow_dex_to_dex_compilation) { + // TODO: add a mode to disable DEX-to-DEX compilation ? + compiled_method = (*dex_to_dex_compiler_)(*this, code_item, access_flags, + invoke_type, class_def_idx, + method_idx, class_loader, dex_file); + // No native code is generated. + CHECK(compiled_method == NULL) << PrettyMethod(method_idx, dex_file); } } uint64_t duration_ns = NanoTime() - start_ns; -- cgit v1.2.3 From 7467ee05012e1fd9834df74663c1ebda46f5636b Mon Sep 17 00:00:00 2001 From: Dragos Sbirlea Date: Fri, 21 Jun 2013 09:20:34 -0700 Subject: Added support for SEA IR. - Modified makefile to take the existance of SEA_IR_ART file to mean "switch to sea ir mode". - Switching SEA IR mode on leads to the new compiler being fed the fibonacci methods only, if they are used as input. - Added partial support for the control flow subgraph of the SEA IR (instruction nodes and region nodes for conditional and unconditional branches). Change-Id: I29020b8e2df5a00fde75715c3683cc25038589f4 Conflicts: src/compiler/driver/compiler_driver.cc --- src/compiler/driver/compiler_driver.cc | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 4a6eb962e3..122988aa5b 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -374,6 +374,11 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet dex_to_dex_compiler_ = FindFunction(compiler_so_name, compiler_library_, "ArtCompileDEX"); + sea_ir_compiler_ = NULL; + if (Runtime::Current()->IsSeaIRMode()) { + sea_ir_compiler_ = FindFunction(compiler_so_name, compiler_library_, "SeaIrCompileMethod"); + } + init_compiler_context(*this); if (compiler_backend_ == kPortable) { @@ -2149,10 +2154,22 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t // Do compile small methods. dont_compile = false; } - if (!dont_compile) { - compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx, + bool use_sea = false; + + if (Runtime::Current()->IsSeaIRMode()) { + use_sea = true; + } + if (use_sea) { + use_sea = (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci")); + } + if (!use_sea) { + compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file); + } else { + compiled_method = (*sea_ir_compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx, + method_idx, class_loader, dex_file); + } CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file); } else if (allow_dex_to_dex_compilation) { // TODO: add a mode to disable DEX-to-DEX compilation ? -- cgit v1.2.3 From 0b4e3ef67508a0b8c121b6b26ab5ea0a1d8e7141 Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Mon, 1 Jul 2013 09:29:04 -0700 Subject: Add StandardCharsets to the class_initializer_black_list Change-Id: Id13a58fc6da8a2c39f47bcee14a743c88fc899b7 --- src/compiler/driver/compiler_driver.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/compiler/driver/compiler_driver.cc') diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 122988aa5b..24299ea9bc 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -1850,6 +1850,7 @@ static const char* class_initializer_black_list[] = { "Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants. "Ljava/nio/charset/CharsetICU;", // Sub-class of Charset. "Ljava/nio/charset/Charsets;", // Calls Charset.forName. + "Ljava/nio/charset/StandardCharsets;", // Calls OsConstants.initConstants. "Ljava/security/AlgorithmParameterGenerator;", // Calls OsConstants.initConstants. "Ljava/security/KeyPairGenerator$KeyPairGeneratorImpl;", // Calls OsConstants.initConstants. "Ljava/security/KeyPairGenerator;", // Calls OsConstants.initConstants. -- cgit v1.2.3