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
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index d7a66f1..b674937 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -6391,6 +6391,21 @@
// Used for classes outside boot image referenced by AOT-compiled app and boot image code.
kBssEntry,
+ // Load from an entry for public class in the .bss section using a PC-relative load.
+ // Used for classes that were unresolved during AOT-compilation outside the literal
+ // package of the compiling class. Such classes are accessible only if they are public
+ // and the .bss entry shall therefore be filled only if the resolved class is public.
+ kBssEntryPublic,
+
+ // Load from an entry for package class in the .bss section using a PC-relative load.
+ // Used for classes that were unresolved during AOT-compilation but within the literal
+ // package of the compiling class. Such classes are accessible if they are public or
+ // in the same package which, given the literal package match, requires only matching
+ // defining class loader and the .bss entry shall therefore be filled only if at least
+ // one of those conditions holds. Note that all code in an oat file belongs to classes
+ // with the same defining class loader.
+ kBssEntryPackage,
+
// Use a known boot image Class* address, embedded in the code by the codegen.
// Used for boot image classes referenced by apps in JIT-compiled code.
kJitBootImageAddress,
@@ -6443,7 +6458,9 @@
bool HasPcRelativeLoadKind() const {
return GetLoadKind() == LoadKind::kBootImageLinkTimePcRelative ||
GetLoadKind() == LoadKind::kBootImageRelRo ||
- GetLoadKind() == LoadKind::kBssEntry;
+ GetLoadKind() == LoadKind::kBssEntry ||
+ GetLoadKind() == LoadKind::kBssEntryPublic ||
+ GetLoadKind() == LoadKind::kBssEntryPackage;
}
bool CanBeMoved() const override { return true; }
@@ -6459,9 +6476,6 @@
}
void SetMustGenerateClinitCheck(bool generate_clinit_check) {
- // The entrypoint the code generator is going to call does not do
- // clinit of the class.
- DCHECK(!NeedsAccessCheck());
SetPackedFlag<kFlagGenerateClInitCheck>(generate_clinit_check);
}
@@ -6514,9 +6528,14 @@
bool MustResolveTypeOnSlowPath() const {
// Check that this instruction has a slow path.
- DCHECK(GetLoadKind() != LoadKind::kRuntimeCall); // kRuntimeCall calls on main path.
- DCHECK(GetLoadKind() == LoadKind::kBssEntry || MustGenerateClinitCheck());
- return GetLoadKind() == LoadKind::kBssEntry;
+ LoadKind load_kind = GetLoadKind();
+ DCHECK(load_kind != LoadKind::kRuntimeCall); // kRuntimeCall calls on main path.
+ bool must_resolve_type_on_slow_path =
+ load_kind == LoadKind::kBssEntry ||
+ load_kind == LoadKind::kBssEntryPublic ||
+ load_kind == LoadKind::kBssEntryPackage;
+ DCHECK(must_resolve_type_on_slow_path || MustGenerateClinitCheck());
+ return must_resolve_type_on_slow_path;
}
void MarkInBootImage() {
@@ -6558,6 +6577,8 @@
return load_kind == LoadKind::kReferrersClass ||
load_kind == LoadKind::kBootImageLinkTimePcRelative ||
load_kind == LoadKind::kBssEntry ||
+ load_kind == LoadKind::kBssEntryPublic ||
+ load_kind == LoadKind::kBssEntryPackage ||
load_kind == LoadKind::kRuntimeCall;
}
@@ -6565,14 +6586,14 @@
// The special input is the HCurrentMethod for kRuntimeCall or kReferrersClass.
// For other load kinds it's empty or possibly some architecture-specific instruction
- // for PC-relative loads, i.e. kBssEntry or kBootImageLinkTimePcRelative.
+ // for PC-relative loads, i.e. kBssEntry* or kBootImageLinkTimePcRelative.
HUserRecord<HInstruction*> special_input_;
// A type index and dex file where the class can be accessed. The dex file can be:
// - The compiling method's dex file if the class is defined there too.
// - The compiling method's dex file if the class is referenced there.
// - The dex file where the class is defined. When the load kind can only be
- // kBssEntry or kRuntimeCall, we cannot emit code for this `HLoadClass`.
+ // kBssEntry* or kRuntimeCall, we cannot emit code for this `HLoadClass`.
const dex::TypeIndex type_index_;
const DexFile& dex_file_;
@@ -6601,6 +6622,8 @@
DCHECK(GetLoadKind() == LoadKind::kBootImageLinkTimePcRelative ||
GetLoadKind() == LoadKind::kBootImageRelRo ||
GetLoadKind() == LoadKind::kBssEntry ||
+ GetLoadKind() == LoadKind::kBssEntryPublic ||
+ GetLoadKind() == LoadKind::kBssEntryPackage ||
GetLoadKind() == LoadKind::kJitBootImageAddress) << GetLoadKind();
DCHECK(special_input_.GetInstruction() == nullptr);
special_input_ = HUserRecord<HInstruction*>(special_input);