diff options
Diffstat (limited to 'compiler/optimizing/builder.cc')
| -rw-r--r-- | compiler/optimizing/builder.cc | 237 |
1 files changed, 155 insertions, 82 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 0a3f083e10..3012346a95 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -339,11 +339,13 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) // Bit vector stores information on which blocks contain throwing instructions. // Must be expandable because catch blocks may be split into two. - ArenaBitVector can_block_throw(arena_, graph_->GetBlocks().Size(), /* expandable */ true); + ArenaBitVector can_block_throw(arena_, graph_->GetBlocks().size(), /* expandable */ true); // Scan blocks and mark those which contain throwing instructions. - for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) { - HBasicBlock* block = graph_->GetBlocks().Get(block_id); + // NOTE: We're appending new blocks inside the loop, so we need to use index because iterators + // can be invalidated. We remember the initial size to avoid iterating over the new blocks. + for (size_t block_id = 0u, end = graph_->GetBlocks().size(); block_id != end; ++block_id) { + HBasicBlock* block = graph_->GetBlocks()[block_id]; bool can_throw = false; for (HInstructionIterator insn(block->GetInstructions()); !insn.Done(); insn.Advance()) { if (insn.Current()->CanThrow()) { @@ -381,9 +383,10 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) // (c) link the new blocks to corresponding exception handlers. // We cannot iterate only over blocks in `branch_targets_` because switch-case // blocks share the same dex_pc. - for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) { - HBasicBlock* try_block = graph_->GetBlocks().Get(block_id); - + // NOTE: We're appending new blocks inside the loop, so we need to use index because iterators + // can be invalidated. We remember the initial size to avoid iterating over the new blocks. + for (size_t block_id = 0u, end = graph_->GetBlocks().size(); block_id != end; ++block_id) { + HBasicBlock* try_block = graph_->GetBlocks()[block_id]; // TryBoundary blocks are added at the end of the list and not iterated over. DCHECK(!try_block->IsSingleTryBoundary()); @@ -465,7 +468,7 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) } bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { - DCHECK(graph_->GetBlocks().IsEmpty()); + DCHECK(graph_->GetBlocks().empty()); const uint16_t* code_ptr = code_item.insns_; const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_; @@ -797,10 +800,42 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, } MethodReference target_method(dex_file_, method_idx); - int32_t table_index; - uintptr_t direct_code; - uintptr_t direct_method; + int32_t table_index = 0; + uintptr_t direct_code = 0; + uintptr_t direct_method = 0; + // Special handling for string init. + int32_t string_init_offset = 0; + bool is_string_init = compiler_driver_->IsStringInit(method_idx, + dex_file_, + &string_init_offset); + // Replace calls to String.<init> with StringFactory. + if (is_string_init) { + HInvokeStaticOrDirect::DispatchInfo dispatch_info = ComputeDispatchInfo(is_string_init, + string_init_offset, + target_method, + direct_method, + direct_code); + HInvoke* invoke = new (arena_) HInvokeStaticOrDirect( + arena_, + number_of_arguments - 1, + Primitive::kPrimNot /*return_type */, + dex_pc, + method_idx, + target_method, + dispatch_info, + original_invoke_type, + kStatic /* optimized_invoke_type */, + HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit); + return HandleStringInit(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor); + } + + // Handle unresolved methods. if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, true /* update_stats */, @@ -810,42 +845,39 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, &table_index, &direct_code, &direct_method)) { - VLOG(compiler) << "Did not compile " - << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) - << " because a method call could not be resolved"; - MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedMethod); - return false; - } + MaybeRecordStat(MethodCompilationStat::kUnresolvedMethod); + HInvoke* invoke = new (arena_) HInvokeUnresolved(arena_, + number_of_arguments, + return_type, + dex_pc, + method_idx, + original_invoke_type); + return HandleInvoke(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + nullptr /* clinit_check */); + } + + // Handle resolved methods (non string init). DCHECK(optimized_invoke_type != kSuper); - // Special handling for string init. - int32_t string_init_offset = 0; - bool is_string_init = compiler_driver_->IsStringInit(method_idx, dex_file_, - &string_init_offset); - // Potential class initialization check, in the case of a static method call. HClinitCheck* clinit_check = nullptr; HInvoke* invoke = nullptr; - if (is_string_init - || optimized_invoke_type == kDirect - || optimized_invoke_type == kStatic) { + if (optimized_invoke_type == kDirect || optimized_invoke_type == kStatic) { // By default, consider that the called method implicitly requires // an initialization check of its declaring method. HInvokeStaticOrDirect::ClinitCheckRequirement clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit; - if (optimized_invoke_type == kStatic && !is_string_init) { + if (optimized_invoke_type == kStatic) { clinit_check = ProcessClinitCheckForInvoke(dex_pc, method_idx, &clinit_check_requirement); } - // Replace calls to String.<init> with StringFactory. - if (is_string_init) { - return_type = Primitive::kPrimNot; - number_of_arguments--; - optimized_invoke_type = kStatic; - } - HInvokeStaticOrDirect::DispatchInfo dispatch_info = ComputeDispatchInfo(is_string_init, string_init_offset, target_method, @@ -878,13 +910,13 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, table_index); } - return SetupArgumentsAndAddInvoke(invoke, - number_of_vreg_arguments, - args, - register_index, - is_range, - descriptor, - clinit_check); + return HandleInvoke(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + clinit_check); } HClinitCheck* HGraphBuilder::ProcessClinitCheckForInvoke( @@ -1033,42 +1065,23 @@ HInvokeStaticOrDirect::DispatchInfo HGraphBuilder::ComputeDispatchInfo( method_load_kind, code_ptr_location, method_load_data, direct_code_ptr }; } -bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke, - uint32_t number_of_vreg_arguments, - uint32_t* args, - uint32_t register_index, - bool is_range, - const char* descriptor, - HClinitCheck* clinit_check) { - size_t start_index = 0; - size_t argument_index = 0; +bool HGraphBuilder::SetupInvokeArguments(HInvoke* invoke, + uint32_t number_of_vreg_arguments, + uint32_t* args, + uint32_t register_index, + bool is_range, + const char* descriptor, + size_t start_index, + size_t* argument_index) { uint32_t descriptor_index = 1; // Skip the return type. uint32_t dex_pc = invoke->GetDexPc(); - bool is_instance_call = invoke->GetOriginalInvokeType() != InvokeType::kStatic; - bool is_string_init = invoke->IsInvokeStaticOrDirect() - && invoke->AsInvokeStaticOrDirect()->IsStringInit(); - - if (is_string_init) { - start_index = 1; - argument_index = 0; - } else if (is_instance_call) { - Temporaries temps(graph_); - HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot, dex_pc); - 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; - } - for (size_t i = start_index; // Make sure we don't go over the expected arguments or over the number of // dex registers given. If the instruction was seen as dead by the verifier, // it hasn't been properly checked. - (i < number_of_vreg_arguments) && (argument_index < invoke->GetNumberOfArguments()); - i++, argument_index++) { + (i < number_of_vreg_arguments) && (*argument_index < invoke->GetNumberOfArguments()); + i++, (*argument_index)++) { Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]); bool is_wide = (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble); if (!is_range @@ -1084,13 +1097,13 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke, return false; } HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc); - invoke->SetArgumentAt(argument_index, arg); + invoke->SetArgumentAt(*argument_index, arg); if (is_wide) { i++; } } - if (argument_index != invoke->GetNumberOfArguments()) { + if (*argument_index != invoke->GetNumberOfArguments()) { VLOG(compiler) << "Did not compile " << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) << " because of wrong number of arguments in invoke instruction"; @@ -1099,13 +1112,49 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke, } if (invoke->IsInvokeStaticOrDirect()) { - invoke->SetArgumentAt(argument_index, graph_->GetCurrentMethod()); - argument_index++; + invoke->SetArgumentAt(*argument_index, graph_->GetCurrentMethod()); + (*argument_index)++; + } + + return true; +} + +bool HGraphBuilder::HandleInvoke(HInvoke* invoke, + uint32_t number_of_vreg_arguments, + uint32_t* args, + uint32_t register_index, + bool is_range, + const char* descriptor, + HClinitCheck* clinit_check) { + DCHECK(!invoke->IsInvokeStaticOrDirect() || !invoke->AsInvokeStaticOrDirect()->IsStringInit()); + + 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; + } + + if (!SetupInvokeArguments(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + start_index, + &argument_index)) { + return false; } if (clinit_check != nullptr) { // Add the class initialization check as last input of `invoke`. - DCHECK(!is_string_init); DCHECK(invoke->IsInvokeStaticOrDirect()); DCHECK(invoke->AsInvokeStaticOrDirect()->GetClinitCheckRequirement() == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit); @@ -1113,17 +1162,41 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke, argument_index++; } - // Add move-result for StringFactory method. - if (is_string_init) { - uint32_t orig_this_reg = is_range ? register_index : args[0]; - HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot, dex_pc); - invoke->SetArgumentAt(argument_index, fake_string); - current_block_->AddInstruction(invoke); - PotentiallySimplifyFakeString(orig_this_reg, invoke->GetDexPc(), invoke); - } else { - current_block_->AddInstruction(invoke); + current_block_->AddInstruction(invoke); + latest_result_ = invoke; + + return true; +} + +bool HGraphBuilder::HandleStringInit(HInvoke* invoke, + uint32_t number_of_vreg_arguments, + uint32_t* args, + uint32_t register_index, + bool is_range, + const char* descriptor) { + DCHECK(invoke->IsInvokeStaticOrDirect()); + DCHECK(invoke->AsInvokeStaticOrDirect()->IsStringInit()); + + size_t start_index = 1; + size_t argument_index = 0; + if (!SetupInvokeArguments(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + start_index, + &argument_index)) { + return false; } + // 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); + current_block_->AddInstruction(invoke); + PotentiallySimplifyFakeString(orig_this_reg, invoke->GetDexPc(), invoke); + latest_result_ = invoke; return true; |