Index: runtime/vm/flow_graph_optimizer.cc |
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc |
index 7096933a90cae095d5c24cab3825c965771c7431..ad05b66b5a364c90701f1b4b6590684e539b07a1 100644 |
--- a/runtime/vm/flow_graph_optimizer.cc |
+++ b/runtime/vm/flow_graph_optimizer.cc |
@@ -603,10 +603,8 @@ bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { |
case kUint8ArrayCid: |
case kFloat32ArrayCid: |
case kFloat64ArrayCid: { |
- ConstantInstr* null_constant = new ConstantInstr(Object::ZoneHandle()); |
- InsertBefore(call, null_constant, NULL, Definition::kValue); |
- instantiator = new Value(null_constant); |
- type_args = new Value(null_constant); |
+ instantiator = new Value(flow_graph_->constant_null()); |
+ type_args = new Value(flow_graph_->constant_null()); |
ASSERT((class_id != kUint8ArrayCid) || value_type.IsIntType()); |
ASSERT((class_id != kFloat32ArrayCid && class_id != kFloat64ArrayCid) || |
value_type.IsDoubleType()); |
@@ -964,6 +962,23 @@ bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( |
} |
+bool FlowGraphOptimizer::MethodExtractorNeedsClassCheck( |
+ InstanceCallInstr* call) const { |
+ if (!FLAG_use_cha) return true; |
+ Definition* callee_receiver = call->ArgumentAt(0)->value()->definition(); |
+ ASSERT(callee_receiver != NULL); |
+ const Function& function = flow_graph_->parsed_function().function(); |
+ if (function.IsDynamicFunction() && |
+ callee_receiver->IsParameter() && |
+ (callee_receiver->AsParameter()->index() == 0)) { |
+ const String& field_name = |
+ String::Handle(Field::NameFromGetter(call->function_name())); |
+ return CHA::HasOverride(Class::Handle(function.Owner()), field_name); |
+ } |
+ return true; |
+} |
+ |
+ |
void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { |
ASSERT(call->HasICData()); |
const ICData& ic_data = *call->ic_data(); |
@@ -1111,6 +1126,8 @@ bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
} |
InlineImplicitInstanceGetter(call); |
return true; |
+ } else if (target.kind() == RawFunction::kMethodExtractor) { |
+ return false; |
} |
// Not an implicit getter. |
@@ -1363,6 +1380,7 @@ void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
const ICData& unary_checks = |
ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); |
+ |
if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) && |
InstanceCallNeedsClassCheck(instr)) { |
// Too many checks, it will be megamorphic which needs unary checks. |
@@ -1395,17 +1413,27 @@ void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
if (TryInlineInstanceMethod(instr)) { |
return; |
} |
- if (!InstanceCallNeedsClassCheck(instr)) { |
- const bool call_with_checks = false; |
- PolymorphicInstanceCallInstr* call = |
- new PolymorphicInstanceCallInstr(instr, unary_checks, |
- call_with_checks); |
- instr->ReplaceWith(call, current_iterator()); |
- return; |
+ |
+ const bool has_one_target = unary_checks.HasOneTarget(); |
+ |
+ if (has_one_target) { |
+ const bool is_method_extraction = |
+ Function::Handle(unary_checks.GetTargetAt(0)).IsMethodExtractor(); |
+ |
+ if ((is_method_extraction && !MethodExtractorNeedsClassCheck(instr)) || |
+ (!is_method_extraction && !InstanceCallNeedsClassCheck(instr))) { |
+ const bool call_with_checks = false; |
+ PolymorphicInstanceCallInstr* call = |
+ new PolymorphicInstanceCallInstr(instr, unary_checks, |
+ call_with_checks); |
+ instr->ReplaceWith(call, current_iterator()); |
+ return; |
+ } |
} |
+ |
if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
bool call_with_checks; |
- if (unary_checks.HasOneTarget()) { |
+ if (has_one_target) { |
// Type propagation has not run yet, we cannot eliminate the check. |
AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); |
// Call can still deoptimize, do not detach environment from instr. |