diff options
Diffstat (limited to 'compiler/optimizing/builder.cc')
-rw-r--r-- | compiler/optimizing/builder.cc | 320 |
1 files changed, 81 insertions, 239 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 4dd0d26b89..1b62531cb1 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -32,114 +32,12 @@ #include "nodes.h" #include "primitive.h" #include "scoped_thread_state_change.h" +#include "ssa_builder.h" #include "thread.h" #include "utils/dex_cache_arrays_layout-inl.h" namespace art { -/** - * Helper class to add HTemporary instructions. This class is used when - * converting a DEX instruction to multiple HInstruction, and where those - * instructions do not die at the following instruction, but instead spans - * multiple instructions. - */ -class Temporaries : public ValueObject { - public: - explicit Temporaries(HGraph* graph) : graph_(graph), index_(0) {} - - void Add(HInstruction* instruction) { - HInstruction* temp = new (graph_->GetArena()) HTemporary(index_, instruction->GetDexPc()); - instruction->GetBlock()->AddInstruction(temp); - - DCHECK(temp->GetPrevious() == instruction); - - size_t offset; - if (instruction->GetType() == Primitive::kPrimLong - || instruction->GetType() == Primitive::kPrimDouble) { - offset = 2; - } else { - offset = 1; - } - index_ += offset; - - graph_->UpdateTemporariesVRegSlots(index_); - } - - private: - HGraph* const graph_; - - // Current index in the temporary stack, updated by `Add`. - size_t index_; -}; - -class SwitchTable : public ValueObject { - public: - SwitchTable(const Instruction& instruction, uint32_t dex_pc, bool sparse) - : instruction_(instruction), dex_pc_(dex_pc), sparse_(sparse) { - int32_t table_offset = instruction.VRegB_31t(); - const uint16_t* table = reinterpret_cast<const uint16_t*>(&instruction) + table_offset; - if (sparse) { - CHECK_EQ(table[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature)); - } else { - CHECK_EQ(table[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature)); - } - num_entries_ = table[1]; - values_ = reinterpret_cast<const int32_t*>(&table[2]); - } - - uint16_t GetNumEntries() const { - return num_entries_; - } - - void CheckIndex(size_t index) const { - if (sparse_) { - // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order. - DCHECK_LT(index, 2 * static_cast<size_t>(num_entries_)); - } else { - // In a packed table, we have the starting key and num_entries_ values. - DCHECK_LT(index, 1 + static_cast<size_t>(num_entries_)); - } - } - - int32_t GetEntryAt(size_t index) const { - CheckIndex(index); - return values_[index]; - } - - uint32_t GetDexPcForIndex(size_t index) const { - CheckIndex(index); - return dex_pc_ + - (reinterpret_cast<const int16_t*>(values_ + index) - - reinterpret_cast<const int16_t*>(&instruction_)); - } - - // Index of the first value in the table. - size_t GetFirstValueIndex() const { - if (sparse_) { - // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order. - return num_entries_; - } else { - // In a packed table, we have the starting key and num_entries_ values. - return 1; - } - } - - private: - const Instruction& instruction_; - const uint32_t dex_pc_; - - // Whether this is a sparse-switch table (or a packed-switch one). - const bool sparse_; - - // This can't be const as it needs to be computed off of the given instruction, and complicated - // expressions in the initializer list seemed very ugly. - uint16_t num_entries_; - - const int32_t* values_; - - DISALLOW_COPY_AND_ASSIGN(SwitchTable); -}; - void HGraphBuilder::InitializeLocals(uint16_t count) { graph_->SetNumberOfVRegs(count); locals_.resize(count); @@ -208,7 +106,6 @@ void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_pc) { HBasicBlock* fallthrough_target = FindBlockStartingAt(dex_pc + instruction.SizeInCodeUnits()); DCHECK(branch_target != nullptr); DCHECK(fallthrough_target != nullptr); - PotentiallyAddSuspendCheck(branch_target, dex_pc); HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc); HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc); T* comparison = new (arena_) T(first, second, dex_pc); @@ -227,7 +124,6 @@ void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_pc) { HBasicBlock* fallthrough_target = FindBlockStartingAt(dex_pc + instruction.SizeInCodeUnits()); DCHECK(branch_target != nullptr); DCHECK(fallthrough_target != nullptr); - PotentiallyAddSuspendCheck(branch_target, dex_pc); HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc); T* comparison = new (arena_) T(value, graph_->GetIntConstant(0, dex_pc), dex_pc); current_block_->AddInstruction(comparison); @@ -247,8 +143,8 @@ void HGraphBuilder::MaybeRecordStat(MethodCompilationStat compilation_stat) { bool HGraphBuilder::SkipCompilation(const DexFile::CodeItem& code_item, size_t number_of_branches) { const CompilerOptions& compiler_options = compiler_driver_->GetCompilerOptions(); - CompilerOptions::CompilerFilter compiler_filter = compiler_options.GetCompilerFilter(); - if (compiler_filter == CompilerOptions::kEverything) { + CompilerFilter::Filter compiler_filter = compiler_options.GetCompilerFilter(); + if (compiler_filter == CompilerFilter::kEverything) { return false; } @@ -351,7 +247,7 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) // loop for synchronized blocks. if (block->HasThrowingInstructions()) { // Try to find a TryItem covering the block. - DCHECK_NE(block->GetDexPc(), kNoDexPc) << "Block must have a dec_pc to find its TryItem."; + DCHECK_NE(block->GetDexPc(), kNoDexPc) << "Block must have a dex_pc to find its TryItem."; const int32_t try_item_idx = DexFile::FindTryItem(code_item, block->GetDexPc()); if (try_item_idx != -1) { // Block throwing and in a TryItem. Store the try block information. @@ -384,7 +280,7 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) // Found a predecessor not covered by the same TryItem. Insert entering // boundary block. HTryBoundary* try_entry = - new (arena_) HTryBoundary(HTryBoundary::kEntry, try_block->GetDexPc()); + new (arena_) HTryBoundary(HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc()); try_block->CreateImmediateDominator()->AddInstruction(try_entry); LinkToCatchBlocks(try_entry, code_item, entry.second); break; @@ -418,14 +314,15 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) // Insert TryBoundary and link to catch blocks. HTryBoundary* try_exit = - new (arena_) HTryBoundary(HTryBoundary::kExit, successor->GetDexPc()); + new (arena_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc()); graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit); LinkToCatchBlocks(try_exit, code_item, entry.second); } } } -bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { +GraphAnalysisResult HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item, + StackHandleScopeCollection* handles) { DCHECK(graph_->GetBlocks().empty()); const uint16_t* code_ptr = code_item.insns_; @@ -452,12 +349,12 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { // start a new block, and create these blocks. if (!ComputeBranchTargets(code_ptr, code_end, &number_of_branches)) { MaybeRecordStat(MethodCompilationStat::kNotCompiledBranchOutsideMethodCode); - return false; + return kAnalysisInvalidBytecode; } // Note that the compiler driver is null when unit testing. if ((compiler_driver_ != nullptr) && SkipCompilation(code_item, number_of_branches)) { - return false; + return kAnalysisInvalidBytecode; } // Find locations where we want to generate extra stackmaps for native debugging. @@ -468,8 +365,8 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { ArenaBitVector* native_debug_info_locations; if (native_debuggable) { const uint32_t num_instructions = code_item.insns_size_in_code_units_; - native_debug_info_locations = new (arena_) ArenaBitVector (arena_, num_instructions, false); - native_debug_info_locations->ClearAllBits(); + native_debug_info_locations = + ArenaBitVector::Create(arena_, num_instructions, false, kArenaAllocGraphBuilder); FindNativeDebugInfoLocations(code_item, native_debug_info_locations); } @@ -488,7 +385,7 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { } } if (!AnalyzeDexInstruction(instruction, dex_pc)) { - return false; + return kAnalysisInvalidBytecode; } dex_pc += instruction.SizeInCodeUnits(); code_ptr += instruction.SizeInCodeUnits(); @@ -507,7 +404,13 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { // non-exceptional edges to have been created. InsertTryBoundaryBlocks(code_item); - return true; + GraphAnalysisResult result = graph_->BuildDominatorTree(); + if (result != kAnalysisSuccess) { + return result; + } + + graph_->InitializeInexactObjectRTI(handles); + return SsaBuilder(graph_, handles).BuildSsa(); } void HGraphBuilder::MaybeUpdateCurrentBlock(size_t dex_pc) { @@ -538,23 +441,15 @@ void HGraphBuilder::FindNativeDebugInfoLocations(const DexFile::CodeItem& code_i } }; dex_file_->DecodeDebugPositionInfo(&code_item, Callback::Position, locations); - // Add native debug info at the start of every basic block. - for (uint32_t pc = 0; pc < code_item.insns_size_in_code_units_; pc++) { - if (FindBlockStartingAt(pc) != nullptr) { - locations->SetBit(pc); - } - } // Instruction-specific tweaks. const Instruction* const begin = Instruction::At(code_item.insns_); const Instruction* const end = begin->RelativeAt(code_item.insns_size_in_code_units_); for (const Instruction* inst = begin; inst < end; inst = inst->Next()) { switch (inst->Opcode()) { - case Instruction::MOVE_EXCEPTION: - case Instruction::MOVE_RESULT: - case Instruction::MOVE_RESULT_WIDE: - case Instruction::MOVE_RESULT_OBJECT: { - // The compiler checks that there are no instructions before those. - // So generate HNativeDebugInfo after them instead. + case Instruction::MOVE_EXCEPTION: { + // Stop in native debugger after the exception has been moved. + // The compiler also expects the move at the start of basic block so + // we do not want to interfere by inserting native-debug-info before it. locations->ClearBit(inst->GetDexPc(code_item.insns_)); const Instruction* next = inst->Next(); if (next < end) { @@ -798,7 +693,7 @@ static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) { ArtMethod* HGraphBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_type) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); + StackHandleScope<3> hs(soa.Self()); ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker(); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( @@ -833,31 +728,56 @@ ArtMethod* HGraphBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_t } // We have to special case the invoke-super case, as ClassLinker::ResolveMethod does not. - // We need to look at the referrer's super class vtable. + // We need to look at the referrer's super class vtable. We need to do this to know if we need to + // make this an invoke-unresolved to handle cross-dex invokes or abstract super methods, both of + // which require runtime handling. if (invoke_type == kSuper) { if (compiling_class.Get() == nullptr) { - // Invoking a super method requires knowing the actual super class. If we did not resolve - // the compiling method's declaring class (which only happens for ahead of time compilation), - // bail out. + // We could not determine the method's class we need to wait until runtime. DCHECK(Runtime::Current()->IsAotCompiler()); return nullptr; } - uint16_t vtable_index = resolved_method->GetMethodIndex(); - ArtMethod* actual_method = compiling_class->GetSuperClass()->GetVTableEntry( - vtable_index, class_linker->GetImagePointerSize()); - if (actual_method != resolved_method && - !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { - // TODO: The actual method could still be referenced in the current dex file, so we - // could try locating it. - // TODO: Remove the dex_file restriction. - return nullptr; - } - if (!actual_method->IsInvokable()) { - // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub - // could resolve the callee to the wrong method. + ArtMethod* current_method = graph_->GetArtMethod(); + DCHECK(current_method != nullptr); + Handle<mirror::Class> methods_class(hs.NewHandle( + dex_compilation_unit_->GetClassLinker()->ResolveReferencedClassOfMethod(Thread::Current(), + method_idx, + current_method))); + if (methods_class.Get() == nullptr) { + // Invoking a super method requires knowing the actual super class. If we did not resolve + // the compiling method's declaring class (which only happens for ahead of time + // compilation), bail out. + DCHECK(Runtime::Current()->IsAotCompiler()); return nullptr; + } else { + ArtMethod* actual_method; + if (methods_class->IsInterface()) { + actual_method = methods_class->FindVirtualMethodForInterfaceSuper( + resolved_method, class_linker->GetImagePointerSize()); + } else { + uint16_t vtable_index = resolved_method->GetMethodIndex(); + actual_method = compiling_class->GetSuperClass()->GetVTableEntry( + vtable_index, class_linker->GetImagePointerSize()); + } + if (actual_method != resolved_method && + !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { + // The back-end code generator relies on this check in order to ensure that it will not + // attempt to read the dex_cache with a dex_method_index that is not from the correct + // dex_file. If we didn't do this check then the dex_method_index will not be updated in the + // builder, which means that the code-generator (and compiler driver during sharpening and + // inliner, maybe) might invoke an incorrect method. + // TODO: The actual method could still be referenced in the current dex file, so we + // could try locating it. + // TODO: Remove the dex_file restriction. + return nullptr; + } + if (!actual_method->IsInvokable()) { + // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub + // could resolve the callee to the wrong method. + return nullptr; + } + resolved_method = actual_method; } - resolved_method = actual_method; } // Check for incompatible class changes. The class linker has a fast path for @@ -923,7 +843,7 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, ArtMethod* resolved_method = ResolveMethod(method_idx, invoke_type); - if (resolved_method == nullptr) { + if (UNLIKELY(resolved_method == nullptr)) { MaybeRecordStat(MethodCompilationStat::kUnresolvedMethod); HInvoke* invoke = new (arena_) HInvokeUnresolved(arena_, number_of_arguments, @@ -943,7 +863,6 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, // Potential class initialization check, in the case of a static method call. HClinitCheck* clinit_check = nullptr; HInvoke* invoke = nullptr; - if (invoke_type == kDirect || invoke_type == kStatic || invoke_type == kSuper) { // By default, consider that the called method implicitly requires // an initialization check of its declaring method. @@ -1210,12 +1129,10 @@ bool HGraphBuilder::HandleInvoke(HInvoke* invoke, size_t start_index = 0; size_t argument_index = 0; if (invoke->GetOriginalInvokeType() != InvokeType::kStatic) { // Instance call. - Temporaries temps(graph_); HInstruction* arg = LoadLocal( is_range ? register_index : args[0], Primitive::kPrimNot, invoke->GetDexPc()); HNullCheck* null_check = new (arena_) HNullCheck(arg, invoke->GetDexPc()); current_block_->AddInstruction(null_check); - temps.Add(null_check); invoke->SetArgumentAt(0, null_check); start_index = 1; argument_index = 1; @@ -1271,44 +1188,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); @@ -1343,9 +1230,6 @@ bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction, ? GetFieldAccessType(*dex_file_, field_index) : resolved_field->GetTypeAsPrimitiveType(); if (is_put) { - Temporaries temps(graph_); - // We need one temporary for the null check. - temps.Add(null_check); HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc); HInstruction* field_set = nullptr; if (resolved_field == nullptr) { @@ -1530,8 +1414,6 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, uint16_t class_def_index = klass->GetDexClassDefIndex(); if (is_put) { // We need to keep the class alive before loading the value. - Temporaries temps(graph_); - temps.Add(cls); HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc); DCHECK_EQ(value->GetType(), field_type); current_block_->AddInstruction(new (arena_) HStaticFieldSet(cls, @@ -1584,9 +1466,7 @@ void HGraphBuilder::BuildCheckedDivRem(uint16_t out_vreg, || (type == Primitive::kPrimInt && second->AsIntConstant()->GetValue() == 0) || (type == Primitive::kPrimLong && second->AsLongConstant()->GetValue() == 0)) { second = new (arena_) HDivZeroCheck(second, dex_pc); - Temporaries temps(graph_); current_block_->AddInstruction(second); - temps.Add(current_block_->GetLastInstruction()); } if (isDiv) { @@ -1605,21 +1485,15 @@ void HGraphBuilder::BuildArrayAccess(const Instruction& instruction, uint8_t array_reg = instruction.VRegB_23x(); uint8_t index_reg = instruction.VRegC_23x(); - // We need one temporary for the null check, one for the index, and one for the length. - Temporaries temps(graph_); - HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot, dex_pc); object = new (arena_) HNullCheck(object, dex_pc); current_block_->AddInstruction(object); - temps.Add(object); HInstruction* length = new (arena_) HArrayLength(object, dex_pc); current_block_->AddInstruction(length); - temps.Add(length); HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt, dex_pc); index = new (arena_) HBoundsCheck(index, length, dex_pc); current_block_->AddInstruction(index); - temps.Add(index); if (is_put) { HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type, dex_pc); // TODO: Insert a type check node if the type is Object. @@ -1660,8 +1534,6 @@ void HGraphBuilder::BuildFilledNewArray(uint32_t dex_pc, bool is_reference_array = (primitive == 'L') || (primitive == '['); Primitive::Type type = is_reference_array ? Primitive::kPrimNot : Primitive::kPrimInt; - Temporaries temps(graph_); - temps.Add(object); for (size_t i = 0; i < number_of_vreg_arguments; ++i) { HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc); HInstruction* index = graph_->GetIntConstant(i, dex_pc); @@ -1686,11 +1558,9 @@ void HGraphBuilder::BuildFillArrayData(HInstruction* object, } void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc) { - Temporaries temps(graph_); HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot, dex_pc); HNullCheck* null_check = new (arena_) HNullCheck(array, dex_pc); current_block_->AddInstruction(null_check); - temps.Add(null_check); HInstruction* length = new (arena_) HArrayLength(null_check, dex_pc); current_block_->AddInstruction(length); @@ -1807,17 +1677,18 @@ void HGraphBuilder::BuildTypeCheck(const Instruction& instruction, compiler_driver_->CanAssumeTypeIsPresentInDexCache(dex_file, type_index)); current_block_->AddInstruction(cls); - // The class needs a temporary before being used by the type check. - Temporaries temps(graph_); - temps.Add(cls); - TypeCheckKind check_kind = ComputeTypeCheckKind(resolved_class); if (instruction.Opcode() == Instruction::INSTANCE_OF) { current_block_->AddInstruction(new (arena_) HInstanceOf(object, cls, check_kind, dex_pc)); UpdateLocal(destination, current_block_->GetLastInstruction(), dex_pc); } else { DCHECK_EQ(instruction.Opcode(), Instruction::CHECK_CAST); + // We emit a CheckCast followed by a BoundType. CheckCast is a statement + // which may throw. If it succeeds BoundType sets the new type of `object` + // for all subsequent uses. current_block_->AddInstruction(new (arena_) HCheckCast(object, cls, check_kind, dex_pc)); + current_block_->AddInstruction(new (arena_) HBoundType(object, dex_pc)); + UpdateLocal(reference, current_block_->GetLastInstruction(), dex_pc); } } @@ -1915,7 +1786,6 @@ void HGraphBuilder::BuildSwitchCaseHelper(const Instruction& instruction, size_t int32_t target_offset, uint32_t dex_pc) { HBasicBlock* case_target = FindBlockStartingAt(dex_pc + target_offset); DCHECK(case_target != nullptr); - PotentiallyAddSuspendCheck(case_target, dex_pc); // The current case's value. HInstruction* this_case_value = graph_->GetIntConstant(case_value_int, dex_pc); @@ -1951,23 +1821,6 @@ void HGraphBuilder::BuildSwitchCaseHelper(const Instruction& instruction, size_t } } -void HGraphBuilder::PotentiallyAddSuspendCheck(HBasicBlock* target, uint32_t dex_pc) { - int32_t target_offset = target->GetDexPc() - dex_pc; - if (target_offset <= 0) { - // DX generates back edges to the first encountered return. We can save - // time of later passes by not adding redundant suspend checks. - HInstruction* last_in_target = target->GetLastInstruction(); - if (last_in_target != nullptr && - (last_in_target->IsReturn() || last_in_target->IsReturnVoid())) { - return; - } - - // Add a suspend check to backward branches which may potentially loop. We - // can remove them after we recognize loops in the graph. - current_block_->AddInstruction(new (arena_) HSuspendCheck(dex_pc)); - } -} - bool HGraphBuilder::CanDecodeQuickenedInfo() const { return interpreter_metadata_ != nullptr; } @@ -2099,7 +1952,6 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 int32_t offset = instruction.GetTargetOffset(); HBasicBlock* target = FindBlockStartingAt(offset + dex_pc); DCHECK(target != nullptr); - PotentiallyAddSuspendCheck(target, dex_pc); current_block_->AddInstruction(new (arena_) HGoto(dex_pc)); current_block_->AddSuccessor(target); current_block_ = nullptr; @@ -2693,18 +2545,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; } @@ -2892,8 +2736,6 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::ARRAY_LENGTH: { HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot, dex_pc); - // No need for a temporary for the null check, it is the only input of the following - // instruction. object = new (arena_) HNullCheck(object, dex_pc); current_block_->AddInstruction(object); current_block_->AddInstruction(new (arena_) HArrayLength(object, dex_pc)); @@ -2981,7 +2823,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::MONITOR_ENTER: { current_block_->AddInstruction(new (arena_) HMonitorOperation( LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc), - HMonitorOperation::kEnter, + HMonitorOperation::OperationKind::kEnter, dex_pc)); break; } @@ -2989,7 +2831,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::MONITOR_EXIT: { current_block_->AddInstruction(new (arena_) HMonitorOperation( LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc), - HMonitorOperation::kExit, + HMonitorOperation::OperationKind::kExit, dex_pc)); break; } |