diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/builder.h | 5 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/inliner.cc | 9 | ||||
-rw-r--r-- | compiler/optimizing/instruction_builder.cc | 215 | ||||
-rw-r--r-- | compiler/optimizing/instruction_builder.h | 18 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 9 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 21 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/sharpening.cc | 143 | ||||
-rw-r--r-- | compiler/optimizing/sharpening.h | 12 | ||||
-rw-r--r-- | compiler/optimizing/ssa_builder.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/stack_map_stream.cc | 2 |
18 files changed, 268 insertions, 196 deletions
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 8cf4089eba..e4ad4222fb 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -32,6 +32,8 @@ namespace art { +class CodeGenerator; + class HGraphBuilder : public ValueObject { public: HGraphBuilder(HGraph* graph, @@ -40,6 +42,7 @@ class HGraphBuilder : public ValueObject { const DexFile* dex_file, const DexFile::CodeItem& code_item, CompilerDriver* driver, + CodeGenerator* code_generator, OptimizingCompilerStats* compiler_stats, const uint8_t* interpreter_metadata, Handle<mirror::DexCache> dex_cache, @@ -61,6 +64,7 @@ class HGraphBuilder : public ValueObject { dex_compilation_unit, outer_compilation_unit, driver, + code_generator, interpreter_metadata, compiler_stats, dex_cache, @@ -89,6 +93,7 @@ class HGraphBuilder : public ValueObject { /* dex_compilation_unit */ nullptr, /* outer_compilation_unit */ nullptr, /* compiler_driver */ nullptr, + /* code_generator */ nullptr, /* interpreter_metadata */ nullptr, /* compiler_stats */ nullptr, null_dex_cache_, diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 1893029cad..20cdae3619 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -5722,6 +5722,9 @@ void ParallelMoveResolverARM::RestoreScratch(int reg) { HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kInvalid: + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimeAddress: @@ -5852,6 +5855,7 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFE break; } case HLoadClass::LoadKind::kDexCacheViaMethod: + case HLoadClass::LoadKind::kInvalid: LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 26c8254c76..598be4715b 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -4360,6 +4360,9 @@ void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { HLoadClass::LoadKind CodeGeneratorARM64::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kInvalid: + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimeAddress: @@ -4498,6 +4501,7 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SA break; } case HLoadClass::LoadKind::kDexCacheViaMethod: + case HLoadClass::LoadKind::kInvalid: LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index f4d3ec54ee..0d31d830c8 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -5796,6 +5796,9 @@ void ParallelMoveResolverARMVIXL::RestoreScratch(int reg ATTRIBUTE_UNUSED) { HLoadClass::LoadKind CodeGeneratorARMVIXL::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kInvalid: + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimeAddress: @@ -5916,6 +5919,7 @@ void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) NO_THREAD_ break; } case HLoadClass::LoadKind::kDexCacheViaMethod: + case HLoadClass::LoadKind::kInvalid: LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 00969443c1..0677dad078 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -5308,6 +5308,9 @@ HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind( bool is_r6 = GetInstructionSetFeatures().IsR6(); bool fallback_load = has_irreducible_loops && !is_r6; switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kInvalid: + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); case HLoadClass::LoadKind::kReferrersClass: fallback_load = false; break; @@ -5660,6 +5663,7 @@ void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAF break; } case HLoadClass::LoadKind::kDexCacheViaMethod: + case HLoadClass::LoadKind::kInvalid: LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 55904a3679..4c8dabfede 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -3368,6 +3368,9 @@ HLoadClass::LoadKind CodeGeneratorMIPS64::GetSupportedLoadClassKind( } bool fallback_load = false; switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kInvalid: + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimeAddress: @@ -3629,6 +3632,7 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_S GenerateGcRootFieldLoad(cls, out_loc, out, 0); break; case HLoadClass::LoadKind::kDexCacheViaMethod: + case HLoadClass::LoadKind::kInvalid: LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 3e795c7bf8..137b55423b 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -6024,6 +6024,9 @@ void ParallelMoveResolverX86::RestoreScratch(int reg) { HLoadClass::LoadKind CodeGeneratorX86::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kInvalid: + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimeAddress: @@ -6159,6 +6162,7 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFE break; } case HLoadClass::LoadKind::kDexCacheViaMethod: + case HLoadClass::LoadKind::kInvalid: LOG(FATAL) << "UNREACHABLE"; UNREACHABLE(); } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index abd8246325..c5367ce86e 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -5427,6 +5427,9 @@ void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck( HLoadClass::LoadKind CodeGeneratorX86_64::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kInvalid: + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimeAddress: diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 7772e8f973..b08c7a0615 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -558,9 +558,13 @@ HInstruction* HInliner::AddTypeGuard(HInstruction* receiver, is_referrer, invoke_instruction->GetDexPc(), /* needs_access_check */ false); + HLoadClass::LoadKind kind = HSharpening::SharpenClass( + load_class, codegen_, compiler_driver_, caller_compilation_unit_); + DCHECK(kind != HLoadClass::LoadKind::kInvalid) + << "We should always be able to reference a class for inline caches"; + // Insert before setting the kind, as setting the kind affects the inputs. bb_cursor->InsertInstructionAfter(load_class, receiver_class); - // Sharpen after adding the instruction, as the sharpening may remove inputs. - HSharpening::SharpenClass(load_class, codegen_, compiler_driver_); + load_class->SetLoadKind(kind); // TODO: Extend reference type propagation to understand the guard. HNotEqual* compare = new (graph_->GetArena()) HNotEqual(load_class, receiver_class); @@ -1286,6 +1290,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, resolved_method->GetDexFile(), *code_item, compiler_driver_, + codegen_, inline_stats.get(), resolved_method->GetQuickenedInfo(class_linker->GetImagePointerSize()), dex_cache, diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index cac385ce3c..9a3fd2b054 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -22,6 +22,7 @@ #include "dex_instruction-inl.h" #include "driver/compiler_options.h" #include "imtable-inl.h" +#include "sharpening.h" #include "scoped_thread_state_change-inl.h" namespace art { @@ -847,7 +848,7 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, ScopedObjectAccess soa(Thread::Current()); if (invoke_type == kStatic) { clinit_check = ProcessClinitCheckForInvoke( - dex_pc, resolved_method, method_idx, &clinit_check_requirement); + 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 @@ -941,7 +942,7 @@ bool HInstructionBuilder::BuildNewInstance(dex::TypeIndex type_index, uint32_t d return false; } - HLoadClass* load_class = BuildLoadClass(type_index, dex_pc, /* check_access */ true); + HLoadClass* load_class = BuildLoadClass(type_index, dex_pc); HInstruction* cls = load_class; Handle<mirror::Class> klass = load_class->GetClass(); @@ -1005,39 +1006,23 @@ bool HInstructionBuilder::IsInitialized(Handle<mirror::Class> cls) const { HClinitCheck* HInstructionBuilder::ProcessClinitCheckForInvoke( uint32_t dex_pc, ArtMethod* resolved_method, - uint32_t method_idx, HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement) { - Thread* self = Thread::Current(); - StackHandleScope<2> hs(self); - Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache(); - Handle<mirror::DexCache> outer_dex_cache = outer_compilation_unit_->GetDexCache(); - Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); - Handle<mirror::Class> resolved_method_class(hs.NewHandle(resolved_method->GetDeclaringClass())); - - // The index at which the method's class is stored in the DexCache's type array. - dex::TypeIndex storage_index; - bool is_outer_class = (resolved_method->GetDeclaringClass() == outer_class.Get()); - if (is_outer_class) { - storage_index = outer_class->GetDexTypeIndex(); - } else if (outer_dex_cache.Get() == dex_cache.Get()) { - // Get `storage_index` from IsClassOfStaticMethodAvailableToReferrer. - compiler_driver_->IsClassOfStaticMethodAvailableToReferrer(outer_dex_cache.Get(), - GetCompilingClass(), - resolved_method, - method_idx, - &storage_index); - } + Handle<mirror::Class> klass = handles_->NewHandle(resolved_method->GetDeclaringClass()); HClinitCheck* clinit_check = nullptr; - - if (IsInitialized(resolved_method_class)) { + if (IsInitialized(klass)) { *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone; - } else if (storage_index.IsValid()) { - *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit; - HLoadClass* cls = BuildLoadClass( - storage_index, dex_pc, /* check_access */ false, /* outer */ true); - clinit_check = new (arena_) HClinitCheck(cls, dex_pc); - AppendInstruction(clinit_check); + } else { + HLoadClass* cls = BuildLoadClass(klass->GetDexTypeIndex(), + klass->GetDexFile(), + klass, + dex_pc, + /* needs_access_check */ false); + if (cls != nullptr) { + *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit; + clinit_check = new (arena_) HClinitCheck(cls, dex_pc); + AppendInstruction(clinit_check); + } } return clinit_check; } @@ -1216,9 +1201,7 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio } ScopedObjectAccess soa(Thread::Current()); - ArtField* resolved_field = - compiler_driver_->ComputeInstanceFieldInfo(field_index, dex_compilation_unit_, is_put, soa); - + ArtField* resolved_field = ResolveField(field_index, /* is_static */ false, is_put); // Generate an explicit null check on the reference, unless the field access // is unresolved. In that case, we rely on the runtime to perform various @@ -1336,6 +1319,56 @@ 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(hs.NewHandle( + soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); + Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass())); + + ArtField* resolved_field = class_linker->ResolveField(*dex_compilation_unit_->GetDexFile(), + field_idx, + dex_compilation_unit_->GetDexCache(), + class_loader, + is_static); + + if (UNLIKELY(resolved_field == nullptr)) { + // Clean up any exception left by type resolution. + soa.Self()->ClearException(); + return nullptr; + } + + // Check static/instance. The class linker has a fast path for looking into the dex cache + // and does not check static/instance if it hits it. + if (UNLIKELY(resolved_field->IsStatic() != is_static)) { + return nullptr; + } + + // Check access. + if (compiling_class.Get() == nullptr) { + if (!resolved_field->IsPublic()) { + return nullptr; + } + } else if (!compiling_class->CanAccessResolvedField(resolved_field->GetDeclaringClass(), + resolved_field, + dex_compilation_unit_->GetDexCache().Get(), + field_idx)) { + return nullptr; + } + + if (is_put && + resolved_field->IsFinal() && + (compiling_class.Get() != resolved_field->GetDeclaringClass())) { + // Final fields can only be updated within their own class. + // TODO: Only allow it in constructors. b/34966607. + return nullptr; + } + + return resolved_field; +} + bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put) { @@ -1343,12 +1376,7 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction, uint16_t field_index = instruction.VRegB_21c(); ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<3> hs(soa.Self()); - Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache(); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); - ArtField* resolved_field = compiler_driver_->ResolveField( - soa, dex_cache, class_loader, dex_compilation_unit_, field_index, true); + ArtField* resolved_field = ResolveField(field_index, /* is_static */ true, is_put); if (resolved_field == nullptr) { MaybeRecordStat(MethodCompilationStat::kUnresolvedField); @@ -1358,38 +1386,23 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction, } Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType(); - Handle<mirror::DexCache> outer_dex_cache = outer_compilation_unit_->GetDexCache(); - Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); - // The index at which the field's class is stored in the DexCache's type array. - dex::TypeIndex storage_index; - bool is_outer_class = (outer_class.Get() == resolved_field->GetDeclaringClass()); - if (is_outer_class) { - storage_index = outer_class->GetDexTypeIndex(); - } else if (outer_dex_cache.Get() != dex_cache.Get()) { - // The compiler driver cannot currently understand multiple dex caches involved. Just bailout. - return false; - } else { - // TODO: This is rather expensive. Perf it and cache the results if needed. - std::pair<bool, bool> pair = compiler_driver_->IsFastStaticField( - outer_dex_cache.Get(), - GetCompilingClass(), - resolved_field, - field_index, - &storage_index); - bool can_easily_access = is_put ? pair.second : pair.first; - if (!can_easily_access) { - MaybeRecordStat(MethodCompilationStat::kUnresolvedFieldNotAFastAccess); - BuildUnresolvedStaticFieldAccess(instruction, dex_pc, is_put, field_type); - return true; - } + Handle<mirror::Class> klass = handles_->NewHandle(resolved_field->GetDeclaringClass()); + HLoadClass* constant = BuildLoadClass(klass->GetDexTypeIndex(), + klass->GetDexFile(), + klass, + dex_pc, + /* needs_access_check */ false); + + if (constant == nullptr) { + // The class cannot be referenced from this compiled code. Generate + // an unresolved access. + MaybeRecordStat(MethodCompilationStat::kUnresolvedFieldNotAFastAccess); + BuildUnresolvedStaticFieldAccess(instruction, dex_pc, is_put, field_type); + return true; } - HLoadClass* constant = BuildLoadClass( - storage_index, dex_pc, /* check_access */ false, /* outer */ true); - HInstruction* cls = constant; - Handle<mirror::Class> klass(hs.NewHandle(resolved_field->GetDeclaringClass())); if (!IsInitialized(klass)) { cls = new (arena_) HClinitCheck(constant, dex_pc); AppendInstruction(cls); @@ -1497,7 +1510,7 @@ void HInstructionBuilder::BuildFilledNewArray(uint32_t dex_pc, uint32_t* args, uint32_t register_index) { HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments, dex_pc); - HLoadClass* cls = BuildLoadClass(type_index, dex_pc, /* check_access */ true); + HLoadClass* cls = BuildLoadClass(type_index, dex_pc); HInstruction* object = new (arena_) HNewArray(cls, length, dex_pc); AppendInstruction(object); @@ -1627,44 +1640,68 @@ static TypeCheckKind ComputeTypeCheckKind(Handle<mirror::Class> cls) } } -HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, - uint32_t dex_pc, - bool check_access, - bool outer) { +HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, uint32_t dex_pc) { ScopedObjectAccess soa(Thread::Current()); - const DexCompilationUnit* compilation_unit = - outer ? outer_compilation_unit_ : dex_compilation_unit_; - const DexFile& dex_file = *compilation_unit->GetDexFile(); - StackHandleScope<1> hs(soa.Self()); + StackHandleScope<2> hs(soa.Self()); + const DexFile& dex_file = *dex_compilation_unit_->GetDexFile(); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); Handle<mirror::Class> klass = handles_->NewHandle(compiler_driver_->ResolveClass( - soa, compilation_unit->GetDexCache(), class_loader, type_index, compilation_unit)); + soa, dex_compilation_unit_->GetDexCache(), class_loader, type_index, dex_compilation_unit_)); - bool is_accessible = false; - if (!check_access) { - is_accessible = true; - } else if (klass.Get() != nullptr) { + bool needs_access_check = true; + if (klass.Get() != nullptr) { if (klass->IsPublic()) { - is_accessible = true; + needs_access_check = false; } else { mirror::Class* compiling_class = GetCompilingClass(); if (compiling_class != nullptr && compiling_class->CanAccess(klass.Get())) { - is_accessible = true; + needs_access_check = false; } } } + return BuildLoadClass(type_index, dex_file, klass, dex_pc, needs_access_check); +} + +HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, + const DexFile& dex_file, + Handle<mirror::Class> klass, + uint32_t dex_pc, + bool needs_access_check) { + // Try to find a reference in the compiling dex file. + const DexFile* actual_dex_file = &dex_file; + if (!IsSameDexFile(dex_file, *dex_compilation_unit_->GetDexFile())) { + dex::TypeIndex local_type_index = + klass->FindTypeIndexInOtherDexFile(*dex_compilation_unit_->GetDexFile()); + if (local_type_index.IsValid()) { + type_index = local_type_index; + actual_dex_file = dex_compilation_unit_->GetDexFile(); + } + } + + // Note: `klass` must be from `handles_`. HLoadClass* load_class = new (arena_) HLoadClass( graph_->GetCurrentMethod(), type_index, - dex_file, + *actual_dex_file, klass, klass.Get() != nullptr && (klass.Get() == GetOutermostCompilingClass()), dex_pc, - !is_accessible); + needs_access_check); + HLoadClass::LoadKind load_kind = HSharpening::SharpenClass(load_class, + code_generator_, + compiler_driver_, + *dex_compilation_unit_); + + if (load_kind == HLoadClass::LoadKind::kInvalid) { + // We actually cannot reference this class, we're forced to bail. + return nullptr; + } + // Append the instruction first, as setting the load kind affects the inputs. AppendInstruction(load_class); + load_class->SetLoadKind(load_kind); return load_class; } @@ -1674,7 +1711,7 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction, dex::TypeIndex type_index, uint32_t dex_pc) { HInstruction* object = LoadLocal(reference, Primitive::kPrimNot); - HLoadClass* cls = BuildLoadClass(type_index, dex_pc, /* check_access */ true); + HLoadClass* cls = BuildLoadClass(type_index, dex_pc); ScopedObjectAccess soa(Thread::Current()); TypeCheckKind check_kind = ComputeTypeCheckKind(cls->GetClass()); @@ -2498,7 +2535,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, case Instruction::NEW_ARRAY: { dex::TypeIndex type_index(instruction.VRegC_22c()); HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt); - HLoadClass* cls = BuildLoadClass(type_index, dex_pc, /* check_access */ true); + HLoadClass* cls = BuildLoadClass(type_index, dex_pc); AppendInstruction(new (arena_) HNewArray(cls, length, dex_pc)); UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction()); break; @@ -2673,7 +2710,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, case Instruction::CONST_CLASS: { dex::TypeIndex type_index(instruction.VRegB_21c()); - BuildLoadClass(type_index, dex_pc, /* check_access */ true); + BuildLoadClass(type_index, dex_pc); UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction()); break; } diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 5efe95094c..3bb680ce44 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -31,6 +31,7 @@ namespace art { +class CodeGenerator; class Instruction; class HInstructionBuilder : public ValueObject { @@ -44,6 +45,7 @@ class HInstructionBuilder : public ValueObject { DexCompilationUnit* dex_compilation_unit, const DexCompilationUnit* const outer_compilation_unit, CompilerDriver* driver, + CodeGenerator* code_generator, const uint8_t* interpreter_metadata, OptimizingCompilerStats* compiler_stats, Handle<mirror::DexCache> dex_cache, @@ -61,6 +63,7 @@ class HInstructionBuilder : public ValueObject { current_locals_(nullptr), latest_result_(nullptr), compiler_driver_(driver), + code_generator_(code_generator), dex_compilation_unit_(dex_compilation_unit), outer_compilation_unit_(outer_compilation_unit), interpreter_metadata_(interpreter_metadata), @@ -228,10 +231,14 @@ class HInstructionBuilder : public ValueObject { // Builds a `HLoadClass` loading the given `type_index`. If `outer` is true, // this method will use the outer class's dex file to lookup the type at // `type_index`. + HLoadClass* BuildLoadClass(dex::TypeIndex type_index, uint32_t dex_pc); + HLoadClass* BuildLoadClass(dex::TypeIndex type_index, + const DexFile& dex_file, + Handle<mirror::Class> klass, uint32_t dex_pc, - bool check_access, - bool outer = false); + bool needs_access_check) + REQUIRES_SHARED(Locks::mutator_lock_); // Returns the outer-most compiling method's class. mirror::Class* GetOutermostCompilingClass() const; @@ -275,7 +282,6 @@ class HInstructionBuilder : public ValueObject { HClinitCheck* ProcessClinitCheckForInvoke( uint32_t dex_pc, ArtMethod* method, - uint32_t method_idx, HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement) REQUIRES_SHARED(Locks::mutator_lock_); @@ -290,6 +296,10 @@ class HInstructionBuilder : public ValueObject { // not be resolved. ArtMethod* ResolveMethod(uint16_t method_idx, InvokeType invoke_type); + // Try to resolve a field using the class linker. Return null if it could not + // be found. + ArtField* ResolveField(uint16_t field_idx, bool is_static, bool is_put); + ArenaAllocator* const arena_; HGraph* const graph_; VariableSizedHandleScope* handles_; @@ -311,6 +321,8 @@ class HInstructionBuilder : public ValueObject { CompilerDriver* const compiler_driver_; + CodeGenerator* const code_generator_; + // The compilation unit of the current method being compiled. Note that // it can be an inlined method. DexCompilationUnit* const dex_compilation_unit_; diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 76900f23a9..abbb91a1a9 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2464,16 +2464,15 @@ bool HLoadClass::InstructionDataEquals(const HInstruction* other) const { } } -void HLoadClass::SetLoadKindInternal(LoadKind load_kind) { - // Once sharpened, the load kind should not be changed again. - // Also, kReferrersClass should never be overwritten. - DCHECK_EQ(GetLoadKind(), LoadKind::kDexCacheViaMethod); +void HLoadClass::SetLoadKind(LoadKind load_kind) { SetPackedField<LoadKindField>(load_kind); - if (load_kind != LoadKind::kDexCacheViaMethod) { + if (load_kind != LoadKind::kDexCacheViaMethod && + load_kind != LoadKind::kReferrersClass) { RemoveAsUserOfInput(0u); SetRawInputAt(0u, nullptr); } + if (!NeedsEnvironment()) { RemoveEnvironment(); SetSideEffects(SideEffects::None()); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index acf14aa726..fae164aa0b 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -5508,6 +5508,9 @@ class HLoadClass FINAL : public HInstruction { public: // Determines how to load the Class. enum class LoadKind { + // We cannot load this class. See HSharpening::SharpenLoadClass. + kInvalid = -1, + // Use the Class* from the method's own ArtMethod*. kReferrersClass, @@ -5564,18 +5567,7 @@ class HLoadClass FINAL : public HInstruction { SetPackedFlag<kFlagGenerateClInitCheck>(false); } - void SetLoadKind(LoadKind load_kind) { - SetLoadKindInternal(load_kind); - } - - void SetLoadKindWithTypeReference(LoadKind load_kind, - const DexFile& dex_file, - dex::TypeIndex type_index) { - DCHECK(HasTypeReference(load_kind)); - DCHECK(IsSameDexFile(dex_file_, dex_file)); - DCHECK_EQ(type_index_, type_index); - SetLoadKindInternal(load_kind); - } + void SetLoadKind(LoadKind load_kind); LoadKind GetLoadKind() const { return GetPackedField<LoadKindField>(); @@ -5694,6 +5686,11 @@ class HLoadClass FINAL : public HInstruction { // 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 kDexCacheViaMethod, we cannot emit code for this `HLoadClass`. const dex::TypeIndex type_index_; const DexFile& dex_file_; diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 1ab671022b..4bc6ff1b65 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -999,6 +999,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, &dex_file, *code_item, compiler_driver, + codegen.get(), compilation_stats_.get(), interpreter_metadata, dex_cache, diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc index e745c73091..f07f02a719 100644 --- a/compiler/optimizing/sharpening.cc +++ b/compiler/optimizing/sharpening.cc @@ -42,8 +42,6 @@ void HSharpening::Run() { HInstruction* instruction = it.Current(); if (instruction->IsInvokeStaticOrDirect()) { ProcessInvokeStaticOrDirect(instruction->AsInvokeStaticOrDirect()); - } else if (instruction->IsLoadClass()) { - ProcessLoadClass(instruction->AsLoadClass()); } else if (instruction->IsLoadString()) { ProcessLoadString(instruction->AsLoadString()); } @@ -133,104 +131,93 @@ void HSharpening::ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { invoke->SetDispatchInfo(dispatch_info); } -void HSharpening::ProcessLoadClass(HLoadClass* load_class) { - ScopedObjectAccess soa(Thread::Current()); - SharpenClass(load_class, codegen_, compiler_driver_); -} - -void HSharpening::SharpenClass(HLoadClass* load_class, - CodeGenerator* codegen, - CompilerDriver* compiler_driver) { +HLoadClass::LoadKind HSharpening::SharpenClass(HLoadClass* load_class, + CodeGenerator* codegen, + CompilerDriver* compiler_driver, + const DexCompilationUnit& dex_compilation_unit) { Handle<mirror::Class> klass = load_class->GetClass(); DCHECK(load_class->GetLoadKind() == HLoadClass::LoadKind::kDexCacheViaMethod || load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass) << load_class->GetLoadKind(); DCHECK(!load_class->IsInBootImage()) << "HLoadClass should not be optimized before sharpening."; + HLoadClass::LoadKind load_kind = load_class->GetLoadKind(); + if (load_class->NeedsAccessCheck()) { // We need to call the runtime anyway, so we simply get the class as that call's return value. - return; - } - - if (load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass) { + } else if (load_kind == HLoadClass::LoadKind::kReferrersClass) { // 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. - return; - } - - const DexFile& dex_file = load_class->GetDexFile(); - dex::TypeIndex type_index = load_class->GetTypeIndex(); + } 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 = static_cast<HLoadClass::LoadKind>(-1); - Runtime* runtime = Runtime::Current(); - if (codegen->GetCompilerOptions().IsBootImage()) { - // Compiling boot image. Check if the class is a boot image class. - DCHECK(!runtime->UseJitCompilation()); - if (!compiler_driver->GetSupportBootImageFixup()) { - // compiler_driver_test. Do not sharpen. - desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod; - } else if ((klass.Get() != nullptr) && compiler_driver->IsImageClass( - dex_file.StringDataByIdx(dex_file.GetTypeId(type_index).descriptor_idx_))) { - is_in_boot_image = true; - desired_load_kind = codegen->GetCompilerOptions().GetCompilePic() - ? HLoadClass::LoadKind::kBootImageLinkTimePcRelative - : HLoadClass::LoadKind::kBootImageLinkTimeAddress; + bool is_in_boot_image = false; + HLoadClass::LoadKind desired_load_kind = HLoadClass::LoadKind::kInvalid; + Runtime* runtime = Runtime::Current(); + if (codegen->GetCompilerOptions().IsBootImage()) { + // Compiling boot image. Check if the class is a boot image class. + DCHECK(!runtime->UseJitCompilation()); + if (!compiler_driver->GetSupportBootImageFixup()) { + // compiler_driver_test. Do not sharpen. + desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod; + } else if ((klass.Get() != nullptr) && compiler_driver->IsImageClass( + dex_file.StringDataByIdx(dex_file.GetTypeId(type_index).descriptor_idx_))) { + is_in_boot_image = true; + desired_load_kind = codegen->GetCompilerOptions().GetCompilePic() + ? HLoadClass::LoadKind::kBootImageLinkTimePcRelative + : HLoadClass::LoadKind::kBootImageLinkTimeAddress; + } else { + // Not a boot image class. + DCHECK(ContainsElement(compiler_driver->GetDexFilesForOatFile(), &dex_file)); + desired_load_kind = HLoadClass::LoadKind::kBssEntry; + } } else { - // Not a boot image class. - DCHECK(ContainsElement(compiler_driver->GetDexFilesForOatFile(), &dex_file)); - desired_load_kind = HLoadClass::LoadKind::kBssEntry; - } - } else { - is_in_boot_image = (klass.Get() != nullptr) && - runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get()); - if (runtime->UseJitCompilation()) { - // TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus. - // DCHECK(!codegen_->GetCompilerOptions().GetCompilePic()); - if (is_in_boot_image) { - // TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787 + is_in_boot_image = (klass.Get() != nullptr) && + runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get()); + if (runtime->UseJitCompilation()) { + // TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus. + // DCHECK(!codegen_->GetCompilerOptions().GetCompilePic()); + if (is_in_boot_image) { + // TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787 + desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; + } else if (klass.Get() != nullptr) { + desired_load_kind = HLoadClass::LoadKind::kJitTableAddress; + } else { + // Class not loaded yet. This happens when the dex code requesting + // this `HLoadClass` hasn't been executed in the interpreter. + // Fallback to the dex cache. + // TODO(ngeoffray): Generate HDeoptimize instead. + desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod; + } + } else if (is_in_boot_image && !codegen->GetCompilerOptions().GetCompilePic()) { + // AOT app compilation. Check if the class is in the boot image. desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; - } else if (klass.Get() != nullptr) { - desired_load_kind = HLoadClass::LoadKind::kJitTableAddress; } else { - // Class not loaded yet. This happens when the dex code requesting - // this `HLoadClass` hasn't been executed in the interpreter. - // Fallback to the dex cache. - // TODO(ngeoffray): Generate HDeoptimize instead. - desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod; + // Not JIT and either the klass is not in boot image or we are compiling in PIC mode. + desired_load_kind = HLoadClass::LoadKind::kBssEntry; } - } else if (is_in_boot_image && !codegen->GetCompilerOptions().GetCompilePic()) { - // AOT app compilation. Check if the class is in the boot image. - desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; - } else { - // Not JIT and either the klass is not in boot image or we are compiling in PIC mode. - desired_load_kind = HLoadClass::LoadKind::kBssEntry; } - } - DCHECK_NE(desired_load_kind, static_cast<HLoadClass::LoadKind>(-1)); + DCHECK_NE(desired_load_kind, HLoadClass::LoadKind::kInvalid); - if (is_in_boot_image) { - load_class->MarkInBootImage(); + if (is_in_boot_image) { + load_class->MarkInBootImage(); + } + load_kind = codegen->GetSupportedLoadClassKind(desired_load_kind); } - HLoadClass::LoadKind load_kind = codegen->GetSupportedLoadClassKind(desired_load_kind); - switch (load_kind) { - case HLoadClass::LoadKind::kBootImageLinkTimeAddress: - case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: - case HLoadClass::LoadKind::kBssEntry: - case HLoadClass::LoadKind::kDexCacheViaMethod: - load_class->SetLoadKindWithTypeReference(load_kind, dex_file, type_index); - break; - case HLoadClass::LoadKind::kBootImageAddress: - case HLoadClass::LoadKind::kJitTableAddress: - load_class->SetLoadKind(load_kind); - break; - default: - LOG(FATAL) << "Unexpected load kind: " << load_kind; - UNREACHABLE(); + if (!IsSameDexFile(load_class->GetDexFile(), *dex_compilation_unit.GetDexFile())) { + if ((load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) || + (load_kind == HLoadClass::LoadKind::kBssEntry)) { + // 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. + return HLoadClass::LoadKind::kInvalid; + } } + return load_kind; } void HSharpening::ProcessLoadString(HLoadString* load_string) { diff --git a/compiler/optimizing/sharpening.h b/compiler/optimizing/sharpening.h index ae3d83ef2c..4240b2f339 100644 --- a/compiler/optimizing/sharpening.h +++ b/compiler/optimizing/sharpening.h @@ -17,6 +17,7 @@ #ifndef ART_COMPILER_OPTIMIZING_SHARPENING_H_ #define ART_COMPILER_OPTIMIZING_SHARPENING_H_ +#include "nodes.h" #include "optimization.h" namespace art { @@ -24,7 +25,6 @@ namespace art { class CodeGenerator; class CompilerDriver; class DexCompilationUnit; -class HInvokeStaticOrDirect; // Optimization that tries to improve the way we dispatch methods and access types, // fields, etc. Besides actual method sharpening based on receiver type (for example @@ -47,15 +47,15 @@ class HSharpening : public HOptimization { static constexpr const char* kSharpeningPassName = "sharpening"; - // Used internally but also by the inliner. - static void SharpenClass(HLoadClass* load_class, - CodeGenerator* codegen, - CompilerDriver* compiler_driver) + // Used by the builder and the inliner. + static HLoadClass::LoadKind SharpenClass(HLoadClass* load_class, + CodeGenerator* codegen, + CompilerDriver* compiler_driver, + const DexCompilationUnit& dex_compilation_unit) REQUIRES_SHARED(Locks::mutator_lock_); private: void ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke); - void ProcessLoadClass(HLoadClass* load_class); void ProcessLoadString(HLoadString* load_string); CodeGenerator* codegen_; diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index ae1e369999..487e4dd498 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -17,8 +17,10 @@ #include "ssa_builder.h" #include "bytecode_utils.h" +#include "mirror/class-inl.h" #include "nodes.h" #include "reference_type_propagation.h" +#include "scoped_thread_state_change-inl.h" #include "ssa_phi_elimination.h" namespace art { diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index 668108daa4..e4d480061d 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -18,8 +18,8 @@ #include <unordered_map> +#include "art_method-inl.h" #include "base/stl_util.h" -#include "art_method.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" |