Chromium Code Reviews| 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. |