summaryrefslogtreecommitdiff
path: root/compiler/optimizing/sharpening.cc
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2020-09-28 12:10:28 +0100
committer Vladimir Marko <vmarko@google.com> 2020-09-30 13:58:32 +0000
commit8f63f1084b013a129f66cf8a7ed8ab1cae9f02aa (patch)
tree6e9bbf5ad71a55f701f740e2995e0b84e9b87307 /compiler/optimizing/sharpening.cc
parent7aa2bfc09541ea5d2516738de84c24cd0269fed0 (diff)
Faster access to unresolved classes from compiled code.
Add two new load kinds to LoadClass, similar to kBssEntry but using the access-checking entrypoint on the slow-path. One is used for classes that are in the literal package and the other for classes outside the literal package of the compiling class. Associate new .bss entries with these load kinds and update them from entrypoints based on the resolved class properties. If the resolved class is public, both types of entries can be updated, otherwise only the package local entry can be updated and only if the defining class loader of the class is the same as the caller's defining class loader (which is identical for all code in an oat file) because the run time access check for same package requires both class loader and literal package name match. Test: Additional tests in 727-checker-unresolved-class. Test: m test-art-host-gtest Test: testrunner.py --host --optimizing Test: aosp_blueline-userdebug boots. Test: run-gtests.sh Test: testrunner.py --target --optimizing Bug: 161898207 Change-Id: I281e06ac2825caf81c6d7ee3128af833abd39992
Diffstat (limited to 'compiler/optimizing/sharpening.cc')
-rw-r--r--compiler/optimizing/sharpening.cc67
1 files changed, 50 insertions, 17 deletions
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 393369dcb6..f570c60843 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -158,24 +158,55 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(
load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass)
<< load_class->GetLoadKind();
DCHECK(!load_class->IsInBootImage()) << "HLoadClass should not be optimized before sharpening.";
+ const DexFile& dex_file = load_class->GetDexFile();
+ dex::TypeIndex type_index = load_class->GetTypeIndex();
+ const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
- HLoadClass::LoadKind load_kind = load_class->GetLoadKind();
+ bool is_in_boot_image = false;
+ HLoadClass::LoadKind desired_load_kind = HLoadClass::LoadKind::kInvalid;
- if (load_class->NeedsAccessCheck()) {
- // We need to call the runtime anyway, so we simply get the class as that call's return value.
- } else if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
+ if (load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass) {
+ DCHECK(!load_class->NeedsAccessCheck());
// Loading from the ArtMethod* is the most efficient retrieval in code size.
// TODO: This may not actually be true for all architectures and
// locations of target classes. The additional register pressure
// for using the ArtMethod* should be considered.
+ desired_load_kind = HLoadClass::LoadKind::kReferrersClass;
+ } else if (load_class->NeedsAccessCheck()) {
+ DCHECK_EQ(load_class->GetLoadKind(), HLoadClass::LoadKind::kRuntimeCall);
+ if (klass != nullptr) {
+ // Resolved class that needs access check must be really inaccessible
+ // and the access check is bound to fail. Just emit the runtime call.
+ desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
+ } else if (compiler_options.IsJitCompiler()) {
+ // Unresolved class while JITting means that either we never hit this
+ // instruction or it failed. Either way, just emit the runtime call.
+ // (Though we could consider emitting Deoptimize instead and
+ // recompile if the instruction succeeds in interpreter.)
+ desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
+ } else {
+ // For AOT, check if the class is in the same literal package as the
+ // compiling class and pick an appropriate .bss entry.
+ auto package_length = [](const char* descriptor) {
+ const char* slash_pos = strrchr(descriptor, '/');
+ return (slash_pos != nullptr) ? static_cast<size_t>(slash_pos - descriptor) : 0u;
+ };
+ const char* klass_descriptor = dex_file.StringByTypeIdx(type_index);
+ const uint32_t klass_package_length = package_length(klass_descriptor);
+ const DexFile* referrer_dex_file = dex_compilation_unit.GetDexFile();
+ const dex::TypeIndex referrer_type_index =
+ referrer_dex_file->GetClassDef(dex_compilation_unit.GetClassDefIndex()).class_idx_;
+ const char* referrer_descriptor = referrer_dex_file->StringByTypeIdx(referrer_type_index);
+ const uint32_t referrer_package_length = package_length(referrer_descriptor);
+ bool same_package =
+ (referrer_package_length == klass_package_length) &&
+ memcmp(referrer_descriptor, klass_descriptor, referrer_package_length) == 0;
+ desired_load_kind = same_package
+ ? HLoadClass::LoadKind::kBssEntryPackage
+ : HLoadClass::LoadKind::kBssEntryPublic;
+ }
} else {
- const DexFile& dex_file = load_class->GetDexFile();
- dex::TypeIndex type_index = load_class->GetTypeIndex();
-
- bool is_in_boot_image = false;
- HLoadClass::LoadKind desired_load_kind = HLoadClass::LoadKind::kInvalid;
Runtime* runtime = Runtime::Current();
- const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
if (compiler_options.IsBootImage() || compiler_options.IsBootImageExtension()) {
// Compiling boot image or boot image extension. Check if the class is a boot image class.
DCHECK(!compiler_options.IsJitCompiler());
@@ -227,17 +258,19 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(
desired_load_kind = HLoadClass::LoadKind::kBssEntry;
}
}
- DCHECK_NE(desired_load_kind, HLoadClass::LoadKind::kInvalid);
+ }
+ DCHECK_NE(desired_load_kind, HLoadClass::LoadKind::kInvalid);
- if (is_in_boot_image) {
- load_class->MarkInBootImage();
- }
- load_kind = codegen->GetSupportedLoadClassKind(desired_load_kind);
+ if (is_in_boot_image) {
+ load_class->MarkInBootImage();
}
+ HLoadClass::LoadKind load_kind = codegen->GetSupportedLoadClassKind(desired_load_kind);
if (!IsSameDexFile(load_class->GetDexFile(), *dex_compilation_unit.GetDexFile())) {
- if ((load_kind == HLoadClass::LoadKind::kRuntimeCall) ||
- (load_kind == HLoadClass::LoadKind::kBssEntry)) {
+ if (load_kind == HLoadClass::LoadKind::kRuntimeCall ||
+ load_kind == HLoadClass::LoadKind::kBssEntry ||
+ load_kind == HLoadClass::LoadKind::kBssEntryPublic ||
+ load_kind == HLoadClass::LoadKind::kBssEntryPackage) {
// We actually cannot reference this class, we're forced to bail.
// We cannot reference this class with Bss, as the entrypoint will lookup the class
// in the caller's dex file, but that dex file does not reference the class.