diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/builder.cc | 477 | ||||
| -rw-r--r-- | compiler/optimizing/builder.h | 13 | ||||
| -rw-r--r-- | compiler/optimizing/dead_code_elimination.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 62 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.h | 6 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics.cc | 16 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm64.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_list.h | 134 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86_64.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 38 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 4 |
13 files changed, 431 insertions, 336 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index a8f6a24908..7b42db8a7f 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -759,33 +759,214 @@ void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type current_block_ = nullptr; } -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; +static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) { + switch (opcode) { + case Instruction::INVOKE_STATIC: + case Instruction::INVOKE_STATIC_RANGE: + return kStatic; + case Instruction::INVOKE_DIRECT: + case Instruction::INVOKE_DIRECT_RANGE: + return kDirect; + case Instruction::INVOKE_VIRTUAL: + case Instruction::INVOKE_VIRTUAL_QUICK: + case Instruction::INVOKE_VIRTUAL_RANGE: + case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: + return kVirtual; + case Instruction::INVOKE_INTERFACE: + case Instruction::INVOKE_INTERFACE_RANGE: + return kInterface; + case Instruction::INVOKE_SUPER_RANGE: + case Instruction::INVOKE_SUPER: + return kSuper; + default: + LOG(FATAL) << "Unexpected invoke opcode: " << opcode; + UNREACHABLE(); } - const VerifiedMethod* verified_method = - compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex()); - if (verified_method != nullptr) { - UpdateLocal(original_dex_register, actual_string); - 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()) { - std::set<uint32_t> reg_set = map_it->second; - for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) { - HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot); - UpdateLocal(*set_it, load_local); - } +} + +bool HGraphBuilder::BuildInvoke(const Instruction& instruction, + uint32_t dex_pc, + uint32_t method_idx, + uint32_t number_of_vreg_arguments, + bool is_range, + uint32_t* args, + uint32_t register_index) { + InvokeType original_invoke_type = GetInvokeTypeFromOpCode(instruction.Opcode()); + InvokeType optimized_invoke_type = original_invoke_type; + const char* descriptor = dex_file_->GetMethodShorty(method_idx); + Primitive::Type return_type = Primitive::GetType(descriptor[0]); + + // Remove the return type from the 'proto'. + size_t number_of_arguments = strlen(descriptor) - 1; + if (original_invoke_type != kStatic) { // instance call + // One extra argument for 'this'. + number_of_arguments++; + } + + MethodReference target_method(dex_file_, method_idx); + int32_t table_index; + uintptr_t direct_code; + uintptr_t direct_method; + + if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, + dex_pc, + true /* update_stats */, + true /* enable_devirtualization */, + &optimized_invoke_type, + &target_method, + &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; + } + + 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) { + // 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) { + 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, + direct_method, + direct_code); + invoke = new (arena_) HInvokeStaticOrDirect(arena_, + number_of_arguments, + return_type, + dex_pc, + method_idx, + target_method, + dispatch_info, + original_invoke_type, + optimized_invoke_type, + clinit_check_requirement); + } else if (optimized_invoke_type == kVirtual) { + invoke = new (arena_) HInvokeVirtual(arena_, + number_of_arguments, + return_type, + dex_pc, + method_idx, + table_index); } else { - can_use_baseline_for_string_init_ = false; + DCHECK_EQ(optimized_invoke_type, kInterface); + invoke = new (arena_) HInvokeInterface(arena_, + number_of_arguments, + return_type, + dex_pc, + method_idx, + table_index); + } + + return SetupArgumentsAndAddInvoke(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + clinit_check); +} + +HClinitCheck* HGraphBuilder::ProcessClinitCheckForInvoke( + uint32_t dex_pc, + uint32_t method_idx, + HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement) { + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<4> hs(soa.Self()); + Handle<mirror::DexCache> dex_cache(hs.NewHandle( + dex_compilation_unit_->GetClassLinker()->FindDexCache( + *dex_compilation_unit_->GetDexFile()))); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader()))); + ArtMethod* resolved_method = compiler_driver_->ResolveMethod( + soa, dex_cache, class_loader, dex_compilation_unit_, method_idx, InvokeType::kStatic); + + DCHECK(resolved_method != nullptr); + + const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile(); + Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle( + outer_compilation_unit_->GetClassLinker()->FindDexCache(outer_dex_file))); + Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); + + // The index at which the method's class is stored in the DexCache's type array. + uint32_t storage_index = DexFile::kDexNoIndex; + bool is_outer_class = (resolved_method->GetDeclaringClass() == outer_class.Get()); + if (is_outer_class) { + storage_index = outer_class->GetDexTypeIndex(); + } else if (outer_dex_cache.Get() == dex_cache.Get()) { + // Get `storage_index` from IsClassOfStaticMethodAvailableToReferrer. + compiler_driver_->IsClassOfStaticMethodAvailableToReferrer(outer_dex_cache.Get(), + GetCompilingClass(), + resolved_method, + method_idx, + &storage_index); + } + + HClinitCheck* clinit_check = nullptr; + + if (!outer_class->IsInterface() + && outer_class->IsSubClass(resolved_method->GetDeclaringClass())) { + // If the outer class is the declaring class or a subclass + // of the declaring class, no class initialization is needed + // before the static method call. + // Note that in case of inlining, we do not need to add clinit checks + // to calls that satisfy this subclass check with any inlined methods. This + // will be detected by the optimization passes. + *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone; + } else if (storage_index != DexFile::kDexNoIndex) { + // If the method's class type index is available, check + // whether we should add an explicit class initialization + // check for its declaring class before the static method call. + + // TODO: find out why this check is needed. + bool is_in_dex_cache = compiler_driver_->CanAssumeTypeIsPresentInDexCache( + *outer_compilation_unit_->GetDexFile(), storage_index); + bool is_initialized = + resolved_method->GetDeclaringClass()->IsInitialized() && is_in_dex_cache; + + if (is_initialized) { + *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone; + } else { + *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit; + HLoadClass* load_class = new (arena_) HLoadClass( + graph_->GetCurrentMethod(), + storage_index, + *dex_compilation_unit_->GetDexFile(), + is_outer_class, + dex_pc); + current_block_->AddInstruction(load_class); + clinit_check = new (arena_) HClinitCheck(load_class, dex_pc); + current_block_->AddInstruction(clinit_check); + } } + return clinit_check; } HInvokeStaticOrDirect::DispatchInfo HGraphBuilder::ComputeDispatchInfo( @@ -859,210 +1040,40 @@ HInvokeStaticOrDirect::DispatchInfo HGraphBuilder::ComputeDispatchInfo( method_load_kind, code_ptr_location, method_load_data, direct_code_ptr }; } -bool HGraphBuilder::BuildInvoke(const Instruction& instruction, - uint32_t dex_pc, - uint32_t method_idx, - uint32_t number_of_vreg_arguments, - bool is_range, - uint32_t* args, - uint32_t register_index) { - Instruction::Code opcode = instruction.Opcode(); - InvokeType invoke_type; - switch (opcode) { - case Instruction::INVOKE_STATIC: - case Instruction::INVOKE_STATIC_RANGE: - invoke_type = kStatic; - break; - case Instruction::INVOKE_DIRECT: - case Instruction::INVOKE_DIRECT_RANGE: - invoke_type = kDirect; - break; - case Instruction::INVOKE_VIRTUAL: - case Instruction::INVOKE_VIRTUAL_QUICK: - case Instruction::INVOKE_VIRTUAL_RANGE: - case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: - invoke_type = kVirtual; - break; - case Instruction::INVOKE_INTERFACE: - case Instruction::INVOKE_INTERFACE_RANGE: - invoke_type = kInterface; - break; - case Instruction::INVOKE_SUPER_RANGE: - case Instruction::INVOKE_SUPER: - invoke_type = kSuper; - break; - default: - LOG(FATAL) << "Unexpected invoke op: " << opcode; - return false; - } - - const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); - const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_id.proto_idx_); - const char* descriptor = dex_file_->StringDataByIdx(proto_id.shorty_idx_); - Primitive::Type return_type = Primitive::GetType(descriptor[0]); - bool is_instance_call = invoke_type != kStatic; - // Remove the return type from the 'proto'. - size_t number_of_arguments = strlen(descriptor) - 1; - if (is_instance_call) { - // One extra argument for 'this'. - ++number_of_arguments; - } +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; + uint32_t descriptor_index = 1; // Skip the return type. - MethodReference target_method(dex_file_, method_idx); - uintptr_t direct_code; - uintptr_t direct_method; - int table_index; - InvokeType optimized_invoke_type = invoke_type; + bool is_instance_call = invoke->GetOriginalInvokeType() != InvokeType::kStatic; + bool is_string_init = invoke->IsInvokeStaticOrDirect() + && invoke->AsInvokeStaticOrDirect()->IsStringInit(); - if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, true, true, - &optimized_invoke_type, &target_method, &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; - } - DCHECK(optimized_invoke_type != kSuper); - - // By default, consider that the called method implicitly requires - // an initialization check of its declaring method. - HInvokeStaticOrDirect::ClinitCheckRequirement clinit_check_requirement = - HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit; - // Potential class initialization check, in the case of a static method call. - HClinitCheck* clinit_check = nullptr; - // Replace calls to String.<init> with StringFactory. - int32_t string_init_offset = 0; - bool is_string_init = compiler_driver_->IsStringInit(method_idx, dex_file_, &string_init_offset); if (is_string_init) { - return_type = Primitive::kPrimNot; - is_instance_call = false; - number_of_arguments--; - invoke_type = kStatic; - optimized_invoke_type = kStatic; - } - - HInvoke* invoke = nullptr; - - if (optimized_invoke_type == kVirtual) { - invoke = new (arena_) HInvokeVirtual( - arena_, number_of_arguments, return_type, dex_pc, method_idx, table_index); - } else if (optimized_invoke_type == kInterface) { - invoke = new (arena_) HInvokeInterface( - arena_, number_of_arguments, return_type, dex_pc, method_idx, table_index); - } else { - DCHECK(optimized_invoke_type == kDirect || optimized_invoke_type == kStatic); - - if (optimized_invoke_type == kStatic && !is_string_init) { - ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<4> hs(soa.Self()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle( - dex_compilation_unit_->GetClassLinker()->FindDexCache( - *dex_compilation_unit_->GetDexFile()))); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader()))); - ArtMethod* resolved_method = compiler_driver_->ResolveMethod( - soa, dex_cache, class_loader, dex_compilation_unit_, method_idx, optimized_invoke_type); - - if (resolved_method == nullptr) { - MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedMethod); - return false; - } - - const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile(); - Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle( - outer_compilation_unit_->GetClassLinker()->FindDexCache(outer_dex_file))); - Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); - - // The index at which the method's class is stored in the DexCache's type array. - uint32_t storage_index = DexFile::kDexNoIndex; - bool is_outer_class = (resolved_method->GetDeclaringClass() == outer_class.Get()); - if (is_outer_class) { - storage_index = outer_class->GetDexTypeIndex(); - } else if (outer_dex_cache.Get() == dex_cache.Get()) { - // Get `storage_index` from IsClassOfStaticMethodAvailableToReferrer. - compiler_driver_->IsClassOfStaticMethodAvailableToReferrer(outer_dex_cache.Get(), - GetCompilingClass(), - resolved_method, - method_idx, - &storage_index); - } - - if (!outer_class->IsInterface() - && outer_class->IsSubClass(resolved_method->GetDeclaringClass())) { - // If the outer class is the declaring class or a subclass - // of the declaring class, no class initialization is needed - // before the static method call. - // Note that in case of inlining, we do not need to add clinit checks - // to calls that satisfy this subclass check with any inlined methods. This - // will be detected by the optimization passes. - clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone; - } else if (storage_index != DexFile::kDexNoIndex) { - // If the method's class type index is available, check - // whether we should add an explicit class initialization - // check for its declaring class before the static method call. - - // TODO: find out why this check is needed. - bool is_in_dex_cache = compiler_driver_->CanAssumeTypeIsPresentInDexCache( - *outer_compilation_unit_->GetDexFile(), storage_index); - bool is_initialized = - resolved_method->GetDeclaringClass()->IsInitialized() && is_in_dex_cache; - - if (is_initialized) { - clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone; - } else { - clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit; - HLoadClass* load_class = new (arena_) HLoadClass( - graph_->GetCurrentMethod(), - storage_index, - *dex_compilation_unit_->GetDexFile(), - is_outer_class, - dex_pc); - current_block_->AddInstruction(load_class); - clinit_check = new (arena_) HClinitCheck(load_class, dex_pc); - current_block_->AddInstruction(clinit_check); - } - } - } - - HInvokeStaticOrDirect::DispatchInfo dispatch_info = ComputeDispatchInfo(is_string_init, - string_init_offset, - target_method, - direct_method, - direct_code); - invoke = new (arena_) HInvokeStaticOrDirect(arena_, - number_of_arguments, - return_type, - dex_pc, - method_idx, - target_method, - dispatch_info, - invoke_type, - optimized_invoke_type, - clinit_check_requirement); - } - - size_t start_index = 0; - Temporaries temps(graph_); - if (is_instance_call) { + 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); - HNullCheck* null_check = new (arena_) HNullCheck(arg, 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; } - uint32_t descriptor_index = 1; // Skip the return type. - uint32_t argument_index = start_index; - if (is_string_init) { - start_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 < number_of_arguments); + (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); @@ -1085,7 +1096,7 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, } } - if (argument_index != number_of_arguments) { + 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,10 +1109,12 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, argument_index++; } - if (clinit_check_requirement == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit) { + if (clinit_check != nullptr) { // Add the class initialization check as last input of `invoke`. - DCHECK(clinit_check != nullptr); DCHECK(!is_string_init); + DCHECK(invoke->IsInvokeStaticOrDirect()); + DCHECK(invoke->AsInvokeStaticOrDirect()->GetClinitCheckRequirement() + == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit); invoke->SetArgumentAt(argument_index, clinit_check); argument_index++; } @@ -1112,15 +1125,45 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot); invoke->SetArgumentAt(argument_index, fake_string); current_block_->AddInstruction(invoke); - PotentiallySimplifyFakeString(orig_this_reg, dex_pc, invoke); + PotentiallySimplifyFakeString(orig_this_reg, invoke->GetDexPc(), invoke); } else { current_block_->AddInstruction(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); + 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()) { + std::set<uint32_t> reg_set = map_it->second; + for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) { + HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot); + UpdateLocal(*set_it, load_local); + } + } + } else { + can_use_baseline_for_string_init_ = false; + } +} + bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put) { diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 08600c756d..19dd94475a 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -272,6 +272,19 @@ class HGraphBuilder : public ValueObject { uintptr_t direct_method, uintptr_t direct_code); + bool 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); + + HClinitCheck* ProcessClinitCheckForInvoke( + uint32_t dex_pc, + uint32_t method_idx, + HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement); + ArenaAllocator* const arena_; // A list of the size of the dex code holding block information for diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc index 78470db834..50cbf5ca77 100644 --- a/compiler/optimizing/dead_code_elimination.cc +++ b/compiler/optimizing/dead_code_elimination.cc @@ -133,6 +133,7 @@ void HDeadCodeElimination::RemoveDeadInstructions() { && !inst->IsSuspendCheck() // If we added an explicit barrier then we should keep it. && !inst->IsMemoryBarrier() + && !inst->IsParameterValue() && !inst->HasUses()) { block->RemoveInstruction(inst); MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction); diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 202f3f074d..ff90f32754 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -40,6 +40,8 @@ namespace art { +static constexpr size_t kMaximumNumberOfHInstructions = 12; + void HInliner::Run() { if (graph_->IsDebuggable()) { // For simplicity, we currently never inline when the graph is debuggable. This avoids @@ -169,7 +171,7 @@ static uint32_t FindMethodIndexIn(ArtMethod* method, } } -bool HInliner::TryInline(HInvoke* invoke_instruction) const { +bool HInliner::TryInline(HInvoke* invoke_instruction) { uint32_t method_index = invoke_instruction->GetDexMethodIndex(); ScopedObjectAccess soa(Thread::Current()); const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); @@ -244,12 +246,6 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) const { return false; } - if (resolved_method->ShouldNotInline()) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) - << " was already flagged as non inlineable"; - return false; - } - if (invoke_instruction->IsInvokeStaticOrDirect() && invoke_instruction->AsInvokeStaticOrDirect()->IsStaticWithImplicitClinitCheck()) { // Case of a static method that cannot be inlined because it implicitly @@ -271,7 +267,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) const { bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, HInvoke* invoke_instruction, - bool same_dex_file) const { + bool same_dex_file) { ScopedObjectAccess soa(Thread::Current()); const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); const DexFile& callee_dex_file = *resolved_method->GetDexFile(); @@ -335,9 +331,6 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, if (!builder.BuildGraph(*code_item)) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be built, so cannot be inlined"; - // There could be multiple reasons why the graph could not be built, including - // unaccessible methods/fields due to using a different dex cache. We do not mark - // the method as non-inlineable so that other callers can still try to inline it. return false; } @@ -345,17 +338,41 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, compiler_driver_->GetInstructionSet())) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " cannot be inlined because of the register allocator"; - resolved_method->SetShouldNotInline(); return false; } if (!callee_graph->TryBuildingSsa()) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be transformed to SSA"; - resolved_method->SetShouldNotInline(); return false; } + size_t parameter_index = 0; + for (HInstructionIterator instructions(callee_graph->GetEntryBlock()->GetInstructions()); + !instructions.Done(); + instructions.Advance()) { + HInstruction* current = instructions.Current(); + if (current->IsParameterValue()) { + HInstruction* argument = invoke_instruction->InputAt(parameter_index++); + if (argument->IsNullConstant()) { + current->ReplaceWith(callee_graph->GetNullConstant()); + } else if (argument->IsIntConstant()) { + current->ReplaceWith(callee_graph->GetIntConstant(argument->AsIntConstant()->GetValue())); + } else if (argument->IsLongConstant()) { + current->ReplaceWith(callee_graph->GetLongConstant(argument->AsLongConstant()->GetValue())); + } else if (argument->IsFloatConstant()) { + current->ReplaceWith( + callee_graph->GetFloatConstant(argument->AsFloatConstant()->GetValue())); + } else if (argument->IsDoubleConstant()) { + current->ReplaceWith( + callee_graph->GetDoubleConstant(argument->AsDoubleConstant()->GetValue())); + } else if (argument->GetType() == Primitive::kPrimNot) { + current->SetReferenceTypeInfo(argument->GetReferenceTypeInfo()); + current->AsParameterValue()->SetCanBeNull(argument->CanBeNull()); + } + } + } + // Run simple optimizations on the graph. HDeadCodeElimination dce(callee_graph, stats_); HConstantFolding fold(callee_graph); @@ -365,10 +382,10 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, HOptimization* optimizations[] = { &intrinsics, - &dce, - &fold, &type_propagation, &simplify, + &dce, + &fold, }; for (size_t i = 0; i < arraysize(optimizations); ++i) { @@ -376,6 +393,7 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, optimization->Run(); } + size_t number_of_instructions_budget = kMaximumNumberOfHInstructions; if (depth_ + 1 < compiler_driver_->GetCompilerOptions().GetInlineDepthLimit()) { HInliner inliner(callee_graph, outer_compilation_unit_, @@ -385,6 +403,7 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, stats_, depth_ + 1); inliner.Run(); + number_of_instructions_budget += inliner.number_of_inlined_instructions_; } // TODO: We should abort only if all predecessors throw. However, @@ -394,7 +413,6 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, if (exit_block == nullptr) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because it has an infinite loop"; - resolved_method->SetShouldNotInline(); return false; } @@ -408,24 +426,28 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, if (has_throw_predecessor) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because one branch always throws"; - resolved_method->SetShouldNotInline(); return false; } HReversePostOrderIterator it(*callee_graph); it.Advance(); // Past the entry block, it does not contain instructions that prevent inlining. + size_t number_of_instructions = 0; for (; !it.Done(); it.Advance()) { HBasicBlock* block = it.Current(); if (block->IsLoopHeader()) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because it contains a loop"; - resolved_method->SetShouldNotInline(); return false; } for (HInstructionIterator instr_it(block->GetInstructions()); !instr_it.Done(); instr_it.Advance()) { + if (number_of_instructions++ == number_of_instructions_budget) { + VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + << " could not be inlined because it is too big."; + return false; + } HInstruction* current = instr_it.Current(); if (current->IsInvokeInterface()) { @@ -433,7 +455,6 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, // resolution conflict is currently too high. VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because it has an interface call."; - resolved_method->SetShouldNotInline(); return false; } @@ -448,12 +469,11 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " could not be inlined because " << current->DebugName() << " it is in a different dex file and requires access to the dex cache"; - // Do not flag the method as not-inlineable. A caller within the same - // dex file could still successfully inline it. return false; } } } + number_of_inlined_instructions_ += number_of_instructions; HInstruction* return_replacement = callee_graph->InlineInto(graph_, invoke_instruction); diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index 9062e1ab00..bce5915219 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -42,6 +42,7 @@ class HInliner : public HOptimization { caller_compilation_unit_(caller_compilation_unit), compiler_driver_(compiler_driver), depth_(depth), + number_of_inlined_instructions_(0), handles_(handles) {} void Run() OVERRIDE; @@ -49,15 +50,16 @@ class HInliner : public HOptimization { static constexpr const char* kInlinerPassName = "inliner"; private: - bool TryInline(HInvoke* invoke_instruction) const; + bool TryInline(HInvoke* invoke_instruction); bool TryBuildAndInline(ArtMethod* resolved_method, HInvoke* invoke_instruction, - bool same_dex_file) const; + bool same_dex_file); const DexCompilationUnit& outer_compilation_unit_; const DexCompilationUnit& caller_compilation_unit_; CompilerDriver* const compiler_driver_; const size_t depth_; + size_t number_of_inlined_instructions_; StackHandleScopeCollection* const handles_; DISALLOW_COPY_AND_ASSIGN(HInliner); diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 3db9816173..075ec1ee2e 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -31,7 +31,7 @@ static inline InvokeType GetIntrinsicInvokeType(Intrinsics i) { switch (i) { case Intrinsics::kNone: return kInterface; // Non-sensical for intrinsic. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ case Intrinsics::k ## Name: \ return IsStatic; #include "intrinsics_list.h" @@ -43,19 +43,19 @@ INTRINSICS_LIST(OPTIMIZING_INTRINSICS) } // Function that returns whether an intrinsic needs an environment or not. -static inline IntrinsicNeedsEnvironment IntrinsicNeedsEnvironment(Intrinsics i) { +static inline IntrinsicNeedsEnvironmentOrCache NeedsEnvironmentOrCache(Intrinsics i) { switch (i) { case Intrinsics::kNone: - return kNeedsEnvironment; // Non-sensical for intrinsic. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ + return kNeedsEnvironmentOrCache; // Non-sensical for intrinsic. +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ case Intrinsics::k ## Name: \ - return NeedsEnvironment; + return NeedsEnvironmentOrCache; #include "intrinsics_list.h" INTRINSICS_LIST(OPTIMIZING_INTRINSICS) #undef INTRINSICS_LIST #undef OPTIMIZING_INTRINSICS } - return kNeedsEnvironment; + return kNeedsEnvironmentOrCache; } static Primitive::Type GetType(uint64_t data, bool is_op_size) { @@ -376,7 +376,7 @@ void IntrinsicsRecognizer::Run() { << intrinsic << " for " << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile()); } else { - invoke->SetIntrinsic(intrinsic, IntrinsicNeedsEnvironment(intrinsic)); + invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic)); } } } @@ -390,7 +390,7 @@ std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) { case Intrinsics::kNone: os << "None"; break; -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ case Intrinsics::k ## Name: \ os << # Name; \ break; diff --git a/compiler/optimizing/intrinsics_arm.h b/compiler/optimizing/intrinsics_arm.h index f013bd6083..2abb605e6e 100644 --- a/compiler/optimizing/intrinsics_arm.h +++ b/compiler/optimizing/intrinsics_arm.h @@ -38,7 +38,7 @@ class IntrinsicLocationsBuilderARM FINAL : public IntrinsicVisitor { // Define visitor methods. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ void Visit ## Name(HInvoke* invoke) OVERRIDE; #include "intrinsics_list.h" INTRINSICS_LIST(OPTIMIZING_INTRINSICS) @@ -64,7 +64,7 @@ class IntrinsicCodeGeneratorARM FINAL : public IntrinsicVisitor { // Define visitor methods. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ void Visit ## Name(HInvoke* invoke) OVERRIDE; #include "intrinsics_list.h" INTRINSICS_LIST(OPTIMIZING_INTRINSICS) diff --git a/compiler/optimizing/intrinsics_arm64.h b/compiler/optimizing/intrinsics_arm64.h index ebaf5e5952..4250ecf358 100644 --- a/compiler/optimizing/intrinsics_arm64.h +++ b/compiler/optimizing/intrinsics_arm64.h @@ -41,7 +41,7 @@ class IntrinsicLocationsBuilderARM64 FINAL : public IntrinsicVisitor { // Define visitor methods. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ void Visit ## Name(HInvoke* invoke) OVERRIDE; #include "intrinsics_list.h" INTRINSICS_LIST(OPTIMIZING_INTRINSICS) @@ -65,7 +65,7 @@ class IntrinsicCodeGeneratorARM64 FINAL : public IntrinsicVisitor { // Define visitor methods. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ void Visit ## Name(HInvoke* invoke) OVERRIDE; #include "intrinsics_list.h" INTRINSICS_LIST(OPTIMIZING_INTRINSICS) diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h index 15ee5d4d12..7e5339ec21 100644 --- a/compiler/optimizing/intrinsics_list.h +++ b/compiler/optimizing/intrinsics_list.h @@ -22,73 +22,73 @@ // environment. #define INTRINSICS_LIST(V) \ - V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironment) \ - V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironment) \ - V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironment) \ - V(FloatIntBitsToFloat, kStatic, kNeedsEnvironment) \ - V(IntegerReverse, kStatic, kNeedsEnvironment) \ - V(IntegerReverseBytes, kStatic, kNeedsEnvironment) \ - V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironment) \ - V(LongReverse, kStatic, kNeedsEnvironment) \ - V(LongReverseBytes, kStatic, kNeedsEnvironment) \ - V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironment) \ - V(ShortReverseBytes, kStatic, kNeedsEnvironment) \ - V(MathAbsDouble, kStatic, kNeedsEnvironment) \ - V(MathAbsFloat, kStatic, kNeedsEnvironment) \ - V(MathAbsLong, kStatic, kNeedsEnvironment) \ - V(MathAbsInt, kStatic, kNeedsEnvironment) \ - V(MathMinDoubleDouble, kStatic, kNeedsEnvironment) \ - V(MathMinFloatFloat, kStatic, kNeedsEnvironment) \ - V(MathMinLongLong, kStatic, kNeedsEnvironment) \ - V(MathMinIntInt, kStatic, kNeedsEnvironment) \ - V(MathMaxDoubleDouble, kStatic, kNeedsEnvironment) \ - V(MathMaxFloatFloat, kStatic, kNeedsEnvironment) \ - V(MathMaxLongLong, kStatic, kNeedsEnvironment) \ - V(MathMaxIntInt, kStatic, kNeedsEnvironment) \ - V(MathSqrt, kStatic, kNeedsEnvironment) \ - V(MathCeil, kStatic, kNeedsEnvironment) \ - V(MathFloor, kStatic, kNeedsEnvironment) \ - V(MathRint, kStatic, kNeedsEnvironment) \ - V(MathRoundDouble, kStatic, kNeedsEnvironment) \ - V(MathRoundFloat, kStatic, kNeedsEnvironment) \ - V(SystemArrayCopyChar, kStatic, kNeedsEnvironment) \ - V(ThreadCurrentThread, kStatic, kNeedsEnvironment) \ - V(MemoryPeekByte, kStatic, kNeedsEnvironment) \ - V(MemoryPeekIntNative, kStatic, kNeedsEnvironment) \ - V(MemoryPeekLongNative, kStatic, kNeedsEnvironment) \ - V(MemoryPeekShortNative, kStatic, kNeedsEnvironment) \ - V(MemoryPokeByte, kStatic, kNeedsEnvironment) \ - V(MemoryPokeIntNative, kStatic, kNeedsEnvironment) \ - V(MemoryPokeLongNative, kStatic, kNeedsEnvironment) \ - V(MemoryPokeShortNative, kStatic, kNeedsEnvironment) \ - V(StringCharAt, kDirect, kNeedsEnvironment) \ - V(StringCompareTo, kDirect, kNeedsEnvironment) \ - V(StringEquals, kDirect, kNeedsEnvironment) \ - V(StringGetCharsNoCheck, kDirect, kNeedsEnvironment) \ - V(StringIndexOf, kDirect, kNeedsEnvironment) \ - V(StringIndexOfAfter, kDirect, kNeedsEnvironment) \ - V(StringNewStringFromBytes, kStatic, kNeedsEnvironment) \ - V(StringNewStringFromChars, kStatic, kNeedsEnvironment) \ - V(StringNewStringFromString, kStatic, kNeedsEnvironment) \ - V(UnsafeCASInt, kDirect, kNeedsEnvironment) \ - V(UnsafeCASLong, kDirect, kNeedsEnvironment) \ - V(UnsafeCASObject, kDirect, kNeedsEnvironment) \ - V(UnsafeGet, kDirect, kNeedsEnvironment) \ - V(UnsafeGetVolatile, kDirect, kNeedsEnvironment) \ - V(UnsafeGetObject, kDirect, kNeedsEnvironment) \ - V(UnsafeGetObjectVolatile, kDirect, kNeedsEnvironment) \ - V(UnsafeGetLong, kDirect, kNeedsEnvironment) \ - V(UnsafeGetLongVolatile, kDirect, kNeedsEnvironment) \ - V(UnsafePut, kDirect, kNeedsEnvironment) \ - V(UnsafePutOrdered, kDirect, kNeedsEnvironment) \ - V(UnsafePutVolatile, kDirect, kNeedsEnvironment) \ - V(UnsafePutObject, kDirect, kNeedsEnvironment) \ - V(UnsafePutObjectOrdered, kDirect, kNeedsEnvironment) \ - V(UnsafePutObjectVolatile, kDirect, kNeedsEnvironment) \ - V(UnsafePutLong, kDirect, kNeedsEnvironment) \ - V(UnsafePutLongOrdered, kDirect, kNeedsEnvironment) \ - V(UnsafePutLongVolatile, kDirect, kNeedsEnvironment) \ - V(ReferenceGetReferent, kDirect, kNeedsEnvironment) + V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache) \ + V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironmentOrCache) \ + V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironmentOrCache) \ + V(FloatIntBitsToFloat, kStatic, kNeedsEnvironmentOrCache) \ + V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache) \ + V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache) \ + V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache) \ + V(LongReverse, kStatic, kNeedsEnvironmentOrCache) \ + V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache) \ + V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache) \ + V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache) \ + V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache) \ + V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache) \ + V(MathAbsLong, kStatic, kNeedsEnvironmentOrCache) \ + V(MathAbsInt, kStatic, kNeedsEnvironmentOrCache) \ + V(MathMinDoubleDouble, kStatic, kNeedsEnvironmentOrCache) \ + V(MathMinFloatFloat, kStatic, kNeedsEnvironmentOrCache) \ + V(MathMinLongLong, kStatic, kNeedsEnvironmentOrCache) \ + V(MathMinIntInt, kStatic, kNeedsEnvironmentOrCache) \ + V(MathMaxDoubleDouble, kStatic, kNeedsEnvironmentOrCache) \ + V(MathMaxFloatFloat, kStatic, kNeedsEnvironmentOrCache) \ + V(MathMaxLongLong, kStatic, kNeedsEnvironmentOrCache) \ + V(MathMaxIntInt, kStatic, kNeedsEnvironmentOrCache) \ + V(MathSqrt, kStatic, kNeedsEnvironmentOrCache) \ + V(MathCeil, kStatic, kNeedsEnvironmentOrCache) \ + V(MathFloor, kStatic, kNeedsEnvironmentOrCache) \ + V(MathRint, kStatic, kNeedsEnvironmentOrCache) \ + V(MathRoundDouble, kStatic, kNeedsEnvironmentOrCache) \ + V(MathRoundFloat, kStatic, kNeedsEnvironmentOrCache) \ + V(SystemArrayCopyChar, kStatic, kNeedsEnvironmentOrCache) \ + V(ThreadCurrentThread, kStatic, kNeedsEnvironmentOrCache) \ + V(MemoryPeekByte, kStatic, kNeedsEnvironmentOrCache) \ + V(MemoryPeekIntNative, kStatic, kNeedsEnvironmentOrCache) \ + V(MemoryPeekLongNative, kStatic, kNeedsEnvironmentOrCache) \ + V(MemoryPeekShortNative, kStatic, kNeedsEnvironmentOrCache) \ + V(MemoryPokeByte, kStatic, kNeedsEnvironmentOrCache) \ + V(MemoryPokeIntNative, kStatic, kNeedsEnvironmentOrCache) \ + V(MemoryPokeLongNative, kStatic, kNeedsEnvironmentOrCache) \ + V(MemoryPokeShortNative, kStatic, kNeedsEnvironmentOrCache) \ + V(StringCharAt, kDirect, kNeedsEnvironmentOrCache) \ + V(StringCompareTo, kDirect, kNeedsEnvironmentOrCache) \ + V(StringEquals, kDirect, kNeedsEnvironmentOrCache) \ + V(StringGetCharsNoCheck, kDirect, kNeedsEnvironmentOrCache) \ + V(StringIndexOf, kDirect, kNeedsEnvironmentOrCache) \ + V(StringIndexOfAfter, kDirect, kNeedsEnvironmentOrCache) \ + V(StringNewStringFromBytes, kStatic, kNeedsEnvironmentOrCache) \ + V(StringNewStringFromChars, kStatic, kNeedsEnvironmentOrCache) \ + V(StringNewStringFromString, kStatic, kNeedsEnvironmentOrCache) \ + V(UnsafeCASInt, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafeCASLong, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafeCASObject, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafeGet, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafeGetVolatile, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafeGetObject, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafeGetObjectVolatile, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafeGetLong, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafeGetLongVolatile, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafePut, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafePutOrdered, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafePutVolatile, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafePutObject, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafePutObjectOrdered, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafePutObjectVolatile, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafePutLong, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafePutLongOrdered, kDirect, kNeedsEnvironmentOrCache) \ + V(UnsafePutLongVolatile, kDirect, kNeedsEnvironmentOrCache) \ + V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache) #endif // ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_ #undef ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_ // #define is only for lint. diff --git a/compiler/optimizing/intrinsics_x86.h b/compiler/optimizing/intrinsics_x86.h index ac68f39904..fefe9c6143 100644 --- a/compiler/optimizing/intrinsics_x86.h +++ b/compiler/optimizing/intrinsics_x86.h @@ -36,7 +36,7 @@ class IntrinsicLocationsBuilderX86 FINAL : public IntrinsicVisitor { // Define visitor methods. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ void Visit ## Name(HInvoke* invoke) OVERRIDE; #include "intrinsics_list.h" INTRINSICS_LIST(OPTIMIZING_INTRINSICS) @@ -61,7 +61,7 @@ class IntrinsicCodeGeneratorX86 FINAL : public IntrinsicVisitor { // Define visitor methods. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ void Visit ## Name(HInvoke* invoke) OVERRIDE; #include "intrinsics_list.h" INTRINSICS_LIST(OPTIMIZING_INTRINSICS) diff --git a/compiler/optimizing/intrinsics_x86_64.h b/compiler/optimizing/intrinsics_x86_64.h index 17293af4d2..6894e1b527 100644 --- a/compiler/optimizing/intrinsics_x86_64.h +++ b/compiler/optimizing/intrinsics_x86_64.h @@ -36,7 +36,7 @@ class IntrinsicLocationsBuilderX86_64 FINAL : public IntrinsicVisitor { // Define visitor methods. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ void Visit ## Name(HInvoke* invoke) OVERRIDE; #include "intrinsics_list.h" INTRINSICS_LIST(OPTIMIZING_INTRINSICS) @@ -61,7 +61,7 @@ class IntrinsicCodeGeneratorX86_64 FINAL : public IntrinsicVisitor { // Define visitor methods. -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) \ +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) \ void Visit ## Name(HInvoke* invoke) OVERRIDE; #include "intrinsics_list.h" INTRINSICS_LIST(OPTIMIZING_INTRINSICS) diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 7e49199b69..2ed2d9ab20 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -2931,7 +2931,7 @@ class HDoubleConstant : public HConstant { }; enum class Intrinsics { -#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment) k ## Name, +#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache) k ## Name, #include "intrinsics_list.h" kNone, INTRINSICS_LIST(OPTIMIZING_INTRINSICS) @@ -2940,9 +2940,9 @@ enum class Intrinsics { }; std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic); -enum IntrinsicNeedsEnvironment { - kNoEnvironment, // Intrinsic does not require an environment. - kNeedsEnvironment // Intrinsic requires an environment. +enum IntrinsicNeedsEnvironmentOrCache { + kNoEnvironmentOrCache, // Intrinsic does not require an environment or dex cache. + kNeedsEnvironmentOrCache // Intrinsic requires an environment or requires a dex cache. }; class HInvoke : public HInstruction { @@ -2951,7 +2951,9 @@ class HInvoke : public HInstruction { // Runtime needs to walk the stack, so Dex -> Dex calls need to // know their environment. - bool NeedsEnvironment() const OVERRIDE { return needs_environment_ == kNeedsEnvironment; } + bool NeedsEnvironment() const OVERRIDE { + return needs_environment_or_cache_ == kNeedsEnvironmentOrCache; + } void SetArgumentAt(size_t index, HInstruction* argument) { SetRawInputAt(index, argument); @@ -2976,9 +2978,9 @@ class HInvoke : public HInstruction { return intrinsic_; } - void SetIntrinsic(Intrinsics intrinsic, IntrinsicNeedsEnvironment needs_environment) { + void SetIntrinsic(Intrinsics intrinsic, IntrinsicNeedsEnvironmentOrCache needs_env_or_cache) { intrinsic_ = intrinsic; - needs_environment_ = needs_environment; + needs_environment_or_cache_ = needs_env_or_cache; } bool IsFromInlinedInvoke() const { @@ -3006,7 +3008,7 @@ class HInvoke : public HInstruction { dex_method_index_(dex_method_index), original_invoke_type_(original_invoke_type), intrinsic_(Intrinsics::kNone), - needs_environment_(kNeedsEnvironment) { + needs_environment_or_cache_(kNeedsEnvironmentOrCache) { uint32_t number_of_inputs = number_of_arguments + number_of_other_inputs; inputs_.SetSize(number_of_inputs); } @@ -3023,7 +3025,7 @@ class HInvoke : public HInstruction { const uint32_t dex_method_index_; const InvokeType original_invoke_type_; Intrinsics intrinsic_; - IntrinsicNeedsEnvironment needs_environment_; + IntrinsicNeedsEnvironmentOrCache needs_environment_or_cache_; private: DISALLOW_COPY_AND_ASSIGN(HInvoke); @@ -3148,7 +3150,10 @@ class HInvokeStaticOrDirect : public HInvoke { MethodLoadKind GetMethodLoadKind() const { return dispatch_info_.method_load_kind; } CodePtrLocation GetCodePtrLocation() const { return dispatch_info_.code_ptr_location; } bool IsRecursive() const { return GetMethodLoadKind() == MethodLoadKind::kRecursive; } - bool NeedsDexCache() const OVERRIDE { return !IsRecursive() && !IsStringInit(); } + bool NeedsDexCache() const OVERRIDE { + if (intrinsic_ != Intrinsics::kNone) { return needs_environment_or_cache_; } + return !IsRecursive() && !IsStringInit(); + } bool IsStringInit() const { return GetMethodLoadKind() == MethodLoadKind::kStringInit; } uint32_t GetCurrentMethodInputIndex() const { return GetNumberOfArguments(); } bool HasMethodAddress() const { return GetMethodLoadKind() == MethodLoadKind::kDirectAddress; } @@ -3176,6 +3181,8 @@ class HInvokeStaticOrDirect : public HInvoke { return dispatch_info_.direct_code_ptr; } + ClinitCheckRequirement GetClinitCheckRequirement() const { return clinit_check_requirement_; } + // Is this instruction a call to a static method? bool IsStatic() const { return GetInvokeType() == kStatic; @@ -3770,11 +3777,15 @@ class HXor : public HBinaryOperation { class HParameterValue : public HExpression<0> { public: HParameterValue(uint8_t index, Primitive::Type parameter_type, bool is_this = false) - : HExpression(parameter_type, SideEffects::None()), index_(index), is_this_(is_this) {} + : HExpression(parameter_type, SideEffects::None()), + index_(index), + is_this_(is_this), + can_be_null_(!is_this) {} uint8_t GetIndex() const { return index_; } - bool CanBeNull() const OVERRIDE { return !is_this_; } + bool CanBeNull() const OVERRIDE { return can_be_null_; } + void SetCanBeNull(bool can_be_null) { can_be_null_ = can_be_null; } bool IsThis() const { return is_this_; } @@ -3788,6 +3799,8 @@ class HParameterValue : public HExpression<0> { // Whether or not the parameter value corresponds to 'this' argument. const bool is_this_; + bool can_be_null_; + DISALLOW_COPY_AND_ASSIGN(HParameterValue); }; @@ -4439,6 +4452,7 @@ class HLoadString : public HExpression<1> { // TODO: Can we deopt or debug when we resolve a string? bool NeedsEnvironment() const OVERRIDE { return false; } bool NeedsDexCache() const OVERRIDE { return true; } + bool CanBeNull() const OVERRIDE { return false; } static SideEffects SideEffectsForArchRuntimeCalls() { return SideEffects::CanTriggerGC(); diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 5d029488fd..45b3df008b 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -414,7 +414,9 @@ void RTPVisitor::VisitNewArray(HNewArray* instr) { } void RTPVisitor::VisitParameterValue(HParameterValue* instr) { - if (instr->GetType() == Primitive::kPrimNot) { + ScopedObjectAccess soa(Thread::Current()); + // We check if the existing type is valid: the inliner may have set it. + if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) { // TODO: parse the signature and add precise types for the parameters. SetClassAsTypeInfo(instr, nullptr, /* is_exact */ false); } |