| Index: runtime/vm/jit_optimizer.cc
|
| diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc
|
| index f85d9c46fb3b212ad580ed0ee36a5428469b0e57..6dbb8194964a4c4b3d569fce522910fa3cab3e01 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());
|
| }
|
| @@ -1444,83 +1448,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;
|
| -
|
| - Function& target_function = Function::Handle(
|
| - Z, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc));
|
| - 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) {
|
| @@ -1578,11 +1505,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,
|
| @@ -1590,7 +1515,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);
|
| @@ -1603,7 +1528,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());
|
| @@ -1614,15 +1539,17 @@ void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
|
| bool call_with_checks;
|
| if (has_one_target && FLAG_polymorphic_with_deopt) {
|
| // 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());
|
| }
|
|
|
|
|