Chromium Code Reviews| 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 return false; |
|
Florian Schneider
2015/06/18 15:51:10
This return makes the code below unreachable.
Mak
srdjan
2015/06/18 16:16:06
Oops, uploaded a cl with the performance testing e
Florian Schneider
2015/06/18 17:34:36
Ok.
| |
| 226 // since it is attached to the assembly instruction itself. | 240 |
| 227 // TODO(srdjan): Prevent modification of ICData object that is | 241 // Check if getter or setter |
| 228 // referenced in assembly code. | 242 if ((call->token_kind() == Token::kGET) || |
| 229 ICData& ic_data = ICData::ZoneHandle(Z, ICData::New( | 243 (call->token_kind() == Token::kSET)) { |
| 230 flow_graph_->function(), | 244 const Class& owner_class = Class::Handle(Z, function().Owner()); |
| 231 call->function_name(), | 245 if (!owner_class.is_abstract()) { |
| 232 args_desc_array, | 246 // Quite aggressive: if functions's owner has a a getter/setter of that |
| 233 call->deopt_id(), | 247 // name we add a check and call the setter directly. Considerable |
| 234 class_ids.length())); | 248 // performance improvement, some increase in code space. |
| 235 if (class_ids.length() > 1) { | 249 // TODO(srdjan): Make sure the getter/setters can be inlined. |
| 236 ic_data.AddCheck(class_ids, function); | 250 const Array& args_desc_array = Array::Handle(Z, |
| 237 } else { | 251 ArgumentsDescriptor::New(call->ArgumentCount(), |
| 238 ASSERT(class_ids.length() == 1); | 252 call->argument_names())); |
| 239 ic_data.AddReceiverCheck(class_ids[0], function); | 253 ArgumentsDescriptor args_desc(args_desc_array); |
| 254 const Function& function = Function::Handle(Z, | |
| 255 Resolver::ResolveDynamicForReceiverClass(owner_class, | |
| 256 call->function_name(), | |
| 257 args_desc)); | |
| 258 if (!function.IsNull()) { | |
| 259 call->ic_data()->AddReceiverCheck(owner_class.id(), function); | |
| 260 return true; | |
| 261 } | |
| 262 } | |
| 240 } | 263 } |
| 241 call->set_ic_data(&ic_data); | 264 |
| 242 return true; | 265 return false; |
| 243 } | 266 } |
| 244 | 267 |
| 245 | 268 |
| 246 const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data, | 269 const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data, |
| 247 intptr_t cid) { | 270 intptr_t cid) { |
| 248 ASSERT(ic_data.NumArgsTested() == 1); | 271 ASSERT(ic_data.NumArgsTested() == 1); |
| 249 | 272 |
| 250 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { | 273 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { |
| 251 return ic_data; // Nothing to do | 274 return ic_data; // Nothing to do |
| 252 } | 275 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 266 new_ic_data.AddReceiverCheck(cid, function); | 289 new_ic_data.AddReceiverCheck(cid, function); |
| 267 return new_ic_data; | 290 return new_ic_data; |
| 268 } | 291 } |
| 269 | 292 |
| 270 return ic_data; | 293 return ic_data; |
| 271 } | 294 } |
| 272 | 295 |
| 273 | 296 |
| 274 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( | 297 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( |
| 275 PolymorphicInstanceCallInstr* call) { | 298 PolymorphicInstanceCallInstr* call) { |
| 299 if (!FLAG_polymorphic_with_deopt) { | |
| 300 // Specialization adds receiver checks which can lead to deoptimization. | |
| 301 return; | |
| 302 } | |
| 276 if (!call->with_checks()) { | 303 if (!call->with_checks()) { |
| 277 return; // Already specialized. | 304 return; // Already specialized. |
| 278 } | 305 } |
| 279 | 306 |
| 280 const intptr_t receiver_cid = | 307 const intptr_t receiver_cid = |
| 281 call->PushArgumentAt(0)->value()->Type()->ToCid(); | 308 call->PushArgumentAt(0)->value()->Type()->ToCid(); |
| 282 if (receiver_cid == kDynamicCid) { | 309 if (receiver_cid == kDynamicCid) { |
| 283 return; // No information about receiver was infered. | 310 return; // No information about receiver was infered. |
| 284 } | 311 } |
| 285 | 312 |
| (...skipping 3928 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4214 ReplaceCall(call, assert_as); | 4241 ReplaceCall(call, assert_as); |
| 4215 } | 4242 } |
| 4216 | 4243 |
| 4217 | 4244 |
| 4218 // Special optimizations when running in --noopt mode. | 4245 // Special optimizations when running in --noopt mode. |
| 4219 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { | 4246 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { |
| 4220 // TODO(srdjan): Investigate other attempts, as they are not allowed to | 4247 // TODO(srdjan): Investigate other attempts, as they are not allowed to |
| 4221 // deoptimize. | 4248 // deoptimize. |
| 4222 const Token::Kind op_kind = instr->token_kind(); | 4249 const Token::Kind op_kind = instr->token_kind(); |
| 4223 if (instr->HasICData() && (instr->ic_data()->NumberOfUsedChecks() > 0)) { | 4250 if (instr->HasICData() && (instr->ic_data()->NumberOfUsedChecks() > 0)) { |
| 4224 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr, false)) { | 4251 const ICData& unary_checks = |
| 4225 return; | 4252 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); |
| 4226 } | 4253 |
| 4254 PolymorphicInstanceCallInstr* call = | |
| 4255 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | |
| 4256 true /* call_with_checks*/); | |
| 4257 instr->ReplaceWith(call, current_iterator()); | |
| 4258 return; | |
| 4227 } | 4259 } |
| 4228 | 4260 |
| 4229 // Type test is special as it always gets converted into inlined code. | 4261 // Type test is special as it always gets converted into inlined code. |
| 4230 if (Token::IsTypeTestOperator(op_kind)) { | 4262 if (Token::IsTypeTestOperator(op_kind)) { |
| 4231 ReplaceWithInstanceOf(instr); | 4263 ReplaceWithInstanceOf(instr); |
| 4232 return; | 4264 return; |
| 4233 } | 4265 } |
| 4234 if (Token::IsTypeCastOperator(op_kind)) { | 4266 if (Token::IsTypeCastOperator(op_kind)) { |
| 4235 ReplaceWithTypeCast(instr); | 4267 ReplaceWithTypeCast(instr); |
| 4236 return; | 4268 return; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4329 PolymorphicInstanceCallInstr* call = | 4361 PolymorphicInstanceCallInstr* call = |
| 4330 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 4362 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 4331 call_with_checks); | 4363 call_with_checks); |
| 4332 instr->ReplaceWith(call, current_iterator()); | 4364 instr->ReplaceWith(call, current_iterator()); |
| 4333 return; | 4365 return; |
| 4334 } | 4366 } |
| 4335 } | 4367 } |
| 4336 | 4368 |
| 4337 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 4369 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 4338 bool call_with_checks; | 4370 bool call_with_checks; |
| 4339 if (has_one_target) { | 4371 if (has_one_target && FLAG_polymorphic_with_deopt) { |
| 4340 // Type propagation has not run yet, we cannot eliminate the check. | 4372 // Type propagation has not run yet, we cannot eliminate the check. |
| 4341 AddReceiverCheck(instr); | 4373 AddReceiverCheck(instr); |
| 4342 // Call can still deoptimize, do not detach environment from instr. | 4374 // Call can still deoptimize, do not detach environment from instr. |
| 4343 call_with_checks = false; | 4375 call_with_checks = false; |
| 4344 } else { | 4376 } else { |
| 4345 call_with_checks = true; | 4377 call_with_checks = true; |
| 4346 } | 4378 } |
| 4347 PolymorphicInstanceCallInstr* call = | 4379 PolymorphicInstanceCallInstr* call = |
| 4348 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 4380 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 4349 call_with_checks); | 4381 call_with_checks); |
| (...skipping 4338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8688 | 8720 |
| 8689 // Insert materializations at environment uses. | 8721 // Insert materializations at environment uses. |
| 8690 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 8722 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
| 8691 CreateMaterializationAt( | 8723 CreateMaterializationAt( |
| 8692 exits_collector_.exits()[i], alloc, *slots); | 8724 exits_collector_.exits()[i], alloc, *slots); |
| 8693 } | 8725 } |
| 8694 } | 8726 } |
| 8695 | 8727 |
| 8696 | 8728 |
| 8697 } // namespace dart | 8729 } // namespace dart |
| OLD | NEW |