| 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/aot_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" |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 return false; | 106 return false; |
| 107 } | 107 } |
| 108 | 108 |
| 109 if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) { | 109 if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) { |
| 110 return false; | 110 return false; |
| 111 } | 111 } |
| 112 | 112 |
| 113 // There is only a single function Object.get:runtimeType that can be invoked | 113 // There is only a single function Object.get:runtimeType that can be invoked |
| 114 // by this call. Convert dynamic invocation to a static one. | 114 // by this call. Convert dynamic invocation to a static one. |
| 115 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); | 115 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); |
| 116 const Array& args_desc_array = Array::Handle( | |
| 117 Z, | |
| 118 ArgumentsDescriptor::New(call->ArgumentCount(), call->argument_names())); | |
| 119 ArgumentsDescriptor args_desc(args_desc_array); | |
| 120 const Function& function = | 116 const Function& function = |
| 121 Function::Handle(Z, Resolver::ResolveDynamicForReceiverClass( | 117 Function::Handle(Z, call->ResolveForReceiverClass(cls)); |
| 122 cls, call->function_name(), args_desc)); | |
| 123 ASSERT(!function.IsNull()); | 118 ASSERT(!function.IsNull()); |
| 124 | 119 const intptr_t kTypeArgsLen = 0; |
| 120 ASSERT(call->type_args_len() == kTypeArgsLen); |
| 125 ZoneGrowableArray<PushArgumentInstr*>* args = | 121 ZoneGrowableArray<PushArgumentInstr*>* args = |
| 126 new (Z) ZoneGrowableArray<PushArgumentInstr*>(call->ArgumentCount()); | 122 new (Z) ZoneGrowableArray<PushArgumentInstr*>(call->ArgumentCount()); |
| 127 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 123 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 128 args->Add(call->PushArgumentAt(i)); | 124 args->Add(call->PushArgumentAt(i)); |
| 129 } | 125 } |
| 130 StaticCallInstr* static_call = new (Z) StaticCallInstr( | 126 StaticCallInstr* static_call = new (Z) StaticCallInstr( |
| 131 call->token_pos(), Function::ZoneHandle(Z, function.raw()), | 127 call->token_pos(), Function::ZoneHandle(Z, function.raw()), kTypeArgsLen, |
| 132 call->argument_names(), args, call->deopt_id()); | 128 call->argument_names(), args, call->deopt_id()); |
| 133 static_call->set_result_cid(kTypeCid); | 129 static_call->set_result_cid(kTypeCid); |
| 134 call->ReplaceWith(static_call, current_iterator()); | 130 call->ReplaceWith(static_call, current_iterator()); |
| 135 return true; | 131 return true; |
| 136 } | 132 } |
| 137 | 133 |
| 138 | 134 |
| 139 // Optimize instance calls using cid. This is called after optimizer | 135 // Optimize instance calls using cid. This is called after optimizer |
| 140 // converted instance calls to instructions. Any remaining | 136 // converted instance calls to instructions. Any remaining |
| 141 // instance calls are either megamorphic calls, cannot be optimized or | 137 // instance calls are either megamorphic calls, cannot be optimized or |
| (...skipping 29 matching lines...) Expand all Loading... |
| 171 | 167 |
| 172 | 168 |
| 173 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) { | 169 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) { |
| 174 ASSERT(call->HasICData()); | 170 ASSERT(call->HasICData()); |
| 175 if (call->ic_data()->NumberOfUsedChecks() > 0) { | 171 if (call->ic_data()->NumberOfUsedChecks() > 0) { |
| 176 // This occurs when an instance call has too many checks, will be converted | 172 // This occurs when an instance call has too many checks, will be converted |
| 177 // to megamorphic call. | 173 // to megamorphic call. |
| 178 return false; | 174 return false; |
| 179 } | 175 } |
| 180 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); | 176 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); |
| 181 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); | 177 const intptr_t receiver_idx = call->FirstParamIndex(); |
| 178 ASSERT(call->ic_data()->NumArgsTested() <= |
| 179 call->ArgumentCountWithoutTypeArgs()); |
| 182 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { | 180 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { |
| 183 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); | 181 class_ids.Add( |
| 182 call->PushArgumentAt(receiver_idx + i)->value()->Type()->ToCid()); |
| 184 } | 183 } |
| 185 | 184 |
| 186 const Token::Kind op_kind = call->token_kind(); | 185 const Token::Kind op_kind = call->token_kind(); |
| 187 if (FLAG_guess_icdata_cid) { | 186 if (FLAG_guess_icdata_cid) { |
| 188 if (Token::IsBinaryBitwiseOperator(op_kind)) { | 187 if (Token::IsBinaryBitwiseOperator(op_kind)) { |
| 189 class_ids[0] = kSmiCid; | 188 class_ids[0] = kSmiCid; |
| 190 class_ids[1] = kSmiCid; | 189 class_ids[1] = kSmiCid; |
| 191 } | 190 } |
| 192 if (Token::IsRelationalOperator(op_kind) || | 191 if (Token::IsRelationalOperator(op_kind) || |
| 193 Token::IsEqualityOperator(op_kind) || | 192 Token::IsEqualityOperator(op_kind) || |
| (...skipping 21 matching lines...) Expand all Loading... |
| 215 | 214 |
| 216 if (all_cids_known) { | 215 if (all_cids_known) { |
| 217 const Class& receiver_class = | 216 const Class& receiver_class = |
| 218 Class::Handle(Z, isolate()->class_table()->At(class_ids[0])); | 217 Class::Handle(Z, isolate()->class_table()->At(class_ids[0])); |
| 219 if (!receiver_class.is_finalized()) { | 218 if (!receiver_class.is_finalized()) { |
| 220 // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can | 219 // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can |
| 221 // cause class finalization, since callee's receiver class may not be | 220 // cause class finalization, since callee's receiver class may not be |
| 222 // finalized yet. | 221 // finalized yet. |
| 223 return false; | 222 return false; |
| 224 } | 223 } |
| 225 const Array& args_desc_array = | 224 const Function& function = |
| 226 Array::Handle(Z, ArgumentsDescriptor::New(call->ArgumentCount(), | 225 Function::Handle(Z, call->ResolveForReceiverClass(receiver_class)); |
| 227 call->argument_names())); | |
| 228 ArgumentsDescriptor args_desc(args_desc_array); | |
| 229 const Function& function = Function::Handle( | |
| 230 Z, Resolver::ResolveDynamicForReceiverClass( | |
| 231 receiver_class, call->function_name(), args_desc)); | |
| 232 if (function.IsNull()) { | 226 if (function.IsNull()) { |
| 233 return false; | 227 return false; |
| 234 } | 228 } |
| 235 | 229 |
| 236 // Create new ICData, do not modify the one attached to the instruction | 230 // Create new ICData, do not modify the one attached to the instruction |
| 237 // since it is attached to the assembly instruction itself. | 231 // since it is attached to the assembly instruction itself. |
| 238 // TODO(srdjan): Prevent modification of ICData object that is | 232 // TODO(srdjan): Prevent modification of ICData object that is |
| 239 // referenced in assembly code. | 233 // referenced in assembly code. |
| 240 const ICData& ic_data = ICData::ZoneHandle( | 234 const ICData& ic_data = ICData::ZoneHandle( |
| 241 Z, ICData::NewFrom(*call->ic_data(), class_ids.length())); | 235 Z, ICData::NewFrom(*call->ic_data(), class_ids.length())); |
| 242 if (class_ids.length() > 1) { | 236 if (class_ids.length() > 1) { |
| 243 ic_data.AddCheck(class_ids, function); | 237 ic_data.AddCheck(class_ids, function); |
| 244 } else { | 238 } else { |
| 245 ASSERT(class_ids.length() == 1); | 239 ASSERT(class_ids.length() == 1); |
| 246 ic_data.AddReceiverCheck(class_ids[0], function); | 240 ic_data.AddReceiverCheck(class_ids[0], function); |
| 247 } | 241 } |
| 248 call->set_ic_data(&ic_data); | 242 call->set_ic_data(&ic_data); |
| 249 return true; | 243 return true; |
| 250 } | 244 } |
| 251 | 245 |
| 252 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { | 246 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { |
| 253 // Check if the target is unique. | 247 // Check if the target is unique. |
| 254 Function& target_function = Function::Handle(Z); | 248 Function& target_function = Function::Handle(Z); |
| 255 GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function); | 249 GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function); |
| 256 // Calls with named arguments must be resolved/checked at runtime. | 250 // Calls passing named arguments and calls to a function taking named |
| 251 // arguments must be resolved/checked at runtime. |
| 252 // Calls passing a type argument vector and calls to a generic function must |
| 253 // be resolved/checked at runtime. |
| 257 if (!target_function.IsNull() && | 254 if (!target_function.IsNull() && |
| 258 !target_function.HasOptionalNamedParameters() && | 255 !target_function.HasOptionalNamedParameters() && |
| 259 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, | 256 !target_function.IsGeneric() && |
| 260 /* error_message = */ NULL)) { | 257 target_function.AreValidArgumentCounts( |
| 258 call->type_args_len(), call->ArgumentCountWithoutTypeArgs(), |
| 259 call->argument_names().IsNull() ? 0 |
| 260 : call->argument_names().Length(), |
| 261 /* error_message = */ NULL)) { |
| 261 const Class& cls = Class::Handle(Z, target_function.Owner()); | 262 const Class& cls = Class::Handle(Z, target_function.Owner()); |
| 262 if (!CHA::IsImplemented(cls) && !CHA::HasSubclasses(cls)) { | 263 if (!CHA::IsImplemented(cls) && !CHA::HasSubclasses(cls)) { |
| 263 const ICData& ic_data = | 264 const ICData& ic_data = |
| 264 ICData::ZoneHandle(Z, ICData::NewFrom(*call->ic_data(), 1)); | 265 ICData::ZoneHandle(Z, ICData::NewFrom(*call->ic_data(), 1)); |
| 265 ic_data.AddReceiverCheck(cls.id(), target_function); | 266 ic_data.AddReceiverCheck(cls.id(), target_function); |
| 266 call->set_ic_data(&ic_data); | 267 call->set_ic_data(&ic_data); |
| 267 if (has_unique_no_such_method_) { | 268 if (has_unique_no_such_method_) { |
| 268 call->set_has_unique_selector(true); | 269 call->set_has_unique_selector(true); |
| 269 // Add redefinition of the receiver to prevent code motion across | 270 // Add redefinition of the receiver to prevent code motion across |
| 270 // this call. | 271 // this call. |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 606 } | 607 } |
| 607 | 608 |
| 608 | 609 |
| 609 // Recognize a.runtimeType == b.runtimeType and fold it into | 610 // Recognize a.runtimeType == b.runtimeType and fold it into |
| 610 // Object._haveSameRuntimeType(a, b). | 611 // Object._haveSameRuntimeType(a, b). |
| 611 // Note: this optimization is not speculative. | 612 // Note: this optimization is not speculative. |
| 612 bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) { | 613 bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) { |
| 613 const ICData& ic_data = *call->ic_data(); | 614 const ICData& ic_data = *call->ic_data(); |
| 614 ASSERT(ic_data.NumArgsTested() == 2); | 615 ASSERT(ic_data.NumArgsTested() == 2); |
| 615 | 616 |
| 617 ASSERT(call->type_args_len() == 0); |
| 616 ASSERT(call->ArgumentCount() == 2); | 618 ASSERT(call->ArgumentCount() == 2); |
| 617 Definition* left = call->ArgumentAt(0); | 619 Definition* left = call->ArgumentAt(0); |
| 618 Definition* right = call->ArgumentAt(1); | 620 Definition* right = call->ArgumentAt(1); |
| 619 | 621 |
| 620 if (IsGetRuntimeType(left) && left->input_use_list()->IsSingleUse() && | 622 if (IsGetRuntimeType(left) && left->input_use_list()->IsSingleUse() && |
| 621 IsGetRuntimeType(right) && right->input_use_list()->IsSingleUse()) { | 623 IsGetRuntimeType(right) && right->input_use_list()->IsSingleUse()) { |
| 622 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); | 624 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); |
| 623 const Function& have_same_runtime_type = Function::ZoneHandle( | 625 const Function& have_same_runtime_type = Function::ZoneHandle( |
| 624 Z, | 626 Z, |
| 625 cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType())); | 627 cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType())); |
| 626 ASSERT(!have_same_runtime_type.IsNull()); | 628 ASSERT(!have_same_runtime_type.IsNull()); |
| 627 | 629 |
| 628 ZoneGrowableArray<PushArgumentInstr*>* args = | 630 ZoneGrowableArray<PushArgumentInstr*>* args = |
| 629 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); | 631 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); |
| 630 PushArgumentInstr* arg = | 632 PushArgumentInstr* arg = |
| 631 new (Z) PushArgumentInstr(new (Z) Value(left->ArgumentAt(0))); | 633 new (Z) PushArgumentInstr(new (Z) Value(left->ArgumentAt(0))); |
| 632 InsertBefore(call, arg, NULL, FlowGraph::kEffect); | 634 InsertBefore(call, arg, NULL, FlowGraph::kEffect); |
| 633 args->Add(arg); | 635 args->Add(arg); |
| 634 arg = new (Z) PushArgumentInstr(new (Z) Value(right->ArgumentAt(0))); | 636 arg = new (Z) PushArgumentInstr(new (Z) Value(right->ArgumentAt(0))); |
| 635 InsertBefore(call, arg, NULL, FlowGraph::kEffect); | 637 InsertBefore(call, arg, NULL, FlowGraph::kEffect); |
| 636 args->Add(arg); | 638 args->Add(arg); |
| 637 StaticCallInstr* static_call = | 639 const intptr_t kTypeArgsLen = 0; |
| 638 new (Z) StaticCallInstr(call->token_pos(), have_same_runtime_type, | 640 ASSERT(call->type_args_len() == kTypeArgsLen); |
| 639 Object::null_array(), // argument_names | 641 StaticCallInstr* static_call = new (Z) |
| 640 args, call->deopt_id()); | 642 StaticCallInstr(call->token_pos(), have_same_runtime_type, kTypeArgsLen, |
| 643 Object::null_array(), // argument_names |
| 644 args, call->deopt_id()); |
| 641 static_call->set_result_cid(kBoolCid); | 645 static_call->set_result_cid(kBoolCid); |
| 642 ReplaceCall(call, static_call); | 646 ReplaceCall(call, static_call); |
| 643 return true; | 647 return true; |
| 644 } | 648 } |
| 645 | 649 |
| 646 return false; | 650 return false; |
| 647 } | 651 } |
| 648 | 652 |
| 649 | 653 |
| 650 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 654 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
| 651 Token::Kind op_kind) { | 655 Token::Kind op_kind) { |
| 652 const ICData& ic_data = *call->ic_data(); | 656 const ICData& ic_data = *call->ic_data(); |
| 653 ASSERT(ic_data.NumArgsTested() == 2); | 657 ASSERT(ic_data.NumArgsTested() == 2); |
| 654 | 658 |
| 659 ASSERT(call->type_args_len() == 0); |
| 655 ASSERT(call->ArgumentCount() == 2); | 660 ASSERT(call->ArgumentCount() == 2); |
| 656 Definition* const left = call->ArgumentAt(0); | 661 Definition* const left = call->ArgumentAt(0); |
| 657 Definition* const right = call->ArgumentAt(1); | 662 Definition* const right = call->ArgumentAt(1); |
| 658 | 663 |
| 659 intptr_t cid = kIllegalCid; | 664 intptr_t cid = kIllegalCid; |
| 660 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { | 665 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
| 661 return TryStringLengthOneEquality(call, op_kind); | 666 return TryStringLengthOneEquality(call, op_kind); |
| 662 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 667 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 663 InsertBefore(call, | 668 InsertBefore(call, |
| 664 new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(), | 669 new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(), |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 727 ReplaceCall(call, comp); | 732 ReplaceCall(call, comp); |
| 728 return true; | 733 return true; |
| 729 } | 734 } |
| 730 | 735 |
| 731 | 736 |
| 732 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 737 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
| 733 Token::Kind op_kind) { | 738 Token::Kind op_kind) { |
| 734 const ICData& ic_data = *call->ic_data(); | 739 const ICData& ic_data = *call->ic_data(); |
| 735 ASSERT(ic_data.NumArgsTested() == 2); | 740 ASSERT(ic_data.NumArgsTested() == 2); |
| 736 | 741 |
| 742 ASSERT(call->type_args_len() == 0); |
| 737 ASSERT(call->ArgumentCount() == 2); | 743 ASSERT(call->ArgumentCount() == 2); |
| 738 Definition* left = call->ArgumentAt(0); | 744 Definition* left = call->ArgumentAt(0); |
| 739 Definition* right = call->ArgumentAt(1); | 745 Definition* right = call->ArgumentAt(1); |
| 740 | 746 |
| 741 intptr_t cid = kIllegalCid; | 747 intptr_t cid = kIllegalCid; |
| 742 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 748 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 743 InsertBefore(call, | 749 InsertBefore(call, |
| 744 new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(), | 750 new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(), |
| 745 call->token_pos()), | 751 call->token_pos()), |
| 746 call->env(), FlowGraph::kEffect); | 752 call->env(), FlowGraph::kEffect); |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 876 } | 882 } |
| 877 operands_type = kSmiCid; | 883 operands_type = kSmiCid; |
| 878 } else { | 884 } else { |
| 879 return false; | 885 return false; |
| 880 } | 886 } |
| 881 break; | 887 break; |
| 882 default: | 888 default: |
| 883 UNREACHABLE(); | 889 UNREACHABLE(); |
| 884 } | 890 } |
| 885 | 891 |
| 892 ASSERT(call->type_args_len() == 0); |
| 886 ASSERT(call->ArgumentCount() == 2); | 893 ASSERT(call->ArgumentCount() == 2); |
| 887 Definition* left = call->ArgumentAt(0); | 894 Definition* left = call->ArgumentAt(0); |
| 888 Definition* right = call->ArgumentAt(1); | 895 Definition* right = call->ArgumentAt(1); |
| 889 if (operands_type == kDoubleCid) { | 896 if (operands_type == kDoubleCid) { |
| 890 if (!CanUnboxDouble()) { | 897 if (!CanUnboxDouble()) { |
| 891 return false; | 898 return false; |
| 892 } | 899 } |
| 893 // Check that either left or right are not a smi. Result of a | 900 // Check that either left or right are not a smi. Result of a |
| 894 // binary operation with two smis is a smi not a double, except '/' which | 901 // binary operation with two smis is a smi not a double, except '/' which |
| 895 // returns a double for two smis. | 902 // returns a double for two smis. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 964 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr( | 971 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr( |
| 965 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 972 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 966 ReplaceCall(call, bin_op); | 973 ReplaceCall(call, bin_op); |
| 967 } | 974 } |
| 968 return true; | 975 return true; |
| 969 } | 976 } |
| 970 | 977 |
| 971 | 978 |
| 972 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, | 979 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, |
| 973 Token::Kind op_kind) { | 980 Token::Kind op_kind) { |
| 981 ASSERT(call->type_args_len() == 0); |
| 974 ASSERT(call->ArgumentCount() == 1); | 982 ASSERT(call->ArgumentCount() == 1); |
| 975 Definition* input = call->ArgumentAt(0); | 983 Definition* input = call->ArgumentAt(0); |
| 976 Definition* unary_op = NULL; | 984 Definition* unary_op = NULL; |
| 977 if (HasOnlyOneSmi(*call->ic_data())) { | 985 if (HasOnlyOneSmi(*call->ic_data())) { |
| 978 InsertBefore(call, | 986 InsertBefore(call, |
| 979 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(), | 987 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(), |
| 980 call->token_pos()), | 988 call->token_pos()), |
| 981 call->env(), FlowGraph::kEffect); | 989 call->env(), FlowGraph::kEffect); |
| 982 unary_op = new (Z) | 990 unary_op = new (Z) |
| 983 UnarySmiOpInstr(op_kind, new (Z) Value(input), call->deopt_id()); | 991 UnarySmiOpInstr(op_kind, new (Z) Value(input), call->deopt_id()); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 } | 1058 } |
| 1051 return true; | 1059 return true; |
| 1052 } | 1060 } |
| 1053 | 1061 |
| 1054 | 1062 |
| 1055 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, | 1063 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, |
| 1056 Token::Kind op_kind) { | 1064 Token::Kind op_kind) { |
| 1057 if (!ShouldInlineSimd()) { | 1065 if (!ShouldInlineSimd()) { |
| 1058 return false; | 1066 return false; |
| 1059 } | 1067 } |
| 1068 ASSERT(call->type_args_len() == 0); |
| 1060 ASSERT(call->ArgumentCount() == 2); | 1069 ASSERT(call->ArgumentCount() == 2); |
| 1061 Definition* const left = call->ArgumentAt(0); | 1070 Definition* const left = call->ArgumentAt(0); |
| 1062 Definition* const right = call->ArgumentAt(1); | 1071 Definition* const right = call->ArgumentAt(1); |
| 1063 // Type check left and right. | 1072 // Type check left and right. |
| 1064 AddChecksForArgNr(call, left, /* arg_number = */ 0); | 1073 AddChecksForArgNr(call, left, /* arg_number = */ 0); |
| 1065 AddChecksForArgNr(call, right, /* arg_number = */ 1); | 1074 AddChecksForArgNr(call, right, /* arg_number = */ 1); |
| 1066 // Replace call. | 1075 // Replace call. |
| 1067 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr( | 1076 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr( |
| 1068 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 1077 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 1069 ReplaceCall(call, float32x4_bin_op); | 1078 ReplaceCall(call, float32x4_bin_op); |
| 1070 | 1079 |
| 1071 return true; | 1080 return true; |
| 1072 } | 1081 } |
| 1073 | 1082 |
| 1074 | 1083 |
| 1075 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, | 1084 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, |
| 1076 Token::Kind op_kind) { | 1085 Token::Kind op_kind) { |
| 1077 if (!ShouldInlineSimd()) { | 1086 if (!ShouldInlineSimd()) { |
| 1078 return false; | 1087 return false; |
| 1079 } | 1088 } |
| 1089 ASSERT(call->type_args_len() == 0); |
| 1080 ASSERT(call->ArgumentCount() == 2); | 1090 ASSERT(call->ArgumentCount() == 2); |
| 1081 Definition* const left = call->ArgumentAt(0); | 1091 Definition* const left = call->ArgumentAt(0); |
| 1082 Definition* const right = call->ArgumentAt(1); | 1092 Definition* const right = call->ArgumentAt(1); |
| 1083 // Type check left and right. | 1093 // Type check left and right. |
| 1084 AddChecksForArgNr(call, left, /* arg_number = */ 0); | 1094 AddChecksForArgNr(call, left, /* arg_number = */ 0); |
| 1085 AddChecksForArgNr(call, right, /* arg_number = */ 1); | 1095 AddChecksForArgNr(call, right, /* arg_number = */ 1); |
| 1086 // Replace call. | 1096 // Replace call. |
| 1087 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr( | 1097 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr( |
| 1088 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 1098 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 1089 ReplaceCall(call, int32x4_bin_op); | 1099 ReplaceCall(call, int32x4_bin_op); |
| 1090 return true; | 1100 return true; |
| 1091 } | 1101 } |
| 1092 | 1102 |
| 1093 | 1103 |
| 1094 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, | 1104 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, |
| 1095 Token::Kind op_kind) { | 1105 Token::Kind op_kind) { |
| 1096 if (!ShouldInlineSimd()) { | 1106 if (!ShouldInlineSimd()) { |
| 1097 return false; | 1107 return false; |
| 1098 } | 1108 } |
| 1109 ASSERT(call->type_args_len() == 0); |
| 1099 ASSERT(call->ArgumentCount() == 2); | 1110 ASSERT(call->ArgumentCount() == 2); |
| 1100 Definition* const left = call->ArgumentAt(0); | 1111 Definition* const left = call->ArgumentAt(0); |
| 1101 Definition* const right = call->ArgumentAt(1); | 1112 Definition* const right = call->ArgumentAt(1); |
| 1102 // Type check left and right. | 1113 // Type check left and right. |
| 1103 AddChecksForArgNr(call, left, /* arg_number = */ 0); | 1114 AddChecksForArgNr(call, left, /* arg_number = */ 0); |
| 1104 AddChecksForArgNr(call, right, /* arg_number = */ 1); | 1115 AddChecksForArgNr(call, right, /* arg_number = */ 1); |
| 1105 // Replace call. | 1116 // Replace call. |
| 1106 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr( | 1117 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr( |
| 1107 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 1118 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 1108 ReplaceCall(call, float64x2_bin_op); | 1119 ReplaceCall(call, float64x2_bin_op); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1131 // inlining in FlowGraphInliner. | 1142 // inlining in FlowGraphInliner. |
| 1132 return false; | 1143 return false; |
| 1133 } | 1144 } |
| 1134 return InlineImplicitInstanceGetter(call); | 1145 return InlineImplicitInstanceGetter(call); |
| 1135 } | 1146 } |
| 1136 | 1147 |
| 1137 | 1148 |
| 1138 void AotOptimizer::ReplaceWithMathCFunction( | 1149 void AotOptimizer::ReplaceWithMathCFunction( |
| 1139 InstanceCallInstr* call, | 1150 InstanceCallInstr* call, |
| 1140 MethodRecognizer::Kind recognized_kind) { | 1151 MethodRecognizer::Kind recognized_kind) { |
| 1152 ASSERT(call->type_args_len() == 0); |
| 1141 AddReceiverCheck(call); | 1153 AddReceiverCheck(call); |
| 1142 ZoneGrowableArray<Value*>* args = | 1154 ZoneGrowableArray<Value*>* args = |
| 1143 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1155 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 1144 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1156 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 1145 args->Add(new (Z) Value(call->ArgumentAt(i))); | 1157 args->Add(new (Z) Value(call->ArgumentAt(i))); |
| 1146 } | 1158 } |
| 1147 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr( | 1159 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr( |
| 1148 args, call->deopt_id(), recognized_kind, call->token_pos()); | 1160 args, call->deopt_id(), recognized_kind, call->token_pos()); |
| 1149 ReplaceCall(call, invoke); | 1161 ReplaceCall(call, invoke); |
| 1150 } | 1162 } |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1411 } | 1423 } |
| 1412 | 1424 |
| 1413 | 1425 |
| 1414 // TODO(srdjan): Use ICData to check if always true or false. | 1426 // TODO(srdjan): Use ICData to check if always true or false. |
| 1415 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 1427 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 1416 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 1428 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 1417 Definition* left = call->ArgumentAt(0); | 1429 Definition* left = call->ArgumentAt(0); |
| 1418 Definition* instantiator_type_args = NULL; | 1430 Definition* instantiator_type_args = NULL; |
| 1419 Definition* function_type_args = NULL; | 1431 Definition* function_type_args = NULL; |
| 1420 AbstractType& type = AbstractType::ZoneHandle(Z); | 1432 AbstractType& type = AbstractType::ZoneHandle(Z); |
| 1433 ASSERT(call->type_args_len() == 0); |
| 1421 if (call->ArgumentCount() == 2) { | 1434 if (call->ArgumentCount() == 2) { |
| 1422 instantiator_type_args = flow_graph()->constant_null(); | 1435 instantiator_type_args = flow_graph()->constant_null(); |
| 1423 function_type_args = flow_graph()->constant_null(); | 1436 function_type_args = flow_graph()->constant_null(); |
| 1424 ASSERT(call->MatchesCoreName(Symbols::_simpleInstanceOf())); | 1437 ASSERT(call->MatchesCoreName(Symbols::_simpleInstanceOf())); |
| 1425 type = AbstractType::Cast(call->ArgumentAt(1)->AsConstant()->value()).raw(); | 1438 type = AbstractType::Cast(call->ArgumentAt(1)->AsConstant()->value()).raw(); |
| 1426 } else { | 1439 } else { |
| 1427 instantiator_type_args = call->ArgumentAt(1); | 1440 instantiator_type_args = call->ArgumentAt(1); |
| 1428 function_type_args = call->ArgumentAt(2); | 1441 function_type_args = call->ArgumentAt(2); |
| 1429 type = AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()).raw(); | 1442 type = AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()).raw(); |
| 1430 } | 1443 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1474 args->Add(arg); | 1487 args->Add(arg); |
| 1475 | 1488 |
| 1476 const Library& dart_internal = | 1489 const Library& dart_internal = |
| 1477 Library::Handle(Z, Library::InternalLibrary()); | 1490 Library::Handle(Z, Library::InternalLibrary()); |
| 1478 const String& target_name = Symbols::_classRangeCheck(); | 1491 const String& target_name = Symbols::_classRangeCheck(); |
| 1479 const Function& target = Function::ZoneHandle( | 1492 const Function& target = Function::ZoneHandle( |
| 1480 Z, dart_internal.LookupFunctionAllowPrivate(target_name)); | 1493 Z, dart_internal.LookupFunctionAllowPrivate(target_name)); |
| 1481 ASSERT(!target.IsNull()); | 1494 ASSERT(!target.IsNull()); |
| 1482 ASSERT(target.IsRecognized() && target.always_inline()); | 1495 ASSERT(target.IsRecognized() && target.always_inline()); |
| 1483 | 1496 |
| 1497 const intptr_t kTypeArgsLen = 0; |
| 1484 StaticCallInstr* new_call = | 1498 StaticCallInstr* new_call = |
| 1485 new (Z) StaticCallInstr(call->token_pos(), target, | 1499 new (Z) StaticCallInstr(call->token_pos(), target, kTypeArgsLen, |
| 1486 Object::null_array(), // argument_names | 1500 Object::null_array(), // argument_names |
| 1487 args, call->deopt_id()); | 1501 args, call->deopt_id()); |
| 1488 Environment* copy = call->env()->DeepCopy( | 1502 Environment* copy = call->env()->DeepCopy( |
| 1489 Z, call->env()->Length() - call->ArgumentCount()); | 1503 Z, call->env()->Length() - call->ArgumentCount()); |
| 1490 for (intptr_t i = 0; i < args->length(); ++i) { | 1504 for (intptr_t i = 0; i < args->length(); ++i) { |
| 1491 copy->PushValue(new (Z) Value((*args)[i]->value()->definition())); | 1505 copy->PushValue(new (Z) Value((*args)[i]->value()->definition())); |
| 1492 } | 1506 } |
| 1493 call->RemoveEnvironment(); | 1507 call->RemoveEnvironment(); |
| 1494 ReplaceCall(call, new_call); | 1508 ReplaceCall(call, new_call); |
| 1495 copy->DeepCopyTo(Z, new_call); | 1509 copy->DeepCopyTo(Z, new_call); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1523 call->token_pos(), new (Z) Value(left), | 1537 call->token_pos(), new (Z) Value(left), |
| 1524 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), | 1538 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), |
| 1525 type, call->deopt_id()); | 1539 type, call->deopt_id()); |
| 1526 ReplaceCall(call, instance_of); | 1540 ReplaceCall(call, instance_of); |
| 1527 } | 1541 } |
| 1528 | 1542 |
| 1529 | 1543 |
| 1530 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). | 1544 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). |
| 1531 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 1545 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
| 1532 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 1546 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
| 1547 ASSERT(call->type_args_len() == 0); |
| 1533 Definition* left = call->ArgumentAt(0); | 1548 Definition* left = call->ArgumentAt(0); |
| 1534 Definition* instantiator_type_args = call->ArgumentAt(1); | 1549 Definition* instantiator_type_args = call->ArgumentAt(1); |
| 1535 Definition* function_type_args = call->ArgumentAt(2); | 1550 Definition* function_type_args = call->ArgumentAt(2); |
| 1536 const AbstractType& type = | 1551 const AbstractType& type = |
| 1537 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 1552 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
| 1538 ASSERT(!type.IsMalformedOrMalbounded()); | 1553 ASSERT(!type.IsMalformedOrMalbounded()); |
| 1539 | 1554 |
| 1540 if (TypeCheckAsClassEquality(type)) { | 1555 if (TypeCheckAsClassEquality(type)) { |
| 1541 LoadClassIdInstr* left_cid = new (Z) LoadClassIdInstr(new (Z) Value(left)); | 1556 LoadClassIdInstr* left_cid = new (Z) LoadClassIdInstr(new (Z) Value(left)); |
| 1542 InsertBefore(call, left_cid, NULL, FlowGraph::kValue); | 1557 InsertBefore(call, left_cid, NULL, FlowGraph::kValue); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1566 args->Add(arg); | 1581 args->Add(arg); |
| 1567 | 1582 |
| 1568 const Library& dart_internal = Library::Handle(Z, Library::CoreLibrary()); | 1583 const Library& dart_internal = Library::Handle(Z, Library::CoreLibrary()); |
| 1569 const String& target_name = Symbols::_classIdEqualsAssert(); | 1584 const String& target_name = Symbols::_classIdEqualsAssert(); |
| 1570 const Function& target = Function::ZoneHandle( | 1585 const Function& target = Function::ZoneHandle( |
| 1571 Z, dart_internal.LookupFunctionAllowPrivate(target_name)); | 1586 Z, dart_internal.LookupFunctionAllowPrivate(target_name)); |
| 1572 ASSERT(!target.IsNull()); | 1587 ASSERT(!target.IsNull()); |
| 1573 ASSERT(target.IsRecognized()); | 1588 ASSERT(target.IsRecognized()); |
| 1574 ASSERT(target.always_inline()); | 1589 ASSERT(target.always_inline()); |
| 1575 | 1590 |
| 1591 const intptr_t kTypeArgsLen = 0; |
| 1576 StaticCallInstr* new_call = | 1592 StaticCallInstr* new_call = |
| 1577 new (Z) StaticCallInstr(call->token_pos(), target, | 1593 new (Z) StaticCallInstr(call->token_pos(), target, kTypeArgsLen, |
| 1578 Object::null_array(), // argument_names | 1594 Object::null_array(), // argument_names |
| 1579 args, call->deopt_id()); | 1595 args, call->deopt_id()); |
| 1580 Environment* copy = | 1596 Environment* copy = |
| 1581 call->env()->DeepCopy(Z, call->env()->Length() - call->ArgumentCount()); | 1597 call->env()->DeepCopy(Z, call->env()->Length() - call->ArgumentCount()); |
| 1582 for (intptr_t i = 0; i < args->length(); ++i) { | 1598 for (intptr_t i = 0; i < args->length(); ++i) { |
| 1583 copy->PushValue(new (Z) Value((*args)[i]->value()->definition())); | 1599 copy->PushValue(new (Z) Value((*args)[i]->value()->definition())); |
| 1584 } | 1600 } |
| 1585 call->RemoveEnvironment(); | 1601 call->RemoveEnvironment(); |
| 1586 ReplaceCall(call, new_call); | 1602 ReplaceCall(call, new_call); |
| 1587 copy->DeepCopyTo(Z, new_call); | 1603 copy->DeepCopyTo(Z, new_call); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1629 args->Add(arg); | 1645 args->Add(arg); |
| 1630 | 1646 |
| 1631 const Library& dart_internal = Library::Handle(Z, Library::CoreLibrary()); | 1647 const Library& dart_internal = Library::Handle(Z, Library::CoreLibrary()); |
| 1632 const String& target_name = Symbols::_classRangeAssert(); | 1648 const String& target_name = Symbols::_classRangeAssert(); |
| 1633 const Function& target = Function::ZoneHandle( | 1649 const Function& target = Function::ZoneHandle( |
| 1634 Z, dart_internal.LookupFunctionAllowPrivate(target_name)); | 1650 Z, dart_internal.LookupFunctionAllowPrivate(target_name)); |
| 1635 ASSERT(!target.IsNull()); | 1651 ASSERT(!target.IsNull()); |
| 1636 ASSERT(target.IsRecognized()); | 1652 ASSERT(target.IsRecognized()); |
| 1637 ASSERT(target.always_inline()); | 1653 ASSERT(target.always_inline()); |
| 1638 | 1654 |
| 1655 const intptr_t kTypeArgsLen = 0; |
| 1639 StaticCallInstr* new_call = | 1656 StaticCallInstr* new_call = |
| 1640 new (Z) StaticCallInstr(call->token_pos(), target, | 1657 new (Z) StaticCallInstr(call->token_pos(), target, kTypeArgsLen, |
| 1641 Object::null_array(), // argument_names | 1658 Object::null_array(), // argument_names |
| 1642 args, call->deopt_id()); | 1659 args, call->deopt_id()); |
| 1643 Environment* copy = call->env()->DeepCopy( | 1660 Environment* copy = call->env()->DeepCopy( |
| 1644 Z, call->env()->Length() - call->ArgumentCount()); | 1661 Z, call->env()->Length() - call->ArgumentCount()); |
| 1645 for (intptr_t i = 0; i < args->length(); ++i) { | 1662 for (intptr_t i = 0; i < args->length(); ++i) { |
| 1646 copy->PushValue(new (Z) Value((*args)[i]->value()->definition())); | 1663 copy->PushValue(new (Z) Value((*args)[i]->value()->definition())); |
| 1647 } | 1664 } |
| 1648 call->RemoveEnvironment(); | 1665 call->RemoveEnvironment(); |
| 1649 ReplaceCall(call, new_call); | 1666 ReplaceCall(call, new_call); |
| 1650 copy->DeepCopyTo(Z, new_call); | 1667 copy->DeepCopyTo(Z, new_call); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1690 bool AotOptimizer::IsAllowedForInlining(intptr_t call_deopt_id) { | 1707 bool AotOptimizer::IsAllowedForInlining(intptr_t call_deopt_id) { |
| 1691 if (!use_speculative_inlining_) return false; | 1708 if (!use_speculative_inlining_) return false; |
| 1692 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { | 1709 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { |
| 1693 if ((*inlining_black_list_)[i] == call_deopt_id) return false; | 1710 if ((*inlining_black_list_)[i] == call_deopt_id) return false; |
| 1694 } | 1711 } |
| 1695 return true; | 1712 return true; |
| 1696 } | 1713 } |
| 1697 | 1714 |
| 1698 | 1715 |
| 1699 static bool HasLikelySmiOperand(InstanceCallInstr* instr) { | 1716 static bool HasLikelySmiOperand(InstanceCallInstr* instr) { |
| 1717 ASSERT(instr->type_args_len() == 0); |
| 1700 // Phis with at least one known smi are // guessed to be likely smi as well. | 1718 // Phis with at least one known smi are // guessed to be likely smi as well. |
| 1701 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { | 1719 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { |
| 1702 PhiInstr* phi = instr->ArgumentAt(i)->AsPhi(); | 1720 PhiInstr* phi = instr->ArgumentAt(i)->AsPhi(); |
| 1703 if (phi != NULL) { | 1721 if (phi != NULL) { |
| 1704 for (intptr_t j = 0; j < phi->InputCount(); ++j) { | 1722 for (intptr_t j = 0; j < phi->InputCount(); ++j) { |
| 1705 if (phi->InputAt(j)->Type()->ToCid() == kSmiCid) return true; | 1723 if (phi->InputAt(j)->Type()->ToCid() == kSmiCid) return true; |
| 1706 } | 1724 } |
| 1707 } | 1725 } |
| 1708 } | 1726 } |
| 1709 // If all of the inputs are known smis or the result of CheckedSmiOp, | 1727 // If all of the inputs are known smis or the result of CheckedSmiOp, |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1861 default: | 1879 default: |
| 1862 break; | 1880 break; |
| 1863 } | 1881 } |
| 1864 | 1882 |
| 1865 // No IC data checks. Try resolve target using the propagated cid. | 1883 // No IC data checks. Try resolve target using the propagated cid. |
| 1866 const intptr_t receiver_cid = | 1884 const intptr_t receiver_cid = |
| 1867 instr->PushArgumentAt(0)->value()->Type()->ToCid(); | 1885 instr->PushArgumentAt(0)->value()->Type()->ToCid(); |
| 1868 if (receiver_cid != kDynamicCid) { | 1886 if (receiver_cid != kDynamicCid) { |
| 1869 const Class& receiver_class = | 1887 const Class& receiver_class = |
| 1870 Class::Handle(Z, isolate()->class_table()->At(receiver_cid)); | 1888 Class::Handle(Z, isolate()->class_table()->At(receiver_cid)); |
| 1871 | 1889 const Function& function = |
| 1872 const Array& args_desc_array = | 1890 Function::Handle(Z, instr->ResolveForReceiverClass(receiver_class)); |
| 1873 Array::Handle(Z, ArgumentsDescriptor::New(instr->ArgumentCount(), | |
| 1874 instr->argument_names())); | |
| 1875 ArgumentsDescriptor args_desc(args_desc_array); | |
| 1876 Function& function = Function::Handle( | |
| 1877 Z, Resolver::ResolveDynamicForReceiverClass( | |
| 1878 receiver_class, instr->function_name(), args_desc)); | |
| 1879 if (!function.IsNull()) { | 1891 if (!function.IsNull()) { |
| 1880 CallTargets* targets = new (Z) CallTargets(Z); | 1892 CallTargets* targets = new (Z) CallTargets(Z); |
| 1881 Function& target = Function::ZoneHandle(Z, function.raw()); | 1893 Function& target = Function::ZoneHandle(Z, function.raw()); |
| 1882 targets->Add(new (Z) TargetInfo(receiver_class.id(), receiver_class.id(), | 1894 targets->Add(new (Z) TargetInfo(receiver_class.id(), receiver_class.id(), |
| 1883 &target, /*count = */ 1)); | 1895 &target, /*count = */ 1)); |
| 1884 PolymorphicInstanceCallInstr* call = | 1896 PolymorphicInstanceCallInstr* call = |
| 1885 new (Z) PolymorphicInstanceCallInstr(instr, *targets, | 1897 new (Z) PolymorphicInstanceCallInstr(instr, *targets, |
| 1886 /* with_checks = */ false, | 1898 /* with_checks = */ false, |
| 1887 /* complete = */ true); | 1899 /* complete = */ true); |
| 1888 instr->ReplaceWith(call, current_iterator()); | 1900 instr->ReplaceWith(call, current_iterator()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1912 if (!receiver_class.IsNull()) { | 1924 if (!receiver_class.IsNull()) { |
| 1913 GrowableArray<intptr_t> class_ids(6); | 1925 GrowableArray<intptr_t> class_ids(6); |
| 1914 if (thread()->cha()->ConcreteSubclasses(receiver_class, &class_ids)) { | 1926 if (thread()->cha()->ConcreteSubclasses(receiver_class, &class_ids)) { |
| 1915 // First check if all subclasses end up calling the same method. | 1927 // First check if all subclasses end up calling the same method. |
| 1916 // If this is the case we will replace instance call with a direct | 1928 // If this is the case we will replace instance call with a direct |
| 1917 // static call. | 1929 // static call. |
| 1918 // Otherwise we will try to create ICData that contains all possible | 1930 // Otherwise we will try to create ICData that contains all possible |
| 1919 // targets with appropriate checks. | 1931 // targets with appropriate checks. |
| 1920 Function& single_target = Function::Handle(Z); | 1932 Function& single_target = Function::Handle(Z); |
| 1921 ICData& ic_data = ICData::Handle(Z); | 1933 ICData& ic_data = ICData::Handle(Z); |
| 1922 | |
| 1923 const Array& args_desc_array = | 1934 const Array& args_desc_array = |
| 1924 Array::Handle(Z, ArgumentsDescriptor::New(instr->ArgumentCount(), | 1935 Array::Handle(Z, instr->GetArgumentsDescriptor()); |
| 1925 instr->argument_names())); | |
| 1926 ArgumentsDescriptor args_desc(args_desc_array); | |
| 1927 | |
| 1928 Function& target = Function::Handle(Z); | 1936 Function& target = Function::Handle(Z); |
| 1929 Class& cls = Class::Handle(Z); | 1937 Class& cls = Class::Handle(Z); |
| 1930 for (intptr_t i = 0; i < class_ids.length(); i++) { | 1938 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 1931 const intptr_t cid = class_ids[i]; | 1939 const intptr_t cid = class_ids[i]; |
| 1932 cls = isolate()->class_table()->At(cid); | 1940 cls = isolate()->class_table()->At(cid); |
| 1933 target = Resolver::ResolveDynamicForReceiverClass( | 1941 target = instr->ResolveForReceiverClass(cls); |
| 1934 cls, instr->function_name(), args_desc); | |
| 1935 | |
| 1936 if (target.IsNull()) { | 1942 if (target.IsNull()) { |
| 1937 // Can't resolve the target. It might be a noSuchMethod, | 1943 // Can't resolve the target. It might be a noSuchMethod, |
| 1938 // call through getter or closurization. | 1944 // call through getter or closurization. |
| 1939 single_target = Function::null(); | 1945 single_target = Function::null(); |
| 1940 ic_data = ICData::null(); | 1946 ic_data = ICData::null(); |
| 1941 break; | 1947 break; |
| 1942 } else if (ic_data.IsNull()) { | 1948 } else if (ic_data.IsNull()) { |
| 1943 // First we are trying to compute a single target for all subclasses. | 1949 // First we are trying to compute a single target for all subclasses. |
| 1944 if (single_target.IsNull()) { | 1950 if (single_target.IsNull()) { |
| 1945 ASSERT(i == 0); | 1951 ASSERT(i == 0); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1993 | 1999 |
| 1994 // We have computed that there is only a single target for this call | 2000 // We have computed that there is only a single target for this call |
| 1995 // within the whole hierarchy. Replace InstanceCall with StaticCall. | 2001 // within the whole hierarchy. Replace InstanceCall with StaticCall. |
| 1996 ZoneGrowableArray<PushArgumentInstr*>* args = new (Z) | 2002 ZoneGrowableArray<PushArgumentInstr*>* args = new (Z) |
| 1997 ZoneGrowableArray<PushArgumentInstr*>(instr->ArgumentCount()); | 2003 ZoneGrowableArray<PushArgumentInstr*>(instr->ArgumentCount()); |
| 1998 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { | 2004 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { |
| 1999 args->Add(instr->PushArgumentAt(i)); | 2005 args->Add(instr->PushArgumentAt(i)); |
| 2000 } | 2006 } |
| 2001 StaticCallInstr* call = new (Z) StaticCallInstr( | 2007 StaticCallInstr* call = new (Z) StaticCallInstr( |
| 2002 instr->token_pos(), Function::ZoneHandle(Z, single_target.raw()), | 2008 instr->token_pos(), Function::ZoneHandle(Z, single_target.raw()), |
| 2003 instr->argument_names(), args, instr->deopt_id()); | 2009 instr->type_args_len(), instr->argument_names(), args, |
| 2010 instr->deopt_id()); |
| 2004 instr->ReplaceWith(call, current_iterator()); | 2011 instr->ReplaceWith(call, current_iterator()); |
| 2005 return; | 2012 return; |
| 2006 } else if ((ic_data.raw() != ICData::null()) && | 2013 } else if ((ic_data.raw() != ICData::null()) && |
| 2007 !ic_data.NumberOfChecksIs(0)) { | 2014 !ic_data.NumberOfChecksIs(0)) { |
| 2008 CallTargets* targets = CallTargets::Create(Z, ic_data); | 2015 CallTargets* targets = CallTargets::Create(Z, ic_data); |
| 2009 PolymorphicInstanceCallInstr* call = | 2016 PolymorphicInstanceCallInstr* call = |
| 2010 new (Z) PolymorphicInstanceCallInstr(instr, *targets, | 2017 new (Z) PolymorphicInstanceCallInstr(instr, *targets, |
| 2011 /* with_checks = */ true, | 2018 /* with_checks = */ true, |
| 2012 /* complete = */ true); | 2019 /* complete = */ true); |
| 2013 instr->ReplaceWith(call, current_iterator()); | 2020 instr->ReplaceWith(call, current_iterator()); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2034 | 2041 |
| 2035 | 2042 |
| 2036 void AotOptimizer::VisitPolymorphicInstanceCall( | 2043 void AotOptimizer::VisitPolymorphicInstanceCall( |
| 2037 PolymorphicInstanceCallInstr* call) { | 2044 PolymorphicInstanceCallInstr* call) { |
| 2038 if (call->with_checks()) { | 2045 if (call->with_checks()) { |
| 2039 const intptr_t receiver_cid = | 2046 const intptr_t receiver_cid = |
| 2040 call->PushArgumentAt(0)->value()->Type()->ToCid(); | 2047 call->PushArgumentAt(0)->value()->Type()->ToCid(); |
| 2041 if (receiver_cid != kDynamicCid) { | 2048 if (receiver_cid != kDynamicCid) { |
| 2042 const Class& receiver_class = | 2049 const Class& receiver_class = |
| 2043 Class::Handle(Z, isolate()->class_table()->At(receiver_cid)); | 2050 Class::Handle(Z, isolate()->class_table()->At(receiver_cid)); |
| 2044 | |
| 2045 const Array& args_desc_array = Array::Handle( | |
| 2046 Z, ArgumentsDescriptor::New(call->ArgumentCount(), | |
| 2047 call->instance_call()->argument_names())); | |
| 2048 ArgumentsDescriptor args_desc(args_desc_array); | |
| 2049 const Function& function = Function::Handle( | 2051 const Function& function = Function::Handle( |
| 2050 Z, Resolver::ResolveDynamicForReceiverClass( | 2052 Z, call->instance_call()->ResolveForReceiverClass(receiver_class)); |
| 2051 receiver_class, call->instance_call()->function_name(), | |
| 2052 args_desc)); | |
| 2053 if (!function.IsNull()) { | 2053 if (!function.IsNull()) { |
| 2054 call->set_with_checks(false); | 2054 call->set_with_checks(false); |
| 2055 } | 2055 } |
| 2056 } | 2056 } |
| 2057 } | 2057 } |
| 2058 } | 2058 } |
| 2059 | 2059 |
| 2060 | 2060 |
| 2061 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { | 2061 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 2062 if (!IsAllowedForInlining(call->deopt_id())) { | 2062 if (!IsAllowedForInlining(call->deopt_id())) { |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2222 FlowGraph::kEffect); | 2222 FlowGraph::kEffect); |
| 2223 current_iterator()->RemoveCurrentFromGraph(); | 2223 current_iterator()->RemoveCurrentFromGraph(); |
| 2224 } | 2224 } |
| 2225 } | 2225 } |
| 2226 } | 2226 } |
| 2227 } | 2227 } |
| 2228 | 2228 |
| 2229 #endif // DART_PRECOMPILER | 2229 #endif // DART_PRECOMPILER |
| 2230 | 2230 |
| 2231 } // namespace dart | 2231 } // namespace dart |
| OLD | NEW |