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