Index: runtime/vm/flow_graph_optimizer.cc |
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc |
index 40a36f8a6b4428f559284525b86c24e44a417899..87a1ebdfcd3dd593e66a074db273cdd5fb6afd10 100644 |
--- a/runtime/vm/flow_graph_optimizer.cc |
+++ b/runtime/vm/flow_graph_optimizer.cc |
@@ -572,10 +572,8 @@ bool FlowGraphOptimizer::TryReplaceWithStoreIndexed(InstanceCallInstr* call) { |
} |
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(value_type.IsDoubleType()); |
ASSERT(value_type.IsInstantiated()); |
break; |
@@ -927,6 +925,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())); |
srdjan
2013/01/16 22:08:56
indent 4 spaces
|
+ 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(); |
@@ -1040,6 +1055,49 @@ void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) { |
} |
+void FlowGraphOptimizer::InlineMethodExtractor(InstanceCallInstr* call) { |
+ Value* receiver = call->ArgumentAt(0)->value(); |
+ if (MethodExtractorNeedsClassCheck(call)) { |
+ AddCheckClass(call, receiver->Copy()); |
+ } |
+ |
+ // Load and push type arguments. |
+ Definition* type_arguments = NULL; |
+ |
+ const Class& receiver_class = Class::Handle( |
+ Isolate::Current()->class_table()->At(ReceiverClassId(call))); |
+ const intptr_t type_arguments_field_offset = |
+ receiver_class.type_arguments_field_offset(); |
+ if (type_arguments_field_offset != Class::kNoTypeArguments) { |
+ type_arguments = new LoadFieldInstr(receiver->Copy(), |
+ type_arguments_field_offset, |
+ Type::ZoneHandle()); // No type. |
+ InsertBefore(call, type_arguments, NULL, Definition::kValue); |
+ } else { |
+ type_arguments = flow_graph_->constant_null(); |
+ } |
+ |
+ PushArgumentInstr* push_type_arguments = |
+ new PushArgumentInstr(new Value(type_arguments)); |
+ InsertBefore(call, push_type_arguments, NULL, Definition::kEffect); |
+ |
+ ZoneGrowableArray<PushArgumentInstr*>* args = |
+ new ZoneGrowableArray<PushArgumentInstr*>(2); |
+ |
+ args->Add(call->ArgumentAt(0)); |
+ args->Add(push_type_arguments); |
+ |
+ const Function& extractor = Function::Handle(call->ic_data()->GetTargetAt(0)); |
+ const Function& function = |
+ Function::ZoneHandle(extractor.extracted_method_closure()); |
+ ASSERT(function.IsImplicitInstanceClosureFunction()); |
+ call->set_env(NULL); |
+ CreateClosureInstr* create_closure = |
+ new CreateClosureInstr(function, args, call->token_pos()); |
+ call->ReplaceWith(create_closure, current_iterator()); |
+} |
+ |
+ |
// Only unique implicit instance getters can be currently handled. |
bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
ASSERT(call->HasICData()); |
@@ -1056,6 +1114,12 @@ bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
} |
InlineImplicitInstanceGetter(call); |
return true; |
+ } else if (target.kind() == RawFunction::kMethodExtractor) { |
+ if (!ic_data.HasOneTarget()) { |
+ return false; |
+ } |
+ InlineMethodExtractor(call); |
+ return true; |
} |
// Not an implicit getter. |
@@ -1224,6 +1288,7 @@ void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
const ICData& unary_checks = |
ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); |
+ const bool has_one_target = unary_checks.HasOneTarget(); |
if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) && |
InstanceCallNeedsClassCheck(instr)) { |
// Too many checks, it will be megamorphic which needs unary checks. |
@@ -1257,7 +1322,8 @@ void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
if (TryInlineInstanceMethod(instr)) { |
return; |
} |
- if (!InstanceCallNeedsClassCheck(instr)) { |
+ if (has_one_target && !InstanceCallNeedsClassCheck(instr)) { |
+ ASSERT(!Function::Handle(unary_checks.GetTargetAt(0)).IsMethodExtractor()); |
const bool call_with_checks = false; |
PolymorphicInstanceCallInstr* call = |
new PolymorphicInstanceCallInstr(instr, unary_checks, |
@@ -1267,7 +1333,7 @@ void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
} |
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. |