summaryrefslogtreecommitdiff
path: root/compiler/optimizing/builder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/builder.cc')
-rw-r--r--compiler/optimizing/builder.cc237
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;