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.cc151
1 files changed, 95 insertions, 56 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index cdd7636c0b..e527e8bc7c 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -378,15 +378,15 @@ bool HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr,
dex_pc += instruction.SizeInCodeUnits();
code_ptr += instruction.SizeInCodeUnits();
- if (code_ptr >= code_end) {
- if (instruction.CanFlowThrough()) {
+ if (instruction.CanFlowThrough()) {
+ if (code_ptr >= code_end) {
// In the normal case we should never hit this but someone can artificially forge a dex
// file to fall-through out the method code. In this case we bail out compilation.
return false;
+ } else if (FindBlockStartingAt(dex_pc) == nullptr) {
+ block = new (arena_) HBasicBlock(graph_, dex_pc);
+ branch_targets_.Put(dex_pc, block);
}
- } else if (FindBlockStartingAt(dex_pc) == nullptr) {
- block = new (arena_) HBasicBlock(graph_, dex_pc);
- branch_targets_.Put(dex_pc, block);
}
} else if (instruction.IsSwitch()) {
SwitchTable table(instruction, dex_pc, instruction.Opcode() == Instruction::SPARSE_SWITCH);
@@ -483,10 +483,11 @@ void HGraphBuilder::Binop_23x_shift(const Instruction& instruction,
void HGraphBuilder::Binop_23x_cmp(const Instruction& instruction,
Primitive::Type type,
- HCompare::Bias bias) {
+ HCompare::Bias bias,
+ uint32_t dex_pc) {
HInstruction* first = LoadLocal(instruction.VRegB(), type);
HInstruction* second = LoadLocal(instruction.VRegC(), type);
- current_block_->AddInstruction(new (arena_) HCompare(type, first, second, bias));
+ current_block_->AddInstruction(new (arena_) HCompare(type, first, second, bias, dex_pc));
UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
}
@@ -603,7 +604,12 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
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;
- size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1);
+ // 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;
+ }
MethodReference target_method(dex_file_, method_idx);
uintptr_t direct_code;
@@ -614,7 +620,8 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
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(method_idx, *dex_file_)
+ 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;
@@ -655,7 +662,7 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
(target_method.dex_method_index == outer_compilation_unit_->GetDexMethodIndex())
&& (target_method.dex_file == outer_compilation_unit_->GetDexFile());
- if (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(
@@ -674,26 +681,30 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
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> referrer_class(hs.NewHandle(GetOutermostCompilingClass()));
+ 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_referrer_class = (resolved_method->GetDeclaringClass() == referrer_class.Get());
- if (is_referrer_class) {
- storage_index = referrer_class->GetDexTypeIndex();
+ 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(),
- referrer_class.Get(),
+ GetCompilingClass(),
resolved_method,
method_idx,
&storage_index);
}
- if (referrer_class.Get()->IsSubClass(resolved_method->GetDeclaringClass())) {
- // If the referrer class is the declaring class or a subclass
+ 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
@@ -714,7 +725,7 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
graph_->GetCurrentMethod(),
storage_index,
*dex_compilation_unit_->GetDexFile(),
- is_referrer_class,
+ is_outer_class,
dex_pc);
current_block_->AddInstruction(load_class);
clinit_check = new (arena_) HClinitCheck(load_class, dex_pc);
@@ -746,26 +757,45 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
start_index = 1;
}
- uint32_t descriptor_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; i < number_of_vreg_arguments; i++, argument_index++) {
+ 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++, argument_index++) {
Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]);
bool is_wide = (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble);
- // Longs and doubles should be in pairs, that is, sequential registers. The verifier should
- // reject any class where this is violated.
- DCHECK(is_range || !is_wide || (args[i] + 1 == args[i + 1]))
- << "Non sequential register pair in " << dex_compilation_unit_->GetSymbol()
- << " at " << dex_pc;
+ if (!is_range
+ && is_wide
+ && ((i + 1 == number_of_vreg_arguments) || (args[i] + 1 != args[i + 1]))) {
+ // Longs and doubles should be in pairs, that is, sequential registers. The verifier should
+ // reject any class where this is violated. However, the verifier only does these checks
+ // on non trivially dead instructions, so we just bailout the compilation.
+ VLOG(compiler) << "Did not compile "
+ << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_)
+ << " because of non-sequential dex register pair in wide argument";
+ MaybeRecordStat(MethodCompilationStat::kNotCompiledMalformedOpcode);
+ return false;
+ }
HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type);
invoke->SetArgumentAt(argument_index, arg);
if (is_wide) {
i++;
}
}
- DCHECK_EQ(argument_index, number_of_arguments);
+
+ if (argument_index != number_of_arguments) {
+ VLOG(compiler) << "Did not compile "
+ << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_)
+ << " because of wrong number of arguments in invoke instruction";
+ MaybeRecordStat(MethodCompilationStat::kNotCompiledMalformedOpcode);
+ return false;
+ }
if (invoke->IsInvokeStaticOrDirect()) {
invoke->SetArgumentAt(argument_index, graph_->GetCurrentMethod());
@@ -784,6 +814,7 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
// Add move-result for StringFactory method.
if (is_string_init) {
uint32_t orig_this_reg = is_range ? register_index : args[0];
+ UpdateLocal(orig_this_reg, invoke);
const VerifiedMethod* verified_method =
compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
if (verified_method == nullptr) {
@@ -797,10 +828,10 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
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) {
- UpdateLocal(*set_it, invoke);
+ HInstruction* load_local = LoadLocal(orig_this_reg, Primitive::kPrimNot);
+ UpdateLocal(*set_it, load_local);
}
}
- UpdateLocal(orig_this_reg, invoke);
}
return true;
}
@@ -853,17 +884,25 @@ bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction,
return true;
}
-mirror::Class* HGraphBuilder::GetOutermostCompilingClass() const {
+static mirror::Class* GetClassFrom(CompilerDriver* driver,
+ const DexCompilationUnit& compilation_unit) {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
- const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile();
+ const DexFile& dex_file = *compilation_unit.GetDexFile();
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
- Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle(
- outer_compilation_unit_->GetClassLinker()->FindDexCache(outer_dex_file)));
+ soa.Decode<mirror::ClassLoader*>(compilation_unit.GetClassLoader())));
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(
+ compilation_unit.GetClassLinker()->FindDexCache(dex_file)));
- return compiler_driver_->ResolveCompilingMethodsClass(
- soa, outer_dex_cache, class_loader, outer_compilation_unit_);
+ return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit);
+}
+
+mirror::Class* HGraphBuilder::GetOutermostCompilingClass() const {
+ return GetClassFrom(compiler_driver_, *outer_compilation_unit_);
+}
+
+mirror::Class* HGraphBuilder::GetCompilingClass() const {
+ return GetClassFrom(compiler_driver_, *dex_compilation_unit_);
}
bool HGraphBuilder::IsOutermostCompilingClass(uint16_t type_index) const {
@@ -875,9 +914,9 @@ bool HGraphBuilder::IsOutermostCompilingClass(uint16_t type_index) const {
soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
Handle<mirror::Class> cls(hs.NewHandle(compiler_driver_->ResolveClass(
soa, dex_cache, class_loader, type_index, dex_compilation_unit_)));
- Handle<mirror::Class> compiling_class(hs.NewHandle(GetOutermostCompilingClass()));
+ Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
- return compiling_class.Get() == cls.Get();
+ return outer_class.Get() == cls.Get();
}
bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
@@ -903,20 +942,20 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
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> referrer_class(hs.NewHandle(GetOutermostCompilingClass()));
+ Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
// The index at which the field's class is stored in the DexCache's type array.
uint32_t storage_index;
- bool is_referrer_class = (referrer_class.Get() == resolved_field->GetDeclaringClass());
- if (is_referrer_class) {
- storage_index = referrer_class->GetDexTypeIndex();
+ bool is_outer_class = (outer_class.Get() == resolved_field->GetDeclaringClass());
+ if (is_outer_class) {
+ storage_index = outer_class->GetDexTypeIndex();
} else if (outer_dex_cache.Get() != dex_cache.Get()) {
// The compiler driver cannot currently understand multiple dex caches involved. Just bailout.
return false;
} else {
std::pair<bool, bool> pair = compiler_driver_->IsFastStaticField(
outer_dex_cache.Get(),
- referrer_class.Get(),
+ GetCompilingClass(),
resolved_field,
field_index,
&storage_index);
@@ -934,12 +973,12 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
HLoadClass* constant = new (arena_) HLoadClass(graph_->GetCurrentMethod(),
storage_index,
*dex_compilation_unit_->GetDexFile(),
- is_referrer_class,
+ is_outer_class,
dex_pc);
current_block_->AddInstruction(constant);
HInstruction* cls = constant;
- if (!is_initialized && !is_referrer_class) {
+ if (!is_initialized && !is_outer_class) {
cls = new (arena_) HClinitCheck(constant, dex_pc);
current_block_->AddInstruction(cls);
}
@@ -1438,21 +1477,16 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
}
case Instruction::RETURN: {
- DCHECK_NE(return_type_, Primitive::kPrimNot);
- DCHECK_NE(return_type_, Primitive::kPrimLong);
- DCHECK_NE(return_type_, Primitive::kPrimDouble);
BuildReturn(instruction, return_type_);
break;
}
case Instruction::RETURN_OBJECT: {
- DCHECK(return_type_ == Primitive::kPrimNot);
BuildReturn(instruction, return_type_);
break;
}
case Instruction::RETURN_WIDE: {
- DCHECK(return_type_ == Primitive::kPrimDouble || return_type_ == Primitive::kPrimLong);
BuildReturn(instruction, return_type_);
break;
}
@@ -2075,32 +2109,37 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
case Instruction::MOVE_RESULT:
case Instruction::MOVE_RESULT_WIDE:
case Instruction::MOVE_RESULT_OBJECT:
- UpdateLocal(instruction.VRegA(), latest_result_);
- latest_result_ = nullptr;
+ if (latest_result_ == nullptr) {
+ // Only dead code can lead to this situation, where the verifier
+ // does not reject the method.
+ } else {
+ UpdateLocal(instruction.VRegA(), latest_result_);
+ latest_result_ = nullptr;
+ }
break;
case Instruction::CMP_LONG: {
- Binop_23x_cmp(instruction, Primitive::kPrimLong, HCompare::kNoBias);
+ Binop_23x_cmp(instruction, Primitive::kPrimLong, HCompare::kNoBias, dex_pc);
break;
}
case Instruction::CMPG_FLOAT: {
- Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kGtBias);
+ Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kGtBias, dex_pc);
break;
}
case Instruction::CMPG_DOUBLE: {
- Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kGtBias);
+ Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kGtBias, dex_pc);
break;
}
case Instruction::CMPL_FLOAT: {
- Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kLtBias);
+ Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kLtBias, dex_pc);
break;
}
case Instruction::CMPL_DOUBLE: {
- Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kLtBias);
+ Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kLtBias, dex_pc);
break;
}