| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 DEFINE_FLAG(bool, trace_load_optimization, false, | 38 DEFINE_FLAG(bool, trace_load_optimization, false, |
| 39 "Print live sets for load optimization pass."); | 39 "Print live sets for load optimization pass."); |
| 40 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 40 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
| 41 DEFINE_FLAG(bool, truncating_left_shift, true, | 41 DEFINE_FLAG(bool, truncating_left_shift, true, |
| 42 "Optimize left shift to truncate if possible"); | 42 "Optimize left shift to truncate if possible"); |
| 43 DEFINE_FLAG(bool, use_cha_deopt, true, | 43 DEFINE_FLAG(bool, use_cha_deopt, true, |
| 44 "Use class hierarchy analysis even if it can cause deoptimization."); | 44 "Use class hierarchy analysis even if it can cause deoptimization."); |
| 45 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) | 45 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) |
| 46 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass."); | 46 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass."); |
| 47 #endif | 47 #endif |
| 48 |
| 49 DECLARE_FLAG(bool, polymorphic_with_deopt); |
| 48 DECLARE_FLAG(bool, source_lines); | 50 DECLARE_FLAG(bool, source_lines); |
| 49 DECLARE_FLAG(bool, trace_type_check_elimination); | 51 DECLARE_FLAG(bool, trace_type_check_elimination); |
| 50 DECLARE_FLAG(bool, warn_on_javascript_compatibility); | 52 DECLARE_FLAG(bool, warn_on_javascript_compatibility); |
| 51 | 53 |
| 52 // Quick access to the current isolate and zone. | 54 // Quick access to the current isolate and zone. |
| 53 #define I (isolate()) | 55 #define I (isolate()) |
| 54 #define Z (zone()) | 56 #define Z (zone()) |
| 55 | 57 |
| 56 static bool ShouldInlineSimd() { | 58 static bool ShouldInlineSimd() { |
| 57 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 59 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 const intptr_t cid_0 = class_ids[0]; | 197 const intptr_t cid_0 = class_ids[0]; |
| 196 const intptr_t cid_1 = class_ids[1]; | 198 const intptr_t cid_1 = class_ids[1]; |
| 197 if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) { | 199 if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) { |
| 198 class_ids[0] = cid_1; | 200 class_ids[0] = cid_1; |
| 199 } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) { | 201 } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) { |
| 200 class_ids[1] = cid_0; | 202 class_ids[1] = cid_0; |
| 201 } | 203 } |
| 202 } | 204 } |
| 203 } | 205 } |
| 204 | 206 |
| 207 bool all_cids_known = true; |
| 205 for (intptr_t i = 0; i < class_ids.length(); i++) { | 208 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 206 if (class_ids[i] == kDynamicCid) { | 209 if (class_ids[i] == kDynamicCid) { |
| 207 // Not all cid-s known. | 210 // Not all cid-s known. |
| 208 return false; | 211 all_cids_known = false; |
| 212 break; |
| 209 } | 213 } |
| 210 } | 214 } |
| 211 | 215 |
| 212 const Array& args_desc_array = Array::Handle(Z, | 216 if (all_cids_known) { |
| 213 ArgumentsDescriptor::New(call->ArgumentCount(), call->argument_names())); | 217 const Array& args_desc_array = Array::Handle(Z, |
| 214 ArgumentsDescriptor args_desc(args_desc_array); | 218 ArgumentsDescriptor::New(call->ArgumentCount(), |
| 215 const Class& receiver_class = Class::Handle(Z, | 219 call->argument_names())); |
| 216 isolate()->class_table()->At(class_ids[0])); | 220 ArgumentsDescriptor args_desc(args_desc_array); |
| 217 const Function& function = Function::Handle(Z, | 221 const Class& receiver_class = Class::Handle(Z, |
| 218 Resolver::ResolveDynamicForReceiverClass( | 222 isolate()->class_table()->At(class_ids[0])); |
| 219 receiver_class, | 223 const Function& function = Function::Handle(Z, |
| 220 call->function_name(), | 224 Resolver::ResolveDynamicForReceiverClass( |
| 221 args_desc)); | 225 receiver_class, |
| 222 if (function.IsNull()) { | 226 call->function_name(), |
| 223 return false; | 227 args_desc)); |
| 228 if (function.IsNull()) { |
| 229 return false; |
| 230 } |
| 231 if (class_ids.length() > 1) { |
| 232 call->ic_data()->AddCheck(class_ids, function); |
| 233 } else { |
| 234 ASSERT(class_ids.length() == 1); |
| 235 call->ic_data()->AddReceiverCheck(class_ids[0], function); |
| 236 } |
| 237 return true; |
| 224 } | 238 } |
| 225 // Create new ICData, do not modify the one attached to the instruction | 239 |
| 226 // since it is attached to the assembly instruction itself. | 240 // Check if getter or setter |
| 227 // TODO(srdjan): Prevent modification of ICData object that is | 241 if ((call->token_kind() == Token::kGET) || |
| 228 // referenced in assembly code. | 242 (call->token_kind() == Token::kSET)) { |
| 229 ICData& ic_data = ICData::ZoneHandle(Z, ICData::New( | 243 const Class& owner_class = Class::Handle(Z, function().Owner()); |
| 230 flow_graph_->function(), | 244 if (!owner_class.is_abstract()) { |
| 231 call->function_name(), | 245 // Quite aggressive: if functions's owner has a a getter/setter of that |
| 232 args_desc_array, | 246 // name we add a check and call the setter directly. Considerable |
| 233 call->deopt_id(), | 247 // performance improvement, some increase in code space. |
| 234 class_ids.length())); | 248 // TODO(srdjan): Make sure the getter/setters can be inlined. |
| 235 if (class_ids.length() > 1) { | 249 const Array& args_desc_array = Array::Handle(Z, |
| 236 ic_data.AddCheck(class_ids, function); | 250 ArgumentsDescriptor::New(call->ArgumentCount(), |
| 237 } else { | 251 call->argument_names())); |
| 238 ASSERT(class_ids.length() == 1); | 252 ArgumentsDescriptor args_desc(args_desc_array); |
| 239 ic_data.AddReceiverCheck(class_ids[0], function); | 253 const Function& function = Function::Handle(Z, |
| 254 Resolver::ResolveDynamicForReceiverClass(owner_class, |
| 255 call->function_name(), |
| 256 args_desc)); |
| 257 if (!function.IsNull()) { |
| 258 call->ic_data()->AddReceiverCheck(owner_class.id(), function); |
| 259 return true; |
| 260 } |
| 261 } |
| 240 } | 262 } |
| 241 call->set_ic_data(&ic_data); | 263 |
| 242 return true; | 264 return false; |
| 243 } | 265 } |
| 244 | 266 |
| 245 | 267 |
| 246 const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data, | 268 const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data, |
| 247 intptr_t cid) { | 269 intptr_t cid) { |
| 248 ASSERT(ic_data.NumArgsTested() == 1); | 270 ASSERT(ic_data.NumArgsTested() == 1); |
| 249 | 271 |
| 250 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { | 272 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { |
| 251 return ic_data; // Nothing to do | 273 return ic_data; // Nothing to do |
| 252 } | 274 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 266 new_ic_data.AddReceiverCheck(cid, function); | 288 new_ic_data.AddReceiverCheck(cid, function); |
| 267 return new_ic_data; | 289 return new_ic_data; |
| 268 } | 290 } |
| 269 | 291 |
| 270 return ic_data; | 292 return ic_data; |
| 271 } | 293 } |
| 272 | 294 |
| 273 | 295 |
| 274 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( | 296 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( |
| 275 PolymorphicInstanceCallInstr* call) { | 297 PolymorphicInstanceCallInstr* call) { |
| 298 if (!FLAG_polymorphic_with_deopt) { |
| 299 // Specialization adds receiver checks which can lead to deoptimization. |
| 300 return; |
| 301 } |
| 276 if (!call->with_checks()) { | 302 if (!call->with_checks()) { |
| 277 return; // Already specialized. | 303 return; // Already specialized. |
| 278 } | 304 } |
| 279 | 305 |
| 280 const intptr_t receiver_cid = | 306 const intptr_t receiver_cid = |
| 281 call->PushArgumentAt(0)->value()->Type()->ToCid(); | 307 call->PushArgumentAt(0)->value()->Type()->ToCid(); |
| 282 if (receiver_cid == kDynamicCid) { | 308 if (receiver_cid == kDynamicCid) { |
| 283 return; // No information about receiver was infered. | 309 return; // No information about receiver was infered. |
| 284 } | 310 } |
| 285 | 311 |
| (...skipping 3928 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4214 ReplaceCall(call, assert_as); | 4240 ReplaceCall(call, assert_as); |
| 4215 } | 4241 } |
| 4216 | 4242 |
| 4217 | 4243 |
| 4218 // Special optimizations when running in --noopt mode. | 4244 // Special optimizations when running in --noopt mode. |
| 4219 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { | 4245 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { |
| 4220 // TODO(srdjan): Investigate other attempts, as they are not allowed to | 4246 // TODO(srdjan): Investigate other attempts, as they are not allowed to |
| 4221 // deoptimize. | 4247 // deoptimize. |
| 4222 const Token::Kind op_kind = instr->token_kind(); | 4248 const Token::Kind op_kind = instr->token_kind(); |
| 4223 if (instr->HasICData() && (instr->ic_data()->NumberOfUsedChecks() > 0)) { | 4249 if (instr->HasICData() && (instr->ic_data()->NumberOfUsedChecks() > 0)) { |
| 4224 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr, false)) { | 4250 const ICData& unary_checks = |
| 4225 return; | 4251 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); |
| 4226 } | 4252 |
| 4253 PolymorphicInstanceCallInstr* call = |
| 4254 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 4255 true /* call_with_checks*/); |
| 4256 instr->ReplaceWith(call, current_iterator()); |
| 4257 return; |
| 4227 } | 4258 } |
| 4228 | 4259 |
| 4229 // Type test is special as it always gets converted into inlined code. | 4260 // Type test is special as it always gets converted into inlined code. |
| 4230 if (Token::IsTypeTestOperator(op_kind)) { | 4261 if (Token::IsTypeTestOperator(op_kind)) { |
| 4231 ReplaceWithInstanceOf(instr); | 4262 ReplaceWithInstanceOf(instr); |
| 4232 return; | 4263 return; |
| 4233 } | 4264 } |
| 4234 if (Token::IsTypeCastOperator(op_kind)) { | 4265 if (Token::IsTypeCastOperator(op_kind)) { |
| 4235 ReplaceWithTypeCast(instr); | 4266 ReplaceWithTypeCast(instr); |
| 4236 return; | 4267 return; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4329 PolymorphicInstanceCallInstr* call = | 4360 PolymorphicInstanceCallInstr* call = |
| 4330 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 4361 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 4331 call_with_checks); | 4362 call_with_checks); |
| 4332 instr->ReplaceWith(call, current_iterator()); | 4363 instr->ReplaceWith(call, current_iterator()); |
| 4333 return; | 4364 return; |
| 4334 } | 4365 } |
| 4335 } | 4366 } |
| 4336 | 4367 |
| 4337 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 4368 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 4338 bool call_with_checks; | 4369 bool call_with_checks; |
| 4339 if (has_one_target) { | 4370 if (has_one_target && FLAG_polymorphic_with_deopt) { |
| 4340 // Type propagation has not run yet, we cannot eliminate the check. | 4371 // Type propagation has not run yet, we cannot eliminate the check. |
| 4341 AddReceiverCheck(instr); | 4372 AddReceiverCheck(instr); |
| 4342 // Call can still deoptimize, do not detach environment from instr. | 4373 // Call can still deoptimize, do not detach environment from instr. |
| 4343 call_with_checks = false; | 4374 call_with_checks = false; |
| 4344 } else { | 4375 } else { |
| 4345 call_with_checks = true; | 4376 call_with_checks = true; |
| 4346 } | 4377 } |
| 4347 PolymorphicInstanceCallInstr* call = | 4378 PolymorphicInstanceCallInstr* call = |
| 4348 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 4379 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 4349 call_with_checks); | 4380 call_with_checks); |
| (...skipping 4338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8688 | 8719 |
| 8689 // Insert materializations at environment uses. | 8720 // Insert materializations at environment uses. |
| 8690 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 8721 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
| 8691 CreateMaterializationAt( | 8722 CreateMaterializationAt( |
| 8692 exits_collector_.exits()[i], alloc, *slots); | 8723 exits_collector_.exits()[i], alloc, *slots); |
| 8693 } | 8724 } |
| 8694 } | 8725 } |
| 8695 | 8726 |
| 8696 | 8727 |
| 8697 } // namespace dart | 8728 } // namespace dart |
| OLD | NEW |