diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/optimizing/builder.cc | 21 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 82 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.h | 2 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 107 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.h | 2 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 94 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 2 | ||||
| -rw-r--r-- | compiler/optimizing/locations.h | 7 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 41 | ||||
| -rw-r--r-- | compiler/optimizing/prepare_for_register_allocation.cc | 9 |
10 files changed, 268 insertions, 99 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 434d9efbcf..d168fc80f1 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -505,11 +505,11 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, } HLoadClass* constant = new (arena_) HLoadClass( - storage_index, is_referrers_class, is_initialized, dex_offset); + storage_index, is_referrers_class, dex_offset); current_block_->AddInstruction(constant); HInstruction* cls = constant; - if (constant->NeedsInitialization()) { + if (!is_initialized) { cls = new (arena_) HClinitCheck(constant, dex_offset); current_block_->AddInstruction(cls); } @@ -1185,6 +1185,23 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::CONST_CLASS: { + uint16_t type_index = instruction.VRegB_21c(); + bool type_known_final; + bool type_known_abstract; + bool is_referrers_class; + bool can_access = compiler_driver_->CanAccessTypeWithoutChecks( + dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index, + &type_known_final, &type_known_abstract, &is_referrers_class); + if (!can_access) { + return false; + } + current_block_->AddInstruction( + new (arena_) HLoadClass(instruction.VRegB_21c(), is_referrers_class, dex_offset)); + UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction()); + break; + } + default: return false; } diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 0cec4b404a..0b55f87c69 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -170,30 +170,55 @@ class BoundsCheckSlowPathARM : public SlowPathCodeARM { DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM); }; -class ClinitCheckSlowPathARM : public SlowPathCodeARM { +class LoadClassSlowPathARM : public SlowPathCodeARM { public: - explicit ClinitCheckSlowPathARM(HClinitCheck* instruction) : instruction_(instruction) {} + LoadClassSlowPathARM(HLoadClass* cls, + HInstruction* at, + uint32_t dex_pc, + bool do_clinit) + : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { + DCHECK(at->IsLoadClass() || at->IsClinitCheck()); + } virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + LocationSummary* locations = at_->GetLocations(); + CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); __ Bind(GetEntryLabel()); - codegen->SaveLiveRegisters(instruction_->GetLocations()); + codegen->SaveLiveRegisters(locations); - HLoadClass* cls = instruction_->GetLoadClass(); InvokeRuntimeCallingConvention calling_convention; - __ LoadImmediate(calling_convention.GetRegisterAt(0), cls->GetTypeIndex()); + __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex()); arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); - arm_codegen->InvokeRuntime( - QUICK_ENTRY_POINT(pInitializeStaticStorage), instruction_, instruction_->GetDexPc()); - arm_codegen->Move32(instruction_->GetLocations()->InAt(0), Location::RegisterLocation(R0)); - codegen->RestoreLiveRegisters(instruction_->GetLocations()); + int32_t entry_point_offset = do_clinit_ + ? QUICK_ENTRY_POINT(pInitializeStaticStorage) + : QUICK_ENTRY_POINT(pInitializeType); + arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_); + + // Move the class to the desired location. + if (locations->Out().IsValid()) { + DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); + } + codegen->RestoreLiveRegisters(locations); __ b(GetExitLabel()); } private: - HClinitCheck* const instruction_; + // The class this slow path will load. + HLoadClass* const cls_; + + // The instruction where this slow path is happening. + // (Might be the load class or an initialization check). + HInstruction* const at_; - DISALLOW_COPY_AND_ASSIGN(ClinitCheckSlowPathARM); + // The dex PC of `at_`. + const uint32_t dex_pc_; + + // Whether to initialize the class. + const bool do_clinit_; + + DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM); }; class LoadStringSlowPathARM : public SlowPathCodeARM { @@ -2143,21 +2168,38 @@ void ParallelMoveResolverARM::RestoreScratch(int reg) { } void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) { + LocationSummary::CallKind call_kind = cls->CanCallRuntime() + ? LocationSummary::kCallOnSlowPath + : LocationSummary::kNoCall; LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(cls, LocationSummary::kNoCall); + new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { Register out = cls->GetLocations()->Out().As<Register>(); if (cls->IsReferrersClass()) { + DCHECK(!cls->CanCallRuntime()); + DCHECK(!cls->MustGenerateClinitCheck()); codegen_->LoadCurrentMethod(out); __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()); } else { + DCHECK(cls->CanCallRuntime()); codegen_->LoadCurrentMethod(out); __ LoadFromOffset( kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()); __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); + + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( + cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); + codegen_->AddSlowPath(slow_path); + __ cmp(out, ShifterOperand(0)); + __ b(slow_path->GetEntryLabel(), EQ); + if (cls->MustGenerateClinitCheck()) { + GenerateClassInitializationCheck(slow_path, out); + } else { + __ Bind(slow_path->GetExitLabel()); + } } } @@ -2171,17 +2213,15 @@ void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) { } void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) { - SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) ClinitCheckSlowPathARM(check); + // We assume the class is not null. + SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( + check->GetLoadClass(), check, check->GetDexPc(), true); codegen_->AddSlowPath(slow_path); + GenerateClassInitializationCheck(slow_path, check->GetLocations()->InAt(0).As<Register>()); +} - LocationSummary* locations = check->GetLocations(); - // We remove the class as a live register, we know it's null or unused in the slow path. - RegisterSet* register_set = locations->GetLiveRegisters(); - register_set->Remove(locations->InAt(0)); - - Register class_reg = locations->InAt(0).As<Register>(); - __ cmp(class_reg, ShifterOperand(0)); - __ b(slow_path->GetEntryLabel(), EQ); +void InstructionCodeGeneratorARM::GenerateClassInitializationCheck( + SlowPathCodeARM* slow_path, Register class_reg) { __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value()); __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized)); __ b(slow_path->GetEntryLabel(), LT); diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index c65b42649e..5076a4bc38 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -26,6 +26,7 @@ namespace art { namespace arm { class CodeGeneratorARM; +class SlowPathCodeARM; static constexpr size_t kArmWordSize = 4; @@ -131,6 +132,7 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { // is the block to branch to if the suspend check is not needed, and after // the suspend call. void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); + void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg); ArmAssembler* const assembler_; CodeGeneratorARM* const codegen_; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index ac328c319c..447daa82d8 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -157,59 +157,83 @@ class SuspendCheckSlowPathX86 : public SlowPathCodeX86 { DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86); }; -class ClinitCheckSlowPathX86 : public SlowPathCodeX86 { +class LoadStringSlowPathX86 : public SlowPathCodeX86 { public: - explicit ClinitCheckSlowPathX86(HClinitCheck* instruction) : instruction_(instruction) {} + explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {} virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + LocationSummary* locations = instruction_->GetLocations(); + DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); __ Bind(GetEntryLabel()); - codegen->SaveLiveRegisters(instruction_->GetLocations()); + codegen->SaveLiveRegisters(locations); - HLoadClass* cls = instruction_->GetLoadClass(); InvokeRuntimeCallingConvention calling_convention; - __ movl(calling_convention.GetRegisterAt(0), Immediate(cls->GetTypeIndex())); - x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); - __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage))); + x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0)); + __ movl(calling_convention.GetRegisterAt(1), Immediate(instruction_->GetStringIndex())); + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString))); codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); - x86_codegen->Move32(instruction_->GetLocations()->InAt(0), Location::RegisterLocation(EAX)); - codegen->RestoreLiveRegisters(instruction_->GetLocations()); + x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX)); + codegen->RestoreLiveRegisters(locations); + __ jmp(GetExitLabel()); } private: - HClinitCheck* const instruction_; + HLoadString* const instruction_; - DISALLOW_COPY_AND_ASSIGN(ClinitCheckSlowPathX86); + DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86); }; -class LoadStringSlowPathX86 : public SlowPathCodeX86 { +class LoadClassSlowPathX86 : public SlowPathCodeX86 { public: - explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {} + LoadClassSlowPathX86(HLoadClass* cls, + HInstruction* at, + uint32_t dex_pc, + bool do_clinit) + : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { + DCHECK(at->IsLoadClass() || at->IsClinitCheck()); + } virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { - LocationSummary* locations = instruction_->GetLocations(); - DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); - + LocationSummary* locations = at_->GetLocations(); CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); __ Bind(GetEntryLabel()); codegen->SaveLiveRegisters(locations); InvokeRuntimeCallingConvention calling_convention; - x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0)); - __ movl(calling_convention.GetRegisterAt(1), Immediate(instruction_->GetStringIndex())); - __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString))); - codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); - x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX)); - codegen->RestoreLiveRegisters(locations); + __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex())); + x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); + __ fs()->call(Address::Absolute(do_clinit_ + ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage) + : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeType))); + codegen->RecordPcInfo(at_, dex_pc_); + // Move the class to the desired location. + if (locations->Out().IsValid()) { + DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX)); + } + codegen->RestoreLiveRegisters(locations); __ jmp(GetExitLabel()); } private: - HLoadString* const instruction_; + // The class this slow path will load. + HLoadClass* const cls_; - DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86); + // The instruction where this slow path is happening. + // (Might be the load class or an initialization check). + HInstruction* const at_; + + // The dex PC of `at_`. + const uint32_t dex_pc_; + + // Whether to initialize the class. + const bool do_clinit_; + + DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86); }; #undef __ @@ -2181,20 +2205,37 @@ void ParallelMoveResolverX86::RestoreScratch(int reg) { } void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) { + LocationSummary::CallKind call_kind = cls->CanCallRuntime() + ? LocationSummary::kCallOnSlowPath + : LocationSummary::kNoCall; LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(cls, LocationSummary::kNoCall); + new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) { Register out = cls->GetLocations()->Out().As<Register>(); if (cls->IsReferrersClass()) { + DCHECK(!cls->CanCallRuntime()); + DCHECK(!cls->MustGenerateClinitCheck()); codegen_->LoadCurrentMethod(out); __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value())); } else { + DCHECK(cls->CanCallRuntime()); codegen_->LoadCurrentMethod(out); __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value())); __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); + + SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86( + cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); + codegen_->AddSlowPath(slow_path); + __ testl(out, out); + __ j(kEqual, slow_path->GetEntryLabel()); + if (cls->MustGenerateClinitCheck()) { + GenerateClassInitializationCheck(slow_path, out); + } else { + __ Bind(slow_path->GetExitLabel()); + } } } @@ -2208,17 +2249,15 @@ void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) { } void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) { - SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) ClinitCheckSlowPathX86(check); + // We assume the class to not be null. + SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86( + check->GetLoadClass(), check, check->GetDexPc(), true); codegen_->AddSlowPath(slow_path); + GenerateClassInitializationCheck(slow_path, check->GetLocations()->InAt(0).As<Register>()); +} - LocationSummary* locations = check->GetLocations(); - // We remove the class as a live register, we know it's null or unused in the slow path. - RegisterSet* register_set = locations->GetLiveRegisters(); - register_set->Remove(locations->InAt(0)); - - Register class_reg = locations->InAt(0).As<Register>(); - __ testl(class_reg, class_reg); - __ j(kEqual, slow_path->GetEntryLabel()); +void InstructionCodeGeneratorX86::GenerateClassInitializationCheck( + SlowPathCodeX86* slow_path, Register class_reg) { __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()), Immediate(mirror::Class::kStatusInitialized)); __ j(kLess, slow_path->GetEntryLabel()); diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index bcceaad00f..176a269ac4 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -28,6 +28,7 @@ namespace x86 { static constexpr size_t kX86WordSize = 4; class CodeGeneratorX86; +class SlowPathCodeX86; static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX }; static constexpr RegisterPair kParameterCorePairRegisters[] = { ECX_EDX, EDX_EBX }; @@ -126,6 +127,7 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { // is the block to branch to if the suspend check is not needed, and after // the suspend call. void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); + void GenerateClassInitializationCheck(SlowPathCodeX86* slow_path, Register class_reg); X86Assembler* const assembler_; CodeGeneratorX86* const codegen_; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 0bc2bad896..40eec9b15d 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -168,32 +168,56 @@ class BoundsCheckSlowPathX86_64 : public SlowPathCodeX86_64 { DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64); }; -class ClinitCheckSlowPathX86_64 : public SlowPathCodeX86_64 { +class LoadClassSlowPathX86_64 : public SlowPathCodeX86_64 { public: - explicit ClinitCheckSlowPathX86_64(HClinitCheck* instruction) : instruction_(instruction) {} + LoadClassSlowPathX86_64(HLoadClass* cls, + HInstruction* at, + uint32_t dex_pc, + bool do_clinit) + : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { + DCHECK(at->IsLoadClass() || at->IsClinitCheck()); + } virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { + LocationSummary* locations = at_->GetLocations(); CodeGeneratorX86_64* x64_codegen = down_cast<CodeGeneratorX86_64*>(codegen); __ Bind(GetEntryLabel()); - codegen->SaveLiveRegisters(instruction_->GetLocations()); - HLoadClass* cls = instruction_->GetLoadClass(); + codegen->SaveLiveRegisters(locations); + InvokeRuntimeCallingConvention calling_convention; - __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls->GetTypeIndex())); + __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex())); x64_codegen->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1))); - __ gs()->call(Address::Absolute( - QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage), true)); + __ gs()->call(Address::Absolute((do_clinit_ + ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage) + : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true)); + codegen->RecordPcInfo(at_, dex_pc_); - codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); - x64_codegen->Move(instruction_->GetLocations()->InAt(0), Location::RegisterLocation(RAX)); - codegen->RestoreLiveRegisters(instruction_->GetLocations()); + // Move the class to the desired location. + if (locations->Out().IsValid()) { + DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + x64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX)); + } + + codegen->RestoreLiveRegisters(locations); __ jmp(GetExitLabel()); } private: - HClinitCheck* const instruction_; + // The class this slow path will load. + HLoadClass* const cls_; + + // The instruction where this slow path is happening. + // (Might be the load class or an initialization check). + HInstruction* const at_; + + // The dex PC of `at_`. + const uint32_t dex_pc_; - DISALLOW_COPY_AND_ASSIGN(ClinitCheckSlowPathX86_64); + // Whether to initialize the class. + const bool do_clinit_; + + DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64); }; class LoadStringSlowPathX86_64 : public SlowPathCodeX86_64 { @@ -2151,21 +2175,46 @@ void ParallelMoveResolverX86_64::RestoreScratch(int reg) { __ popq(CpuRegister(reg)); } +void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck( + SlowPathCodeX86_64* slow_path, CpuRegister class_reg) { + __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()), + Immediate(mirror::Class::kStatusInitialized)); + __ j(kLess, slow_path->GetEntryLabel()); + __ Bind(slow_path->GetExitLabel()); + // No need for memory fence, thanks to the X86_64 memory model. +} + void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) { + LocationSummary::CallKind call_kind = cls->CanCallRuntime() + ? LocationSummary::kCallOnSlowPath + : LocationSummary::kNoCall; LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(cls, LocationSummary::kNoCall); + new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) { CpuRegister out = cls->GetLocations()->Out().As<CpuRegister>(); if (cls->IsReferrersClass()) { + DCHECK(!cls->CanCallRuntime()); + DCHECK(!cls->MustGenerateClinitCheck()); codegen_->LoadCurrentMethod(out); __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value())); } else { + DCHECK(cls->CanCallRuntime()); codegen_->LoadCurrentMethod(out); __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value())); __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); + SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64( + cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); + codegen_->AddSlowPath(slow_path); + __ testl(out, out); + __ j(kEqual, slow_path->GetEntryLabel()); + if (cls->MustGenerateClinitCheck()) { + GenerateClassInitializationCheck(slow_path, out); + } else { + __ Bind(slow_path->GetExitLabel()); + } } } @@ -2179,22 +2228,11 @@ void LocationsBuilderX86_64::VisitClinitCheck(HClinitCheck* check) { } void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) { - SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) ClinitCheckSlowPathX86_64(check); + // We assume the class to not be null. + SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64( + check->GetLoadClass(), check, check->GetDexPc(), true); codegen_->AddSlowPath(slow_path); - - LocationSummary* locations = check->GetLocations(); - // We remove the class as a live register, we know it's null or unused in the slow path. - RegisterSet* register_set = locations->GetLiveRegisters(); - register_set->Remove(locations->InAt(0)); - - CpuRegister class_reg = locations->InAt(0).As<CpuRegister>(); - __ testl(class_reg, class_reg); - __ j(kEqual, slow_path->GetEntryLabel()); - __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()), - Immediate(mirror::Class::kStatusInitialized)); - __ j(kLess, slow_path->GetEntryLabel()); - __ Bind(slow_path->GetExitLabel()); - // No need for memory fence, thanks to the X86_64 memory model. + GenerateClassInitializationCheck(slow_path, check->GetLocations()->InAt(0).As<CpuRegister>()); } void LocationsBuilderX86_64::VisitStaticFieldGet(HStaticFieldGet* instruction) { diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 32d2702d72..0de304538f 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -65,6 +65,7 @@ class InvokeDexCallingConventionVisitor { }; class CodeGeneratorX86_64; +class SlowPathCodeX86_64; class ParallelMoveResolverX86_64 : public ParallelMoveResolver { public: @@ -130,6 +131,7 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor { // is the block to branch to if the suspend check is not needed, and after // the suspend call. void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); + void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg); X86_64Assembler* const assembler_; CodeGeneratorX86_64* const codegen_; diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h index d96131ab83..bed688b5e3 100644 --- a/compiler/optimizing/locations.h +++ b/compiler/optimizing/locations.h @@ -27,6 +27,9 @@ namespace art { class HConstant; class HInstruction; +class Location; + +std::ostream& operator<<(std::ostream& os, const Location& location); /** * A Location is an abstraction over the potential location @@ -371,7 +374,7 @@ class RegisterSet : public ValueObject { if (loc.IsRegister()) { core_registers_ &= ~(1 << loc.reg()); } else { - DCHECK(loc.IsFpuRegister()); + DCHECK(loc.IsFpuRegister()) << loc; floating_point_registers_ &= ~(1 << loc.reg()); } } @@ -528,8 +531,6 @@ class LocationSummary : public ArenaObject<kArenaAllocMisc> { DISALLOW_COPY_AND_ASSIGN(LocationSummary); }; -std::ostream& operator<<(std::ostream& os, const Location& location); - } // namespace art #endif // ART_COMPILER_OPTIMIZING_LOCATIONS_H_ diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 7549ebfbe4..79638b3545 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -2052,9 +2052,6 @@ class HSuspendCheck : public HTemplateInstruction<0> { DISALLOW_COPY_AND_ASSIGN(HSuspendCheck); }; -// TODO: Make this class handle the case the load is null (dex cache -// is null). This will be required when using it for other things than -// initialization check. /** * Instruction to load a Class object. */ @@ -2062,13 +2059,14 @@ class HLoadClass : public HExpression<0> { public: HLoadClass(uint16_t type_index, bool is_referrers_class, - bool is_initialized, uint32_t dex_pc) : HExpression(Primitive::kPrimNot, SideEffects::None()), type_index_(type_index), is_referrers_class_(is_referrers_class), - is_initialized_(is_initialized), - dex_pc_(dex_pc) {} + dex_pc_(dex_pc), + generate_clinit_check_(false) {} + + bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(HInstruction* other) const OVERRIDE { return other->AsLoadClass()->type_index_ == type_index_; @@ -2078,20 +2076,35 @@ class HLoadClass : public HExpression<0> { uint32_t GetDexPc() const { return dex_pc_; } uint16_t GetTypeIndex() const { return type_index_; } + bool IsReferrersClass() const { return is_referrers_class_; } - bool NeedsInitialization() const { - return !is_initialized_ && !is_referrers_class_; + bool NeedsEnvironment() const OVERRIDE { + // Will call runtime and load the class if the class is not loaded yet. + // TODO: finer grain decision. + return !is_referrers_class_; } - bool IsReferrersClass() const { return is_referrers_class_; } + bool MustGenerateClinitCheck() const { + return generate_clinit_check_; + } + + void SetMustGenerateClinitCheck() { + generate_clinit_check_ = true; + } + + bool CanCallRuntime() const { + return MustGenerateClinitCheck() || !is_referrers_class_; + } DECLARE_INSTRUCTION(LoadClass); private: const uint16_t type_index_; const bool is_referrers_class_; - const bool is_initialized_; const uint32_t dex_pc_; + // Whether this instruction must generate the initialization check. + // Used for code generation. + bool generate_clinit_check_; DISALLOW_COPY_AND_ASSIGN(HLoadClass); }; @@ -2103,6 +2116,8 @@ class HLoadString : public HExpression<0> { string_index_(string_index), dex_pc_(dex_pc) {} + bool CanBeMoved() const OVERRIDE { return true; } + bool InstructionDataEquals(HInstruction* other) const OVERRIDE { return other->AsLoadString()->string_index_ == string_index_; } @@ -2136,6 +2151,12 @@ class HClinitCheck : public HExpression<1> { SetRawInputAt(0, constant); } + bool CanBeMoved() const OVERRIDE { return true; } + bool InstructionDataEquals(HInstruction* other) const OVERRIDE { + UNUSED(other); + return true; + } + bool NeedsEnvironment() const OVERRIDE { // May call runtime to initialize the class. return true; diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc index 2387141a39..900371b48e 100644 --- a/compiler/optimizing/prepare_for_register_allocation.cc +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -38,7 +38,14 @@ void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) { } void PrepareForRegisterAllocation::VisitClinitCheck(HClinitCheck* check) { - check->ReplaceWith(check->InputAt(0)); + HLoadClass* cls = check->GetLoadClass(); + check->ReplaceWith(cls); + if (check->GetPrevious() == cls) { + // Pass the initialization duty to the `HLoadClass` instruction, + // and remove the instruction from the graph. + cls->SetMustGenerateClinitCheck(); + check->GetBlock()->RemoveInstruction(check); + } } void PrepareForRegisterAllocation::VisitCondition(HCondition* condition) { |