diff options
Diffstat (limited to 'compiler/optimizing/builder.cc')
-rw-r--r-- | compiler/optimizing/builder.cc | 300 |
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; } |