summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/builder.cc477
-rw-r--r--compiler/optimizing/builder.h13
-rw-r--r--compiler/optimizing/dead_code_elimination.cc1
-rw-r--r--compiler/optimizing/inliner.cc62
-rw-r--r--compiler/optimizing/inliner.h6
-rw-r--r--compiler/optimizing/intrinsics.cc16
-rw-r--r--compiler/optimizing/intrinsics_arm.h4
-rw-r--r--compiler/optimizing/intrinsics_arm64.h4
-rw-r--r--compiler/optimizing/intrinsics_list.h134
-rw-r--r--compiler/optimizing/intrinsics_x86.h4
-rw-r--r--compiler/optimizing/intrinsics_x86_64.h4
-rw-r--r--compiler/optimizing/nodes.h38
-rw-r--r--compiler/optimizing/reference_type_propagation.cc4
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);
}