diff options
author | Nicolas Geoffray <ngeoffray@google.com> | 2014-11-04 11:23:47 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-11-04 11:23:48 +0000 |
commit | 636e1f55be6657a49d1ec536ba576d4c22833bc4 (patch) | |
tree | bdd8fbb9c2401465d9a0536e94dec74acc8b4f3b | |
parent | 793d1023785f81eb8e29a3eb67fec17d7ee7dcbe (diff) | |
parent | 424f676379f2f872acd1478672022f19f3240fc1 (diff) | |
download | art-636e1f55be6657a49d1ec536ba576d4c22833bc4.tar.gz art-636e1f55be6657a49d1ec536ba576d4c22833bc4.tar.bz2 art-636e1f55be6657a49d1ec536ba576d4c22833bc4.zip |
Merge "Implement CONST_CLASS in optimizing 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 | ||||
-rw-r--r-- | test/420-const-class/expected.txt | 16 | ||||
-rw-r--r-- | test/420-const-class/info.txt | 1 | ||||
-rw-r--r-- | test/420-const-class/src/Main.java | 77 | ||||
-rw-r--r-- | test/Android.run-test.mk | 1 |
14 files changed, 363 insertions, 99 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 434d9efbc..d168fc80f 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 0cec4b404..0b55f87c6 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 c65b42649..5076a4bc3 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 ac328c319..447daa82d 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 bcceaad00..176a269ac 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 0bc2bad89..40eec9b15 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 32d2702d7..0de304538 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 d96131ab8..bed688b5e 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 7549ebfbe..79638b354 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 2387141a3..900371b48 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) { diff --git a/test/420-const-class/expected.txt b/test/420-const-class/expected.txt new file mode 100644 index 000000000..321302661 --- /dev/null +++ b/test/420-const-class/expected.txt @@ -0,0 +1,16 @@ +class Main +class Main +class Main$Other +class Main$Other +class java.lang.System +class java.lang.System +Hello from OtherWithClinit +42 +class Main$OtherWithClinit +42 +class Main$OtherWithClinit +class Main$OtherWithClinit2 +Hello from OtherWithClinit2 +43 +class Main$OtherWithClinit2 +43 diff --git a/test/420-const-class/info.txt b/test/420-const-class/info.txt new file mode 100644 index 000000000..81cbac7fa --- /dev/null +++ b/test/420-const-class/info.txt @@ -0,0 +1 @@ +Test for the CONST_CLASS opcode. diff --git a/test/420-const-class/src/Main.java b/test/420-const-class/src/Main.java new file mode 100644 index 000000000..44a743610 --- /dev/null +++ b/test/420-const-class/src/Main.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + static class Other { + } + + static class OtherWithClinit { + static int a; + static { + System.out.println("Hello from OtherWithClinit"); + a = 42; + } + } + + static class OtherWithClinit2 { + static int a; + static { + System.out.println("Hello from OtherWithClinit2"); + a = 43; + } + } + + public static void main(String[] args) { + // Call methods twice in case they have a slow path. + + System.out.println($opt$LoadThisClass()); + System.out.println($opt$LoadThisClass()); + + System.out.println($opt$LoadOtherClass()); + System.out.println($opt$LoadOtherClass()); + + System.out.println($opt$LoadSystemClass()); + System.out.println($opt$LoadSystemClass()); + + $opt$ClinitCheckAndLoad(); + $opt$ClinitCheckAndLoad(); + + $opt$LoadAndClinitCheck(); + $opt$LoadAndClinitCheck(); + } + + public static Class $opt$LoadThisClass() { + return Main.class; + } + + public static Class $opt$LoadOtherClass() { + return Other.class; + } + + public static Class $opt$LoadSystemClass() { + return System.class; + } + + public static void $opt$ClinitCheckAndLoad() { + System.out.println(OtherWithClinit.a); + System.out.println(OtherWithClinit.class); + } + + public static void $opt$LoadAndClinitCheck() { + System.out.println(OtherWithClinit2.class); + System.out.println(OtherWithClinit2.a); + } +} diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 7dd4c9099..312500b57 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -404,6 +404,7 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \ 417-optimizing-arith-div \ 418-const-string \ 419-long-parameter \ + 420-const-class \ 700-LoadArgRegs \ 701-easy-div-rem \ 702-LargeBranchOffset \ |