diff options
Diffstat (limited to 'compiler/optimizing/builder.cc')
-rw-r--r-- | compiler/optimizing/builder.cc | 475 |
1 files changed, 296 insertions, 179 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 52a3a1534a..7b42db8a7f 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -31,6 +31,7 @@ #include "primitive.h" #include "scoped_thread_state_change.h" #include "thread.h" +#include "utils/dex_cache_arrays_layout-inl.h" namespace art { @@ -306,7 +307,8 @@ void HGraphBuilder::CreateBlocksForTryCatch(const DexFile::CodeItem& code_item) for (; iterator.HasNext(); iterator.Next()) { uint32_t address = iterator.GetHandlerAddress(); HBasicBlock* block = FindOrCreateBlockStartingAt(address); - block->SetIsCatchBlock(); + block->SetTryCatchInformation( + new (arena_) TryCatchInformation(iterator.GetHandlerTypeIndex(), *dex_file_)); } handlers_ptr = iterator.EndDataPointer(); } @@ -357,9 +359,10 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) HInstruction* first_insn = block->GetFirstInstruction(); if (first_insn->IsLoadException()) { // Catch block starts with a LoadException. Split the block after the - // StoreLocal that must come after the load. + // StoreLocal and ClearException which must come after the load. DCHECK(first_insn->GetNext()->IsStoreLocal()); - block = block->SplitBefore(first_insn->GetNext()->GetNext()); + DCHECK(first_insn->GetNext()->GetNext()->IsClearException()); + block = block->SplitBefore(first_insn->GetNext()->GetNext()->GetNext()); } else { // Catch block does not load the exception. Split at the beginning to // create an empty catch block. @@ -756,240 +759,321 @@ 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; - } - 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::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; +static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) { switch (opcode) { case Instruction::INVOKE_STATIC: case Instruction::INVOKE_STATIC_RANGE: - invoke_type = kStatic; - break; + return kStatic; case Instruction::INVOKE_DIRECT: case Instruction::INVOKE_DIRECT_RANGE: - invoke_type = kDirect; - break; + return kDirect; case Instruction::INVOKE_VIRTUAL: case Instruction::INVOKE_VIRTUAL_QUICK: case Instruction::INVOKE_VIRTUAL_RANGE: case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: - invoke_type = kVirtual; - break; + return kVirtual; case Instruction::INVOKE_INTERFACE: case Instruction::INVOKE_INTERFACE_RANGE: - invoke_type = kInterface; - break; + return kInterface; case Instruction::INVOKE_SUPER_RANGE: case Instruction::INVOKE_SUPER: - invoke_type = kSuper; - break; + return kSuper; default: - LOG(FATAL) << "Unexpected invoke op: " << opcode; - return false; + LOG(FATAL) << "Unexpected invoke opcode: " << opcode; + UNREACHABLE(); } +} - 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_); +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]); - 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) { + if (original_invoke_type != kStatic) { // instance call // One extra argument for 'this'. - ++number_of_arguments; + number_of_arguments++; } MethodReference target_method(dex_file_, method_idx); + int32_t table_index; uintptr_t direct_code; uintptr_t direct_method; - int table_index; - InvokeType optimized_invoke_type = invoke_type; - if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, true, true, - &optimized_invoke_type, &target_method, &table_index, - &direct_code, &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); - // 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. + // 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); - if (is_string_init) { - return_type = Primitive::kPrimNot; - is_instance_call = false; - number_of_arguments--; - invoke_type = kStatic; - optimized_invoke_type = kStatic; - } + 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 (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); - // Sharpening to kDirect only works if we compile PIC. - DCHECK((optimized_invoke_type == invoke_type) || (optimized_invoke_type != kDirect) - || compiler_driver_->GetCompilerOptions().GetCompilePic()); - bool is_recursive = - (target_method.dex_method_index == outer_compilation_unit_->GetDexMethodIndex()) - && (target_method.dex_file == outer_compilation_unit_->GetDexFile()); - + 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) { - 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); - } + clinit_check = ProcessClinitCheckForInvoke(dex_pc, method_idx, &clinit_check_requirement); + } - 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); - } - } + // 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, - target_method.dex_method_index, - is_recursive, - string_init_offset, - invoke_type, + 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 { + 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( + bool is_string_init, + int32_t string_init_offset, + MethodReference target_method, + uintptr_t direct_method, + uintptr_t direct_code) { + HInvokeStaticOrDirect::MethodLoadKind method_load_kind; + HInvokeStaticOrDirect::CodePtrLocation code_ptr_location; + uint64_t method_load_data = 0u; + uint64_t direct_code_ptr = 0u; + + if (is_string_init) { + // TODO: Use direct_method and direct_code for the appropriate StringFactory method. + method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kStringInit; + code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod; + method_load_data = string_init_offset; + } else if (target_method.dex_file == outer_compilation_unit_->GetDexFile() && + target_method.dex_method_index == outer_compilation_unit_->GetDexMethodIndex()) { + method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRecursive; + code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallSelf; + } else { + if (direct_method != 0u) { // Should we use a direct pointer to the method? + if (direct_method != static_cast<uintptr_t>(-1)) { // Is the method pointer known now? + method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress; + method_load_data = direct_method; + } else { // The direct pointer will be known at link time. + method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup; + } + } else { // Use dex cache. + DCHECK(target_method.dex_file == dex_compilation_unit_->GetDexFile()); + DexCacheArraysLayout layout = + compiler_driver_->GetDexCacheArraysLayout(target_method.dex_file); + if (layout.Valid()) { // Can we use PC-relative access to the dex cache arrays? + method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative; + method_load_data = layout.MethodOffset(target_method.dex_method_index); + } else { // We must go through the ArtMethod's pointer to resolved methods. + method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod; + } + } + if (direct_code != 0u) { // Should we use a direct pointer to the code? + if (direct_code != static_cast<uintptr_t>(-1)) { // Is the code pointer known now? + code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallDirect; + direct_code_ptr = direct_code; + } else if (compiler_driver_->IsImage() || + target_method.dex_file == dex_compilation_unit_->GetDexFile()) { + // Use PC-relative calls for invokes within a multi-dex oat file. + // TODO: Recognize when the target dex file is within the current oat file for + // app compilation. At the moment we recognize only the boot image as multi-dex. + // NOTE: This will require changing the ARM backend which currently falls + // through from kCallPCRelative to kDirectCodeFixup for different dex files. + code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative; + } else { // The direct pointer will be known at link time. + // NOTE: This is used for app->boot calls when compiling an app against + // a relocatable but not yet relocated image. + code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup; + } + } else { // We must use the code pointer from the ArtMethod. + code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod; + } + } + + if (graph_->IsDebuggable()) { + // For debuggable apps always use the code pointer from ArtMethod + // so that we don't circumvent instrumentation stubs if installed. + code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod; + } + + return HInvokeStaticOrDirect::DispatchInfo { + 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; - Temporaries temps(graph_); - if (is_instance_call) { + size_t argument_index = 0; + uint32_t descriptor_index = 1; // Skip the return type. + + 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); - 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); @@ -1012,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"; @@ -1025,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++; } @@ -1039,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) { @@ -2552,6 +2668,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::MOVE_EXCEPTION: { current_block_->AddInstruction(new (arena_) HLoadException()); UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction()); + current_block_->AddInstruction(new (arena_) HClearException()); break; } |