Index: runtime/vm/jit_optimizer.cc |
diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc |
index bdfcddcf09c00fd4e391dfcdc6dc4debc786c0ba..fb6ee1d43be1d01be334cbb573a14b2f57af868e 100644 |
--- a/runtime/vm/jit_optimizer.cc |
+++ b/runtime/vm/jit_optimizer.cc |
@@ -209,9 +209,13 @@ void JitOptimizer::SpecializePolymorphicInstanceCall( |
return; // No information about receiver was infered. |
} |
- const ICData& ic_data = FlowGraphCompiler::TrySpecializeICDataByReceiverCid( |
- call->ic_data(), receiver_cid); |
- if (ic_data.raw() == call->ic_data().raw()) { |
+ const ICData& ic_data = *call->instance_call()->ic_data(); |
+ |
+ const CallTargets* targets = |
+ FlowGraphCompiler::ResolveCallTargetsForReceiverCid( |
+ receiver_cid, String::Handle(zone(), ic_data.target_name()), |
+ Array::Handle(zone(), ic_data.arguments_descriptor())); |
+ if (targets == NULL) { |
// No specialization. |
return; |
} |
@@ -219,7 +223,7 @@ void JitOptimizer::SpecializePolymorphicInstanceCall( |
const bool with_checks = false; |
const bool complete = false; |
PolymorphicInstanceCallInstr* specialized = |
- new (Z) PolymorphicInstanceCallInstr(call->instance_call(), ic_data, |
+ new (Z) PolymorphicInstanceCallInstr(call->instance_call(), *targets, |
with_checks, complete); |
call->ReplaceWith(specialized, current_iterator()); |
} |
@@ -1448,85 +1452,6 @@ void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
} |
-bool JitOptimizer::LookupMethodFor(int class_id, |
- const ArgumentsDescriptor& args_desc, |
- const String& name, |
- Function* fn_return) { |
- if (class_id < 0) return false; |
- if (class_id >= I->class_table()->NumCids()) return false; |
- |
- RawClass* raw_class = I->class_table()->At(class_id); |
- if (raw_class == NULL) return false; |
- Class& cls = Class::Handle(Z, raw_class); |
- if (cls.IsNull()) return false; |
- if (!cls.is_finalized()) return false; |
- if (Array::Handle(cls.functions()).IsNull()) return false; |
- |
- bool allow_add = false; |
- Function& target_function = |
- Function::Handle(Z, Resolver::ResolveDynamicForReceiverClass( |
- cls, name, args_desc, allow_add)); |
- if (target_function.IsNull()) return false; |
- *fn_return ^= target_function.raw(); |
- return true; |
-} |
- |
- |
-static int OrderById(const intptr_t* a, const intptr_t* b) { |
- // Negative if 'a' should sort before 'b'. |
- return *a - *b; |
-} |
- |
- |
-void JitOptimizer::TryExpandClassesInICData(const ICData& ic_data) { |
- if (ic_data.NumberOfChecks() == 0) return; |
- |
- Function& dummy = Function::Handle(Z); |
- |
- GrowableArray<intptr_t> ids; |
- for (int i = 0; i < ic_data.NumberOfChecks(); i++) { |
- // The API works for multi dispatch ICs that check more than one argument, |
- // but we know we only check one arg here, so only the 0th element of id |
- // will be used. |
- GrowableArray<intptr_t> id; |
- ic_data.GetCheckAt(i, &id, &dummy); |
- ids.Add(id[0]); |
- } |
- ids.Sort(OrderById); |
- |
- Array& args_desc_array = Array::Handle(Z, ic_data.arguments_descriptor()); |
- ArgumentsDescriptor args_desc(args_desc_array); |
- String& name = String::Handle(Z, ic_data.target_name()); |
- |
- Function& fn = Function::Handle(Z); |
- Function& fn_high = Function::Handle(Z); |
- Function& possible_match = Function::Handle(Z); |
- |
- for (int cid_index = 0; cid_index < ids.length() - 1; cid_index++) { |
- int low_cid = ids[cid_index]; |
- int high_cid = ids[cid_index + 1]; |
- if (low_cid + 1 == high_cid) continue; |
- if (LookupMethodFor(low_cid, args_desc, name, &fn) && |
- LookupMethodFor(high_cid, args_desc, name, &fn_high) && |
- fn.raw() == fn_high.raw()) { |
- // Try to fill in the IC table by going downwards from a known class-id. |
- bool can_fill_in = true; |
- for (int i = low_cid + 1; i < high_cid; i++) { |
- if (!LookupMethodFor(i, args_desc, name, &possible_match) || |
- possible_match.raw() != fn.raw()) { |
- can_fill_in = false; |
- break; |
- } |
- } |
- if (can_fill_in) { |
- for (int i = low_cid + 1; i < high_cid; i++) { |
- ic_data.AddReceiverCheck(i, fn, 0); |
- } |
- } |
- } |
- } |
-} |
- |
// Tries to optimize instance call by replacing it with a faster instruction |
// (e.g, binary op, field load, ..). |
void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
@@ -1584,11 +1509,9 @@ void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
return; |
} |
- // Now we are done trying the inlining options that benefit from only having |
- // 1 entry in the IC table. |
- TryExpandClassesInICData(unary_checks); |
+ CallTargets* targets = CallTargets::Create(Z, unary_checks); |
- bool has_one_target = unary_checks.HasOneTarget(); |
+ bool has_one_target = targets->HasSingleTarget(); |
if (has_one_target) { |
// Check if the single target is a polymorphic target, if it is, |
@@ -1596,7 +1519,7 @@ void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); |
if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { |
has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType( |
- unary_checks) != Type::null(); |
+ *targets) != Type::null(); |
} else { |
const bool polymorphic_target = |
MethodRecognizer::PolymorphicTarget(target); |
@@ -1609,7 +1532,7 @@ void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
const RawFunction::Kind function_kind = target.kind(); |
if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { |
PolymorphicInstanceCallInstr* call = |
- new (Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
+ new (Z) PolymorphicInstanceCallInstr(instr, *targets, |
/* call_with_checks = */ false, |
/* complete = */ false); |
instr->ReplaceWith(call, current_iterator()); |
@@ -1632,15 +1555,17 @@ void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
(!instr->ic_data()->HasDeoptReason(ICData::kDeoptCheckClass) || |
unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { |
// Type propagation has not run yet, we cannot eliminate the check. |
+ // TODO(erikcorry): The receiver check should use the off-heap targets |
+ // array, not the IC array. |
AddReceiverCheck(instr); |
// Call can still deoptimize, do not detach environment from instr. |
call_with_checks = false; |
} else { |
call_with_checks = true; |
} |
- PolymorphicInstanceCallInstr* call = new (Z) |
- PolymorphicInstanceCallInstr(instr, unary_checks, call_with_checks, |
- /* complete = */ false); |
+ PolymorphicInstanceCallInstr* call = |
+ new (Z) PolymorphicInstanceCallInstr(instr, *targets, call_with_checks, |
+ /* complete = */ false); |
instr->ReplaceWith(call, current_iterator()); |
} |