Chromium Code Reviews| Index: runtime/vm/intermediate_language.cc |
| diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc |
| index 1ed759b493a3e8fd8574373539a3366afc7cdde3..27c7461e76c8280d9df85dc470ecffbcc17a4dd2 100644 |
| --- a/runtime/vm/intermediate_language.cc |
| +++ b/runtime/vm/intermediate_language.cc |
| @@ -3167,10 +3167,66 @@ bool InstanceCallInstr::MatchesCoreName(const String& name) { |
| bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const { |
| if (FLAG_precompiled_mode && with_checks()) return false; |
| + return targets_.HasSingleRecognizedTarget(); |
| +} |
| + |
| + |
| +bool PolymorphicTargets::HasSingleRecognizedTarget() const { |
|
Vyacheslav Egorov (Google)
2017/04/10 10:59:28
Please don't intersperse implementations of two di
erikcorry
2017/04/19 15:06:40
Done.
|
| + if (!HasSingleTarget()) return false; |
| + return MethodRecognizer::RecognizeKind(FirstTarget()) != |
|
Vyacheslav Egorov (Google)
2017/04/10 10:59:28
I think FirstTarget() should better be named Singl
erikcorry
2017/04/19 15:06:40
I'd like to leave it because it is sometimes used
|
| + MethodRecognizer::kUnknown; |
| +} |
| + |
| + |
| +bool PolymorphicTargets::HasSingleTarget() const { |
| + ASSERT(length() != 0); |
| + for (int i = 0; i < length(); i++) { |
| + if (cid_ranges_[i].target->raw() != cid_ranges_[0].target->raw()) |
| + return false; |
| + } |
| + return true; |
| +} |
| - return ic_data().HasOneTarget() && |
| - (MethodRecognizer::RecognizeKind(Function::Handle( |
| - ic_data().GetTargetAt(0))) != MethodRecognizer::kUnknown); |
| + |
| +bool PolymorphicInstanceCallInstr::HasOnlyDispatcherOrImplicitAccessorTargets() |
| + const { |
| + const intptr_t len = targets_.length(); |
| + Function& target = Function::Handle(); |
| + for (intptr_t i = 0; i < len; i++) { |
| + target ^= targets_[i].target->raw(); |
| + if (!target.IsDispatcherOrImplicitAccessor()) { |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| + |
| +bool PolymorphicInstanceCallInstr::HasSingleRecognizedCid() const { |
|
Vyacheslav Egorov (Google)
2017/04/10 10:59:28
Why is this function called HasSingleRecognizedCid
erikcorry
2017/04/19 15:06:40
Done.
|
| + if (targets_.length() != 1) return false; |
| + return targets_[0].cid_start == targets_[0].cid_end; |
| +} |
| + |
| + |
| +intptr_t PolymorphicInstanceCallInstr::SingleCid() const { |
|
Vyacheslav Egorov (Google)
2017/04/10 10:59:28
Better name would be MonomorphicReceiverCid().
erikcorry
2017/04/19 15:06:40
Done.
|
| + ASSERT(HasSingleRecognizedCid()); |
| + return targets_[0].cid_start; |
| +} |
| + |
| + |
| +Function& PolymorphicTargets::FirstTarget() const { |
|
Vyacheslav Egorov (Google)
2017/04/10 10:59:28
This should probably be SingleTarget()
erikcorry
2017/04/19 15:06:40
See above.
|
| + ASSERT(length() != 0); |
| + ASSERT(cid_ranges_[0].target->IsZoneHandle()); |
| + return *cid_ranges_[0].target; |
| +} |
| + |
| + |
| +intptr_t PolymorphicInstanceCallInstr::CallCount() const { |
|
Vyacheslav Egorov (Google)
2017/04/10 10:59:28
This should probably be just calling the method on
erikcorry
2017/04/19 15:06:40
Done.
|
| + intptr_t sum = 0; |
| + for (int i = 0; i < targets_.length(); i++) { |
| + sum += targets_[i].count; |
| + } |
| + return sum; |
| } |
| @@ -3178,10 +3234,9 @@ bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const { |
| // PolymorphicInstanceCallInstr. |
| #if !defined(TARGET_ARCH_DBC) |
| void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| - ASSERT(ic_data().NumArgsTested() == 1); |
| if (!with_checks()) { |
| - ASSERT(ic_data().HasOneTarget()); |
| - const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); |
| + ASSERT(HasSingleTarget()); |
| + const Function& target = Function::ZoneHandle(targets_[0].target->raw()); |
|
Vyacheslav Egorov (Google)
2017/04/10 10:59:28
Instead of the targets[0].target access use target
erikcorry
2017/04/19 15:06:40
Done.
|
| compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), |
| target, instance_call()->ArgumentCount(), |
| instance_call()->argument_names(), locs(), |
| @@ -3190,7 +3245,7 @@ void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| } |
| compiler->EmitPolymorphicInstanceCall( |
| - ic_data(), instance_call()->ArgumentCount(), |
| + targets_, *instance_call(), instance_call()->ArgumentCount(), |
| instance_call()->argument_names(), deopt_id(), |
| instance_call()->token_pos(), locs(), complete(), total_call_count()); |
| } |
| @@ -3198,22 +3253,29 @@ void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( |
| - const ICData& ic_data) { |
| + const PolymorphicTargets& targets) { |
| bool is_string = true; |
| bool is_integer = true; |
| bool is_double = true; |
| - const intptr_t num_checks = ic_data.NumberOfChecks(); |
| + const intptr_t num_checks = targets.length(); |
| for (intptr_t i = 0; i < num_checks; i++) { |
| - const intptr_t cid = ic_data.GetReceiverClassIdAt(i); |
| - is_string = is_string && RawObject::IsStringClassId(cid); |
| - is_integer = is_integer && RawObject::IsIntegerClassId(cid); |
| - is_double = is_double && (cid == kDoubleCid); |
| + ASSERT(targets[i].target->raw() == targets[0].target->raw()); |
| + const intptr_t start = targets[i].cid_start; |
| + const intptr_t end = targets[i].cid_end; |
| + for (intptr_t cid = start; cid <= end; cid++) { |
| + is_string = is_string && RawObject::IsStringClassId(cid); |
| + is_integer = is_integer && RawObject::IsIntegerClassId(cid); |
| + is_double = is_double && (cid == kDoubleCid); |
| + } |
| } |
| if (is_string) { |
| + ASSERT(!is_integer); |
| + ASSERT(!is_double); |
| return Type::StringType(); |
| } else if (is_integer) { |
| + ASSERT(!is_double); |
| return Type::IntType(); |
| } else if (is_double) { |
| return Type::Double(); |
| @@ -3226,12 +3288,20 @@ RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( |
| Definition* InstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { |
| const intptr_t receiver_cid = PushArgumentAt(0)->value()->Type()->ToCid(); |
| - if (!HasICData()) return this; |
| + if (ic_data()->NumArgsTested() != 1) return this; |
|
Vyacheslav Egorov (Google)
2017/04/10 10:59:28
Please elaborate why this check is here so that th
erikcorry
2017/04/19 15:06:40
I can't remember :-/. I have the benchmarking ser
|
| + |
| + // TODO(erikcorry): Even for cold call sites we could still try to look up |
| + // methods when we know the receiver cid. We don't currently do this because |
| + // it turns the InstanceCall into a PolymorphicInstanceCall which doesn't get |
| + // recognized or inlined when it is cold. |
|
Vyacheslav Egorov (Google)
2017/04/10 10:59:28
I don't think coldness has anything to do with it.
erikcorry
2017/04/19 15:06:40
Things seem to work with this check here, that che
|
| + if (ic_data()->NumberOfUsedChecks() == 0) return this; |
| - const ICData& new_ic_data = |
| - FlowGraphCompiler::TrySpecializeICDataByReceiverCid(*ic_data(), |
| - receiver_cid); |
| - if (new_ic_data.raw() == ic_data()->raw()) { |
| + const PolymorphicTargets* new_target = |
| + FlowGraphCompiler::TrySpecializeByReceiverCid( |
| + Array::Handle(flow_graph->zone(), ic_data()->arguments_descriptor()), |
| + String::Handle(flow_graph->zone(), ic_data()->target_name()), |
| + receiver_cid); |
| + if (new_target == NULL) { |
| // No specialization. |
| return this; |
| } |
| @@ -3239,21 +3309,21 @@ Definition* InstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { |
| const bool with_checks = false; |
| const bool complete = false; |
| PolymorphicInstanceCallInstr* specialized = new PolymorphicInstanceCallInstr( |
| - this, new_ic_data, with_checks, complete); |
| + this, *new_target, with_checks, complete); |
| flow_graph->InsertBefore(this, specialized, env(), FlowGraph::kValue); |
| return specialized; |
| } |
| Definition* PolymorphicInstanceCallInstr::Canonicalize(FlowGraph* flow_graph) { |
| - if (!HasSingleRecognizedTarget() || with_checks()) { |
| + if (!HasSingleRecognizedTarget()) { |
| return this; |
| } |
| - const Function& target = Function::Handle(ic_data().GetTargetAt(0)); |
| + const Function& target = FirstTarget(); |
| if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { |
| const AbstractType& type = |
| - AbstractType::Handle(ComputeRuntimeType(ic_data())); |
| + AbstractType::Handle(ComputeRuntimeType(targets_)); |
| if (!type.IsNull()) { |
| return flow_graph->GetConstant(type); |
| } |