Chromium Code Reviews| Index: runtime/vm/flow_graph_optimizer.cc |
| =================================================================== |
| --- runtime/vm/flow_graph_optimizer.cc (revision 13762) |
| +++ runtime/vm/flow_graph_optimizer.cc (working copy) |
| @@ -13,6 +13,7 @@ |
| #include "vm/intermediate_language.h" |
| #include "vm/object_store.h" |
| #include "vm/parser.h" |
| +#include "vm/resolver.h" |
| #include "vm/scopes.h" |
| #include "vm/symbols.h" |
| @@ -28,11 +29,82 @@ |
| DEFINE_FLAG(bool, trace_constant_propagation, false, |
| "Print constant propagation and useless code elimination."); |
| + |
| void FlowGraphOptimizer::ApplyICData() { |
| VisitBlocks(); |
| } |
| +// Attempts to convert an instance call (IC call) using propagated class-ids, |
| +// e.g., receiver class id. |
| +void FlowGraphOptimizer::ApplyClassIds() { |
| + ASSERT(current_iterator_ == NULL); |
| + for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| + BlockEntryInstr* entry = block_order_[i]; |
| + ForwardInstructionIterator it(entry); |
| + current_iterator_ = ⁢ |
| + for (; !it.Done(); it.Advance()) { |
| + if (it.Current()->IsInstanceCall()) { |
| + InstanceCallInstr* call = it.Current()->AsInstanceCall(); |
| + if (call->HasICData()) { |
| + if (TryCreateICData(call)) { |
| + VisitInstanceCall(call); |
| + } |
| + } |
| + } |
| + } |
| + current_iterator_ = NULL; |
| + } |
| +} |
| + |
| + |
| +// Attempt to build ICData for call using propagated class-ids. |
| +bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { |
| + ASSERT(call->HasICData()); |
| + if (call->ic_data()->NumberOfChecks() > 0) { |
| + // This occurs when an instance call has too many checks. |
| + // TODO(srdjan): Replace IC call with megamorphic call. |
| + return false; |
| + } |
| + GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested()); |
| + ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount()); |
| + for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) { |
| + intptr_t cid = call->ArgumentAt(i)->value()->ResultCid(); |
| + class_ids.Add(cid); |
| + } |
| + // TODO(srdjan): Test for other class_ids > 1. |
| + if (class_ids.length() != 1) return false; |
| + if (class_ids[0] != kDynamicCid) { |
| + const intptr_t num_named_arguments = call->argument_names().IsNull() ? |
| + 0 : call->argument_names().Length(); |
| + const Class& receiver_class = Class::Handle( |
| + Isolate::Current()->class_table()->At(class_ids[0])); |
| + Function& function = Function::Handle(); |
| + function = Resolver::ResolveDynamicForReceiverClass( |
| + receiver_class, |
| + call->function_name(), |
| + call->ArgumentCount(), |
| + num_named_arguments); |
| + if (function.IsNull()) { |
| + return false; |
| + } |
| + // Create new ICData, do not modify the one attached to instruction |
|
Florian Schneider
2012/10/18 17:42:59
[...] to _the_ instruction
srdjan
2012/10/18 18:41:39
Done.
|
| + // since it is attached to the assembly instruction itself. |
| + // TODO(srdjan): Prevent modification of ICData object that is |
| + // referenced in assembly code. |
| + ICData& ic_data = ICData::ZoneHandle(ICData::New( |
| + flow_graph_->parsed_function().function(), |
| + call->function_name(), |
| + call->deopt_id(), |
| + class_ids.length())); |
| + ic_data.AddReceiverCheck(class_ids[0], function); |
| + call->set_ic_data(&ic_data); |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| + |
| static void ReplaceCurrentInstruction(ForwardInstructionIterator* it, |
| Instruction* current, |
| Instruction* replacement) { |
| @@ -1063,8 +1135,7 @@ |
| instr->ReplaceWith(call, current_iterator()); |
| } |
| } |
| - // An instance call without ICData should continue calling via IC calls |
| - // which should trigger reoptimization of optimized code. |
| + // An instance call without ICData will trigger deoptimization. |
| } |