diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/optimizing/builder.cc | 48 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 42 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 47 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 45 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 41 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 43 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 42 | ||||
| -rw-r--r-- | compiler/optimizing/graph_checker.cc | 28 | ||||
| -rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 43 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 157 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_builder.cc | 18 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_builder.h | 15 |
14 files changed, 263 insertions, 316 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 1af684683b..37218139fb 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -1271,44 +1271,14 @@ bool HGraphBuilder::HandleStringInit(HInvoke* invoke, // Add move-result for StringFactory method. uint32_t orig_this_reg = is_range ? register_index : args[0]; - HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot, invoke->GetDexPc()); - invoke->SetArgumentAt(argument_index, fake_string); + HInstruction* new_instance = LoadLocal(orig_this_reg, Primitive::kPrimNot, invoke->GetDexPc()); + invoke->SetArgumentAt(argument_index, new_instance); current_block_->AddInstruction(invoke); - PotentiallySimplifyFakeString(orig_this_reg, invoke->GetDexPc(), invoke); latest_result_ = invoke; - return true; } -void HGraphBuilder::PotentiallySimplifyFakeString(uint16_t original_dex_register, - uint32_t dex_pc, - HInvoke* actual_string) { - if (!graph_->IsDebuggable()) { - // Notify that we cannot compile with baseline. The dex registers aliasing - // with `original_dex_register` will be handled when we optimize - // (see HInstructionSimplifer::VisitFakeString). - can_use_baseline_for_string_init_ = false; - return; - } - const VerifiedMethod* verified_method = - compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex()); - if (verified_method != nullptr) { - UpdateLocal(original_dex_register, actual_string, dex_pc); - const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map = - verified_method->GetStringInitPcRegMap(); - auto map_it = string_init_map.find(dex_pc); - if (map_it != string_init_map.end()) { - for (uint32_t reg : map_it->second) { - HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot, dex_pc); - UpdateLocal(reg, load_local, dex_pc); - } - } - } else { - can_use_baseline_for_string_init_ = false; - } -} - static Primitive::Type GetFieldAccessType(const DexFile& dex_file, uint16_t field_index) { const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); const char* type = dex_file.GetFieldTypeDescriptor(field_id); @@ -2698,18 +2668,10 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::NEW_INSTANCE: { - uint16_t type_index = instruction.VRegB_21c(); - if (compiler_driver_->IsStringTypeIndex(type_index, dex_file_)) { - int32_t register_index = instruction.VRegA(); - HFakeString* fake_string = new (arena_) HFakeString(dex_pc); - current_block_->AddInstruction(fake_string); - UpdateLocal(register_index, fake_string, dex_pc); - } else { - if (!BuildNewInstance(type_index, dex_pc)) { - return false; - } - UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); + if (!BuildNewInstance(instruction.VRegB_21c(), dex_pc)) { + return false; } + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc); break; } diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 45520b45bf..5720cb8fd8 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -3651,20 +3651,34 @@ void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) { void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); - InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); - locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + if (instruction->IsStringAlloc()) { + locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument)); + } else { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + } locations->SetOut(Location::RegisterLocation(R0)); } void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime(instruction->GetEntrypoint(), - instruction, - instruction->GetDexPc(), - nullptr); - CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + if (instruction->IsStringAlloc()) { + // String is allocated through StringFactory. Call NewEmptyString entry point. + Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>(); + MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmWordSize); + __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString)); + __ LoadFromOffset(kLoadWord, LR, temp, code_offset.Int32Value()); + __ blx(LR); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); + } else { + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); + CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + } } void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) { @@ -6486,18 +6500,6 @@ void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction ATTRIBU LOG(FATAL) << "Unreachable"; } -void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) { - DCHECK(codegen_->IsBaseline()); - LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant())); -} - -void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) { - DCHECK(codegen_->IsBaseline()); - // Will be generated at use site. -} - // Simple implementation of packed switch - generate cascaded compare/jumps. void LocationsBuilderARM::VisitPackedSwitch(HPackedSwitch* switch_instr) { LocationSummary* locations = diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index a3150d3d22..5e905fc9aa 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -1032,13 +1032,6 @@ void CodeGeneratorARM64::Move(HInstruction* instruction, Primitive::Type type = instruction->GetType(); DCHECK_NE(type, Primitive::kPrimVoid); - if (instruction->IsFakeString()) { - // The fake string is an alias for null. - DCHECK(IsBaseline()); - instruction = locations->Out().GetConstant(); - DCHECK(instruction->IsNullConstant()) << instruction->DebugName(); - } - if (instruction->IsCurrentMethod()) { MoveLocation(location, Location::DoubleStackSlot(kCurrentMethodStackOffset), @@ -4061,19 +4054,33 @@ void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); - locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1))); + if (instruction->IsStringAlloc()) { + locations->AddTemp(LocationFrom(kArtMethodRegister)); + } else { + locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1))); + } locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot)); } void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) { // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime(instruction->GetEntrypoint(), - instruction, - instruction->GetDexPc(), - nullptr); - CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + if (instruction->IsStringAlloc()) { + // String is allocated through StringFactory. Call NewEmptyString entry point. + Location temp = instruction->GetLocations()->GetTemp(0); + MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize); + __ Ldr(XRegisterFrom(temp), MemOperand(tr, QUICK_ENTRY_POINT(pNewEmptyString))); + __ Ldr(lr, MemOperand(XRegisterFrom(temp), code_offset.Int32Value())); + __ Blr(lr); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); + } else { + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); + CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + } } void LocationsBuilderARM64::VisitNot(HNot* instruction) { @@ -4559,18 +4566,6 @@ void InstructionCodeGeneratorARM64::VisitBoundType(HBoundType* instruction ATTRI LOG(FATAL) << "Unreachable"; } -void LocationsBuilderARM64::VisitFakeString(HFakeString* instruction) { - DCHECK(codegen_->IsBaseline()); - LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant())); -} - -void InstructionCodeGeneratorARM64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) { - DCHECK(codegen_->IsBaseline()); - // Will be generated at use site. -} - // Simple implementation of packed switch - generate cascaded compare/jumps. void LocationsBuilderARM64::VisitPackedSwitch(HPackedSwitch* switch_instr) { LocationSummary* locations = diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 75f5fb3bab..d44067c3cb 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -4350,19 +4350,34 @@ void LocationsBuilderMIPS::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); - locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + if (instruction->IsStringAlloc()) { + locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument)); + } else { + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + } locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot)); } void InstructionCodeGeneratorMIPS::VisitNewInstance(HNewInstance* instruction) { - codegen_->InvokeRuntime( - GetThreadOffset<kMipsWordSize>(instruction->GetEntrypoint()).Int32Value(), - instruction, - instruction->GetDexPc(), - nullptr, - IsDirectEntrypoint(kQuickAllocObjectWithAccessCheck)); - CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + if (instruction->IsStringAlloc()) { + // String is allocated through StringFactory. Call NewEmptyString entry point. + Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>(); + MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsWordSize); + __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString)); + __ LoadFromOffset(kLoadWord, T9, temp, code_offset.Int32Value()); + __ Jalr(T9); + __ Nop(); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); + } else { + codegen_->InvokeRuntime( + GetThreadOffset<kMipsWordSize>(instruction->GetEntrypoint()).Int32Value(), + instruction, + instruction->GetDexPc(), + nullptr, + IsDirectEntrypoint(kQuickAllocObjectWithAccessCheck)); + CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + } } void LocationsBuilderMIPS::VisitNot(HNot* instruction) { @@ -5067,18 +5082,6 @@ void InstructionCodeGeneratorMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) { HandleCondition(comp); } -void LocationsBuilderMIPS::VisitFakeString(HFakeString* instruction) { - DCHECK(codegen_->IsBaseline()); - LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant())); -} - -void InstructionCodeGeneratorMIPS::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) { - DCHECK(codegen_->IsBaseline()); - // Will be generated at use site. -} - void LocationsBuilderMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index abfaae4b50..b6b7d95d9b 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -3515,17 +3515,32 @@ void LocationsBuilderMIPS64::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); - locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + if (instruction->IsStringAlloc()) { + locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument)); + } else { + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + } locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot)); } void InstructionCodeGeneratorMIPS64::VisitNewInstance(HNewInstance* instruction) { - codegen_->InvokeRuntime(instruction->GetEntrypoint(), - instruction, - instruction->GetDexPc(), - nullptr); - CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + if (instruction->IsStringAlloc()) { + // String is allocated through StringFactory. Call NewEmptyString entry point. + GpuRegister temp = instruction->GetLocations()->GetTemp(0).AsRegister<GpuRegister>(); + MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize); + __ LoadFromOffset(kLoadDoubleword, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString)); + __ LoadFromOffset(kLoadDoubleword, T9, temp, code_offset.Int32Value()); + __ Jalr(T9); + __ Nop(); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); + } else { + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); + CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + } } void LocationsBuilderMIPS64::VisitNot(HNot* instruction) { @@ -4176,18 +4191,6 @@ void InstructionCodeGeneratorMIPS64::VisitAboveOrEqual(HAboveOrEqual* comp) { HandleCondition(comp); } -void LocationsBuilderMIPS64::VisitFakeString(HFakeString* instruction) { - DCHECK(codegen_->IsBaseline()); - LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant())); -} - -void InstructionCodeGeneratorMIPS64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) { - DCHECK(codegen_->IsBaseline()); - // Will be generated at use site. -} - // Simple implementation of packed switch - generate cascaded compare/jumps. void LocationsBuilderMIPS64::VisitPackedSwitch(HPackedSwitch* switch_instr) { LocationSummary* locations = diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index c24d25876c..f0ff40dbf7 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -3943,20 +3943,33 @@ void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); locations->SetOut(Location::RegisterLocation(EAX)); - InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); - locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + if (instruction->IsStringAlloc()) { + locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument)); + } else { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + } } void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) { // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime(instruction->GetEntrypoint(), - instruction, - instruction->GetDexPc(), - nullptr); - CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); - DCHECK(!codegen_->IsLeafMethod()); + if (instruction->IsStringAlloc()) { + // String is allocated through StringFactory. Call NewEmptyString entry point. + Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>(); + MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize); + __ fs()->movl(temp, Address::Absolute(QUICK_ENTRY_POINT(pNewEmptyString))); + __ call(Address(temp, code_offset.Int32Value())); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); + } else { + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); + CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + DCHECK(!codegen_->IsLeafMethod()); + } } void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) { @@ -6746,18 +6759,6 @@ void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction ATTRIBU LOG(FATAL) << "Unreachable"; } -void LocationsBuilderX86::VisitFakeString(HFakeString* instruction) { - DCHECK(codegen_->IsBaseline()); - LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant())); -} - -void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) { - DCHECK(codegen_->IsBaseline()); - // Will be generated at use site. -} - // Simple implementation of packed switch - generate cascaded compare/jumps. void LocationsBuilderX86::VisitPackedSwitch(HPackedSwitch* switch_instr) { LocationSummary* locations = diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 294b40e3d4..e024ce2b6c 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -3912,21 +3912,33 @@ void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); - locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + if (instruction->IsStringAlloc()) { + locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument)); + } else { + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + } locations->SetOut(Location::RegisterLocation(RAX)); } void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) { // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime(instruction->GetEntrypoint(), - instruction, - instruction->GetDexPc(), - nullptr); - CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); - - DCHECK(!codegen_->IsLeafMethod()); + if (instruction->IsStringAlloc()) { + // String is allocated through StringFactory. Call NewEmptyString entry point. + CpuRegister temp = instruction->GetLocations()->GetTemp(0).AsRegister<CpuRegister>(); + MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86_64WordSize); + __ gs()->movq(temp, Address::Absolute(QUICK_ENTRY_POINT(pNewEmptyString), /* no_rip */ true)); + __ call(Address(temp, code_offset.SizeValue())); + codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); + } else { + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); + CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); + DCHECK(!codegen_->IsLeafMethod()); + } } void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) { @@ -6323,18 +6335,6 @@ void InstructionCodeGeneratorX86_64::VisitBoundType(HBoundType* instruction ATTR LOG(FATAL) << "Unreachable"; } -void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) { - DCHECK(codegen_->IsBaseline()); - LocationSummary* locations = - new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant())); -} - -void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) { - DCHECK(codegen_->IsBaseline()); - // Will be generated at use site. -} - // Simple implementation of packed switch - generate cascaded compare/jumps. void LocationsBuilderX86_64::VisitPackedSwitch(HPackedSwitch* switch_instr) { LocationSummary* locations = diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index 6d0bdbe19b..2fe5b07b19 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -606,6 +606,34 @@ void SSAChecker::VisitInstruction(HInstruction* instruction) { instruction->GetId())); } } + + if (instruction->CanThrowIntoCatchBlock()) { + // Find the top-level environment. This corresponds to the environment of + // the catch block since we do not inline methods with try/catch. + HEnvironment* environment = instruction->GetEnvironment(); + while (environment->GetParent() != nullptr) { + environment = environment->GetParent(); + } + + // Find all catch blocks and test that `instruction` has an environment + // value for each one. + const HTryBoundary& entry = instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry(); + for (HBasicBlock* catch_block : entry.GetExceptionHandlers()) { + for (HInstructionIterator phi_it(catch_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) { + HPhi* catch_phi = phi_it.Current()->AsPhi(); + if (environment->GetInstructionAt(catch_phi->GetRegNumber()) == nullptr) { + AddError(StringPrintf("Instruction %s:%d throws into catch block %d " + "with catch phi %d for vreg %d but its " + "corresponding environment slot is empty.", + instruction->DebugName(), + instruction->GetId(), + catch_block->GetBlockId(), + catch_phi->GetId(), + catch_phi->GetRegNumber())); + } + } + } + } } static Primitive::Type PrimitiveKind(Primitive::Type type) { diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index b90afb1d73..49fc8c71b3 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -77,7 +77,6 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor { void VisitUShr(HUShr* instruction) OVERRIDE; void VisitXor(HXor* instruction) OVERRIDE; void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE; - void VisitFakeString(HFakeString* fake_string) OVERRIDE; void VisitInvoke(HInvoke* invoke) OVERRIDE; void VisitDeoptimize(HDeoptimize* deoptimize) OVERRIDE; @@ -1179,48 +1178,6 @@ void InstructionSimplifierVisitor::VisitXor(HXor* instruction) { TryReplaceWithRotate(instruction); } -void InstructionSimplifierVisitor::VisitFakeString(HFakeString* instruction) { - HInstruction* actual_string = nullptr; - - // Find the string we need to replace this instruction with. The actual string is - // the return value of a StringFactory call. - for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) { - HInstruction* use = it.Current()->GetUser(); - if (use->IsInvokeStaticOrDirect() - && use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction)) { - use->AsInvokeStaticOrDirect()->RemoveFakeStringArgumentAsLastInput(); - actual_string = use; - break; - } - } - - // Check that there is no other instruction that thinks it is the factory for that string. - if (kIsDebugBuild) { - CHECK(actual_string != nullptr); - for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) { - HInstruction* use = it.Current()->GetUser(); - if (use->IsInvokeStaticOrDirect()) { - CHECK(!use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction)); - } - } - } - - // We need to remove any environment uses of the fake string that are not dominated by - // `actual_string` to null. - for (HUseIterator<HEnvironment*> it(instruction->GetEnvUses()); !it.Done(); it.Advance()) { - HEnvironment* environment = it.Current()->GetUser(); - if (!actual_string->StrictlyDominates(environment->GetHolder())) { - environment->RemoveAsUserOfInput(it.Current()->GetIndex()); - environment->SetRawEnvAt(it.Current()->GetIndex(), nullptr); - } - } - - // Only uses dominated by `actual_string` must remain. We can safely replace and remove - // `instruction`. - instruction->ReplaceWith(actual_string); - instruction->GetBlock()->RemoveInstruction(instruction); -} - void InstructionSimplifierVisitor::SimplifyStringEquals(HInvoke* instruction) { HInstruction* argument = instruction->InputAt(1); HInstruction* receiver = instruction->InputAt(0); diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 8de9700250..e33e6ca76a 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2169,6 +2169,11 @@ void HInvoke::SetIntrinsic(Intrinsics intrinsic, } } +bool HNewInstance::IsStringAlloc() const { + ScopedObjectAccess soa(Thread::Current()); + return GetReferenceTypeInfo().IsStringClass(); +} + bool HInvoke::NeedsEnvironment() const { if (!IsIntrinsic()) { return true; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index b65d0f5750..e2f3b93f91 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -44,7 +44,6 @@ class HBasicBlock; class HCurrentMethod; class HDoubleConstant; class HEnvironment; -class HFakeString; class HFloatConstant; class HGraphBuilder; class HGraphVisitor; @@ -1156,7 +1155,6 @@ class HLoopInformationOutwardIterator : public ValueObject { M(DoubleConstant, Constant) \ M(Equal, Condition) \ M(Exit, Instruction) \ - M(FakeString, Instruction) \ M(FloatConstant, Constant) \ M(Goto, Instruction) \ M(GreaterThan, Condition) \ @@ -3252,6 +3250,61 @@ class HDoubleConstant : public HConstant { DISALLOW_COPY_AND_ASSIGN(HDoubleConstant); }; +class HNewInstance : public HExpression<2> { + public: + HNewInstance(HInstruction* cls, + HCurrentMethod* current_method, + uint32_t dex_pc, + uint16_t type_index, + const DexFile& dex_file, + bool can_throw, + bool finalizable, + QuickEntrypointEnum entrypoint) + : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc), + type_index_(type_index), + dex_file_(dex_file), + can_throw_(can_throw), + finalizable_(finalizable), + entrypoint_(entrypoint) { + SetRawInputAt(0, cls); + SetRawInputAt(1, current_method); + } + + uint16_t GetTypeIndex() const { return type_index_; } + const DexFile& GetDexFile() const { return dex_file_; } + + // Calls runtime so needs an environment. + bool NeedsEnvironment() const OVERRIDE { return true; } + + // It may throw when called on type that's not instantiable/accessible. + // It can throw OOME. + // TODO: distinguish between the two cases so we can for example allow allocation elimination. + bool CanThrow() const OVERRIDE { return can_throw_ || true; } + + bool IsFinalizable() const { return finalizable_; } + + bool CanBeNull() const OVERRIDE { return false; } + + QuickEntrypointEnum GetEntrypoint() const { return entrypoint_; } + + void SetEntrypoint(QuickEntrypointEnum entrypoint) { + entrypoint_ = entrypoint; + } + + bool IsStringAlloc() const; + + DECLARE_INSTRUCTION(NewInstance); + + private: + const uint16_t type_index_; + const DexFile& dex_file_; + const bool can_throw_; + const bool finalizable_; + QuickEntrypointEnum entrypoint_; + + DISALLOW_COPY_AND_ASSIGN(HNewInstance); +}; + enum class Intrinsics { #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \ k ## Name, @@ -3545,10 +3598,9 @@ class HInvokeStaticOrDirect : public HInvoke { // Get the index of the special input, if any. // - // If the invoke IsStringInit(), it initially has a HFakeString special argument - // which is removed by the instruction simplifier; if the invoke HasCurrentMethodInput(), - // the "special input" is the current method pointer; otherwise there may be one - // platform-specific special input, such as PC-relative addressing base. + // If the invoke HasCurrentMethodInput(), the "special input" is the current + // method pointer; otherwise there may be one platform-specific special input, + // such as PC-relative addressing base. uint32_t GetSpecialInputIndex() const { return GetNumberOfArguments(); } InvokeType GetOptimizedInvokeType() const { return optimized_invoke_type_; } @@ -3622,20 +3674,18 @@ class HInvokeStaticOrDirect : public HInvoke { DCHECK(!IsStaticWithExplicitClinitCheck()); } - bool IsStringFactoryFor(HFakeString* str) const { - if (!IsStringInit()) return false; - DCHECK(!HasCurrentMethodInput()); - if (InputCount() == (number_of_arguments_)) return false; - return InputAt(InputCount() - 1)->AsFakeString() == str; + HNewInstance* GetThisArgumentOfStringInit() const { + DCHECK(IsStringInit()); + size_t index = InputCount() - 1; + DCHECK(InputAt(index)->IsNewInstance()); + return InputAt(index)->AsNewInstance(); } - void RemoveFakeStringArgumentAsLastInput() { + void RemoveThisArgumentOfStringInit() { DCHECK(IsStringInit()); - size_t last_input_index = InputCount() - 1; - HInstruction* last_input = InputAt(last_input_index); - DCHECK(last_input != nullptr); - DCHECK(last_input->IsFakeString()) << last_input->DebugName(); - RemoveAsUserOfInput(last_input_index); + size_t index = InputCount() - 1; + DCHECK(InputAt(index)->IsNewInstance()); + RemoveAsUserOfInput(index); inputs_.pop_back(); } @@ -3743,59 +3793,6 @@ class HInvokeInterface : public HInvoke { DISALLOW_COPY_AND_ASSIGN(HInvokeInterface); }; -class HNewInstance : public HExpression<2> { - public: - HNewInstance(HInstruction* cls, - HCurrentMethod* current_method, - uint32_t dex_pc, - uint16_t type_index, - const DexFile& dex_file, - bool can_throw, - bool finalizable, - QuickEntrypointEnum entrypoint) - : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc), - type_index_(type_index), - dex_file_(dex_file), - can_throw_(can_throw), - finalizable_(finalizable), - entrypoint_(entrypoint) { - SetRawInputAt(0, cls); - SetRawInputAt(1, current_method); - } - - uint16_t GetTypeIndex() const { return type_index_; } - const DexFile& GetDexFile() const { return dex_file_; } - - // Calls runtime so needs an environment. - bool NeedsEnvironment() const OVERRIDE { return true; } - - // It may throw when called on type that's not instantiable/accessible. - // It can throw OOME. - // TODO: distinguish between the two cases so we can for example allow allocation elimination. - bool CanThrow() const OVERRIDE { return can_throw_ || true; } - - bool IsFinalizable() const { return finalizable_; } - - bool CanBeNull() const OVERRIDE { return false; } - - QuickEntrypointEnum GetEntrypoint() const { return entrypoint_; } - - void SetEntrypoint(QuickEntrypointEnum entrypoint) { - entrypoint_ = entrypoint; - } - - DECLARE_INSTRUCTION(NewInstance); - - private: - const uint16_t type_index_; - const DexFile& dex_file_; - const bool can_throw_; - const bool finalizable_; - QuickEntrypointEnum entrypoint_; - - DISALLOW_COPY_AND_ASSIGN(HNewInstance); -}; - class HNeg : public HUnaryOperation { public: HNeg(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc) @@ -5574,26 +5571,6 @@ class HMonitorOperation : public HTemplateInstruction<1> { DISALLOW_COPY_AND_ASSIGN(HMonitorOperation); }; -/** - * A HInstruction used as a marker for the replacement of new + <init> - * of a String to a call to a StringFactory. Only baseline will see - * the node at code generation, where it will be be treated as null. - * When compiling non-baseline, `HFakeString` instructions are being removed - * in the instruction simplifier. - */ -class HFakeString : public HTemplateInstruction<0> { - public: - explicit HFakeString(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::None(), dex_pc) {} - - Primitive::Type GetType() const OVERRIDE { return Primitive::kPrimNot; } - - DECLARE_INSTRUCTION(FakeString); - - private: - DISALLOW_COPY_AND_ASSIGN(HFakeString); -}; - class MoveOperands : public ArenaObject<kArenaAllocMoveOperands> { public: MoveOperands(Location source, diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 1c25e4824c..527c242916 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -58,7 +58,6 @@ class RTPVisitor : public HGraphDelegateVisitor { void VisitCheckCast(HCheckCast* instr) OVERRIDE; void VisitBoundType(HBoundType* instr) OVERRIDE; void VisitNullCheck(HNullCheck* instr) OVERRIDE; - void VisitFakeString(HFakeString* instr) OVERRIDE; void UpdateReferenceTypeInfo(HInstruction* instr, uint16_t type_idx, const DexFile& dex_file, @@ -568,10 +567,6 @@ void RTPVisitor::VisitNullCheck(HNullCheck* instr) { } } -void RTPVisitor::VisitFakeString(HFakeString* instr) { - instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true)); -} - void RTPVisitor::VisitBoundType(HBoundType* instr) { ScopedObjectAccess soa(Thread::Current()); diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index f6bab8efcb..96dc300b16 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -885,4 +885,22 @@ void SsaBuilder::VisitArraySet(HArraySet* aset) { VisitInstruction(aset); } +void SsaBuilder::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { + VisitInstruction(invoke); + + if (invoke->IsStringInit()) { + // This is a StringFactory call which acts as a String constructor. Its + // result replaces the empty String pre-allocated by NewInstance. + HNewInstance* new_instance = invoke->GetThisArgumentOfStringInit(); + invoke->RemoveThisArgumentOfStringInit(); + + // Walk over all vregs and replace any occurrence of `new_instance` with `invoke`. + for (size_t vreg = 0, e = current_locals_->size(); vreg < e; ++vreg) { + if ((*current_locals_)[vreg] == new_instance) { + (*current_locals_)[vreg] = invoke; + } + } + } +} + } // namespace art diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h index 0fcc3a1306..efe0dff4ed 100644 --- a/compiler/optimizing/ssa_builder.h +++ b/compiler/optimizing/ssa_builder.h @@ -70,13 +70,14 @@ class SsaBuilder : public HGraphVisitor { ArenaVector<HInstruction*>* GetLocalsFor(HBasicBlock* block); HInstruction* ValueOfLocal(HBasicBlock* block, size_t local); - void VisitBasicBlock(HBasicBlock* block); - void VisitLoadLocal(HLoadLocal* load); - void VisitStoreLocal(HStoreLocal* store); - void VisitInstruction(HInstruction* instruction); - void VisitTemporary(HTemporary* instruction); - void VisitArrayGet(HArrayGet* aget); - void VisitArraySet(HArraySet* aset); + void VisitBasicBlock(HBasicBlock* block) OVERRIDE; + void VisitLoadLocal(HLoadLocal* load) OVERRIDE; + void VisitStoreLocal(HStoreLocal* store) OVERRIDE; + void VisitInstruction(HInstruction* instruction) OVERRIDE; + void VisitTemporary(HTemporary* instruction) OVERRIDE; + void VisitArrayGet(HArrayGet* aget) OVERRIDE; + void VisitArraySet(HArraySet* aset) OVERRIDE; + void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE; static constexpr const char* kSsaBuilderPassName = "ssa_builder"; |