summaryrefslogtreecommitdiff
path: root/compiler/optimizing/instruction_builder.cc
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2018-11-02 10:19:33 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2018-11-02 10:19:33 +0000
commitdb7279080105974ef6cac4648e84f93bb23c367e (patch)
treecb426c014b5f555490a9264fe7e125550ca60772 /compiler/optimizing/instruction_builder.cc
parent63a2365ee9920208b6e53347cccb085295a6471a (diff)
parent3b5062083d3e203d1c72b066150b4fe441588a25 (diff)
Merge changes Icec3de58,Ib4f9b4ea
* changes: ART: Cache resolved types in InstructionBuilder. Add compiling class to the DexCompilationUnit.
Diffstat (limited to 'compiler/optimizing/instruction_builder.cc')
-rw-r--r--compiler/optimizing/instruction_builder.cc158
1 files changed, 59 insertions, 99 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 63b2705b43..5af8796ca0 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -20,11 +20,12 @@
#include "base/arena_bit_vector.h"
#include "base/bit_vector-inl.h"
#include "block_builder.h"
-#include "class_linker.h"
+#include "class_linker-inl.h"
+#include "code_generator.h"
#include "data_type-inl.h"
#include "dex/bytecode_utils.h"
#include "dex/dex_instruction-inl.h"
-#include "driver/compiler_driver-inl.h"
+#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
#include "driver/compiler_options.h"
#include "imtable-inl.h"
@@ -73,7 +74,8 @@ HInstructionBuilder::HInstructionBuilder(HGraph* graph,
current_locals_(nullptr),
latest_result_(nullptr),
current_this_parameter_(nullptr),
- loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)) {
+ loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)),
+ class_cache_(std::less<dex::TypeIndex>(), local_allocator->Adapter(kArenaAllocGraphBuilder)) {
loop_headers_.reserve(kDefaultNumberOfLoops);
}
@@ -319,8 +321,8 @@ bool HInstructionBuilder::Build() {
// Find locations where we want to generate extra stackmaps for native debugging.
// This allows us to generate the info only at interesting points (for example,
// at start of java statement) rather than before every dex instruction.
- const bool native_debuggable = compiler_driver_ != nullptr &&
- compiler_driver_->GetCompilerOptions().GetNativeDebuggable();
+ const bool native_debuggable = code_generator_ != nullptr &&
+ code_generator_->GetCompilerOptions().GetNativeDebuggable();
ArenaBitVector* native_debug_info_locations = nullptr;
if (native_debuggable) {
native_debug_info_locations = FindNativeDebugInfoLocations();
@@ -849,7 +851,7 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
// make this an invoke-unresolved to handle cross-dex invokes or abstract super methods, both of
// which require runtime handling.
if (invoke_type == kSuper) {
- ObjPtr<mirror::Class> compiling_class = ResolveCompilingClass(soa);
+ ObjPtr<mirror::Class> compiling_class = dex_compilation_unit_->GetCompilingClass().Get();
if (compiling_class == nullptr) {
// We could not determine the method's class we need to wait until runtime.
DCHECK(Runtime::Current()->IsAotCompiler());
@@ -969,7 +971,7 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction,
ScopedObjectAccess soa(Thread::Current());
if (invoke_type == kStatic) {
clinit_check =
- ProcessClinitCheckForInvoke(soa, dex_pc, resolved_method, &clinit_check_requirement);
+ ProcessClinitCheckForInvoke(dex_pc, resolved_method, &clinit_check_requirement);
} else if (invoke_type == kSuper) {
if (IsSameDexFile(*resolved_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) {
// Update the method index to the one resolved. Note that this may be a no-op if
@@ -1055,7 +1057,7 @@ HNewInstance* HInstructionBuilder::BuildNewInstance(dex::TypeIndex type_index, u
HInstruction* cls = load_class;
Handle<mirror::Class> klass = load_class->GetClass();
- if (!IsInitialized(soa, klass)) {
+ if (!IsInitialized(klass)) {
cls = new (allocator_) HClinitCheck(load_class, dex_pc);
AppendInstruction(cls);
}
@@ -1284,7 +1286,7 @@ static bool HasTrivialInitialization(ObjPtr<mirror::Class> cls,
return true;
}
-bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle<mirror::Class> cls) const {
+bool HInstructionBuilder::IsInitialized(Handle<mirror::Class> cls) const {
if (cls == nullptr) {
return false;
}
@@ -1299,7 +1301,7 @@ bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle<mirror::
}
// 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.
- if (IsInBootImage(cls.Get(), compiler_driver_->GetCompilerOptions())) {
+ if (IsInBootImage(cls.Get(), code_generator_->GetCompilerOptions())) {
return true;
}
}
@@ -1312,29 +1314,20 @@ bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle<mirror::
// 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.
- ObjPtr<mirror::Class> outermost_cls = ResolveOutermostCompilingClass(soa);
- bool is_outer_static_or_constructor =
- (outer_compilation_unit_->GetAccessFlags() & (kAccStatic | kAccConstructor)) != 0u;
- if (is_outer_static_or_constructor && outermost_cls == cls.Get()) {
+ auto is_static_method_or_constructor_of_cls = [cls](const DexCompilationUnit& compilation_unit)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return (compilation_unit.GetAccessFlags() & (kAccStatic | kAccConstructor)) != 0u &&
+ compilation_unit.GetCompilingClass().Get() == cls.Get();
+ };
+ if (is_static_method_or_constructor_of_cls(*outer_compilation_unit_) ||
+ // Check also the innermost method. Though excessive copies of ClinitCheck can be
+ // eliminated by GVN, that happens only after the decision whether to inline the
+ // graph or not and that may depend on the presence of the ClinitCheck.
+ // TODO: We should walk over the entire inlined method chain, but we don't pass that
+ // information to the builder.
+ is_static_method_or_constructor_of_cls(*dex_compilation_unit_)) {
return true;
}
- // Remember if the compiled class is a subclass of `cls`. By the time this is used
- // below the `outermost_cls` may be invalidated by calling ResolveCompilingClass().
- bool is_subclass = IsSubClass(outermost_cls, cls.Get());
- if (dex_compilation_unit_ != outer_compilation_unit_) {
- // Check also the innermost method. Though excessive copies of ClinitCheck can be
- // eliminated by GVN, that happens only after the decision whether to inline the
- // graph or not and that may depend on the presence of the ClinitCheck.
- // TODO: We should walk over the entire inlined method chain, but we don't pass that
- // information to the builder.
- ObjPtr<mirror::Class> innermost_cls = ResolveCompilingClass(soa);
- bool is_inner_static_or_constructor =
- (dex_compilation_unit_->GetAccessFlags() & (kAccStatic | kAccConstructor)) != 0u;
- if (is_inner_static_or_constructor && innermost_cls == cls.Get()) {
- return true;
- }
- is_subclass = is_subclass || IsSubClass(innermost_cls, cls.Get());
- }
// Otherwise, we may be able to avoid the check if `cls` is a superclass of a method being
// compiled here (anywhere in the inlining chain) as the `cls` must have started initializing
@@ -1355,7 +1348,12 @@ bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle<mirror::
// TODO: We should walk over the entire inlined methods chain, but we don't pass that
// information to the builder. (We could also check if we're guaranteed a non-null instance
// of `cls` at this location but that's outside the scope of the instruction builder.)
- if (is_subclass && HasTrivialInitialization(cls.Get(), compiler_driver_->GetCompilerOptions())) {
+ bool is_subclass = IsSubClass(outer_compilation_unit_->GetCompilingClass().Get(), cls.Get());
+ if (dex_compilation_unit_ != outer_compilation_unit_) {
+ is_subclass = is_subclass ||
+ IsSubClass(dex_compilation_unit_->GetCompilingClass().Get(), cls.Get());
+ }
+ if (is_subclass && HasTrivialInitialization(cls.Get(), code_generator_->GetCompilerOptions())) {
return true;
}
@@ -1363,18 +1361,16 @@ bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle<mirror::
}
HClinitCheck* HInstructionBuilder::ProcessClinitCheckForInvoke(
- ScopedObjectAccess& soa,
uint32_t dex_pc,
ArtMethod* resolved_method,
HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement) {
Handle<mirror::Class> klass = handles_->NewHandle(resolved_method->GetDeclaringClass());
HClinitCheck* clinit_check = nullptr;
- if (IsInitialized(soa, klass)) {
+ if (IsInitialized(klass)) {
*clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
} else {
- HLoadClass* cls = BuildLoadClass(soa,
- klass->GetDexTypeIndex(),
+ HLoadClass* cls = BuildLoadClass(klass->GetDexTypeIndex(),
klass->GetDexFile(),
klass,
dex_pc,
@@ -1610,43 +1606,6 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio
return true;
}
-static ObjPtr<mirror::Class> ResolveClassFrom(ScopedObjectAccess& soa,
- CompilerDriver* driver,
- const DexCompilationUnit& compilation_unit)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- Handle<mirror::ClassLoader> class_loader = compilation_unit.GetClassLoader();
- Handle<mirror::DexCache> dex_cache = compilation_unit.GetDexCache();
-
- return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit);
-}
-
-ObjPtr<mirror::Class> HInstructionBuilder::ResolveOutermostCompilingClass(
- ScopedObjectAccess& soa) const {
- return ResolveClassFrom(soa, compiler_driver_, *outer_compilation_unit_);
-}
-
-ObjPtr<mirror::Class> HInstructionBuilder::ResolveCompilingClass(ScopedObjectAccess& soa) const {
- return ResolveClassFrom(soa, compiler_driver_, *dex_compilation_unit_);
-}
-
-bool HInstructionBuilder::IsOutermostCompilingClass(dex::TypeIndex type_index) const {
- ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
- Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
- Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader();
- Handle<mirror::Class> cls(hs.NewHandle(compiler_driver_->ResolveClass(
- soa, dex_cache, class_loader, type_index, dex_compilation_unit_)));
- Handle<mirror::Class> outer_class(hs.NewHandle(ResolveOutermostCompilingClass(soa)));
-
- // GetOutermostCompilingClass returns null when the class is unresolved
- // (e.g. if it derives from an unresolved class). This is bogus knowing that
- // we are compiling it.
- // When this happens we cannot establish a direct relation between the current
- // class and the outer class, so we return false.
- // (Note that this is only used for optimizing invokes and field accesses)
- return (cls != nullptr) && (outer_class.Get() == cls.Get());
-}
-
void HInstructionBuilder::BuildUnresolvedStaticFieldAccess(const Instruction& instruction,
uint32_t dex_pc,
bool is_put,
@@ -1666,18 +1625,17 @@ void HInstructionBuilder::BuildUnresolvedStaticFieldAccess(const Instruction& in
ArtField* HInstructionBuilder::ResolveField(uint16_t field_idx, bool is_static, bool is_put) {
ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker();
Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader();
- Handle<mirror::Class> compiling_class(hs.NewHandle(ResolveCompilingClass(soa)));
ArtField* resolved_field = class_linker->ResolveField(field_idx,
dex_compilation_unit_->GetDexCache(),
class_loader,
is_static);
+ DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending());
if (UNLIKELY(resolved_field == nullptr)) {
- // Clean up any exception left by type resolution.
+ // Clean up any exception left by field resolution.
soa.Self()->ClearException();
return nullptr;
}
@@ -1689,6 +1647,7 @@ ArtField* HInstructionBuilder::ResolveField(uint16_t field_idx, bool is_static,
}
// Check access.
+ Handle<mirror::Class> compiling_class = dex_compilation_unit_->GetCompilingClass();
if (compiling_class == nullptr) {
if (!resolved_field->IsPublic()) {
return nullptr;
@@ -1731,8 +1690,7 @@ void HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction,
DataType::Type field_type = GetFieldAccessType(*dex_file_, field_index);
Handle<mirror::Class> klass = handles_->NewHandle(resolved_field->GetDeclaringClass());
- HLoadClass* constant = BuildLoadClass(soa,
- klass->GetDexTypeIndex(),
+ HLoadClass* constant = BuildLoadClass(klass->GetDexTypeIndex(),
klass->GetDexFile(),
klass,
dex_pc,
@@ -1748,7 +1706,7 @@ void HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction,
}
HInstruction* cls = constant;
- if (!IsInitialized(soa, klass)) {
+ if (!IsInitialized(klass)) {
cls = new (allocator_) HClinitCheck(constant, dex_pc);
AppendInstruction(cls);
}
@@ -1989,12 +1947,11 @@ HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, uint3
ScopedObjectAccess soa(Thread::Current());
const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
Handle<mirror::Class> klass = ResolveClass(soa, type_index);
- bool needs_access_check = LoadClassNeedsAccessCheck(soa, klass);
- return BuildLoadClass(soa, type_index, dex_file, klass, dex_pc, needs_access_check);
+ bool needs_access_check = LoadClassNeedsAccessCheck(klass);
+ return BuildLoadClass(type_index, dex_file, klass, dex_pc, needs_access_check);
}
-HLoadClass* HInstructionBuilder::BuildLoadClass(ScopedObjectAccess& soa,
- dex::TypeIndex type_index,
+HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index,
const DexFile& dex_file,
Handle<mirror::Class> klass,
uint32_t dex_pc,
@@ -2011,11 +1968,8 @@ HLoadClass* HInstructionBuilder::BuildLoadClass(ScopedObjectAccess& soa,
}
// Note: `klass` must be from `handles_`.
- bool is_referrers_class = false;
- if (klass != nullptr) {
- ObjPtr<mirror::Class> outermost_cls = ResolveOutermostCompilingClass(soa);
- is_referrers_class = (outermost_cls == klass.Get());
- }
+ bool is_referrers_class =
+ (klass != nullptr) && (outer_compilation_unit_->GetCompilingClass().Get() == klass.Get());
HLoadClass* load_class = new (allocator_) HLoadClass(
graph_->GetCurrentMethod(),
type_index,
@@ -2041,22 +1995,28 @@ HLoadClass* HInstructionBuilder::BuildLoadClass(ScopedObjectAccess& soa,
Handle<mirror::Class> HInstructionBuilder::ResolveClass(ScopedObjectAccess& soa,
dex::TypeIndex type_index) {
- Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader();
- ObjPtr<mirror::Class> klass = compiler_driver_->ResolveClass(
- soa, dex_compilation_unit_->GetDexCache(), class_loader, type_index, dex_compilation_unit_);
- // TODO: Avoid creating excessive handles if the method references the same class repeatedly.
- // (Use a map on the local_allocator_.)
- return handles_->NewHandle(klass);
+ auto it = class_cache_.find(type_index);
+ if (it != class_cache_.end()) {
+ return it->second;
+ }
+
+ ObjPtr<mirror::Class> klass = dex_compilation_unit_->GetClassLinker()->ResolveType(
+ type_index, dex_compilation_unit_->GetDexCache(), dex_compilation_unit_->GetClassLoader());
+ DCHECK_EQ(klass == nullptr, soa.Self()->IsExceptionPending());
+ soa.Self()->ClearException(); // Clean up the exception left by type resolution if any.
+
+ Handle<mirror::Class> h_klass = handles_->NewHandle(klass);
+ class_cache_.Put(type_index, h_klass);
+ return h_klass;
}
-bool HInstructionBuilder::LoadClassNeedsAccessCheck(ScopedObjectAccess& soa,
- Handle<mirror::Class> klass) {
+bool HInstructionBuilder::LoadClassNeedsAccessCheck(Handle<mirror::Class> klass) {
if (klass == nullptr) {
return true;
} else if (klass->IsPublic()) {
return false;
} else {
- ObjPtr<mirror::Class> compiling_class = ResolveCompilingClass(soa);
+ ObjPtr<mirror::Class> compiling_class = dex_compilation_unit_->GetCompilingClass().Get();
return compiling_class == nullptr || !compiling_class->CanAccess(klass.Get());
}
}
@@ -2085,7 +2045,7 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
ScopedObjectAccess soa(Thread::Current());
const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
Handle<mirror::Class> klass = ResolveClass(soa, type_index);
- bool needs_access_check = LoadClassNeedsAccessCheck(soa, klass);
+ bool needs_access_check = LoadClassNeedsAccessCheck(klass);
TypeCheckKind check_kind = HSharpening::ComputeTypeCheckKind(
klass.Get(), code_generator_, needs_access_check);
@@ -2103,7 +2063,7 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
bitstring_path_to_root = graph_->GetIntConstant(static_cast<int32_t>(path_to_root), dex_pc);
bitstring_mask = graph_->GetIntConstant(static_cast<int32_t>(mask), dex_pc);
} else {
- class_or_null = BuildLoadClass(soa, type_index, dex_file, klass, dex_pc, needs_access_check);
+ class_or_null = BuildLoadClass(type_index, dex_file, klass, dex_pc, needs_access_check);
}
DCHECK(class_or_null != nullptr);