| 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 if (ic_data.NumberOfChecks() == 0) { |
| 240 // No type feedback collected |
| 241 return; |
| 242 } |
| 243 if (!HasOneTarget(ic_data)) { |
| 244 // TODO(srdjan): Implement when not all targets are the sa,e. |
| 245 return; |
| 246 } |
| 247 Function& target = Function::Handle(); |
| 248 Class& cls = Class::Handle(); |
| 249 ic_data.GetOneClassCheckAt(0, &cls, &target); |
| 250 if (target.kind() != RawFunction::kImplicitSetter) { |
| 251 // Not an implicit setter. |
| 252 // TODO(srdjan): Inline special setters. |
| 253 return; |
| 254 } |
| 255 // Inline implicit instance setter. |
| 256 const Field& field = Field::Handle(GetField(cls, comp->field_name())); |
| 257 ASSERT(!field.IsNull()); |
| 258 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
| 259 field, |
| 260 comp->InputAt(0), |
| 261 comp->InputAt(1), |
| 262 comp, |
| 263 ExtractClassIds(ic_data)); |
| 264 // Replace 'comp' with 'store'. |
| 265 store->set_instr(comp->instr()); |
| 266 comp->instr()->replace_computation(store); |
| 267 } |
| 268 |
| 269 |
| 140 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { | 270 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { |
| 141 if ((comp->ic_data() != NULL) && (!comp->ic_data()->IsNull())) { | 271 if (comp->HasICData()) { |
| 142 Token::Kind op_kind = Token::GetBinaryOp(comp->function_name()); | 272 const String& function_name = comp->function_name(); |
| 273 Token::Kind op_kind = Token::GetBinaryOp(function_name); |
| 143 if (op_kind != Token::kILLEGAL) { | 274 if (op_kind != Token::kILLEGAL) { |
| 144 TryReplaceWithBinaryOp(comp, op_kind); | 275 TryReplaceWithBinaryOp(comp, op_kind); |
| 145 return; | 276 return; |
| 146 } | 277 } |
| 147 op_kind = Token::GetUnaryOp(comp->function_name()); | 278 op_kind = Token::GetUnaryOp(function_name); |
| 148 if (op_kind != Token::kILLEGAL) { | 279 if (op_kind != Token::kILLEGAL) { |
| 149 TryReplaceWithUnaryOp(comp, op_kind); | 280 TryReplaceWithUnaryOp(comp, op_kind); |
| 150 return; | 281 return; |
| 151 } | 282 } |
| 283 if (Field::IsGetterName(function_name)) { |
| 284 TryInlineInstanceGetter(comp); |
| 285 return; |
| 286 } |
| 287 } |
| 288 } |
| 289 |
| 290 |
| 291 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { |
| 292 // TODO(srdjan): Add assigneable check node if --enable_type_checks. |
| 293 if (comp->HasICData() && !FLAG_enable_type_checks) { |
| 294 TryInlineInstanceSetter(comp); |
| 152 } | 295 } |
| 153 } | 296 } |
| 154 | 297 |
| 155 | 298 |
| 156 void FlowGraphOptimizer::VisitDo(DoInstr* instr) { | 299 void FlowGraphOptimizer::VisitDo(DoInstr* instr) { |
| 157 instr->computation()->Accept(this); | 300 instr->computation()->Accept(this); |
| 158 } | 301 } |
| 159 | 302 |
| 160 | 303 |
| 161 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { | 304 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 162 instr->computation()->Accept(this); | 305 instr->computation()->Accept(this); |
| 163 } | 306 } |
| 164 | 307 |
| 165 | 308 |
| 166 } // namespace dart | 309 } // namespace dart |
| OLD | NEW |