diff options
| -rw-r--r-- | compiler/dex/quick/gen_invoke.cc | 14 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 210 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.h | 4 | ||||
| -rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 16 | ||||
| -rw-r--r-- | runtime/object_utils.h | 40 |
5 files changed, 168 insertions, 116 deletions
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 64938f3a73..62feadedcc 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -350,16 +350,13 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, uintptr_t direct_code, uintptr_t direct_method, InvokeType type) { Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); - if (cu->instruction_set != kThumb2) { - // Disable sharpening - direct_code = 0; - direct_method = 0; - } if (direct_code != 0 && direct_method != 0) { switch (state) { case 0: // Get the current Method* [sets kArg0] if (direct_code != static_cast<unsigned int>(-1)) { - cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code); + if (cu->instruction_set != kX86) { + cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code); + } } else { CHECK_EQ(cu->dex_file, target_method.dex_file); LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, @@ -405,6 +402,7 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code); } else { CHECK_EQ(cu->dex_file, target_method.dex_file); + CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds()); LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, target_method.dex_method_index, 0); if (data_target == NULL) { @@ -501,10 +499,6 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, uint32_t unused, uintptr_t unused2, uintptr_t direct_method, InvokeType unused4) { Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); - if (cu->instruction_set != kThumb2) { - // Disable sharpening - direct_method = 0; - } ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline); if (direct_method != 0) { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 7c4a6ce785..e618307e72 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -355,7 +355,7 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet jni_compiler_(NULL), compiler_enable_auto_elf_loading_(NULL), compiler_get_method_code_addr_(NULL), - support_boot_image_fixup_(true), + support_boot_image_fixup_(instruction_set == kThumb2), dedupe_code_("dedupe code"), dedupe_mapping_table_("dedupe mapping table"), dedupe_vmap_table_("dedupe vmap table"), @@ -1058,10 +1058,12 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila return false; // Incomplete knowledge needs slow path. } -void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, +void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type, + bool no_guarantee_of_dex_cache_entry, mirror::Class* referrer_class, mirror::ArtMethod* method, bool update_stats, + MethodReference* target_method, uintptr_t* direct_code, uintptr_t* direct_method) { // For direct and static methods compute possible direct_code and direct_method values, ie @@ -1070,46 +1072,103 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s // invoked, so this can be passed to the out-of-line runtime support code. *direct_code = 0; *direct_method = 0; + bool use_dex_cache = false; + bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1; if (compiler_backend_ == kPortable) { if (sharp_type != kStatic && sharp_type != kDirect) { return; } + use_dex_cache = true; } else { if (sharp_type != kStatic && sharp_type != kDirect && sharp_type != kInterface) { return; } + // TODO: support patching on all architectures. + use_dex_cache = compiling_boot && !support_boot_image_fixup_; } - bool method_code_in_boot = method->GetDeclaringClass()->GetClassLoader() == NULL; - if (!method_code_in_boot) { - return; + bool method_code_in_boot = (method->GetDeclaringClass()->GetClassLoader() == nullptr); + if (!use_dex_cache) { + if (!method_code_in_boot) { + use_dex_cache = true; + } else { + bool has_clinit_trampoline = + method->IsStatic() && !method->GetDeclaringClass()->IsInitialized(); + if (has_clinit_trampoline && (method->GetDeclaringClass() != referrer_class)) { + // Ensure we run the clinit trampoline unless we are invoking a static method in the same + // class. + use_dex_cache = true; + } + } } - bool has_clinit_trampoline = method->IsStatic() && !method->GetDeclaringClass()->IsInitialized(); - if (has_clinit_trampoline && (method->GetDeclaringClass() != referrer_class)) { - // Ensure we run the clinit trampoline unless we are invoking a static method in the same class. - return; + if (update_stats && method_code_in_boot) { + if (sharp_type != kInterface) { // Interfaces always go via a trampoline until we get IMTs. + stats_->DirectCallsToBoot(*type); + } + stats_->DirectMethodsToBoot(*type); } - if (update_stats) { - if (sharp_type != kInterface) { // Interfaces always go via a trampoline. - stats_->DirectCallsToBoot(type); + if (!use_dex_cache && compiling_boot) { + MethodHelper mh(method); + if (!IsImageClass(mh.GetDeclaringClassDescriptorAsStringPiece())) { + // We can only branch directly to Methods that are resolved in the DexCache. + // Otherwise we won't invoke the resolution trampoline. + use_dex_cache = true; } - stats_->DirectMethodsToBoot(type); } - bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1; - if (compiling_boot) { - if (support_boot_image_fixup_) { - MethodHelper mh(method); - if (IsImageClass(mh.GetDeclaringClassDescriptorAsStringPiece())) { - // We can only branch directly to Methods that are resolved in the DexCache. - // Otherwise we won't invoke the resolution trampoline. - *direct_method = -1; - *direct_code = -1; + // The method is defined not within this dex file. We need a dex cache slot within the current + // dex file or direct pointers. + bool must_use_direct_pointers = false; + if (target_method->dex_file == method->GetDeclaringClass()->GetDexCache()->GetDexFile()) { + target_method->dex_method_index = method->GetDexMethodIndex(); + } else { + // TODO: support patching from one dex file to another in the boot image. + use_dex_cache = use_dex_cache || compiling_boot; + if (no_guarantee_of_dex_cache_entry) { + // See if the method is also declared in this dex cache. + uint32_t dex_method_idx = MethodHelper(method).FindDexMethodIndexInOtherDexFile( + *referrer_class->GetDexCache()->GetDexFile()); + if (dex_method_idx != DexFile::kDexNoIndex) { + target_method->dex_method_index = dex_method_idx; + } else { + must_use_direct_pointers = true; } } + } + if (use_dex_cache) { + if (must_use_direct_pointers) { + // Fail. Test above showed the only safe dispatch was via the dex cache, however, the direct + // pointers are required as the dex cache lacks an appropriate entry. + VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method); + } else { + *type = sharp_type; + } } else { - if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace()) { - *direct_method = reinterpret_cast<uintptr_t>(method); + if (compiling_boot) { + *type = sharp_type; + *direct_method = -1; + if (sharp_type != kInterface) { + *direct_code = -1; + } + } else { + bool method_in_image = + Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace(); + if (method_in_image) { + CHECK_EQ(method->IsAbstract(), sharp_type == kInterface); + *type = sharp_type; + *direct_method = reinterpret_cast<uintptr_t>(method); + if (*type != kInterface) { + *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode()); + } + target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); + target_method->dex_method_index = method->GetDexMethodIndex(); + } else if (!must_use_direct_pointers) { + // Set the code and rely on the dex cache for the method. + *type = sharp_type; + *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode()); + } else { + // Direct pointers were required but none were available. + VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method); + } } - *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode()); } } @@ -1126,6 +1185,9 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method->dex_method_index, *invoke_type); if (resolved_method != NULL) { + if (*invoke_type == kVirtual || *invoke_type == kSuper) { + *vtable_idx = resolved_method->GetMethodIndex(); + } // 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 = @@ -1166,13 +1228,14 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // dex cache, check that this resolved method is where we expect it. 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); + InvokeType orig_invoke_type = *invoke_type; + GetCodeAndMethodForDirectCall(invoke_type, kDirect, false, referrer_class, resolved_method, + update_stats, target_method, direct_code, direct_method); + if (update_stats && (*invoke_type == kDirect)) { + stats_->ResolvedMethod(orig_invoke_type); + stats_->VirtualMadeDirect(orig_invoke_type); } - GetCodeAndMethodForDirectCall(*invoke_type, kDirect, referrer_class, resolved_method, - update_stats, direct_code, direct_method); - *invoke_type = kDirect; + DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method); return true; } const bool enableVerifierBasedSharpening = enable_devirtualization; @@ -1194,76 +1257,16 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui kVirtual); CHECK(called_method != NULL); CHECK(!called_method->IsAbstract()); - GetCodeAndMethodForDirectCall(*invoke_type, kDirect, referrer_class, called_method, - update_stats, direct_code, direct_method); - bool compiler_needs_dex_cache = - (GetCompilerBackend() == kPortable) || - (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) || - (*direct_code == 0) || (*direct_code == static_cast<unsigned int>(-1)) || - (*direct_method == 0) || (*direct_method == static_cast<unsigned int>(-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<uint16_t> param_type_idxs; - bool success = - dexfile->CreateTypeList(cm_dexfile->GetMethodSignature(cm_method_id).ToString(), - &return_type_idx, ¶m_type_idxs); - 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; - } - } - } - } - } - } - // 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); - stats_->VirtualMadeDirect(*invoke_type); - stats_->PreciseTypeDevirtualization(); - } - *target_method = *devirt_map_target; - *invoke_type = kDirect; - return true; + InvokeType orig_invoke_type = *invoke_type; + GetCodeAndMethodForDirectCall(invoke_type, kDirect, true, referrer_class, called_method, + update_stats, target_method, direct_code, direct_method); + if (update_stats && (*invoke_type == kDirect)) { + stats_->ResolvedMethod(orig_invoke_type); + stats_->VirtualMadeDirect(orig_invoke_type); + stats_->PreciseTypeDevirtualization(); } + DCHECK_NE(*invoke_type, kSuper); + return true; } } if (*invoke_type == kSuper) { @@ -1273,11 +1276,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui 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, - update_stats, direct_code, direct_method); + GetCodeAndMethodForDirectCall(invoke_type, *invoke_type, false, referrer_class, resolved_method, + update_stats, target_method, direct_code, direct_method); return true; } } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 7657af5cee..971021f903 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -321,10 +321,12 @@ class CompilerDriver { private: // Compute constant code and method pointers when possible - void GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, + void GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type, + bool no_guarantee_of_dex_cache_entry, mirror::Class* referrer_class, mirror::ArtMethod* method, bool update_stats, + MethodReference* target_method, uintptr_t* direct_code, uintptr_t* direct_method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 12291c39a9..01d3549985 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -19,6 +19,7 @@ #include "dex_file-inl.h" #include "dex_instruction-inl.h" #include "entrypoints/entrypoint_utils.h" +#include "gc/accounting/card_table-inl.h" #include "interpreter/interpreter.h" #include "invoke_arg_array_builder.h" #include "mirror/art_method-inl.h" @@ -547,6 +548,21 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called, } else if (invoke_type == kInterface) { called = receiver->GetClass()->FindVirtualMethodForInterface(called); } + if ((invoke_type == kVirtual) || (invoke_type == kInterface)) { + // We came here because of sharpening. Ensure the dex cache is up-to-date on the method index + // of the sharpened method. + if (called->GetDexCacheResolvedMethods() == caller->GetDexCacheResolvedMethods()) { + caller->GetDexCacheResolvedMethods()->Set(called->GetDexMethodIndex(), called); + } else { + // Calling from one dex file to another, need to compute the method index appropriate to + // the caller's dex file. + uint32_t method_index = + MethodHelper(called).FindDexMethodIndexInOtherDexFile(MethodHelper(caller).GetDexFile()); + if (method_index != DexFile::kDexNoIndex) { + caller->GetDexCacheResolvedMethods()->Set(method_index, called); + } + } + } // Ensure that the called method's class is initialized. mirror::Class* called_class = called->GetDeclaringClass(); linker->EnsureInitialized(called_class, true, true); diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 8062a890c2..3ca3c0bcf3 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -700,6 +700,46 @@ class MethodHelper { return s; } + uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile& dexfile = GetDexFile(); + if (&dexfile == &other_dexfile) { + return method_->GetDexMethodIndex(); + } + const DexFile::MethodId& mid = dexfile.GetMethodId(method_->GetDexMethodIndex()); + const char* mid_declaring_class_descriptor = dexfile.StringByTypeIdx(mid.class_idx_); + const DexFile::StringId* other_descriptor = + other_dexfile.FindStringId(mid_declaring_class_descriptor); + if (other_descriptor != nullptr) { + const DexFile::TypeId* other_type_id = + other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor)); + if (other_type_id != nullptr) { + const char* mid_name = dexfile.GetMethodName(mid); + const DexFile::StringId* other_name = other_dexfile.FindStringId(mid_name); + if (other_name != nullptr) { + uint16_t other_return_type_idx; + std::vector<uint16_t> other_param_type_idxs; + bool success = other_dexfile.CreateTypeList(dexfile.GetMethodSignature(mid).ToString(), + &other_return_type_idx, + &other_param_type_idxs); + if (success) { + const DexFile::ProtoId* other_sig = + other_dexfile.FindProtoId(other_return_type_idx, other_param_type_idxs); + if (other_sig != nullptr) { + const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(*other_type_id, + *other_name, + *other_sig); + if (other_mid != nullptr) { + return other_dexfile.GetIndexForMethodId(*other_mid); + } + } + } + } + } + } + return DexFile::kDexNoIndex; + } + private: // Set the method_ field, for proxy methods looking up the interface method via the resolved // methods table. |