summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/driver/compiler_driver.cc86
-rw-r--r--compiler/driver/compiler_driver.h16
-rw-r--r--compiler/optimizing/instruction_builder.cc53
-rw-r--r--compiler/optimizing/instruction_builder.h8
4 files changed, 33 insertions, 130 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 7e6fdaf633..b24b0362a3 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -112,7 +112,6 @@ class CompilerDriver::AOTCompilationStats {
public:
AOTCompilationStats()
: stats_lock_("AOT compilation statistics lock"),
- 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),
@@ -127,7 +126,6 @@ class CompilerDriver::AOTCompilationStats {
}
void Dump() {
- DumpStat(resolved_types_, unresolved_types_, "types resolved");
DumpStat(resolved_instance_fields_, unresolved_instance_fields_, "instance fields resolved");
DumpStat(resolved_local_static_fields_ + resolved_static_fields_, unresolved_static_fields_,
"static fields resolved");
@@ -177,16 +175,6 @@ class CompilerDriver::AOTCompilationStats {
#define STATS_LOCK()
#endif
- void TypeDoesntNeedAccessCheck() REQUIRES(!stats_lock_) {
- STATS_LOCK();
- resolved_types_++;
- }
-
- void TypeNeedsAccessCheck() REQUIRES(!stats_lock_) {
- STATS_LOCK();
- unresolved_types_++;
- }
-
void ResolvedInstanceField() REQUIRES(!stats_lock_) {
STATS_LOCK();
resolved_instance_fields_++;
@@ -233,9 +221,6 @@ class CompilerDriver::AOTCompilationStats {
private:
Mutex stats_lock_;
- size_t resolved_types_;
- size_t unresolved_types_;
-
size_t resolved_instance_fields_;
size_t unresolved_instance_fields_;
@@ -1334,77 +1319,6 @@ void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
}
}
-bool CompilerDriver::CanAssumeClassIsLoaded(mirror::Class* klass) {
- Runtime* runtime = Runtime::Current();
- if (!runtime->IsAotCompiler()) {
- DCHECK(runtime->UseJitCompilation());
- // Having the klass reference here implies that the klass is already loaded.
- return true;
- }
- if (!GetCompilerOptions().IsBootImage()) {
- // Assume loaded only if klass is in the boot image. App classes cannot be assumed
- // loaded because we don't even know what class loader will be used to load them.
- bool class_in_image = runtime->GetHeap()->FindSpaceFromObject(klass, false)->IsImageSpace();
- return class_in_image;
- }
- std::string temp;
- const char* descriptor = klass->GetDescriptor(&temp);
- return GetCompilerOptions().IsImageClass(descriptor);
-}
-
-bool CompilerDriver::CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class,
- ObjPtr<mirror::Class> resolved_class) {
- if (resolved_class == nullptr) {
- stats_->TypeNeedsAccessCheck();
- return false; // Unknown class needs access checks.
- }
- bool is_accessible = resolved_class->IsPublic(); // Public classes are always accessible.
- if (!is_accessible) {
- if (referrer_class == nullptr) {
- stats_->TypeNeedsAccessCheck();
- return false; // Incomplete referrer knowledge needs access check.
- }
- // Perform access check, will return true if access is ok or false if we're going to have to
- // check this at runtime (for example for class loaders).
- is_accessible = referrer_class->CanAccess(resolved_class);
- }
- if (is_accessible) {
- stats_->TypeDoesntNeedAccessCheck();
- } else {
- stats_->TypeNeedsAccessCheck();
- }
- return is_accessible;
-}
-
-bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class,
- ObjPtr<mirror::Class> resolved_class,
- bool* finalizable) {
- if (resolved_class == nullptr) {
- stats_->TypeNeedsAccessCheck();
- // Be conservative.
- *finalizable = true;
- return false; // Unknown class needs access checks.
- }
- *finalizable = resolved_class->IsFinalizable();
- bool is_accessible = resolved_class->IsPublic(); // Public classes are always accessible.
- if (!is_accessible) {
- if (referrer_class == nullptr) {
- stats_->TypeNeedsAccessCheck();
- return false; // Incomplete referrer knowledge needs access check.
- }
- // Perform access and instantiable checks, will return true if access is ok or false if we're
- // going to have to check this at runtime (for example for class loaders).
- is_accessible = referrer_class->CanAccess(resolved_class);
- }
- bool result = is_accessible && resolved_class->IsInstantiable();
- if (result) {
- stats_->TypeDoesntNeedAccessCheck();
- } else {
- stats_->TypeNeedsAccessCheck();
- }
- return result;
-}
-
void CompilerDriver::ProcessedInstanceField(bool resolved) {
if (!resolved) {
stats_->UnresolvedInstanceField();
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 0a8754a6a6..3d3583cb9b 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -197,18 +197,6 @@ class CompilerDriver {
uint16_t class_def_index)
REQUIRES(!requires_constructor_barrier_lock_);
- // Are runtime access checks necessary in the compiled code?
- bool CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class,
- ObjPtr<mirror::Class> resolved_class)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- // Are runtime access and instantiable checks necessary in the code?
- // out_is_finalizable is set to whether the type is finalizable.
- bool CanAccessInstantiableTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class,
- ObjPtr<mirror::Class> resolved_class,
- bool* out_is_finalizable)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
// Resolve compiling method's class. Returns null on failure.
ObjPtr<mirror::Class> ResolveCompilingMethodsClass(const ScopedObjectAccess& soa,
Handle<mirror::DexCache> dex_cache,
@@ -324,10 +312,6 @@ class CompilerDriver {
return &compiled_method_storage_;
}
- // Can we assume that the klass is loaded?
- bool CanAssumeClassIsLoaded(mirror::Class* klass)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
const ProfileCompilationInfo* GetProfileCompilationInfo() const {
return profile_compilation_info_;
}
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index ba160e55f8..771e066d2f 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1147,32 +1147,48 @@ void HInstructionBuilder::BuildConstructorFenceForAllocation(HInstruction* alloc
MethodCompilationStat::kConstructorFenceGeneratedNew);
}
-static bool IsSubClass(ObjPtr<mirror::Class> to_test, ObjPtr<mirror::Class> super_class)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- return to_test != nullptr && !to_test->IsInterface() && to_test->IsSubClass(super_class);
-}
-
bool HInstructionBuilder::IsInitialized(Handle<mirror::Class> cls) const {
if (cls == nullptr) {
return false;
}
- // `CanAssumeClassIsLoaded` will return true if we're JITting, or will
- // check whether the class is in an image for the AOT compilation.
- if (cls->IsInitialized() &&
- compiler_driver_->CanAssumeClassIsLoaded(cls.Get())) {
- return true;
+ // Check if the class will be initialized at runtime.
+ if (cls->IsInitialized()) {
+ Runtime* runtime = Runtime::Current();
+ if (!runtime->IsAotCompiler()) {
+ DCHECK(runtime->UseJitCompilation());
+ // For JIT, the class cannot revert to an uninitialized state.
+ return true;
+ }
+ // Assume loaded only if klass is in the boot image. App classes cannot be assumed
+ // loaded because we don't even know what class loader will be used to load them.
+ const CompilerOptions& compiler_options = compiler_driver_->GetCompilerOptions();
+ if (compiler_options.IsBootImage()) {
+ std::string temp;
+ const char* descriptor = cls->GetDescriptor(&temp);
+ if (compiler_options.IsImageClass(descriptor)) {
+ return true;
+ }
+ } else {
+ if (runtime->GetHeap()->FindSpaceFromObject(cls.Get(), false)->IsImageSpace()) {
+ return true;
+ }
+ }
}
- if (IsSubClass(GetOutermostCompilingClass(), cls.Get())) {
+ // We can avoid the class initialization check for `cls` only in static methods in the
+ // very same class. Instance methods of the same class can run on an escaped instance
+ // of an erroneous class. Even a superclass may need to be checked as the subclass
+ // can be completely initialized while the superclass is initializing and the subclass
+ // remains initialized when the superclass initializer throws afterwards. b/62478025
+ // Note: The HClinitCheck+HInvokeStaticOrDirect merging can still apply.
+ if ((dex_compilation_unit_->GetAccessFlags() & kAccStatic) != 0u &&
+ GetOutermostCompilingClass() == cls.Get()) {
return true;
}
- // TODO: We should walk over the inlined methods, but we don't pass
- // that information to the builder.
- if (IsSubClass(GetCompilingClass(), cls.Get())) {
- return true;
- }
+ // Note: We could walk over the inlined methods to avoid allocating excessive
+ // `HClinitCheck`s in inlined static methods but they shall be eliminated by GVN.
return false;
}
@@ -1926,11 +1942,6 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
}
}
-bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, bool* finalizable) const {
- return !compiler_driver_->CanAccessInstantiableTypeWithoutChecks(
- LookupReferrerClass(), LookupResolvedType(type_index, *dex_compilation_unit_), finalizable);
-}
-
bool HInstructionBuilder::CanDecodeQuickenedInfo() const {
return !quicken_info_.IsNull();
}
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index af7092a0cf..578172a18e 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -98,11 +98,6 @@ class HInstructionBuilder : public ValueObject {
void InitializeParameters();
- // Returns whether the current method needs access check for the type.
- // Output parameter finalizable is set to whether the type is finalizable.
- bool NeedsAccessCheck(dex::TypeIndex type_index, /*out*/bool* finalizable) const
- REQUIRES_SHARED(Locks::mutator_lock_);
-
template<typename T>
void Unop_12x(const Instruction& instruction, DataType::Type type, uint32_t dex_pc);
@@ -287,8 +282,7 @@ class HInstructionBuilder : public ValueObject {
void BuildConstructorFenceForAllocation(HInstruction* allocation);
// Return whether the compiler can assume `cls` is initialized.
- bool IsInitialized(Handle<mirror::Class> cls) const
- REQUIRES_SHARED(Locks::mutator_lock_);
+ bool IsInitialized(Handle<mirror::Class> cls) const REQUIRES_SHARED(Locks::mutator_lock_);
// Try to resolve a method using the class linker. Return null if a method could
// not be resolved.