Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/flow_graph_builder.h" | 7 #include "vm/flow_graph_builder.h" |
| 8 #include "vm/il_printer.h" | 8 #include "vm/il_printer.h" |
| 9 #include "vm/object_store.h" | 9 #include "vm/object_store.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 DECLARE_FLAG(bool, enable_type_checks); | |
| 13 DECLARE_FLAG(bool, print_flow_graph); | 14 DECLARE_FLAG(bool, print_flow_graph); |
| 14 DECLARE_FLAG(bool, trace_optimization); | 15 DECLARE_FLAG(bool, trace_optimization); |
| 15 | 16 |
| 16 void FlowGraphOptimizer::ApplyICData() { | 17 void FlowGraphOptimizer::ApplyICData() { |
| 17 VisitBlocks(); | 18 VisitBlocks(); |
| 18 if (FLAG_print_flow_graph) { | 19 if (FLAG_print_flow_graph) { |
| 19 OS::Print("After Optimizations:\n"); | 20 OS::Print("After Optimizations:\n"); |
| 20 FlowGraphPrinter printer(Function::Handle(), block_order_); | 21 FlowGraphPrinter printer(Function::Handle(), block_order_); |
| 21 printer.PrintBlocks(); | 22 printer.PrintBlocks(); |
| 22 } | 23 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 } | 131 } |
| 131 if (unary_op != NULL) { | 132 if (unary_op != NULL) { |
| 132 ASSERT(unary_op->ic_data() == NULL); | 133 ASSERT(unary_op->ic_data() == NULL); |
| 133 unary_op->set_ic_data(comp->ic_data()); | 134 unary_op->set_ic_data(comp->ic_data()); |
| 134 unary_op->set_instr(comp->instr()); | 135 unary_op->set_instr(comp->instr()); |
| 135 comp->instr()->replace_computation(unary_op); | 136 comp->instr()->replace_computation(unary_op); |
| 136 } | 137 } |
| 137 } | 138 } |
| 138 | 139 |
| 139 | 140 |
| 141 // Returns true if all targets are the same. | |
| 142 static bool HasOneTarget(const ICData& ic_data) { | |
| 143 ASSERT(ic_data.NumberOfChecks() > 0); | |
| 144 Function& prev_target = Function::Handle(); | |
| 145 Class& cls = Class::Handle(); | |
| 146 ic_data.GetOneClassCheckAt(0, &cls, &prev_target); | |
| 147 ASSERT(!prev_target.IsNull()); | |
| 148 Function& target = Function::Handle(); | |
| 149 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { | |
| 150 ic_data.GetOneClassCheckAt(i, &cls, &target); | |
| 151 ASSERT(!target.IsNull()); | |
| 152 if (prev_target.raw() != target.raw()) { | |
| 153 return false; | |
| 154 } | |
| 155 prev_target = target.raw(); | |
| 156 } | |
| 157 return true; | |
| 158 } | |
| 159 | |
| 160 | |
| 161 // Using field class | |
| 162 static RawField* GetField(const Class& field_class, const String& field_name) { | |
| 163 Class& cls = Class::Handle(field_class.raw()); | |
| 164 Field& field = Field::Handle(); | |
| 165 while (!cls.IsNull()) { | |
| 166 field = cls.LookupInstanceField(field_name); | |
| 167 if (!field.IsNull()) { | |
| 168 return field.raw(); | |
| 169 } | |
| 170 cls = cls.SuperClass(); | |
| 171 } | |
| 172 return Field::null(); | |
| 173 } | |
| 174 | |
| 175 | |
| 176 // Returns array of all class ids that are in ic_data. The result is | |
| 177 // normalized so that a smi class is at index 0 if it exists in the ic_data. | |
| 178 static ZoneGrowableArray<intptr_t>* ExtractClassIds(const ICData& ic_data) { | |
| 179 if (ic_data.NumberOfChecks() == 0) return NULL; | |
| 180 ZoneGrowableArray<intptr_t>* result = | |
| 181 new ZoneGrowableArray<intptr_t>(ic_data.NumberOfChecks()); | |
| 182 intptr_t smi_index = -1; | |
| 183 Function& target = Function::Handle(); | |
| 184 Class& cls = Class::Handle(); | |
| 185 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | |
| 186 ic_data.GetOneClassCheckAt(i, &cls, &target); | |
| 187 result->Add(cls.id()); | |
| 188 if (cls.id() == kSmi) { | |
| 189 ASSERT(smi_index < 0); // Classes entered only once in ic_data. | |
| 190 smi_index = i; | |
| 191 } | |
| 192 } | |
| 193 if (smi_index >= 0) { | |
| 194 // Smi class id must be at index 0. | |
| 195 intptr_t temp = (*result)[0]; | |
| 196 (*result)[0] = (*result)[smi_index]; | |
| 197 (*result)[smi_index] = temp; | |
| 198 } | |
| 199 return result; | |
| 200 } | |
| 201 | |
| 202 | |
| 203 // Only unique implicit instance getters can be currently handled. | |
| 204 void FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { | |
| 205 ASSERT(comp->HasICData()); | |
| 206 const ICData& ic_data = *comp->ic_data(); | |
| 207 if (ic_data.NumberOfChecks() == 0) { | |
| 208 // No type feedback collected | |
| 209 return; | |
| 210 } | |
| 211 if (!HasOneTarget(ic_data)) { | |
| 212 // TODO(srdjan): Implement when not all targets are the sa,e. | |
| 213 return; | |
| 214 } | |
| 215 Function& target = Function::Handle(); | |
| 216 Class& cls = Class::Handle(); | |
| 217 ic_data.GetOneClassCheckAt(0, &cls, &target); | |
| 218 if (target.kind() != RawFunction::kImplicitGetter) { | |
| 219 // Not an implicit getter. | |
| 220 // TODO(srdjan): Inline special getters (e.g., array length). | |
| 221 return; | |
| 222 } | |
| 223 // Inline implicit instance getter. | |
| 224 const String& field_name = | |
| 225 String::Handle(Field::NameFromGetter(comp->function_name())); | |
| 226 const Field& field = Field::Handle(GetField(cls, field_name)); | |
| 227 ASSERT(!field.IsNull()); | |
| 228 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( | |
| 229 field, comp->InputAt(0), comp, ExtractClassIds(ic_data)); | |
| 230 // Replace 'comp' with 'load'. | |
| 231 load->set_instr(comp->instr()); | |
| 232 comp->instr()->replace_computation(load); | |
| 233 } | |
| 234 | |
| 235 | |
| 236 void FlowGraphOptimizer::TryInlineInstanceSetter(InstanceSetterComp* comp) { | |
| 237 ASSERT(comp->HasICData()); | |
| 238 const ICData& ic_data = *comp->ic_data(); | |
| 239 OS::Print("TryInlineInstanceSetter %d\n", ic_data.NumberOfChecks()); | |
| 240 if (ic_data.NumberOfChecks() == 0) { | |
| 241 // No type feedback collected | |
| 242 return; | |
| 243 } | |
| 244 if (!HasOneTarget(ic_data)) { | |
| 245 // TODO(srdjan): Implement when not all targets are the sa,e. | |
| 246 return; | |
| 247 } | |
| 248 Function& target = Function::Handle(); | |
| 249 Class& cls = Class::Handle(); | |
| 250 ic_data.GetOneClassCheckAt(0, &cls, &target); | |
| 251 if (target.kind() != RawFunction::kImplicitSetter) { | |
| 252 // Not an implicit setter. | |
| 253 // TODO(srdjan): Inline special getters (e.g., array length). | |
|
Florian Schneider
2012/06/07 08:47:59
s/getter/setter/
srdjan
2012/06/07 18:24:50
Done.
| |
| 254 return; | |
| 255 } | |
| 256 // Inline implicit instance setter. | |
| 257 const Field& field = Field::Handle(GetField(cls, comp->field_name())); | |
| 258 ASSERT(!field.IsNull()); | |
| 259 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( | |
| 260 field, | |
| 261 comp->InputAt(0), | |
| 262 comp->InputAt(1), | |
| 263 comp, | |
| 264 ExtractClassIds(ic_data)); | |
| 265 // Replace 'comp' with 'load'. | |
|
Florian Schneider
2012/06/07 08:47:59
s/load/store/
srdjan
2012/06/07 18:24:50
Done.
| |
| 266 store->set_instr(comp->instr()); | |
| 267 comp->instr()->replace_computation(store); | |
| 268 } | |
| 269 | |
| 270 | |
| 140 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { | 271 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { |
| 141 if ((comp->ic_data() != NULL) && (!comp->ic_data()->IsNull())) { | 272 if (comp->HasICData()) { |
| 142 Token::Kind op_kind = Token::GetBinaryOp(comp->function_name()); | 273 const String& function_name = comp->function_name(); |
| 274 Token::Kind op_kind = Token::GetBinaryOp(function_name); | |
| 143 if (op_kind != Token::kILLEGAL) { | 275 if (op_kind != Token::kILLEGAL) { |
| 144 TryReplaceWithBinaryOp(comp, op_kind); | 276 TryReplaceWithBinaryOp(comp, op_kind); |
| 145 return; | 277 return; |
| 146 } | 278 } |
| 147 op_kind = Token::GetUnaryOp(comp->function_name()); | 279 op_kind = Token::GetUnaryOp(function_name); |
| 148 if (op_kind != Token::kILLEGAL) { | 280 if (op_kind != Token::kILLEGAL) { |
| 149 TryReplaceWithUnaryOp(comp, op_kind); | 281 TryReplaceWithUnaryOp(comp, op_kind); |
| 150 return; | 282 return; |
| 151 } | 283 } |
| 284 if (Field::IsGetterName(function_name)) { | |
| 285 TryInlineInstanceGetter(comp); | |
| 286 return; | |
| 287 } | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 | |
| 292 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { | |
| 293 // TODO(srdjan): Add assigneable check node if --enable_type_checks. | |
| 294 if (comp->HasICData() && !FLAG_enable_type_checks) { | |
| 295 TryInlineInstanceSetter(comp); | |
| 152 } | 296 } |
| 153 } | 297 } |
| 154 | 298 |
| 155 | 299 |
| 156 void FlowGraphOptimizer::VisitDo(DoInstr* instr) { | 300 void FlowGraphOptimizer::VisitDo(DoInstr* instr) { |
| 157 instr->computation()->Accept(this); | 301 instr->computation()->Accept(this); |
| 158 } | 302 } |
| 159 | 303 |
| 160 | 304 |
| 161 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { | 305 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 162 instr->computation()->Accept(this); | 306 instr->computation()->Accept(this); |
| 163 } | 307 } |
| 164 | 308 |
| 165 | 309 |
| 166 } // namespace dart | 310 } // namespace dart |
| OLD | NEW |