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.cc300
1 files changed, 199 insertions, 101 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 7a3aa58149..274a2a699f 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());
@@ -398,8 +401,8 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item)
// Find predecessors which are not covered by the same TryItem range. Such
// edges enter the try block and will have a TryBoundary inserted.
- for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) {
- HBasicBlock* predecessor = try_block->GetPredecessors().Get(i);
+ for (size_t i = 0; i < try_block->GetPredecessors().size(); ++i) {
+ HBasicBlock* predecessor = try_block->GetPredecessor(i);
if (predecessor->IsSingleTryBoundary()) {
// The edge was already split because of an exit from a neighbouring
// TryItem. We split it again and insert an entry point.
@@ -426,8 +429,7 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item)
// Find successors which are not covered by the same TryItem range. Such
// edges exit the try block and will have a TryBoundary inserted.
- for (size_t i = 0; i < try_block->GetSuccessors().Size(); ++i) {
- HBasicBlock* successor = try_block->GetSuccessors().Get(i);
+ for (HBasicBlock* successor : try_block->GetSuccessors()) {
if (successor->IsCatchBlock()) {
// A catch block is always considered an entry point into its TryItem.
// We therefore assume this is an exit point, regardless of whether
@@ -466,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_;
@@ -479,6 +481,8 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
graph_->SetEntryBlock(entry_block_);
graph_->SetExitBlock(exit_block_);
+ graph_->SetHasTryCatch(code_item.tries_size_ != 0);
+
InitializeLocals(code_item.registers_size_);
graph_->SetMaximumNumberOfOutVRegs(code_item.outs_size_);
@@ -796,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 */,
@@ -809,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,
@@ -877,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(
@@ -1032,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
@@ -1083,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";
@@ -1098,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);
@@ -1112,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;
@@ -1540,25 +1614,48 @@ void HGraphBuilder::BuildFillWideArrayData(HInstruction* object,
}
}
+static TypeCheckKind ComputeTypeCheckKind(Handle<mirror::Class> cls)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ if (cls->IsInterface()) {
+ return TypeCheckKind::kInterfaceCheck;
+ } else if (cls->IsArrayClass()) {
+ if (cls->GetComponentType()->IsObjectClass()) {
+ return TypeCheckKind::kArrayObjectCheck;
+ } else if (cls->CannotBeAssignedFromOtherTypes()) {
+ return TypeCheckKind::kExactCheck;
+ } else {
+ return TypeCheckKind::kArrayCheck;
+ }
+ } else if (cls->IsFinal()) {
+ return TypeCheckKind::kExactCheck;
+ } else if (cls->IsAbstract()) {
+ return TypeCheckKind::kAbstractClassCheck;
+ } else {
+ return TypeCheckKind::kClassHierarchyCheck;
+ }
+}
+
bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction,
uint8_t destination,
uint8_t reference,
uint16_t type_index,
uint32_t dex_pc) {
- bool type_known_final;
- bool type_known_abstract;
- // `CanAccessTypeWithoutChecks` will tell whether the method being
- // built is trying to access its own class, so that the generated
- // code can optimize for this case. However, the optimization does not
- // work for inlining, so we use `IsOutermostCompilingClass` instead.
- bool dont_use_is_referrers_class;
- bool can_access = compiler_driver_->CanAccessTypeWithoutChecks(
- dex_compilation_unit_->GetDexMethodIndex(), *dex_file_, type_index,
- &type_known_final, &type_known_abstract, &dont_use_is_referrers_class);
- if (!can_access) {
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(
+ dex_compilation_unit_->GetClassLinker()->FindDexCache(
+ soa.Self(), *dex_compilation_unit_->GetDexFile())));
+ Handle<mirror::Class> resolved_class(hs.NewHandle(dex_cache->GetResolvedType(type_index)));
+
+ if ((resolved_class.Get() == nullptr) ||
+ // TODO: Remove this check once the compiler actually knows which
+ // ArtMethod it is compiling.
+ (GetCompilingClass() == nullptr) ||
+ !GetCompilingClass()->CanAccess(resolved_class.Get())) {
MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType);
return false;
}
+
HInstruction* object = LoadLocal(reference, Primitive::kPrimNot, dex_pc);
HLoadClass* cls = new (arena_) HLoadClass(
graph_->GetCurrentMethod(),
@@ -1567,17 +1664,18 @@ bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction,
IsOutermostCompilingClass(type_index),
dex_pc);
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, type_known_final, dex_pc));
+ 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);
- current_block_->AddInstruction(
- new (arena_) HCheckCast(object, cls, type_known_final, dex_pc));
+ current_block_->AddInstruction(new (arena_) HCheckCast(object, cls, check_kind, dex_pc));
}
return true;
}