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/aot_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
| 9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| 11 #include "vm/cpu.h" | 11 #include "vm/cpu.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/exceptions.h" | 13 #include "vm/exceptions.h" |
| 14 #include "vm/flow_graph_builder.h" | 14 #include "vm/flow_graph_builder.h" |
| 15 #include "vm/flow_graph_compiler.h" | 15 #include "vm/flow_graph_compiler.h" |
| 16 #include "vm/flow_graph_inliner.h" | 16 #include "vm/flow_graph_inliner.h" |
| 17 #include "vm/flow_graph_range_analysis.h" | 17 #include "vm/flow_graph_range_analysis.h" |
| 18 #include "vm/hash_map.h" | 18 #include "vm/hash_map.h" |
| 19 #include "vm/il_printer.h" | 19 #include "vm/il_printer.h" |
| 20 #include "vm/intermediate_language.h" | 20 #include "vm/intermediate_language.h" |
| 21 #include "vm/object.h" | |
| 21 #include "vm/object_store.h" | 22 #include "vm/object_store.h" |
| 22 #include "vm/parser.h" | 23 #include "vm/parser.h" |
| 23 #include "vm/precompiler.h" | 24 #include "vm/precompiler.h" |
| 24 #include "vm/resolver.h" | 25 #include "vm/resolver.h" |
| 25 #include "vm/scopes.h" | 26 #include "vm/scopes.h" |
| 26 #include "vm/stack_frame.h" | 27 #include "vm/stack_frame.h" |
| 27 #include "vm/symbols.h" | 28 #include "vm/symbols.h" |
| 28 | 29 |
| 29 namespace dart { | 30 namespace dart { |
| 30 | 31 |
| 31 DEFINE_FLAG(int, getter_setter_ratio, 13, | |
| 32 "Ratio of getter/setter usage used for double field unboxing heuristics"); | |
| 33 DEFINE_FLAG(bool, guess_icdata_cid, true, | |
| 34 "Artificially create type feedback for arithmetic etc. operations" | |
| 35 " by guessing the other unknown argument cid"); | |
| 36 DEFINE_FLAG(int, max_polymorphic_checks, 4, | |
| 37 "Maximum number of polymorphic check, otherwise it is megamorphic."); | |
| 38 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, | |
| 39 "Maximum number of polymorphic checks in equality operator," | |
| 40 " otherwise use megamorphic dispatch."); | |
| 41 DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos"); | |
| 42 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | |
| 43 DEFINE_FLAG(bool, truncating_left_shift, true, | |
| 44 "Optimize left shift to truncate if possible"); | |
| 45 DEFINE_FLAG(bool, use_cha_deopt, true, | |
| 46 "Use class hierarchy analysis even if it can cause deoptimization."); | |
| 47 | |
| 48 DECLARE_FLAG(bool, precompilation); | 32 DECLARE_FLAG(bool, precompilation); |
| 49 DECLARE_FLAG(bool, polymorphic_with_deopt); | |
| 50 DECLARE_FLAG(bool, trace_cha); | |
| 51 DECLARE_FLAG(bool, trace_field_guards); | |
| 52 | 33 |
| 53 // Quick access to the current isolate and zone. | 34 // Quick access to the current isolate and zone. |
| 54 #define I (isolate()) | 35 #define I (isolate()) |
| 55 #define Z (zone()) | 36 #define Z (zone()) |
| 56 | 37 |
| 57 static bool ShouldInlineSimd() { | 38 static bool ShouldInlineSimd() { |
| 58 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 39 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
| 59 } | 40 } |
| 60 | 41 |
| 61 | 42 |
| 62 static bool CanUnboxDouble() { | 43 static bool CanUnboxDouble() { |
| 63 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 44 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
| 64 } | 45 } |
| 65 | 46 |
| 66 | 47 |
| 67 static bool CanConvertUnboxedMintToDouble() { | 48 static bool CanConvertUnboxedMintToDouble() { |
| 68 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); | 49 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); |
| 69 } | 50 } |
| 70 | 51 |
| 71 | 52 |
| 72 // Optimize instance calls using ICData. | 53 // Optimize instance calls using ICData. |
| 73 void FlowGraphOptimizer::ApplyICData() { | 54 void AotOptimizer::ApplyICData() { |
| 74 VisitBlocks(); | 55 VisitBlocks(); |
| 75 } | 56 } |
| 76 | 57 |
| 77 | 58 |
| 78 void FlowGraphOptimizer::PopulateWithICData() { | 59 void AotOptimizer::PopulateWithICData() { |
| 79 ASSERT(current_iterator_ == NULL); | 60 ASSERT(current_iterator_ == NULL); |
| 80 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 61 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 81 !block_it.Done(); | 62 !block_it.Done(); |
| 82 block_it.Advance()) { | 63 block_it.Advance()) { |
| 83 ForwardInstructionIterator it(block_it.Current()); | 64 ForwardInstructionIterator it(block_it.Current()); |
| 84 for (; !it.Done(); it.Advance()) { | 65 for (; !it.Done(); it.Advance()) { |
| 85 Instruction* instr = it.Current(); | 66 Instruction* instr = it.Current(); |
| 86 if (instr->IsInstanceCall()) { | 67 if (instr->IsInstanceCall()) { |
| 87 InstanceCallInstr* call = instr->AsInstanceCall(); | 68 InstanceCallInstr* call = instr->AsInstanceCall(); |
| 88 if (!call->HasICData()) { | 69 if (!call->HasICData()) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 102 } | 83 } |
| 103 } | 84 } |
| 104 | 85 |
| 105 | 86 |
| 106 // Optimize instance calls using cid. This is called after optimizer | 87 // Optimize instance calls using cid. This is called after optimizer |
| 107 // converted instance calls to instructions. Any remaining | 88 // converted instance calls to instructions. Any remaining |
| 108 // instance calls are either megamorphic calls, cannot be optimized or | 89 // instance calls are either megamorphic calls, cannot be optimized or |
| 109 // have no runtime type feedback collected. | 90 // have no runtime type feedback collected. |
| 110 // Attempts to convert an instance call (IC call) using propagated class-ids, | 91 // Attempts to convert an instance call (IC call) using propagated class-ids, |
| 111 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 92 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
| 112 void FlowGraphOptimizer::ApplyClassIds() { | 93 void AotOptimizer::ApplyClassIds() { |
| 113 ASSERT(current_iterator_ == NULL); | 94 ASSERT(current_iterator_ == NULL); |
| 114 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 95 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 115 !block_it.Done(); | 96 !block_it.Done(); |
| 116 block_it.Advance()) { | 97 block_it.Advance()) { |
| 117 ForwardInstructionIterator it(block_it.Current()); | 98 ForwardInstructionIterator it(block_it.Current()); |
| 118 current_iterator_ = ⁢ | 99 current_iterator_ = ⁢ |
| 119 for (; !it.Done(); it.Advance()) { | 100 for (; !it.Done(); it.Advance()) { |
| 120 Instruction* instr = it.Current(); | 101 Instruction* instr = it.Current(); |
| 121 if (instr->IsInstanceCall()) { | 102 if (instr->IsInstanceCall()) { |
| 122 InstanceCallInstr* call = instr->AsInstanceCall(); | 103 InstanceCallInstr* call = instr->AsInstanceCall(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 133 } | 114 } |
| 134 } | 115 } |
| 135 | 116 |
| 136 | 117 |
| 137 // TODO(srdjan): Test/support other number types as well. | 118 // TODO(srdjan): Test/support other number types as well. |
| 138 static bool IsNumberCid(intptr_t cid) { | 119 static bool IsNumberCid(intptr_t cid) { |
| 139 return (cid == kSmiCid) || (cid == kDoubleCid); | 120 return (cid == kSmiCid) || (cid == kDoubleCid); |
| 140 } | 121 } |
| 141 | 122 |
| 142 | 123 |
| 143 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { | 124 static void GetUniqueDynamicTarget(Isolate* isolate, |
| 125 const String& fname, | |
| 126 Object* function) { | |
| 127 UniqueFunctionsSet functions_set( | |
| 128 isolate->object_store()->unique_dynamic_targets()); | |
| 129 ASSERT(fname.IsSymbol()); | |
| 130 *function = functions_set.GetOrNull(fname); | |
| 131 ASSERT(functions_set.Release().raw() == | |
| 132 isolate->object_store()->unique_dynamic_targets()); | |
| 133 } | |
| 134 | |
| 135 | |
| 136 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) { | |
| 144 ASSERT(call->HasICData()); | 137 ASSERT(call->HasICData()); |
| 145 if (call->ic_data()->NumberOfUsedChecks() > 0) { | 138 if (call->ic_data()->NumberOfUsedChecks() > 0) { |
| 146 // This occurs when an instance call has too many checks, will be converted | 139 // This occurs when an instance call has too many checks, will be converted |
| 147 // to megamorphic call. | 140 // to megamorphic call. |
| 148 return false; | 141 return false; |
| 149 } | 142 } |
| 150 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); | 143 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); |
| 151 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); | 144 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); |
| 152 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { | 145 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { |
| 153 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); | 146 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 210 if (class_ids.length() > 1) { | 203 if (class_ids.length() > 1) { |
| 211 ic_data.AddCheck(class_ids, function); | 204 ic_data.AddCheck(class_ids, function); |
| 212 } else { | 205 } else { |
| 213 ASSERT(class_ids.length() == 1); | 206 ASSERT(class_ids.length() == 1); |
| 214 ic_data.AddReceiverCheck(class_ids[0], function); | 207 ic_data.AddReceiverCheck(class_ids[0], function); |
| 215 } | 208 } |
| 216 call->set_ic_data(&ic_data); | 209 call->set_ic_data(&ic_data); |
| 217 return true; | 210 return true; |
| 218 } | 211 } |
| 219 | 212 |
| 220 #ifdef DART_PRECOMPILER | 213 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { |
| 221 if (FLAG_precompilation && | |
| 222 (isolate()->object_store()->unique_dynamic_targets() != Array::null())) { | |
| 223 // Check if the target is unique. | 214 // Check if the target is unique. |
| 224 Function& target_function = Function::Handle(Z); | 215 Function& target_function = Function::Handle(Z); |
| 225 Precompiler::GetUniqueDynamicTarget( | 216 GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function); |
| 226 isolate(), call->function_name(), &target_function); | |
| 227 // Calls with named arguments must be resolved/checked at runtime. | 217 // Calls with named arguments must be resolved/checked at runtime. |
| 228 String& error_message = String::Handle(Z); | 218 String& error_message = String::Handle(Z); |
| 229 if (!target_function.IsNull() && | 219 if (!target_function.IsNull() && |
| 230 !target_function.HasOptionalNamedParameters() && | 220 !target_function.HasOptionalNamedParameters() && |
| 231 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, | 221 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, |
| 232 &error_message)) { | 222 &error_message)) { |
| 233 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); | 223 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); |
| 234 const ICData& ic_data = ICData::ZoneHandle(Z, | 224 const ICData& ic_data = ICData::ZoneHandle(Z, |
| 235 ICData::NewFrom(*call->ic_data(), 1)); | 225 ICData::NewFrom(*call->ic_data(), 1)); |
| 236 ic_data.AddReceiverCheck(cid, target_function); | 226 ic_data.AddReceiverCheck(cid, target_function); |
| 237 call->set_ic_data(&ic_data); | 227 call->set_ic_data(&ic_data); |
| 238 return true; | 228 return true; |
| 239 } | 229 } |
| 240 } | 230 } |
| 241 #endif | |
| 242 | 231 |
| 243 // Check if getter or setter in function's class and class is currently leaf. | 232 // Check if getter or setter in function's class and class is currently leaf. |
| 244 if (FLAG_guess_icdata_cid && | 233 if (FLAG_guess_icdata_cid && |
| 245 ((call->token_kind() == Token::kGET) || | 234 ((call->token_kind() == Token::kGET) || |
| 246 (call->token_kind() == Token::kSET))) { | 235 (call->token_kind() == Token::kSET))) { |
| 247 const Class& owner_class = Class::Handle(Z, function().Owner()); | 236 const Class& owner_class = Class::Handle(Z, function().Owner()); |
| 248 if (!owner_class.is_abstract() && | 237 if (!owner_class.is_abstract() && |
| 249 !CHA::HasSubclasses(owner_class) && | 238 !CHA::HasSubclasses(owner_class) && |
| 250 !CHA::IsImplemented(owner_class)) { | 239 !CHA::IsImplemented(owner_class)) { |
| 251 const Array& args_desc_array = Array::Handle(Z, | 240 const Array& args_desc_array = Array::Handle(Z, |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 263 call->set_ic_data(&ic_data); | 252 call->set_ic_data(&ic_data); |
| 264 return true; | 253 return true; |
| 265 } | 254 } |
| 266 } | 255 } |
| 267 } | 256 } |
| 268 | 257 |
| 269 return false; | 258 return false; |
| 270 } | 259 } |
| 271 | 260 |
| 272 | 261 |
| 273 const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data, | 262 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data, |
| 274 intptr_t cid) { | 263 intptr_t cid) { |
| 275 ASSERT(ic_data.NumArgsTested() == 1); | 264 ASSERT(ic_data.NumArgsTested() == 1); |
| 276 | 265 |
| 277 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { | 266 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { |
| 278 return ic_data; // Nothing to do | 267 return ic_data; // Nothing to do |
| 279 } | 268 } |
| 280 | 269 |
| 281 const Function& function = | 270 const Function& function = |
| 282 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); | 271 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); |
| 283 // TODO(fschneider): Try looking up the function on the class if it is | 272 // TODO(fschneider): Try looking up the function on the class if it is |
| 284 // not found in the ICData. | 273 // not found in the ICData. |
| 285 if (!function.IsNull()) { | 274 if (!function.IsNull()) { |
| 286 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( | 275 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( |
| 287 Function::Handle(Z, ic_data.Owner()), | 276 Function::Handle(Z, ic_data.Owner()), |
| 288 String::Handle(Z, ic_data.target_name()), | 277 String::Handle(Z, ic_data.target_name()), |
| 289 Object::empty_array(), // Dummy argument descriptor. | 278 Object::empty_array(), // Dummy argument descriptor. |
| 290 ic_data.deopt_id(), | 279 ic_data.deopt_id(), |
| 291 ic_data.NumArgsTested())); | 280 ic_data.NumArgsTested())); |
| 292 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); | 281 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); |
| 293 new_ic_data.AddReceiverCheck(cid, function); | 282 new_ic_data.AddReceiverCheck(cid, function); |
| 294 return new_ic_data; | 283 return new_ic_data; |
| 295 } | 284 } |
| 296 | 285 |
| 297 return ic_data; | 286 return ic_data; |
| 298 } | 287 } |
| 299 | 288 |
| 300 | 289 |
| 301 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( | 290 void AotOptimizer::SpecializePolymorphicInstanceCall( |
| 302 PolymorphicInstanceCallInstr* call) { | 291 PolymorphicInstanceCallInstr* call) { |
| 303 if (!FLAG_polymorphic_with_deopt) { | 292 if (!FLAG_polymorphic_with_deopt) { |
| 304 // Specialization adds receiver checks which can lead to deoptimization. | 293 // Specialization adds receiver checks which can lead to deoptimization. |
| 305 return; | 294 return; |
| 306 } | 295 } |
| 307 if (!call->with_checks()) { | 296 if (!call->with_checks()) { |
| 308 return; // Already specialized. | 297 return; // Already specialized. |
| 309 } | 298 } |
| 310 | 299 |
| 311 const intptr_t receiver_cid = | 300 const intptr_t receiver_cid = |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 340 | 329 |
| 341 static bool IsPositiveOrZeroSmiConst(Definition* d) { | 330 static bool IsPositiveOrZeroSmiConst(Definition* d) { |
| 342 ConstantInstr* const_instr = d->AsConstant(); | 331 ConstantInstr* const_instr = d->AsConstant(); |
| 343 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { | 332 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { |
| 344 return Smi::Cast(const_instr->value()).Value() >= 0; | 333 return Smi::Cast(const_instr->value()).Value() >= 0; |
| 345 } | 334 } |
| 346 return false; | 335 return false; |
| 347 } | 336 } |
| 348 | 337 |
| 349 | 338 |
| 350 void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp( | 339 void AotOptimizer::OptimizeLeftShiftBitAndSmiOp( |
| 351 Definition* bit_and_instr, | 340 Definition* bit_and_instr, |
| 352 Definition* left_instr, | 341 Definition* left_instr, |
| 353 Definition* right_instr) { | 342 Definition* right_instr) { |
| 354 ASSERT(bit_and_instr != NULL); | 343 ASSERT(bit_and_instr != NULL); |
| 355 ASSERT((left_instr != NULL) && (right_instr != NULL)); | 344 ASSERT((left_instr != NULL) && (right_instr != NULL)); |
| 356 | 345 |
| 357 // Check for pattern, smi_shift_left must be single-use. | 346 // Check for pattern, smi_shift_left must be single-use. |
| 358 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); | 347 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); |
| 359 if (!is_positive_or_zero) { | 348 if (!is_positive_or_zero) { |
| 360 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr); | 349 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 378 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr( | 367 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr( |
| 379 Token::kBIT_AND, | 368 Token::kBIT_AND, |
| 380 new(Z) Value(left_instr), | 369 new(Z) Value(left_instr), |
| 381 new(Z) Value(right_instr), | 370 new(Z) Value(right_instr), |
| 382 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. | 371 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. |
| 383 bit_and_instr->ReplaceWith(smi_op, current_iterator()); | 372 bit_and_instr->ReplaceWith(smi_op, current_iterator()); |
| 384 } | 373 } |
| 385 } | 374 } |
| 386 | 375 |
| 387 | 376 |
| 388 void FlowGraphOptimizer::AppendExtractNthOutputForMerged(Definition* instr, | 377 void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr, |
| 389 intptr_t index, | 378 intptr_t index, |
| 390 Representation rep, | 379 Representation rep, |
| 391 intptr_t cid) { | 380 intptr_t cid) { |
| 392 ExtractNthOutputInstr* extract = | 381 ExtractNthOutputInstr* extract = |
| 393 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid); | 382 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid); |
| 394 instr->ReplaceUsesWith(extract); | 383 instr->ReplaceUsesWith(extract); |
| 395 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue); | 384 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue); |
| 396 } | 385 } |
| 397 | 386 |
| 398 | 387 |
| 399 // Dart: | 388 // Dart: |
| 400 // var x = d % 10; | 389 // var x = d % 10; |
| 401 // var y = d ~/ 10; | 390 // var y = d ~/ 10; |
| 402 // var z = x + y; | 391 // var z = x + y; |
| 403 // | 392 // |
| 404 // IL: | 393 // IL: |
| 405 // v4 <- %(v2, v3) | 394 // v4 <- %(v2, v3) |
| 406 // v5 <- ~/(v2, v3) | 395 // v5 <- ~/(v2, v3) |
| 407 // v6 <- +(v4, v5) | 396 // v6 <- +(v4, v5) |
| 408 // | 397 // |
| 409 // IL optimized: | 398 // IL optimized: |
| 410 // v4 <- DIVMOD(v2, v3); | 399 // v4 <- DIVMOD(v2, v3); |
| 411 // v5 <- LoadIndexed(v4, 0); // ~/ result | 400 // v5 <- LoadIndexed(v4, 0); // ~/ result |
| 412 // v6 <- LoadIndexed(v4, 1); // % result | 401 // v6 <- LoadIndexed(v4, 1); // % result |
| 413 // v7 <- +(v5, v6) | 402 // v7 <- +(v5, v6) |
| 414 // Because of the environment it is important that merged instruction replaces | 403 // Because of the environment it is important that merged instruction replaces |
| 415 // first original instruction encountered. | 404 // first original instruction encountered. |
| 416 void FlowGraphOptimizer::TryMergeTruncDivMod( | 405 void AotOptimizer::TryMergeTruncDivMod( |
| 417 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { | 406 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { |
| 418 if (merge_candidates->length() < 2) { | 407 if (merge_candidates->length() < 2) { |
| 419 // Need at least a TRUNCDIV and a MOD. | 408 // Need at least a TRUNCDIV and a MOD. |
| 420 return; | 409 return; |
| 421 } | 410 } |
| 422 for (intptr_t i = 0; i < merge_candidates->length(); i++) { | 411 for (intptr_t i = 0; i < merge_candidates->length(); i++) { |
| 423 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; | 412 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; |
| 424 if (curr_instr == NULL) { | 413 if (curr_instr == NULL) { |
| 425 // Instruction was merged already. | 414 // Instruction was merged already. |
| 426 continue; | 415 continue; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 467 // more candidates are possible. | 456 // more candidates are possible. |
| 468 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. | 457 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. |
| 469 break; | 458 break; |
| 470 } | 459 } |
| 471 } | 460 } |
| 472 } | 461 } |
| 473 } | 462 } |
| 474 | 463 |
| 475 | 464 |
| 476 // Tries to merge MathUnary operations, in this case sinus and cosinus. | 465 // Tries to merge MathUnary operations, in this case sinus and cosinus. |
| 477 void FlowGraphOptimizer::TryMergeMathUnary( | 466 void AotOptimizer::TryMergeMathUnary( |
| 478 GrowableArray<MathUnaryInstr*>* merge_candidates) { | 467 GrowableArray<MathUnaryInstr*>* merge_candidates) { |
| 479 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() || | 468 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() || |
| 480 !FLAG_merge_sin_cos) { | 469 !FLAG_merge_sin_cos) { |
| 481 return; | 470 return; |
| 482 } | 471 } |
| 483 if (merge_candidates->length() < 2) { | 472 if (merge_candidates->length() < 2) { |
| 484 // Need at least a SIN and a COS. | 473 // Need at least a SIN and a COS. |
| 485 return; | 474 return; |
| 486 } | 475 } |
| 487 for (intptr_t i = 0; i < merge_candidates->length(); i++) { | 476 for (intptr_t i = 0; i < merge_candidates->length(); i++) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 528 break; | 517 break; |
| 529 } | 518 } |
| 530 } | 519 } |
| 531 } | 520 } |
| 532 } | 521 } |
| 533 | 522 |
| 534 | 523 |
| 535 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the | 524 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the |
| 536 // shift can be a truncating Smi shift-left and result is always Smi. | 525 // shift can be a truncating Smi shift-left and result is always Smi. |
| 537 // Merging occurs only per basic-block. | 526 // Merging occurs only per basic-block. |
| 538 void FlowGraphOptimizer::TryOptimizePatterns() { | 527 void AotOptimizer::TryOptimizePatterns() { |
| 539 if (!FLAG_truncating_left_shift) return; | 528 if (!FLAG_truncating_left_shift) return; |
| 540 ASSERT(current_iterator_ == NULL); | 529 ASSERT(current_iterator_ == NULL); |
| 541 GrowableArray<BinarySmiOpInstr*> div_mod_merge; | 530 GrowableArray<BinarySmiOpInstr*> div_mod_merge; |
| 542 GrowableArray<MathUnaryInstr*> sin_cos_merge; | 531 GrowableArray<MathUnaryInstr*> sin_cos_merge; |
| 543 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 532 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 544 !block_it.Done(); | 533 !block_it.Done(); |
| 545 block_it.Advance()) { | 534 block_it.Advance()) { |
| 546 // Merging only per basic-block. | 535 // Merging only per basic-block. |
| 547 div_mod_merge.Clear(); | 536 div_mod_merge.Clear(); |
| 548 sin_cos_merge.Clear(); | 537 sin_cos_merge.Clear(); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 714 // Unboxed double operation can't handle case of two smis. | 703 // Unboxed double operation can't handle case of two smis. |
| 715 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 704 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 716 return false; | 705 return false; |
| 717 } | 706 } |
| 718 | 707 |
| 719 // Check that it have seen only smis and doubles. | 708 // Check that it have seen only smis and doubles. |
| 720 return HasTwoDoubleOrSmi(ic_data); | 709 return HasTwoDoubleOrSmi(ic_data); |
| 721 } | 710 } |
| 722 | 711 |
| 723 | 712 |
| 724 void FlowGraphOptimizer::ReplaceCall(Definition* call, | 713 void AotOptimizer::ReplaceCall(Definition* call, |
| 725 Definition* replacement) { | 714 Definition* replacement) { |
| 726 // Remove the original push arguments. | 715 // Remove the original push arguments. |
| 727 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 716 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 728 PushArgumentInstr* push = call->PushArgumentAt(i); | 717 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 729 push->ReplaceUsesWith(push->value()->definition()); | 718 push->ReplaceUsesWith(push->value()->definition()); |
| 730 push->RemoveFromGraph(); | 719 push->RemoveFromGraph(); |
| 731 } | 720 } |
| 732 call->ReplaceWith(replacement, current_iterator()); | 721 call->ReplaceWith(replacement, current_iterator()); |
| 733 } | 722 } |
| 734 | 723 |
| 735 | 724 |
| 736 void FlowGraphOptimizer::AddCheckSmi(Definition* to_check, | 725 void AotOptimizer::AddCheckSmi(Definition* to_check, |
| 737 intptr_t deopt_id, | 726 intptr_t deopt_id, |
| 738 Environment* deopt_environment, | 727 Environment* deopt_environment, |
| 739 Instruction* insert_before) { | 728 Instruction* insert_before) { |
| 740 if (to_check->Type()->ToCid() != kSmiCid) { | 729 if (to_check->Type()->ToCid() != kSmiCid) { |
| 741 InsertBefore(insert_before, | 730 InsertBefore(insert_before, |
| 742 new(Z) CheckSmiInstr(new(Z) Value(to_check), | 731 new(Z) CheckSmiInstr(new(Z) Value(to_check), |
| 743 deopt_id, | 732 deopt_id, |
| 744 insert_before->token_pos()), | 733 insert_before->token_pos()), |
| 745 deopt_environment, | 734 deopt_environment, |
| 746 FlowGraph::kEffect); | 735 FlowGraph::kEffect); |
| 747 } | 736 } |
| 748 } | 737 } |
| 749 | 738 |
| 750 | 739 |
| 751 Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check, | 740 Instruction* AotOptimizer::GetCheckClass(Definition* to_check, |
| 752 const ICData& unary_checks, | 741 const ICData& unary_checks, |
| 753 intptr_t deopt_id, | 742 intptr_t deopt_id, |
| 754 TokenPosition token_pos) { | 743 TokenPosition token_pos) { |
| 755 if ((unary_checks.NumberOfUsedChecks() == 1) && | 744 if ((unary_checks.NumberOfUsedChecks() == 1) && |
| 756 unary_checks.HasReceiverClassId(kSmiCid)) { | 745 unary_checks.HasReceiverClassId(kSmiCid)) { |
| 757 return new(Z) CheckSmiInstr(new(Z) Value(to_check), | 746 return new(Z) CheckSmiInstr(new(Z) Value(to_check), |
| 758 deopt_id, | 747 deopt_id, |
| 759 token_pos); | 748 token_pos); |
| 760 } | 749 } |
| 761 return new(Z) CheckClassInstr( | 750 return new(Z) CheckClassInstr( |
| 762 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); | 751 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); |
| 763 } | 752 } |
| 764 | 753 |
| 765 | 754 |
| 766 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, | 755 void AotOptimizer::AddCheckClass(Definition* to_check, |
| 767 const ICData& unary_checks, | 756 const ICData& unary_checks, |
| 768 intptr_t deopt_id, | 757 intptr_t deopt_id, |
| 769 Environment* deopt_environment, | 758 Environment* deopt_environment, |
| 770 Instruction* insert_before) { | 759 Instruction* insert_before) { |
| 771 // Type propagation has not run yet, we cannot eliminate the check. | 760 // Type propagation has not run yet, we cannot eliminate the check. |
| 772 Instruction* check = GetCheckClass( | 761 Instruction* check = GetCheckClass( |
| 773 to_check, unary_checks, deopt_id, insert_before->token_pos()); | 762 to_check, unary_checks, deopt_id, insert_before->token_pos()); |
| 774 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); | 763 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); |
| 775 } | 764 } |
| 776 | 765 |
| 777 | 766 |
| 778 void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) { | 767 void AotOptimizer::AddReceiverCheck(InstanceCallInstr* call) { |
| 779 AddCheckClass(call->ArgumentAt(0), | 768 AddCheckClass(call->ArgumentAt(0), |
| 780 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), | 769 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), |
| 781 call->deopt_id(), | 770 call->deopt_id(), |
| 782 call->env(), | 771 call->env(), |
| 783 call); | 772 call); |
| 784 } | 773 } |
| 785 | 774 |
| 786 | 775 |
| 787 static bool ArgIsAlways(intptr_t cid, | 776 static bool ArgIsAlways(intptr_t cid, |
| 788 const ICData& ic_data, | 777 const ICData& ic_data, |
| 789 intptr_t arg_number) { | 778 intptr_t arg_number) { |
| 790 ASSERT(ic_data.NumArgsTested() > arg_number); | 779 ASSERT(ic_data.NumArgsTested() > arg_number); |
| 791 if (ic_data.NumberOfUsedChecks() == 0) { | 780 if (ic_data.NumberOfUsedChecks() == 0) { |
| 792 return false; | 781 return false; |
| 793 } | 782 } |
| 794 const intptr_t num_checks = ic_data.NumberOfChecks(); | 783 const intptr_t num_checks = ic_data.NumberOfChecks(); |
| 795 for (intptr_t i = 0; i < num_checks; i++) { | 784 for (intptr_t i = 0; i < num_checks; i++) { |
| 796 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { | 785 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { |
| 797 return false; | 786 return false; |
| 798 } | 787 } |
| 799 } | 788 } |
| 800 return true; | 789 return true; |
| 801 } | 790 } |
| 802 | 791 |
| 803 | 792 |
| 804 bool FlowGraphOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { | 793 bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { |
| 805 // Check for monomorphic IC data. | 794 // Check for monomorphic IC data. |
| 806 if (!call->HasICData()) return false; | 795 if (!call->HasICData()) return false; |
| 807 const ICData& ic_data = | 796 const ICData& ic_data = |
| 808 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); | 797 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 809 if (ic_data.NumberOfChecks() != 1) { | 798 if (ic_data.NumberOfChecks() != 1) { |
| 810 return false; | 799 return false; |
| 811 } | 800 } |
| 812 return TryReplaceInstanceCallWithInline(call); | 801 return TryReplaceInstanceCallWithInline(call); |
| 813 } | 802 } |
| 814 | 803 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 826 } else { | 815 } else { |
| 827 return d->IsStringFromCharCode(); | 816 return d->IsStringFromCharCode(); |
| 828 } | 817 } |
| 829 } | 818 } |
| 830 | 819 |
| 831 | 820 |
| 832 // Returns true if the string comparison was converted into char-code | 821 // Returns true if the string comparison was converted into char-code |
| 833 // comparison. Conversion is only possible for strings of length one. | 822 // comparison. Conversion is only possible for strings of length one. |
| 834 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. | 823 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. |
| 835 // TODO(srdjan): Expand for two-byte and external strings. | 824 // TODO(srdjan): Expand for two-byte and external strings. |
| 836 bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, | 825 bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, |
| 837 Token::Kind op_kind) { | 826 Token::Kind op_kind) { |
| 838 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); | 827 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); |
| 839 // Check that left and right are length one strings (either string constants | 828 // Check that left and right are length one strings (either string constants |
| 840 // or results of string-from-char-code. | 829 // or results of string-from-char-code. |
| 841 Definition* left = call->ArgumentAt(0); | 830 Definition* left = call->ArgumentAt(0); |
| 842 Definition* right = call->ArgumentAt(1); | 831 Definition* right = call->ArgumentAt(1); |
| 843 Value* left_val = NULL; | 832 Value* left_val = NULL; |
| 844 Definition* to_remove_left = NULL; | 833 Definition* to_remove_left = NULL; |
| 845 if (IsLengthOneString(right)) { | 834 if (IsLengthOneString(right)) { |
| 846 // Swap, since we know that both arguments are strings | 835 // Swap, since we know that both arguments are strings |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 913 to_remove_right->RemoveFromGraph(); | 902 to_remove_right->RemoveFromGraph(); |
| 914 } | 903 } |
| 915 return true; | 904 return true; |
| 916 } | 905 } |
| 917 return false; | 906 return false; |
| 918 } | 907 } |
| 919 | 908 |
| 920 | 909 |
| 921 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 910 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
| 922 | 911 |
| 923 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 912 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
| 924 Token::Kind op_kind) { | 913 Token::Kind op_kind) { |
| 925 const ICData& ic_data = *call->ic_data(); | 914 const ICData& ic_data = *call->ic_data(); |
| 926 ASSERT(ic_data.NumArgsTested() == 2); | 915 ASSERT(ic_data.NumArgsTested() == 2); |
| 927 | 916 |
| 928 ASSERT(call->ArgumentCount() == 2); | 917 ASSERT(call->ArgumentCount() == 2); |
| 929 Definition* left = call->ArgumentAt(0); | 918 Definition* left = call->ArgumentAt(0); |
| 930 Definition* right = call->ArgumentAt(1); | 919 Definition* right = call->ArgumentAt(1); |
| 931 | 920 |
| 932 intptr_t cid = kIllegalCid; | 921 intptr_t cid = kIllegalCid; |
| 933 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { | 922 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1022 op_kind, | 1011 op_kind, |
| 1023 new(Z) Value(left), | 1012 new(Z) Value(left), |
| 1024 new(Z) Value(right), | 1013 new(Z) Value(right), |
| 1025 cid, | 1014 cid, |
| 1026 call->deopt_id()); | 1015 call->deopt_id()); |
| 1027 ReplaceCall(call, comp); | 1016 ReplaceCall(call, comp); |
| 1028 return true; | 1017 return true; |
| 1029 } | 1018 } |
| 1030 | 1019 |
| 1031 | 1020 |
| 1032 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 1021 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
| 1033 Token::Kind op_kind) { | 1022 Token::Kind op_kind) { |
| 1034 const ICData& ic_data = *call->ic_data(); | 1023 const ICData& ic_data = *call->ic_data(); |
| 1035 ASSERT(ic_data.NumArgsTested() == 2); | 1024 ASSERT(ic_data.NumArgsTested() == 2); |
| 1036 | 1025 |
| 1037 ASSERT(call->ArgumentCount() == 2); | 1026 ASSERT(call->ArgumentCount() == 2); |
| 1038 Definition* left = call->ArgumentAt(0); | 1027 Definition* left = call->ArgumentAt(0); |
| 1039 Definition* right = call->ArgumentAt(1); | 1028 Definition* right = call->ArgumentAt(1); |
| 1040 | 1029 |
| 1041 intptr_t cid = kIllegalCid; | 1030 intptr_t cid = kIllegalCid; |
| 1042 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1031 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1084 op_kind, | 1073 op_kind, |
| 1085 new(Z) Value(left), | 1074 new(Z) Value(left), |
| 1086 new(Z) Value(right), | 1075 new(Z) Value(right), |
| 1087 cid, | 1076 cid, |
| 1088 call->deopt_id()); | 1077 call->deopt_id()); |
| 1089 ReplaceCall(call, comp); | 1078 ReplaceCall(call, comp); |
| 1090 return true; | 1079 return true; |
| 1091 } | 1080 } |
| 1092 | 1081 |
| 1093 | 1082 |
| 1094 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 1083 bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| 1095 Token::Kind op_kind) { | 1084 Token::Kind op_kind) { |
| 1096 intptr_t operands_type = kIllegalCid; | 1085 intptr_t operands_type = kIllegalCid; |
| 1097 ASSERT(call->HasICData()); | 1086 ASSERT(call->HasICData()); |
| 1098 const ICData& ic_data = *call->ic_data(); | 1087 const ICData& ic_data = *call->ic_data(); |
| 1099 switch (op_kind) { | 1088 switch (op_kind) { |
| 1100 case Token::kADD: | 1089 case Token::kADD: |
| 1101 case Token::kSUB: | 1090 case Token::kSUB: |
| 1102 case Token::kMUL: | 1091 case Token::kMUL: |
| 1103 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1092 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1104 // Don't generate smi code if the IC data is marked because | 1093 // Don't generate smi code if the IC data is marked because |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1293 op_kind, | 1282 op_kind, |
| 1294 new(Z) Value(left), | 1283 new(Z) Value(left), |
| 1295 new(Z) Value(right), | 1284 new(Z) Value(right), |
| 1296 call->deopt_id()); | 1285 call->deopt_id()); |
| 1297 ReplaceCall(call, bin_op); | 1286 ReplaceCall(call, bin_op); |
| 1298 } | 1287 } |
| 1299 return true; | 1288 return true; |
| 1300 } | 1289 } |
| 1301 | 1290 |
| 1302 | 1291 |
| 1303 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, | 1292 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, |
| 1304 Token::Kind op_kind) { | 1293 Token::Kind op_kind) { |
| 1305 ASSERT(call->ArgumentCount() == 1); | 1294 ASSERT(call->ArgumentCount() == 1); |
| 1306 Definition* input = call->ArgumentAt(0); | 1295 Definition* input = call->ArgumentAt(0); |
| 1307 Definition* unary_op = NULL; | 1296 Definition* unary_op = NULL; |
| 1308 if (HasOnlyOneSmi(*call->ic_data())) { | 1297 if (HasOnlyOneSmi(*call->ic_data())) { |
| 1309 InsertBefore(call, | 1298 InsertBefore(call, |
| 1310 new(Z) CheckSmiInstr(new(Z) Value(input), | 1299 new(Z) CheckSmiInstr(new(Z) Value(input), |
| 1311 call->deopt_id(), | 1300 call->deopt_id(), |
| 1312 call->token_pos()), | 1301 call->token_pos()), |
| 1313 call->env(), | 1302 call->env(), |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1328 } else { | 1317 } else { |
| 1329 return false; | 1318 return false; |
| 1330 } | 1319 } |
| 1331 ASSERT(unary_op != NULL); | 1320 ASSERT(unary_op != NULL); |
| 1332 ReplaceCall(call, unary_op); | 1321 ReplaceCall(call, unary_op); |
| 1333 return true; | 1322 return true; |
| 1334 } | 1323 } |
| 1335 | 1324 |
| 1336 | 1325 |
| 1337 // Using field class | 1326 // Using field class |
| 1338 RawField* FlowGraphOptimizer::GetField(intptr_t class_id, | 1327 RawField* AotOptimizer::GetField(intptr_t class_id, |
| 1339 const String& field_name) { | 1328 const String& field_name) { |
| 1340 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); | 1329 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); |
| 1341 Field& field = Field::Handle(Z); | 1330 Field& field = Field::Handle(Z); |
| 1342 while (!cls.IsNull()) { | 1331 while (!cls.IsNull()) { |
| 1343 field = cls.LookupInstanceField(field_name); | 1332 field = cls.LookupInstanceField(field_name); |
| 1344 if (!field.IsNull()) { | 1333 if (!field.IsNull()) { |
| 1345 return field.raw(); | 1334 return field.raw(); |
| 1346 } | 1335 } |
| 1347 cls = cls.SuperClass(); | 1336 cls = cls.SuperClass(); |
| 1348 } | 1337 } |
| 1349 return Field::null(); | 1338 return Field::null(); |
| 1350 } | 1339 } |
| 1351 | 1340 |
| 1352 | 1341 |
| 1353 // Use CHA to determine if the call needs a class check: if the callee's | 1342 // Use CHA to determine if the call needs a class check: if the callee's |
| 1354 // receiver is the same as the caller's receiver and there are no overriden | 1343 // receiver is the same as the caller's receiver and there are no overriden |
| 1355 // callee functions, then no class check is needed. | 1344 // callee functions, then no class check is needed. |
| 1356 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( | 1345 bool AotOptimizer::InstanceCallNeedsClassCheck( |
| 1357 InstanceCallInstr* call, RawFunction::Kind kind) const { | 1346 InstanceCallInstr* call, RawFunction::Kind kind) const { |
| 1358 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { | 1347 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { |
| 1359 // Even if class or function are private, lazy class finalization | 1348 // Even if class or function are private, lazy class finalization |
| 1360 // may later add overriding methods. | 1349 // may later add overriding methods. |
| 1361 return true; | 1350 return true; |
| 1362 } | 1351 } |
| 1363 Definition* callee_receiver = call->ArgumentAt(0); | 1352 Definition* callee_receiver = call->ArgumentAt(0); |
| 1364 ASSERT(callee_receiver != NULL); | 1353 ASSERT(callee_receiver != NULL); |
| 1365 const Function& function = flow_graph_->function(); | 1354 const Function& function = flow_graph_->function(); |
| 1366 if (function.IsDynamicFunction() && | 1355 if (function.IsDynamicFunction() && |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1377 name.ToCString(), cls.ToCString()); | 1366 name.ToCString(), cls.ToCString()); |
| 1378 } | 1367 } |
| 1379 thread()->cha()->AddToLeafClasses(cls); | 1368 thread()->cha()->AddToLeafClasses(cls); |
| 1380 return false; | 1369 return false; |
| 1381 } | 1370 } |
| 1382 } | 1371 } |
| 1383 return true; | 1372 return true; |
| 1384 } | 1373 } |
| 1385 | 1374 |
| 1386 | 1375 |
| 1387 bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call, | 1376 bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call, |
| 1388 bool allow_check) { | 1377 bool allow_check) { |
| 1389 ASSERT(call->HasICData()); | 1378 ASSERT(call->HasICData()); |
| 1390 const ICData& ic_data = *call->ic_data(); | 1379 const ICData& ic_data = *call->ic_data(); |
| 1391 ASSERT(ic_data.HasOneTarget()); | 1380 ASSERT(ic_data.HasOneTarget()); |
| 1392 GrowableArray<intptr_t> class_ids; | 1381 GrowableArray<intptr_t> class_ids; |
| 1393 ic_data.GetClassIdsAt(0, &class_ids); | 1382 ic_data.GetClassIdsAt(0, &class_ids); |
| 1394 ASSERT(class_ids.length() == 1); | 1383 ASSERT(class_ids.length() == 1); |
| 1395 // Inline implicit instance getter. | 1384 // Inline implicit instance getter. |
| 1396 const String& field_name = | 1385 const String& field_name = |
| 1397 String::Handle(Z, Field::NameFromGetter(call->function_name())); | 1386 String::Handle(Z, Field::NameFromGetter(call->function_name())); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 1428 for (Value::Iterator it(load->input_use_list()); | 1417 for (Value::Iterator it(load->input_use_list()); |
| 1429 !it.Done(); | 1418 !it.Done(); |
| 1430 it.Advance()) { | 1419 it.Advance()) { |
| 1431 it.Current()->SetReachingType(NULL); | 1420 it.Current()->SetReachingType(NULL); |
| 1432 } | 1421 } |
| 1433 } | 1422 } |
| 1434 return true; | 1423 return true; |
| 1435 } | 1424 } |
| 1436 | 1425 |
| 1437 | 1426 |
| 1438 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, | 1427 bool AotOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, |
| 1439 MethodRecognizer::Kind getter) { | 1428 MethodRecognizer::Kind getter) { |
| 1440 if (!ShouldInlineSimd()) { | 1429 if (!ShouldInlineSimd()) { |
| 1441 return false; | 1430 return false; |
| 1442 } | 1431 } |
| 1443 AddCheckClass(call->ArgumentAt(0), | 1432 AddCheckClass(call->ArgumentAt(0), |
| 1444 ICData::ZoneHandle( | 1433 ICData::ZoneHandle( |
| 1445 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1434 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1446 call->deopt_id(), | 1435 call->deopt_id(), |
| 1447 call->env(), | 1436 call->env(), |
| 1448 call); | 1437 call); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1503 mask, | 1492 mask, |
| 1504 call->deopt_id()); | 1493 call->deopt_id()); |
| 1505 ReplaceCall(call, instr); | 1494 ReplaceCall(call, instr); |
| 1506 return true; | 1495 return true; |
| 1507 } | 1496 } |
| 1508 UNREACHABLE(); | 1497 UNREACHABLE(); |
| 1509 return false; | 1498 return false; |
| 1510 } | 1499 } |
| 1511 | 1500 |
| 1512 | 1501 |
| 1513 bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call, | 1502 bool AotOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call, |
| 1514 MethodRecognizer::Kind getter) { | 1503 MethodRecognizer::Kind getter) { |
| 1515 if (!ShouldInlineSimd()) { | 1504 if (!ShouldInlineSimd()) { |
| 1516 return false; | 1505 return false; |
| 1517 } | 1506 } |
| 1518 AddCheckClass(call->ArgumentAt(0), | 1507 AddCheckClass(call->ArgumentAt(0), |
| 1519 ICData::ZoneHandle( | 1508 ICData::ZoneHandle( |
| 1520 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1509 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1521 call->deopt_id(), | 1510 call->deopt_id(), |
| 1522 call->env(), | 1511 call->env(), |
| 1523 call); | 1512 call); |
| 1524 if ((getter == MethodRecognizer::kFloat64x2GetX) || | 1513 if ((getter == MethodRecognizer::kFloat64x2GetX) || |
| 1525 (getter == MethodRecognizer::kFloat64x2GetY)) { | 1514 (getter == MethodRecognizer::kFloat64x2GetY)) { |
| 1526 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr( | 1515 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr( |
| 1527 getter, | 1516 getter, |
| 1528 new(Z) Value(call->ArgumentAt(0)), | 1517 new(Z) Value(call->ArgumentAt(0)), |
| 1529 0, | 1518 0, |
| 1530 call->deopt_id()); | 1519 call->deopt_id()); |
| 1531 ReplaceCall(call, instr); | 1520 ReplaceCall(call, instr); |
| 1532 return true; | 1521 return true; |
| 1533 } | 1522 } |
| 1534 UNREACHABLE(); | 1523 UNREACHABLE(); |
| 1535 return false; | 1524 return false; |
| 1536 } | 1525 } |
| 1537 | 1526 |
| 1538 | 1527 |
| 1539 bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call, | 1528 bool AotOptimizer::InlineInt32x4Getter(InstanceCallInstr* call, |
| 1540 MethodRecognizer::Kind getter) { | 1529 MethodRecognizer::Kind getter) { |
| 1541 if (!ShouldInlineSimd()) { | 1530 if (!ShouldInlineSimd()) { |
| 1542 return false; | 1531 return false; |
| 1543 } | 1532 } |
| 1544 AddCheckClass(call->ArgumentAt(0), | 1533 AddCheckClass(call->ArgumentAt(0), |
| 1545 ICData::ZoneHandle( | 1534 ICData::ZoneHandle( |
| 1546 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1535 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1547 call->deopt_id(), | 1536 call->deopt_id(), |
| 1548 call->env(), | 1537 call->env(), |
| 1549 call); | 1538 call); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1604 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr( | 1593 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr( |
| 1605 getter, | 1594 getter, |
| 1606 new(Z) Value(call->ArgumentAt(0)), | 1595 new(Z) Value(call->ArgumentAt(0)), |
| 1607 call->deopt_id()); | 1596 call->deopt_id()); |
| 1608 ReplaceCall(call, instr); | 1597 ReplaceCall(call, instr); |
| 1609 return true; | 1598 return true; |
| 1610 } | 1599 } |
| 1611 } | 1600 } |
| 1612 | 1601 |
| 1613 | 1602 |
| 1614 bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, | 1603 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, |
| 1615 Token::Kind op_kind) { | 1604 Token::Kind op_kind) { |
| 1616 if (!ShouldInlineSimd()) { | 1605 if (!ShouldInlineSimd()) { |
| 1617 return false; | 1606 return false; |
| 1618 } | 1607 } |
| 1619 ASSERT(call->ArgumentCount() == 2); | 1608 ASSERT(call->ArgumentCount() == 2); |
| 1620 Definition* left = call->ArgumentAt(0); | 1609 Definition* left = call->ArgumentAt(0); |
| 1621 Definition* right = call->ArgumentAt(1); | 1610 Definition* right = call->ArgumentAt(1); |
| 1622 // Type check left. | 1611 // Type check left. |
| 1623 AddCheckClass(left, | 1612 AddCheckClass(left, |
| 1624 ICData::ZoneHandle( | 1613 ICData::ZoneHandle( |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1637 BinaryFloat32x4OpInstr* float32x4_bin_op = | 1626 BinaryFloat32x4OpInstr* float32x4_bin_op = |
| 1638 new(Z) BinaryFloat32x4OpInstr( | 1627 new(Z) BinaryFloat32x4OpInstr( |
| 1639 op_kind, new(Z) Value(left), new(Z) Value(right), | 1628 op_kind, new(Z) Value(left), new(Z) Value(right), |
| 1640 call->deopt_id()); | 1629 call->deopt_id()); |
| 1641 ReplaceCall(call, float32x4_bin_op); | 1630 ReplaceCall(call, float32x4_bin_op); |
| 1642 | 1631 |
| 1643 return true; | 1632 return true; |
| 1644 } | 1633 } |
| 1645 | 1634 |
| 1646 | 1635 |
| 1647 bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, | 1636 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, |
| 1648 Token::Kind op_kind) { | 1637 Token::Kind op_kind) { |
| 1649 if (!ShouldInlineSimd()) { | 1638 if (!ShouldInlineSimd()) { |
| 1650 return false; | 1639 return false; |
| 1651 } | 1640 } |
| 1652 ASSERT(call->ArgumentCount() == 2); | 1641 ASSERT(call->ArgumentCount() == 2); |
| 1653 Definition* left = call->ArgumentAt(0); | 1642 Definition* left = call->ArgumentAt(0); |
| 1654 Definition* right = call->ArgumentAt(1); | 1643 Definition* right = call->ArgumentAt(1); |
| 1655 // Type check left. | 1644 // Type check left. |
| 1656 AddCheckClass(left, | 1645 AddCheckClass(left, |
| 1657 ICData::ZoneHandle( | 1646 ICData::ZoneHandle( |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1669 // Replace call. | 1658 // Replace call. |
| 1670 BinaryInt32x4OpInstr* int32x4_bin_op = | 1659 BinaryInt32x4OpInstr* int32x4_bin_op = |
| 1671 new(Z) BinaryInt32x4OpInstr( | 1660 new(Z) BinaryInt32x4OpInstr( |
| 1672 op_kind, new(Z) Value(left), new(Z) Value(right), | 1661 op_kind, new(Z) Value(left), new(Z) Value(right), |
| 1673 call->deopt_id()); | 1662 call->deopt_id()); |
| 1674 ReplaceCall(call, int32x4_bin_op); | 1663 ReplaceCall(call, int32x4_bin_op); |
| 1675 return true; | 1664 return true; |
| 1676 } | 1665 } |
| 1677 | 1666 |
| 1678 | 1667 |
| 1679 bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, | 1668 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, |
| 1680 Token::Kind op_kind) { | 1669 Token::Kind op_kind) { |
| 1681 if (!ShouldInlineSimd()) { | 1670 if (!ShouldInlineSimd()) { |
| 1682 return false; | 1671 return false; |
| 1683 } | 1672 } |
| 1684 ASSERT(call->ArgumentCount() == 2); | 1673 ASSERT(call->ArgumentCount() == 2); |
| 1685 Definition* left = call->ArgumentAt(0); | 1674 Definition* left = call->ArgumentAt(0); |
| 1686 Definition* right = call->ArgumentAt(1); | 1675 Definition* right = call->ArgumentAt(1); |
| 1687 // Type check left. | 1676 // Type check left. |
| 1688 AddCheckClass(left, | 1677 AddCheckClass(left, |
| 1689 ICData::ZoneHandle( | 1678 ICData::ZoneHandle( |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1703 new(Z) BinaryFloat64x2OpInstr( | 1692 new(Z) BinaryFloat64x2OpInstr( |
| 1704 op_kind, new(Z) Value(left), new(Z) Value(right), | 1693 op_kind, new(Z) Value(left), new(Z) Value(right), |
| 1705 call->deopt_id()); | 1694 call->deopt_id()); |
| 1706 ReplaceCall(call, float64x2_bin_op); | 1695 ReplaceCall(call, float64x2_bin_op); |
| 1707 return true; | 1696 return true; |
| 1708 } | 1697 } |
| 1709 | 1698 |
| 1710 | 1699 |
| 1711 // Only unique implicit instance getters can be currently handled. | 1700 // Only unique implicit instance getters can be currently handled. |
| 1712 // Returns false if 'allow_check' is false and a check is needed. | 1701 // Returns false if 'allow_check' is false and a check is needed. |
| 1713 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call, | 1702 bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call, |
| 1714 bool allow_check) { | 1703 bool allow_check) { |
| 1715 ASSERT(call->HasICData()); | 1704 ASSERT(call->HasICData()); |
| 1716 const ICData& ic_data = *call->ic_data(); | 1705 const ICData& ic_data = *call->ic_data(); |
| 1717 if (ic_data.NumberOfUsedChecks() == 0) { | 1706 if (ic_data.NumberOfUsedChecks() == 0) { |
| 1718 // No type feedback collected. | 1707 // No type feedback collected. |
| 1719 return false; | 1708 return false; |
| 1720 } | 1709 } |
| 1721 | 1710 |
| 1722 if (!ic_data.HasOneTarget()) { | 1711 if (!ic_data.HasOneTarget()) { |
| 1723 // Polymorphic sites are inlined like normal methods by conventional | 1712 // Polymorphic sites are inlined like normal methods by conventional |
| 1724 // inlining in FlowGraphInliner. | 1713 // inlining in FlowGraphInliner. |
| 1725 return false; | 1714 return false; |
| 1726 } | 1715 } |
| 1727 | 1716 |
| 1728 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); | 1717 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); |
| 1729 if (target.kind() != RawFunction::kImplicitGetter) { | 1718 if (target.kind() != RawFunction::kImplicitGetter) { |
| 1730 // Non-implicit getters are inlined like normal methods by conventional | 1719 // Non-implicit getters are inlined like normal methods by conventional |
| 1731 // inlining in FlowGraphInliner. | 1720 // inlining in FlowGraphInliner. |
| 1732 return false; | 1721 return false; |
| 1733 } | 1722 } |
| 1734 return InlineImplicitInstanceGetter(call, allow_check); | 1723 return InlineImplicitInstanceGetter(call, allow_check); |
| 1735 } | 1724 } |
| 1736 | 1725 |
| 1737 | 1726 |
| 1738 bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline( | 1727 bool AotOptimizer::TryReplaceInstanceCallWithInline( |
| 1739 InstanceCallInstr* call) { | 1728 InstanceCallInstr* call) { |
| 1740 Function& target = Function::Handle(Z); | 1729 Function& target = Function::Handle(Z); |
| 1741 GrowableArray<intptr_t> class_ids; | 1730 GrowableArray<intptr_t> class_ids; |
| 1742 call->ic_data()->GetCheckAt(0, &class_ids, &target); | 1731 call->ic_data()->GetCheckAt(0, &class_ids, &target); |
| 1743 const intptr_t receiver_cid = class_ids[0]; | 1732 const intptr_t receiver_cid = class_ids[0]; |
| 1744 | 1733 |
| 1745 TargetEntryInstr* entry; | 1734 TargetEntryInstr* entry; |
| 1746 Definition* last; | 1735 Definition* last; |
| 1747 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, | 1736 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, |
| 1748 receiver_cid, | 1737 receiver_cid, |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 1772 last->LinkTo(call); | 1761 last->LinkTo(call); |
| 1773 // Remove through the iterator. | 1762 // Remove through the iterator. |
| 1774 ASSERT(current_iterator()->Current() == call); | 1763 ASSERT(current_iterator()->Current() == call); |
| 1775 current_iterator()->RemoveCurrentFromGraph(); | 1764 current_iterator()->RemoveCurrentFromGraph(); |
| 1776 call->set_previous(NULL); | 1765 call->set_previous(NULL); |
| 1777 call->set_next(NULL); | 1766 call->set_next(NULL); |
| 1778 return true; | 1767 return true; |
| 1779 } | 1768 } |
| 1780 | 1769 |
| 1781 | 1770 |
| 1782 void FlowGraphOptimizer::ReplaceWithMathCFunction( | 1771 void AotOptimizer::ReplaceWithMathCFunction( |
| 1783 InstanceCallInstr* call, | 1772 InstanceCallInstr* call, |
| 1784 MethodRecognizer::Kind recognized_kind) { | 1773 MethodRecognizer::Kind recognized_kind) { |
| 1785 AddReceiverCheck(call); | 1774 AddReceiverCheck(call); |
| 1786 ZoneGrowableArray<Value*>* args = | 1775 ZoneGrowableArray<Value*>* args = |
| 1787 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1776 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 1788 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1777 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 1789 args->Add(new(Z) Value(call->ArgumentAt(i))); | 1778 args->Add(new(Z) Value(call->ArgumentAt(i))); |
| 1790 } | 1779 } |
| 1791 InvokeMathCFunctionInstr* invoke = | 1780 InvokeMathCFunctionInstr* invoke = |
| 1792 new(Z) InvokeMathCFunctionInstr(args, | 1781 new(Z) InvokeMathCFunctionInstr(args, |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1813 case kTypedDataFloat32x4ArrayCid: | 1802 case kTypedDataFloat32x4ArrayCid: |
| 1814 case kTypedDataInt32x4ArrayCid: | 1803 case kTypedDataInt32x4ArrayCid: |
| 1815 return true; | 1804 return true; |
| 1816 default: | 1805 default: |
| 1817 return false; | 1806 return false; |
| 1818 } | 1807 } |
| 1819 } | 1808 } |
| 1820 | 1809 |
| 1821 | 1810 |
| 1822 // Inline only simple, frequently called core library methods. | 1811 // Inline only simple, frequently called core library methods. |
| 1823 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 1812 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
| 1824 ASSERT(call->HasICData()); | 1813 ASSERT(call->HasICData()); |
| 1825 const ICData& ic_data = *call->ic_data(); | 1814 const ICData& ic_data = *call->ic_data(); |
| 1826 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) { | 1815 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) { |
| 1827 // No type feedback collected or multiple targets found. | 1816 // No type feedback collected or multiple targets found. |
| 1828 return false; | 1817 return false; |
| 1829 } | 1818 } |
| 1830 | 1819 |
| 1831 Function& target = Function::Handle(Z); | 1820 Function& target = Function::Handle(Z); |
| 1832 GrowableArray<intptr_t> class_ids; | 1821 GrowableArray<intptr_t> class_ids; |
| 1833 ic_data.GetCheckAt(0, &class_ids, &target); | 1822 ic_data.GetCheckAt(0, &class_ids, &target); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2046 new(Z) Value(int32_mask), | 2035 new(Z) Value(int32_mask), |
| 2047 call->deopt_id()); | 2036 call->deopt_id()); |
| 2048 ReplaceCall(call, bit_and); | 2037 ReplaceCall(call, bit_and); |
| 2049 return true; | 2038 return true; |
| 2050 } | 2039 } |
| 2051 } | 2040 } |
| 2052 return false; | 2041 return false; |
| 2053 } | 2042 } |
| 2054 | 2043 |
| 2055 | 2044 |
| 2056 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( | 2045 bool AotOptimizer::TryInlineFloat32x4Constructor( |
| 2057 StaticCallInstr* call, | 2046 StaticCallInstr* call, |
| 2058 MethodRecognizer::Kind recognized_kind) { | 2047 MethodRecognizer::Kind recognized_kind) { |
| 2059 if (FLAG_precompilation) { | 2048 ASSERT(FLAG_precompilation); |
|
rmacnak
2016/02/19 23:46:03
Keep comment: Cannot handle unboxed instructions.
Florian Schneider
2016/02/23 15:27:03
Done.
| |
| 2060 // Cannot handle unboxed instructions. | |
| 2061 return false; | |
| 2062 } | |
| 2063 if (!ShouldInlineSimd()) { | |
| 2064 return false; | |
| 2065 } | |
| 2066 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { | |
| 2067 Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr(); | |
| 2068 ReplaceCall(call, zero); | |
| 2069 return true; | |
| 2070 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { | |
| 2071 Float32x4SplatInstr* splat = | |
| 2072 new(Z) Float32x4SplatInstr( | |
| 2073 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
| 2074 ReplaceCall(call, splat); | |
| 2075 return true; | |
| 2076 } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) { | |
| 2077 Float32x4ConstructorInstr* con = | |
| 2078 new(Z) Float32x4ConstructorInstr( | |
| 2079 new(Z) Value(call->ArgumentAt(1)), | |
| 2080 new(Z) Value(call->ArgumentAt(2)), | |
| 2081 new(Z) Value(call->ArgumentAt(3)), | |
| 2082 new(Z) Value(call->ArgumentAt(4)), | |
| 2083 call->deopt_id()); | |
| 2084 ReplaceCall(call, con); | |
| 2085 return true; | |
| 2086 } else if (recognized_kind == MethodRecognizer::kFloat32x4FromInt32x4Bits) { | |
| 2087 Int32x4ToFloat32x4Instr* cast = | |
| 2088 new(Z) Int32x4ToFloat32x4Instr( | |
| 2089 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
| 2090 ReplaceCall(call, cast); | |
| 2091 return true; | |
| 2092 } else if (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2) { | |
| 2093 Float64x2ToFloat32x4Instr* cast = | |
| 2094 new(Z) Float64x2ToFloat32x4Instr( | |
| 2095 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
| 2096 ReplaceCall(call, cast); | |
| 2097 return true; | |
| 2098 } | |
| 2099 return false; | 2049 return false; |
| 2100 } | 2050 } |
| 2101 | 2051 |
| 2102 | 2052 |
| 2103 bool FlowGraphOptimizer::TryInlineFloat64x2Constructor( | 2053 bool AotOptimizer::TryInlineFloat64x2Constructor( |
| 2104 StaticCallInstr* call, | 2054 StaticCallInstr* call, |
| 2105 MethodRecognizer::Kind recognized_kind) { | 2055 MethodRecognizer::Kind recognized_kind) { |
| 2106 if (FLAG_precompilation) { | 2056 ASSERT(FLAG_precompilation); |
|
rmacnak
2016/02/19 23:46:04
Keep comment
Florian Schneider
2016/02/23 15:27:02
Done.
| |
| 2107 // Cannot handle unboxed instructions. | |
| 2108 return false; | |
| 2109 } | |
| 2110 if (!ShouldInlineSimd()) { | |
| 2111 return false; | |
| 2112 } | |
| 2113 if (recognized_kind == MethodRecognizer::kFloat64x2Zero) { | |
| 2114 Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr(); | |
| 2115 ReplaceCall(call, zero); | |
| 2116 return true; | |
| 2117 } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) { | |
| 2118 Float64x2SplatInstr* splat = | |
| 2119 new(Z) Float64x2SplatInstr( | |
| 2120 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
| 2121 ReplaceCall(call, splat); | |
| 2122 return true; | |
| 2123 } else if (recognized_kind == MethodRecognizer::kFloat64x2Constructor) { | |
| 2124 Float64x2ConstructorInstr* con = | |
| 2125 new(Z) Float64x2ConstructorInstr( | |
| 2126 new(Z) Value(call->ArgumentAt(1)), | |
| 2127 new(Z) Value(call->ArgumentAt(2)), | |
| 2128 call->deopt_id()); | |
| 2129 ReplaceCall(call, con); | |
| 2130 return true; | |
| 2131 } else if (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4) { | |
| 2132 Float32x4ToFloat64x2Instr* cast = | |
| 2133 new(Z) Float32x4ToFloat64x2Instr( | |
| 2134 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
| 2135 ReplaceCall(call, cast); | |
| 2136 return true; | |
| 2137 } | |
| 2138 return false; | 2057 return false; |
| 2139 } | 2058 } |
| 2140 | 2059 |
| 2141 | 2060 |
| 2142 bool FlowGraphOptimizer::TryInlineInt32x4Constructor( | 2061 bool AotOptimizer::TryInlineInt32x4Constructor( |
| 2143 StaticCallInstr* call, | 2062 StaticCallInstr* call, |
| 2144 MethodRecognizer::Kind recognized_kind) { | 2063 MethodRecognizer::Kind recognized_kind) { |
| 2145 if (FLAG_precompilation) { | 2064 ASSERT(FLAG_precompilation); |
|
rmacnak
2016/02/19 23:46:03
Keep comment
Florian Schneider
2016/02/23 15:27:03
Done.
| |
| 2146 // Cannot handle unboxed instructions. | |
| 2147 return false; | |
| 2148 } | |
| 2149 if (!ShouldInlineSimd()) { | |
| 2150 return false; | |
| 2151 } | |
| 2152 if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) { | |
| 2153 Int32x4BoolConstructorInstr* con = | |
| 2154 new(Z) Int32x4BoolConstructorInstr( | |
| 2155 new(Z) Value(call->ArgumentAt(1)), | |
| 2156 new(Z) Value(call->ArgumentAt(2)), | |
| 2157 new(Z) Value(call->ArgumentAt(3)), | |
| 2158 new(Z) Value(call->ArgumentAt(4)), | |
| 2159 call->deopt_id()); | |
| 2160 ReplaceCall(call, con); | |
| 2161 return true; | |
| 2162 } else if (recognized_kind == MethodRecognizer::kInt32x4FromFloat32x4Bits) { | |
| 2163 Float32x4ToInt32x4Instr* cast = | |
| 2164 new(Z) Float32x4ToInt32x4Instr( | |
| 2165 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
| 2166 ReplaceCall(call, cast); | |
| 2167 return true; | |
| 2168 } else if (recognized_kind == MethodRecognizer::kInt32x4Constructor) { | |
| 2169 Int32x4ConstructorInstr* con = | |
| 2170 new(Z) Int32x4ConstructorInstr( | |
| 2171 new(Z) Value(call->ArgumentAt(1)), | |
| 2172 new(Z) Value(call->ArgumentAt(2)), | |
| 2173 new(Z) Value(call->ArgumentAt(3)), | |
| 2174 new(Z) Value(call->ArgumentAt(4)), | |
| 2175 call->deopt_id()); | |
| 2176 ReplaceCall(call, con); | |
| 2177 return true; | |
| 2178 } | |
| 2179 return false; | 2065 return false; |
| 2180 } | 2066 } |
| 2181 | 2067 |
| 2182 | 2068 |
| 2183 bool FlowGraphOptimizer::TryInlineFloat32x4Method( | 2069 bool AotOptimizer::TryInlineFloat32x4Method( |
| 2184 InstanceCallInstr* call, | 2070 InstanceCallInstr* call, |
| 2185 MethodRecognizer::Kind recognized_kind) { | 2071 MethodRecognizer::Kind recognized_kind) { |
| 2186 if (!ShouldInlineSimd()) { | 2072 return false; |
| 2187 return false; | |
| 2188 } | |
| 2189 ASSERT(call->HasICData()); | |
| 2190 switch (recognized_kind) { | |
| 2191 case MethodRecognizer::kFloat32x4ShuffleX: | |
| 2192 case MethodRecognizer::kFloat32x4ShuffleY: | |
| 2193 case MethodRecognizer::kFloat32x4ShuffleZ: | |
| 2194 case MethodRecognizer::kFloat32x4ShuffleW: | |
| 2195 case MethodRecognizer::kFloat32x4GetSignMask: | |
| 2196 ASSERT(call->ic_data()->HasReceiverClassId(kFloat32x4Cid)); | |
| 2197 ASSERT(call->ic_data()->HasOneTarget()); | |
| 2198 return InlineFloat32x4Getter(call, recognized_kind); | |
| 2199 | |
| 2200 case MethodRecognizer::kFloat32x4Equal: | |
| 2201 case MethodRecognizer::kFloat32x4GreaterThan: | |
| 2202 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: | |
| 2203 case MethodRecognizer::kFloat32x4LessThan: | |
| 2204 case MethodRecognizer::kFloat32x4LessThanOrEqual: | |
| 2205 case MethodRecognizer::kFloat32x4NotEqual: { | |
| 2206 Definition* left = call->ArgumentAt(0); | |
| 2207 Definition* right = call->ArgumentAt(1); | |
| 2208 // Type check left. | |
| 2209 AddCheckClass(left, | |
| 2210 ICData::ZoneHandle( | |
| 2211 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2212 call->deopt_id(), | |
| 2213 call->env(), | |
| 2214 call); | |
| 2215 // Replace call. | |
| 2216 Float32x4ComparisonInstr* cmp = | |
| 2217 new(Z) Float32x4ComparisonInstr(recognized_kind, | |
| 2218 new(Z) Value(left), | |
| 2219 new(Z) Value(right), | |
| 2220 call->deopt_id()); | |
| 2221 ReplaceCall(call, cmp); | |
| 2222 return true; | |
| 2223 } | |
| 2224 case MethodRecognizer::kFloat32x4Min: | |
| 2225 case MethodRecognizer::kFloat32x4Max: { | |
| 2226 Definition* left = call->ArgumentAt(0); | |
| 2227 Definition* right = call->ArgumentAt(1); | |
| 2228 // Type check left. | |
| 2229 AddCheckClass(left, | |
| 2230 ICData::ZoneHandle( | |
| 2231 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2232 call->deopt_id(), | |
| 2233 call->env(), | |
| 2234 call); | |
| 2235 Float32x4MinMaxInstr* minmax = | |
| 2236 new(Z) Float32x4MinMaxInstr( | |
| 2237 recognized_kind, | |
| 2238 new(Z) Value(left), | |
| 2239 new(Z) Value(right), | |
| 2240 call->deopt_id()); | |
| 2241 ReplaceCall(call, minmax); | |
| 2242 return true; | |
| 2243 } | |
| 2244 case MethodRecognizer::kFloat32x4Scale: { | |
| 2245 Definition* left = call->ArgumentAt(0); | |
| 2246 Definition* right = call->ArgumentAt(1); | |
| 2247 // Type check left. | |
| 2248 AddCheckClass(left, | |
| 2249 ICData::ZoneHandle( | |
| 2250 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2251 call->deopt_id(), | |
| 2252 call->env(), | |
| 2253 call); | |
| 2254 // Left and right values are swapped when handed to the instruction, | |
| 2255 // this is done so that the double value is loaded into the output | |
| 2256 // register and can be destroyed. | |
| 2257 Float32x4ScaleInstr* scale = | |
| 2258 new(Z) Float32x4ScaleInstr(recognized_kind, | |
| 2259 new(Z) Value(right), | |
| 2260 new(Z) Value(left), | |
| 2261 call->deopt_id()); | |
| 2262 ReplaceCall(call, scale); | |
| 2263 return true; | |
| 2264 } | |
| 2265 case MethodRecognizer::kFloat32x4Sqrt: | |
| 2266 case MethodRecognizer::kFloat32x4ReciprocalSqrt: | |
| 2267 case MethodRecognizer::kFloat32x4Reciprocal: { | |
| 2268 Definition* left = call->ArgumentAt(0); | |
| 2269 AddCheckClass(left, | |
| 2270 ICData::ZoneHandle( | |
| 2271 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2272 call->deopt_id(), | |
| 2273 call->env(), | |
| 2274 call); | |
| 2275 Float32x4SqrtInstr* sqrt = | |
| 2276 new(Z) Float32x4SqrtInstr(recognized_kind, | |
| 2277 new(Z) Value(left), | |
| 2278 call->deopt_id()); | |
| 2279 ReplaceCall(call, sqrt); | |
| 2280 return true; | |
| 2281 } | |
| 2282 case MethodRecognizer::kFloat32x4WithX: | |
| 2283 case MethodRecognizer::kFloat32x4WithY: | |
| 2284 case MethodRecognizer::kFloat32x4WithZ: | |
| 2285 case MethodRecognizer::kFloat32x4WithW: { | |
| 2286 Definition* left = call->ArgumentAt(0); | |
| 2287 Definition* right = call->ArgumentAt(1); | |
| 2288 // Type check left. | |
| 2289 AddCheckClass(left, | |
| 2290 ICData::ZoneHandle( | |
| 2291 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2292 call->deopt_id(), | |
| 2293 call->env(), | |
| 2294 call); | |
| 2295 Float32x4WithInstr* with = new(Z) Float32x4WithInstr(recognized_kind, | |
| 2296 new(Z) Value(left), | |
| 2297 new(Z) Value(right), | |
| 2298 call->deopt_id()); | |
| 2299 ReplaceCall(call, with); | |
| 2300 return true; | |
| 2301 } | |
| 2302 case MethodRecognizer::kFloat32x4Absolute: | |
| 2303 case MethodRecognizer::kFloat32x4Negate: { | |
| 2304 Definition* left = call->ArgumentAt(0); | |
| 2305 // Type check left. | |
| 2306 AddCheckClass(left, | |
| 2307 ICData::ZoneHandle( | |
| 2308 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2309 call->deopt_id(), | |
| 2310 call->env(), | |
| 2311 call); | |
| 2312 Float32x4ZeroArgInstr* zeroArg = | |
| 2313 new(Z) Float32x4ZeroArgInstr( | |
| 2314 recognized_kind, new(Z) Value(left), call->deopt_id()); | |
| 2315 ReplaceCall(call, zeroArg); | |
| 2316 return true; | |
| 2317 } | |
| 2318 case MethodRecognizer::kFloat32x4Clamp: { | |
| 2319 Definition* left = call->ArgumentAt(0); | |
| 2320 Definition* lower = call->ArgumentAt(1); | |
| 2321 Definition* upper = call->ArgumentAt(2); | |
| 2322 // Type check left. | |
| 2323 AddCheckClass(left, | |
| 2324 ICData::ZoneHandle( | |
| 2325 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2326 call->deopt_id(), | |
| 2327 call->env(), | |
| 2328 call); | |
| 2329 Float32x4ClampInstr* clamp = new(Z) Float32x4ClampInstr( | |
| 2330 new(Z) Value(left), | |
| 2331 new(Z) Value(lower), | |
| 2332 new(Z) Value(upper), | |
| 2333 call->deopt_id()); | |
| 2334 ReplaceCall(call, clamp); | |
| 2335 return true; | |
| 2336 } | |
| 2337 case MethodRecognizer::kFloat32x4ShuffleMix: | |
| 2338 case MethodRecognizer::kFloat32x4Shuffle: { | |
| 2339 return InlineFloat32x4Getter(call, recognized_kind); | |
| 2340 } | |
| 2341 default: | |
| 2342 return false; | |
| 2343 } | |
| 2344 } | 2073 } |
| 2345 | 2074 |
| 2346 | 2075 |
| 2347 bool FlowGraphOptimizer::TryInlineFloat64x2Method( | 2076 bool AotOptimizer::TryInlineFloat64x2Method( |
| 2348 InstanceCallInstr* call, | 2077 InstanceCallInstr* call, |
| 2349 MethodRecognizer::Kind recognized_kind) { | 2078 MethodRecognizer::Kind recognized_kind) { |
| 2350 if (!ShouldInlineSimd()) { | 2079 return false; |
| 2351 return false; | |
| 2352 } | |
| 2353 ASSERT(call->HasICData()); | |
| 2354 switch (recognized_kind) { | |
| 2355 case MethodRecognizer::kFloat64x2GetX: | |
| 2356 case MethodRecognizer::kFloat64x2GetY: | |
| 2357 ASSERT(call->ic_data()->HasReceiverClassId(kFloat64x2Cid)); | |
| 2358 ASSERT(call->ic_data()->HasOneTarget()); | |
| 2359 return InlineFloat64x2Getter(call, recognized_kind); | |
| 2360 case MethodRecognizer::kFloat64x2Negate: | |
| 2361 case MethodRecognizer::kFloat64x2Abs: | |
| 2362 case MethodRecognizer::kFloat64x2Sqrt: | |
| 2363 case MethodRecognizer::kFloat64x2GetSignMask: { | |
| 2364 Definition* left = call->ArgumentAt(0); | |
| 2365 // Type check left. | |
| 2366 AddCheckClass(left, | |
| 2367 ICData::ZoneHandle( | |
| 2368 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2369 call->deopt_id(), | |
| 2370 call->env(), | |
| 2371 call); | |
| 2372 Float64x2ZeroArgInstr* zeroArg = | |
| 2373 new(Z) Float64x2ZeroArgInstr( | |
| 2374 recognized_kind, new(Z) Value(left), call->deopt_id()); | |
| 2375 ReplaceCall(call, zeroArg); | |
| 2376 return true; | |
| 2377 } | |
| 2378 case MethodRecognizer::kFloat64x2Scale: | |
| 2379 case MethodRecognizer::kFloat64x2WithX: | |
| 2380 case MethodRecognizer::kFloat64x2WithY: | |
| 2381 case MethodRecognizer::kFloat64x2Min: | |
| 2382 case MethodRecognizer::kFloat64x2Max: { | |
| 2383 Definition* left = call->ArgumentAt(0); | |
| 2384 Definition* right = call->ArgumentAt(1); | |
| 2385 // Type check left. | |
| 2386 AddCheckClass(left, | |
| 2387 ICData::ZoneHandle( | |
| 2388 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2389 call->deopt_id(), | |
| 2390 call->env(), | |
| 2391 call); | |
| 2392 Float64x2OneArgInstr* zeroArg = | |
| 2393 new(Z) Float64x2OneArgInstr(recognized_kind, | |
| 2394 new(Z) Value(left), | |
| 2395 new(Z) Value(right), | |
| 2396 call->deopt_id()); | |
| 2397 ReplaceCall(call, zeroArg); | |
| 2398 return true; | |
| 2399 } | |
| 2400 default: | |
| 2401 return false; | |
| 2402 } | |
| 2403 } | 2080 } |
| 2404 | 2081 |
| 2405 | 2082 |
| 2406 bool FlowGraphOptimizer::TryInlineInt32x4Method( | 2083 bool AotOptimizer::TryInlineInt32x4Method( |
| 2407 InstanceCallInstr* call, | 2084 InstanceCallInstr* call, |
| 2408 MethodRecognizer::Kind recognized_kind) { | 2085 MethodRecognizer::Kind recognized_kind) { |
| 2409 if (!ShouldInlineSimd()) { | 2086 return false; |
| 2410 return false; | |
| 2411 } | |
| 2412 ASSERT(call->HasICData()); | |
| 2413 switch (recognized_kind) { | |
| 2414 case MethodRecognizer::kInt32x4ShuffleMix: | |
| 2415 case MethodRecognizer::kInt32x4Shuffle: | |
| 2416 case MethodRecognizer::kInt32x4GetFlagX: | |
| 2417 case MethodRecognizer::kInt32x4GetFlagY: | |
| 2418 case MethodRecognizer::kInt32x4GetFlagZ: | |
| 2419 case MethodRecognizer::kInt32x4GetFlagW: | |
| 2420 case MethodRecognizer::kInt32x4GetSignMask: | |
| 2421 ASSERT(call->ic_data()->HasReceiverClassId(kInt32x4Cid)); | |
| 2422 ASSERT(call->ic_data()->HasOneTarget()); | |
| 2423 return InlineInt32x4Getter(call, recognized_kind); | |
| 2424 | |
| 2425 case MethodRecognizer::kInt32x4Select: { | |
| 2426 Definition* mask = call->ArgumentAt(0); | |
| 2427 Definition* trueValue = call->ArgumentAt(1); | |
| 2428 Definition* falseValue = call->ArgumentAt(2); | |
| 2429 // Type check left. | |
| 2430 AddCheckClass(mask, | |
| 2431 ICData::ZoneHandle( | |
| 2432 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2433 call->deopt_id(), | |
| 2434 call->env(), | |
| 2435 call); | |
| 2436 Int32x4SelectInstr* select = new(Z) Int32x4SelectInstr( | |
| 2437 new(Z) Value(mask), | |
| 2438 new(Z) Value(trueValue), | |
| 2439 new(Z) Value(falseValue), | |
| 2440 call->deopt_id()); | |
| 2441 ReplaceCall(call, select); | |
| 2442 return true; | |
| 2443 } | |
| 2444 case MethodRecognizer::kInt32x4WithFlagX: | |
| 2445 case MethodRecognizer::kInt32x4WithFlagY: | |
| 2446 case MethodRecognizer::kInt32x4WithFlagZ: | |
| 2447 case MethodRecognizer::kInt32x4WithFlagW: { | |
| 2448 Definition* left = call->ArgumentAt(0); | |
| 2449 Definition* flag = call->ArgumentAt(1); | |
| 2450 // Type check left. | |
| 2451 AddCheckClass(left, | |
| 2452 ICData::ZoneHandle( | |
| 2453 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 2454 call->deopt_id(), | |
| 2455 call->env(), | |
| 2456 call); | |
| 2457 Int32x4SetFlagInstr* setFlag = new(Z) Int32x4SetFlagInstr( | |
| 2458 recognized_kind, | |
| 2459 new(Z) Value(left), | |
| 2460 new(Z) Value(flag), | |
| 2461 call->deopt_id()); | |
| 2462 ReplaceCall(call, setFlag); | |
| 2463 return true; | |
| 2464 } | |
| 2465 default: | |
| 2466 return false; | |
| 2467 } | |
| 2468 } | 2087 } |
| 2469 | 2088 |
| 2470 | 2089 |
| 2471 // If type tests specified by 'ic_data' do not depend on type arguments, | 2090 // If type tests specified by 'ic_data' do not depend on type arguments, |
| 2472 // return mapping cid->result in 'results' (i : cid; i + 1: result). | 2091 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
| 2473 // If all tests yield the same result, return it otherwise return Bool::null. | 2092 // If all tests yield the same result, return it otherwise return Bool::null. |
| 2474 // If no mapping is possible, 'results' is empty. | 2093 // If no mapping is possible, 'results' is empty. |
| 2475 // An instance-of test returning all same results can be converted to a class | 2094 // An instance-of test returning all same results can be converted to a class |
| 2476 // check. | 2095 // check. |
| 2477 RawBool* FlowGraphOptimizer::InstanceOfAsBool( | 2096 RawBool* AotOptimizer::InstanceOfAsBool( |
| 2478 const ICData& ic_data, | 2097 const ICData& ic_data, |
| 2479 const AbstractType& type, | 2098 const AbstractType& type, |
| 2480 ZoneGrowableArray<intptr_t>* results) const { | 2099 ZoneGrowableArray<intptr_t>* results) const { |
| 2481 ASSERT(results->is_empty()); | 2100 ASSERT(results->is_empty()); |
| 2482 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. | 2101 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. |
| 2483 if (type.IsFunctionType() || type.IsDartFunctionType() || | 2102 if (type.IsFunctionType() || type.IsDartFunctionType() || |
| 2484 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { | 2103 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { |
| 2485 return Bool::null(); | 2104 return Bool::null(); |
| 2486 } | 2105 } |
| 2487 const Class& type_class = Class::Handle(Z, type.type_class()); | 2106 const Class& type_class = Class::Handle(Z, type.type_class()); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2526 if (is_subtype != prev.value()) { | 2145 if (is_subtype != prev.value()) { |
| 2527 results_differ = true; | 2146 results_differ = true; |
| 2528 } | 2147 } |
| 2529 } | 2148 } |
| 2530 } | 2149 } |
| 2531 return results_differ ? Bool::null() : prev.raw(); | 2150 return results_differ ? Bool::null() : prev.raw(); |
| 2532 } | 2151 } |
| 2533 | 2152 |
| 2534 | 2153 |
| 2535 // Returns true if checking against this type is a direct class id comparison. | 2154 // Returns true if checking against this type is a direct class id comparison. |
| 2536 bool FlowGraphOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { | 2155 bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { |
| 2537 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 2156 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
| 2538 // Requires CHA. | 2157 // Requires CHA. |
| 2539 if (!type.IsInstantiated()) return false; | 2158 if (!type.IsInstantiated()) return false; |
| 2540 // Function types have different type checking rules. | 2159 // Function types have different type checking rules. |
| 2541 if (type.IsFunctionType()) return false; | 2160 if (type.IsFunctionType()) return false; |
| 2542 const Class& type_class = Class::Handle(type.type_class()); | 2161 const Class& type_class = Class::Handle(type.type_class()); |
| 2543 // Could be an interface check? | 2162 // Could be an interface check? |
| 2544 if (CHA::IsImplemented(type_class)) return false; | 2163 if (CHA::IsImplemented(type_class)) return false; |
| 2545 // Check if there are subclasses. | 2164 // Check if there are subclasses. |
| 2546 if (CHA::HasSubclasses(type_class)) { | 2165 if (CHA::HasSubclasses(type_class)) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2630 TryAddTest(results, kBigintCid, true); | 2249 TryAddTest(results, kBigintCid, true); |
| 2631 // Cannot deoptimize since all tests returning true have been added. | 2250 // Cannot deoptimize since all tests returning true have been added. |
| 2632 return false; | 2251 return false; |
| 2633 } | 2252 } |
| 2634 | 2253 |
| 2635 return true; // May deoptimize since we have not identified all 'true' tests. | 2254 return true; // May deoptimize since we have not identified all 'true' tests. |
| 2636 } | 2255 } |
| 2637 | 2256 |
| 2638 | 2257 |
| 2639 // TODO(srdjan): Use ICData to check if always true or false. | 2258 // TODO(srdjan): Use ICData to check if always true or false. |
| 2640 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 2259 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 2641 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 2260 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 2642 Definition* left = call->ArgumentAt(0); | 2261 Definition* left = call->ArgumentAt(0); |
| 2643 Definition* type_args = NULL; | 2262 Definition* type_args = NULL; |
| 2644 AbstractType& type = AbstractType::ZoneHandle(Z); | 2263 AbstractType& type = AbstractType::ZoneHandle(Z); |
| 2645 bool negate = false; | 2264 bool negate = false; |
| 2646 if (call->ArgumentCount() == 2) { | 2265 if (call->ArgumentCount() == 2) { |
| 2647 type_args = flow_graph()->constant_null(); | 2266 type_args = flow_graph()->constant_null(); |
| 2648 if (call->function_name().raw() == | 2267 if (call->function_name().raw() == |
| 2649 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { | 2268 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { |
| 2650 type = Type::Number(); | 2269 type = Type::Number(); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2738 new(Z) Value(left), | 2357 new(Z) Value(left), |
| 2739 new(Z) Value(type_args), | 2358 new(Z) Value(type_args), |
| 2740 type, | 2359 type, |
| 2741 negate, | 2360 negate, |
| 2742 call->deopt_id()); | 2361 call->deopt_id()); |
| 2743 ReplaceCall(call, instance_of); | 2362 ReplaceCall(call, instance_of); |
| 2744 } | 2363 } |
| 2745 | 2364 |
| 2746 | 2365 |
| 2747 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). | 2366 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). |
| 2748 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 2367 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
| 2749 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 2368 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
| 2750 Definition* left = call->ArgumentAt(0); | 2369 Definition* left = call->ArgumentAt(0); |
| 2751 Definition* type_args = call->ArgumentAt(1); | 2370 Definition* type_args = call->ArgumentAt(1); |
| 2752 const AbstractType& type = | 2371 const AbstractType& type = |
| 2753 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); | 2372 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); |
| 2754 ASSERT(!type.IsMalformedOrMalbounded()); | 2373 ASSERT(!type.IsMalformedOrMalbounded()); |
| 2755 const ICData& unary_checks = | 2374 const ICData& unary_checks = |
| 2756 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); | 2375 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 2757 if ((unary_checks.NumberOfChecks() > 0) && | 2376 if ((unary_checks.NumberOfChecks() > 0) && |
| 2758 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { | 2377 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 2781 new(Z) AssertAssignableInstr(call->token_pos(), | 2400 new(Z) AssertAssignableInstr(call->token_pos(), |
| 2782 new(Z) Value(left), | 2401 new(Z) Value(left), |
| 2783 new(Z) Value(type_args), | 2402 new(Z) Value(type_args), |
| 2784 type, | 2403 type, |
| 2785 dst_name, | 2404 dst_name, |
| 2786 call->deopt_id()); | 2405 call->deopt_id()); |
| 2787 ReplaceCall(call, assert_as); | 2406 ReplaceCall(call, assert_as); |
| 2788 } | 2407 } |
| 2789 | 2408 |
| 2790 | 2409 |
| 2791 bool FlowGraphOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { | 2410 bool AotOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { |
| 2792 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { | 2411 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { |
| 2793 if ((*inlining_black_list_)[i] == call_deopt_id) return true; | 2412 if ((*inlining_black_list_)[i] == call_deopt_id) return true; |
| 2794 } | 2413 } |
| 2795 return false; | 2414 return false; |
| 2796 } | 2415 } |
| 2797 | 2416 |
| 2798 // Special optimizations when running in --noopt mode. | 2417 // Special optimizations when running in --noopt mode. |
| 2799 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { | 2418 void AotOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { |
| 2800 // TODO(srdjan): Investigate other attempts, as they are not allowed to | 2419 // TODO(srdjan): Investigate other attempts, as they are not allowed to |
| 2801 // deoptimize. | 2420 // deoptimize. |
| 2802 | 2421 |
| 2803 // Type test is special as it always gets converted into inlined code. | 2422 // Type test is special as it always gets converted into inlined code. |
| 2804 const Token::Kind op_kind = instr->token_kind(); | 2423 const Token::Kind op_kind = instr->token_kind(); |
| 2805 if (Token::IsTypeTestOperator(op_kind)) { | 2424 if (Token::IsTypeTestOperator(op_kind)) { |
| 2806 ReplaceWithInstanceOf(instr); | 2425 ReplaceWithInstanceOf(instr); |
| 2807 return; | 2426 return; |
| 2808 } | 2427 } |
| 2809 if (Token::IsTypeCastOperator(op_kind)) { | 2428 if (Token::IsTypeCastOperator(op_kind)) { |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2928 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, | 2547 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, |
| 2929 /* with_checks = */ false); | 2548 /* with_checks = */ false); |
| 2930 instr->ReplaceWith(call, current_iterator()); | 2549 instr->ReplaceWith(call, current_iterator()); |
| 2931 return; | 2550 return; |
| 2932 } | 2551 } |
| 2933 } | 2552 } |
| 2934 | 2553 |
| 2935 | 2554 |
| 2936 // Tries to optimize instance call by replacing it with a faster instruction | 2555 // Tries to optimize instance call by replacing it with a faster instruction |
| 2937 // (e.g, binary op, field load, ..). | 2556 // (e.g, binary op, field load, ..). |
| 2938 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2557 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 2939 if (FLAG_precompilation) { | 2558 ASSERT(FLAG_precompilation); |
| 2940 InstanceCallNoopt(instr); | 2559 InstanceCallNoopt(instr); |
| 2941 return; | |
| 2942 } | |
| 2943 | |
| 2944 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { | |
| 2945 return; | |
| 2946 } | |
| 2947 const Token::Kind op_kind = instr->token_kind(); | |
| 2948 | |
| 2949 // Type test is special as it always gets converted into inlined code. | |
| 2950 if (Token::IsTypeTestOperator(op_kind)) { | |
| 2951 ReplaceWithInstanceOf(instr); | |
| 2952 return; | |
| 2953 } | |
| 2954 | |
| 2955 if (Token::IsTypeCastOperator(op_kind)) { | |
| 2956 ReplaceWithTypeCast(instr); | |
| 2957 return; | |
| 2958 } | |
| 2959 | |
| 2960 const ICData& unary_checks = | |
| 2961 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | |
| 2962 | |
| 2963 const intptr_t max_checks = (op_kind == Token::kEQ) | |
| 2964 ? FLAG_max_equality_polymorphic_checks | |
| 2965 : FLAG_max_polymorphic_checks; | |
| 2966 if ((unary_checks.NumberOfChecks() > max_checks) && | |
| 2967 InstanceCallNeedsClassCheck(instr, RawFunction::kRegularFunction)) { | |
| 2968 // Too many checks, it will be megamorphic which needs unary checks. | |
| 2969 instr->set_ic_data(&unary_checks); | |
| 2970 return; | |
| 2971 } | |
| 2972 | |
| 2973 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | |
| 2974 return; | |
| 2975 } | |
| 2976 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { | |
| 2977 return; | |
| 2978 } | |
| 2979 | |
| 2980 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) { | |
| 2981 return; | |
| 2982 } | |
| 2983 | |
| 2984 if (Token::IsRelationalOperator(op_kind) && | |
| 2985 TryReplaceWithRelationalOp(instr, op_kind)) { | |
| 2986 return; | |
| 2987 } | |
| 2988 | |
| 2989 if (Token::IsBinaryOperator(op_kind) && | |
| 2990 TryReplaceWithBinaryOp(instr, op_kind)) { | |
| 2991 return; | |
| 2992 } | |
| 2993 if (Token::IsUnaryOperator(op_kind) && | |
| 2994 TryReplaceWithUnaryOp(instr, op_kind)) { | |
| 2995 return; | |
| 2996 } | |
| 2997 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { | |
| 2998 return; | |
| 2999 } | |
| 3000 if ((op_kind == Token::kSET) && | |
| 3001 TryInlineInstanceSetter(instr, unary_checks)) { | |
| 3002 return; | |
| 3003 } | |
| 3004 if (TryInlineInstanceMethod(instr)) { | |
| 3005 return; | |
| 3006 } | |
| 3007 | |
| 3008 bool has_one_target = unary_checks.HasOneTarget(); | |
| 3009 | |
| 3010 if (has_one_target) { | |
| 3011 // Check if the single target is a polymorphic target, if it is, | |
| 3012 // we don't have one target. | |
| 3013 const Function& target = | |
| 3014 Function::Handle(Z, unary_checks.GetTargetAt(0)); | |
| 3015 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target); | |
| 3016 has_one_target = !polymorphic_target; | |
| 3017 } | |
| 3018 | |
| 3019 if (has_one_target) { | |
| 3020 RawFunction::Kind function_kind = | |
| 3021 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); | |
| 3022 if (!InstanceCallNeedsClassCheck(instr, function_kind)) { | |
| 3023 PolymorphicInstanceCallInstr* call = | |
| 3024 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | |
| 3025 /* call_with_checks = */ false); | |
| 3026 instr->ReplaceWith(call, current_iterator()); | |
| 3027 return; | |
| 3028 } | |
| 3029 } | |
| 3030 | |
| 3031 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | |
| 3032 bool call_with_checks; | |
| 3033 if (has_one_target && FLAG_polymorphic_with_deopt) { | |
| 3034 // Type propagation has not run yet, we cannot eliminate the check. | |
| 3035 AddReceiverCheck(instr); | |
| 3036 // Call can still deoptimize, do not detach environment from instr. | |
| 3037 call_with_checks = false; | |
| 3038 } else { | |
| 3039 call_with_checks = true; | |
| 3040 } | |
| 3041 PolymorphicInstanceCallInstr* call = | |
| 3042 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | |
| 3043 call_with_checks); | |
| 3044 instr->ReplaceWith(call, current_iterator()); | |
| 3045 } | |
| 3046 } | 2560 } |
| 3047 | 2561 |
| 3048 | 2562 |
| 3049 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { | 2563 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 3050 if (!CanUnboxDouble()) { | 2564 if (!CanUnboxDouble()) { |
| 3051 return; | 2565 return; |
| 3052 } | 2566 } |
| 3053 MethodRecognizer::Kind recognized_kind = | 2567 MethodRecognizer::Kind recognized_kind = |
| 3054 MethodRecognizer::RecognizeKind(call->function()); | 2568 MethodRecognizer::RecognizeKind(call->function()); |
| 3055 MathUnaryInstr::MathUnaryKind unary_kind; | 2569 MathUnaryInstr::MathUnaryKind unary_kind; |
| 3056 switch (recognized_kind) { | 2570 switch (recognized_kind) { |
| 3057 case MethodRecognizer::kMathSqrt: | 2571 case MethodRecognizer::kMathSqrt: |
| 3058 unary_kind = MathUnaryInstr::kSqrt; | 2572 unary_kind = MathUnaryInstr::kSqrt; |
| 3059 break; | 2573 break; |
| 3060 case MethodRecognizer::kMathSin: | 2574 case MethodRecognizer::kMathSin: |
| 3061 unary_kind = MathUnaryInstr::kSin; | 2575 unary_kind = MathUnaryInstr::kSin; |
| 3062 break; | 2576 break; |
| 3063 case MethodRecognizer::kMathCos: | 2577 case MethodRecognizer::kMathCos: |
| 3064 unary_kind = MathUnaryInstr::kCos; | 2578 unary_kind = MathUnaryInstr::kCos; |
| 3065 break; | 2579 break; |
| 3066 default: | 2580 default: |
| 3067 unary_kind = MathUnaryInstr::kIllegal; | 2581 unary_kind = MathUnaryInstr::kIllegal; |
| 3068 break; | 2582 break; |
| 3069 } | 2583 } |
| 3070 if (unary_kind != MathUnaryInstr::kIllegal) { | 2584 if (unary_kind != MathUnaryInstr::kIllegal) { |
| 3071 if (FLAG_precompilation) { | 2585 ASSERT(FLAG_precompilation); |
| 3072 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. | 2586 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. |
| 3073 return; | |
| 3074 } | |
| 3075 MathUnaryInstr* math_unary = | |
| 3076 new(Z) MathUnaryInstr(unary_kind, | |
| 3077 new(Z) Value(call->ArgumentAt(0)), | |
| 3078 call->deopt_id()); | |
| 3079 ReplaceCall(call, math_unary); | |
| 3080 return; | 2587 return; |
| 3081 } | 2588 } |
| 2589 | |
| 3082 switch (recognized_kind) { | 2590 switch (recognized_kind) { |
| 3083 case MethodRecognizer::kFloat32x4Zero: | 2591 case MethodRecognizer::kFloat32x4Zero: |
| 3084 case MethodRecognizer::kFloat32x4Splat: | 2592 case MethodRecognizer::kFloat32x4Splat: |
| 3085 case MethodRecognizer::kFloat32x4Constructor: | 2593 case MethodRecognizer::kFloat32x4Constructor: |
| 3086 case MethodRecognizer::kFloat32x4FromFloat64x2: | 2594 case MethodRecognizer::kFloat32x4FromFloat64x2: |
| 3087 TryInlineFloat32x4Constructor(call, recognized_kind); | 2595 TryInlineFloat32x4Constructor(call, recognized_kind); |
| 3088 break; | 2596 break; |
| 3089 case MethodRecognizer::kFloat64x2Constructor: | 2597 case MethodRecognizer::kFloat64x2Constructor: |
| 3090 case MethodRecognizer::kFloat64x2Zero: | 2598 case MethodRecognizer::kFloat64x2Zero: |
| 3091 case MethodRecognizer::kFloat64x2Splat: | 2599 case MethodRecognizer::kFloat64x2Splat: |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3147 } | 2655 } |
| 3148 } | 2656 } |
| 3149 break; | 2657 break; |
| 3150 } | 2658 } |
| 3151 case MethodRecognizer::kMathDoublePow: | 2659 case MethodRecognizer::kMathDoublePow: |
| 3152 case MethodRecognizer::kMathTan: | 2660 case MethodRecognizer::kMathTan: |
| 3153 case MethodRecognizer::kMathAsin: | 2661 case MethodRecognizer::kMathAsin: |
| 3154 case MethodRecognizer::kMathAcos: | 2662 case MethodRecognizer::kMathAcos: |
| 3155 case MethodRecognizer::kMathAtan: | 2663 case MethodRecognizer::kMathAtan: |
| 3156 case MethodRecognizer::kMathAtan2: { | 2664 case MethodRecognizer::kMathAtan2: { |
| 3157 if (FLAG_precompilation) { | 2665 ASSERT(FLAG_precompilation); |
| 3158 // No UnboxDouble instructons allowed. | 2666 // No UnboxDouble instructions allowed. |
| 3159 return; | 2667 return; |
| 3160 } | |
| 3161 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble | |
| 3162 // instructions contain type checks and conversions to double. | |
| 3163 ZoneGrowableArray<Value*>* args = | |
| 3164 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | |
| 3165 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | |
| 3166 args->Add(new(Z) Value(call->ArgumentAt(i))); | |
| 3167 } | |
| 3168 InvokeMathCFunctionInstr* invoke = | |
| 3169 new(Z) InvokeMathCFunctionInstr(args, | |
| 3170 call->deopt_id(), | |
| 3171 recognized_kind, | |
| 3172 call->token_pos()); | |
| 3173 ReplaceCall(call, invoke); | |
| 3174 break; | |
| 3175 } | 2668 } |
| 3176 case MethodRecognizer::kDoubleFromInteger: { | 2669 case MethodRecognizer::kDoubleFromInteger: { |
| 3177 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { | 2670 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { |
| 3178 const ICData& ic_data = *call->ic_data(); | 2671 const ICData& ic_data = *call->ic_data(); |
| 3179 if (CanUnboxDouble()) { | 2672 if (CanUnboxDouble()) { |
| 3180 if (ArgIsAlways(kSmiCid, ic_data, 1)) { | 2673 if (ArgIsAlways(kSmiCid, ic_data, 1)) { |
| 3181 Definition* arg = call->ArgumentAt(1); | 2674 Definition* arg = call->ArgumentAt(1); |
| 3182 AddCheckSmi(arg, call->deopt_id(), call->env(), call); | 2675 AddCheckSmi(arg, call->deopt_id(), call->env(), call); |
| 3183 ReplaceCall(call, | 2676 ReplaceCall(call, |
| 3184 new(Z) SmiToDoubleInstr(new(Z) Value(arg), | 2677 new(Z) SmiToDoubleInstr(new(Z) Value(arg), |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3220 default: | 2713 default: |
| 3221 break; | 2714 break; |
| 3222 } | 2715 } |
| 3223 } | 2716 } |
| 3224 } | 2717 } |
| 3225 } | 2718 } |
| 3226 } | 2719 } |
| 3227 } | 2720 } |
| 3228 | 2721 |
| 3229 | 2722 |
| 3230 void FlowGraphOptimizer::VisitStoreInstanceField( | 2723 void AotOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { |
| 3231 StoreInstanceFieldInstr* instr) { | |
| 3232 if (instr->IsUnboxedStore()) { | |
| 3233 ASSERT(instr->is_potential_unboxed_initialization_); | |
| 3234 // Determine if this field should be unboxed based on the usage of getter | |
| 3235 // and setter functions: The heuristic requires that the setter has a | |
| 3236 // usage count of at least 1/kGetterSetterRatio of the getter usage count. | |
| 3237 // This is to avoid unboxing fields where the setter is never or rarely | |
| 3238 // executed. | |
| 3239 const Field& field = Field::ZoneHandle(Z, instr->field().raw()); | |
| 3240 const String& field_name = String::Handle(Z, field.name()); | |
| 3241 const Class& owner = Class::Handle(Z, field.owner()); | |
| 3242 const Function& getter = | |
| 3243 Function::Handle(Z, owner.LookupGetterFunction(field_name)); | |
| 3244 const Function& setter = | |
| 3245 Function::Handle(Z, owner.LookupSetterFunction(field_name)); | |
| 3246 bool unboxed_field = false; | |
| 3247 if (!getter.IsNull() && !setter.IsNull()) { | |
| 3248 if (field.is_double_initialized()) { | |
| 3249 unboxed_field = true; | |
| 3250 } else if ((setter.usage_counter() > 0) && | |
| 3251 ((FLAG_getter_setter_ratio * setter.usage_counter()) >= | |
| 3252 getter.usage_counter())) { | |
| 3253 unboxed_field = true; | |
| 3254 } | |
| 3255 } | |
| 3256 if (!unboxed_field) { | |
| 3257 // TODO(srdjan): Instead of aborting pass this field to the mutator thread | |
| 3258 // so that it can: | |
| 3259 // - set it to unboxed | |
| 3260 // - deoptimize dependent code. | |
| 3261 if (Compiler::IsBackgroundCompilation()) { | |
| 3262 isolate()->AddDeoptimizingBoxedField(field); | |
| 3263 Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId); | |
| 3264 UNREACHABLE(); | |
| 3265 } | |
| 3266 if (FLAG_trace_optimization || FLAG_trace_field_guards) { | |
| 3267 THR_Print("Disabling unboxing of %s\n", field.ToCString()); | |
| 3268 if (!setter.IsNull()) { | |
| 3269 OS::Print(" setter usage count: %" Pd "\n", setter.usage_counter()); | |
| 3270 } | |
| 3271 if (!getter.IsNull()) { | |
| 3272 OS::Print(" getter usage count: %" Pd "\n", getter.usage_counter()); | |
| 3273 } | |
| 3274 } | |
| 3275 field.set_is_unboxing_candidate(false); | |
| 3276 field.DeoptimizeDependentCode(); | |
| 3277 } else { | |
| 3278 FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field); | |
| 3279 } | |
| 3280 } | |
| 3281 } | |
| 3282 | |
| 3283 | |
| 3284 void FlowGraphOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { | |
| 3285 // Replace generic allocation with a sequence of inlined allocation and | 2724 // Replace generic allocation with a sequence of inlined allocation and |
| 3286 // explicit initalizing stores. | 2725 // explicit initalizing stores. |
| 3287 AllocateUninitializedContextInstr* replacement = | 2726 AllocateUninitializedContextInstr* replacement = |
| 3288 new AllocateUninitializedContextInstr(instr->token_pos(), | 2727 new AllocateUninitializedContextInstr(instr->token_pos(), |
| 3289 instr->num_context_variables()); | 2728 instr->num_context_variables()); |
| 3290 instr->ReplaceWith(replacement, current_iterator()); | 2729 instr->ReplaceWith(replacement, current_iterator()); |
| 3291 | 2730 |
| 3292 StoreInstanceFieldInstr* store = | 2731 StoreInstanceFieldInstr* store = |
| 3293 new(Z) StoreInstanceFieldInstr(Context::parent_offset(), | 2732 new(Z) StoreInstanceFieldInstr(Context::parent_offset(), |
| 3294 new Value(replacement), | 2733 new Value(replacement), |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 3309 instr->token_pos()); | 2748 instr->token_pos()); |
| 3310 // Storing into uninitialized memory; remember to prevent dead store | 2749 // Storing into uninitialized memory; remember to prevent dead store |
| 3311 // elimination and ensure proper GC barrier. | 2750 // elimination and ensure proper GC barrier. |
| 3312 store->set_is_object_reference_initialization(true); | 2751 store->set_is_object_reference_initialization(true); |
| 3313 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); | 2752 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); |
| 3314 cursor = store; | 2753 cursor = store; |
| 3315 } | 2754 } |
| 3316 } | 2755 } |
| 3317 | 2756 |
| 3318 | 2757 |
| 3319 void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { | 2758 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { |
| 3320 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. | 2759 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. |
| 3321 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) | 2760 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) |
| 3322 if (!instr->can_pack_into_smi()) | 2761 if (!instr->can_pack_into_smi()) |
| 3323 instr->set_representation(kUnboxedMint); | 2762 instr->set_representation(kUnboxedMint); |
| 3324 #endif | 2763 #endif |
| 3325 } | 2764 } |
| 3326 | 2765 |
| 3327 | 2766 |
| 3328 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 2767 bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
| 3329 const ICData& unary_ic_data, | 2768 const ICData& unary_ic_data, |
| 3330 bool allow_checks) { | 2769 bool allow_checks) { |
| 3331 ASSERT((unary_ic_data.NumberOfChecks() > 0) && | 2770 ASSERT((unary_ic_data.NumberOfChecks() > 0) && |
| 3332 (unary_ic_data.NumArgsTested() == 1)); | 2771 (unary_ic_data.NumArgsTested() == 1)); |
| 3333 if (I->flags().type_checks()) { | 2772 if (I->flags().type_checks()) { |
| 3334 // Checked mode setters are inlined like normal methods by conventional | 2773 // Checked mode setters are inlined like normal methods by conventional |
| 3335 // inlining. | 2774 // inlining. |
| 3336 return false; | 2775 return false; |
| 3337 } | 2776 } |
| 3338 | 2777 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3406 | 2845 |
| 3407 // Discard the environment from the original instruction because the store | 2846 // Discard the environment from the original instruction because the store |
| 3408 // can't deoptimize. | 2847 // can't deoptimize. |
| 3409 instr->RemoveEnvironment(); | 2848 instr->RemoveEnvironment(); |
| 3410 ReplaceCall(instr, store); | 2849 ReplaceCall(instr, store); |
| 3411 return true; | 2850 return true; |
| 3412 } | 2851 } |
| 3413 | 2852 |
| 3414 | 2853 |
| 3415 } // namespace dart | 2854 } // namespace dart |
| OLD | NEW |