| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| 11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/hash_map.h" | 12 #include "vm/hash_map.h" |
| 13 #include "vm/il_printer.h" | 13 #include "vm/il_printer.h" |
| 14 #include "vm/intermediate_language.h" | 14 #include "vm/intermediate_language.h" |
| 15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
| 16 #include "vm/parser.h" | 16 #include "vm/parser.h" |
| 17 #include "vm/resolver.h" | 17 #include "vm/resolver.h" |
| 18 #include "vm/scopes.h" | 18 #include "vm/scopes.h" |
| 19 #include "vm/stack_frame.h" | 19 #include "vm/stack_frame.h" |
| 20 #include "vm/symbols.h" | 20 #include "vm/symbols.h" |
| 21 | 21 |
| 22 namespace dart { | 22 namespace dart { |
| 23 | 23 |
| 24 DEFINE_FLAG(bool, array_bounds_check_elimination, true, | 24 DEFINE_FLAG(bool, array_bounds_check_elimination, true, |
| 25 "Eliminate redundant bounds checks."); | 25 "Eliminate redundant bounds checks."); |
| 26 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 26 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
| 27 DEFINE_FLAG(int, max_polymorphic_checks, 4, | 27 DEFINE_FLAG(int, max_polymorphic_checks, 4, |
| 28 "Maximum number of polymorphic check, otherwise it is megamorphic."); | 28 "Maximum number of polymorphic check, otherwise it is megamorphic."); |
| 29 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, |
| 30 "Maximum number of polymorphic checks in equality operator," |
| 31 " otherwise use megamorphic dispatch."); |
| 29 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); | 32 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); |
| 30 DEFINE_FLAG(bool, trace_constant_propagation, false, | 33 DEFINE_FLAG(bool, trace_constant_propagation, false, |
| 31 "Print constant propagation and useless code elimination."); | 34 "Print constant propagation and useless code elimination."); |
| 32 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 35 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
| 33 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); | 36 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); |
| 34 DEFINE_FLAG(bool, truncating_left_shift, true, | 37 DEFINE_FLAG(bool, truncating_left_shift, true, |
| 35 "Optimize left shift to truncate if possible"); | 38 "Optimize left shift to truncate if possible"); |
| 36 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); | 39 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
| 37 DEFINE_FLAG(bool, trace_load_optimization, false, | 40 DEFINE_FLAG(bool, trace_load_optimization, false, |
| 38 "Print live sets for load optimization pass."); | 41 "Print live sets for load optimization pass."); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 } | 81 } |
| 79 } | 82 } |
| 80 } else if (instr->IsPolymorphicInstanceCall()) { | 83 } else if (instr->IsPolymorphicInstanceCall()) { |
| 81 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); | 84 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); |
| 82 } else if (instr->IsStrictCompare()) { | 85 } else if (instr->IsStrictCompare()) { |
| 83 VisitStrictCompare(instr->AsStrictCompare()); | 86 VisitStrictCompare(instr->AsStrictCompare()); |
| 84 } else if (instr->IsBranch()) { | 87 } else if (instr->IsBranch()) { |
| 85 ComparisonInstr* compare = instr->AsBranch()->comparison(); | 88 ComparisonInstr* compare = instr->AsBranch()->comparison(); |
| 86 if (compare->IsStrictCompare()) { | 89 if (compare->IsStrictCompare()) { |
| 87 VisitStrictCompare(compare->AsStrictCompare()); | 90 VisitStrictCompare(compare->AsStrictCompare()); |
| 88 } else if (compare->IsEqualityCompare()) { | |
| 89 StrictifyEqualityCompare(compare->AsEqualityCompare(), | |
| 90 instr->AsBranch()); | |
| 91 } | 91 } |
| 92 } | 92 } |
| 93 } | 93 } |
| 94 current_iterator_ = NULL; | 94 current_iterator_ = NULL; |
| 95 } | 95 } |
| 96 } | 96 } |
| 97 | 97 |
| 98 | 98 |
| 99 // Attempt to build ICData for call using propagated class-ids. | 99 // Attempt to build ICData for call using propagated class-ids. |
| 100 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { | 100 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { |
| (...skipping 1166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1267 ASSERT(current_iterator()->Current() == call); | 1267 ASSERT(current_iterator()->Current() == call); |
| 1268 current_iterator()->RemoveCurrentFromGraph(); | 1268 current_iterator()->RemoveCurrentFromGraph(); |
| 1269 call->set_previous(NULL); | 1269 call->set_previous(NULL); |
| 1270 call->set_next(NULL); | 1270 call->set_next(NULL); |
| 1271 return true; | 1271 return true; |
| 1272 } | 1272 } |
| 1273 | 1273 |
| 1274 | 1274 |
| 1275 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 1275 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
| 1276 | 1276 |
| 1277 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
| 1278 Token::Kind op_kind) { |
| 1279 const ICData& ic_data = *call->ic_data(); |
| 1280 ASSERT(ic_data.num_args_tested() == 2); |
| 1281 |
| 1282 ASSERT(call->ArgumentCount() == 2); |
| 1283 Definition* left = call->ArgumentAt(0); |
| 1284 Definition* right = call->ArgumentAt(1); |
| 1285 |
| 1286 intptr_t cid = kIllegalCid; |
| 1287 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1288 InsertBefore(call, |
| 1289 new CheckSmiInstr(new Value(left), call->deopt_id()), |
| 1290 call->env(), |
| 1291 Definition::kEffect); |
| 1292 InsertBefore(call, |
| 1293 new CheckSmiInstr(new Value(right), call->deopt_id()), |
| 1294 call->env(), |
| 1295 Definition::kEffect); |
| 1296 cid = kSmiCid; |
| 1297 } else if (HasTwoMintOrSmi(ic_data) && |
| 1298 FlowGraphCompiler::SupportsUnboxedMints()) { |
| 1299 cid = kMintCid; |
| 1300 } else if (HasTwoDoubleOrSmi(ic_data)) { |
| 1301 // Use double comparison. |
| 1302 if (SmiFitsInDouble()) { |
| 1303 cid = kDoubleCid; |
| 1304 } else { |
| 1305 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 1306 // We cannot use double comparison on two smis. Need polymorphic |
| 1307 // call. |
| 1308 return false; |
| 1309 } else { |
| 1310 InsertBefore(call, |
| 1311 new CheckEitherNonSmiInstr(new Value(left), |
| 1312 new Value(right), |
| 1313 call->deopt_id()), |
| 1314 call->env(), |
| 1315 Definition::kEffect); |
| 1316 cid = kDoubleCid; |
| 1317 } |
| 1318 } |
| 1319 } else { |
| 1320 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 1321 // we can still emit the optimized Smi equality operation but need to add |
| 1322 // checks for null or Smi. |
| 1323 GrowableArray<intptr_t> smi_or_null(2); |
| 1324 smi_or_null.Add(kSmiCid); |
| 1325 smi_or_null.Add(kNullCid); |
| 1326 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, |
| 1327 smi_or_null, |
| 1328 smi_or_null)) { |
| 1329 const ICData& unary_checks_0 = |
| 1330 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 1331 AddCheckClass(left, |
| 1332 unary_checks_0, |
| 1333 call->deopt_id(), |
| 1334 call->env(), |
| 1335 call); |
| 1336 |
| 1337 const ICData& unary_checks_1 = |
| 1338 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1)); |
| 1339 AddCheckClass(right, |
| 1340 unary_checks_1, |
| 1341 call->deopt_id(), |
| 1342 call->env(), |
| 1343 call); |
| 1344 cid = kSmiCid; |
| 1345 } else { |
| 1346 // Shortcut for equality with null. |
| 1347 ConstantInstr* right_const = right->AsConstant(); |
| 1348 ConstantInstr* left_const = left->AsConstant(); |
| 1349 if ((right_const != NULL && right_const->value().IsNull()) || |
| 1350 (left_const != NULL && left_const->value().IsNull())) { |
| 1351 StrictCompareInstr* comp = new StrictCompareInstr(call->token_pos(), |
| 1352 Token::kEQ_STRICT, |
| 1353 new Value(left), |
| 1354 new Value(right)); |
| 1355 ReplaceCall(call, comp); |
| 1356 return true; |
| 1357 } |
| 1358 return false; |
| 1359 } |
| 1360 } |
| 1361 ASSERT(cid != kIllegalCid); |
| 1362 EqualityCompareInstr* comp = new EqualityCompareInstr(call->token_pos(), |
| 1363 op_kind, |
| 1364 new Value(left), |
| 1365 new Value(right), |
| 1366 cid, |
| 1367 call->deopt_id()); |
| 1368 ReplaceCall(call, comp); |
| 1369 return true; |
| 1370 } |
| 1371 |
| 1277 | 1372 |
| 1278 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 1373 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
| 1279 Token::Kind op_kind) { | 1374 Token::Kind op_kind) { |
| 1280 const ICData& ic_data = *call->ic_data(); | 1375 const ICData& ic_data = *call->ic_data(); |
| 1281 ASSERT(ic_data.num_args_tested() == 2); | 1376 ASSERT(ic_data.num_args_tested() == 2); |
| 1282 | 1377 |
| 1283 ASSERT(call->ArgumentCount() == 2); | 1378 ASSERT(call->ArgumentCount() == 2); |
| 1284 Definition* left = call->ArgumentAt(0); | 1379 Definition* left = call->ArgumentAt(0); |
| 1285 Definition* right = call->ArgumentAt(1); | 1380 Definition* right = call->ArgumentAt(1); |
| 1286 | 1381 |
| (...skipping 1560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2847 if (prev.IsNull()) { | 2942 if (prev.IsNull()) { |
| 2848 prev = Bool::Get(is_subtype).raw(); | 2943 prev = Bool::Get(is_subtype).raw(); |
| 2849 } else { | 2944 } else { |
| 2850 if (is_subtype != prev.value()) return Bool::null(); | 2945 if (is_subtype != prev.value()) return Bool::null(); |
| 2851 } | 2946 } |
| 2852 } | 2947 } |
| 2853 return prev.raw(); | 2948 return prev.raw(); |
| 2854 } | 2949 } |
| 2855 | 2950 |
| 2856 | 2951 |
| 2952 static Definition* OriginalDefinition(Definition* defn) { |
| 2953 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { |
| 2954 if (defn->IsRedefinition()) { |
| 2955 defn = defn->AsRedefinition()->value()->definition(); |
| 2956 } else { |
| 2957 defn = defn->AsAssertAssignable()->value()->definition(); |
| 2958 } |
| 2959 } |
| 2960 return defn; |
| 2961 } |
| 2962 |
| 2963 |
| 2857 // TODO(srdjan): Use ICData to check if always true or false. | 2964 // TODO(srdjan): Use ICData to check if always true or false. |
| 2858 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 2965 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 2859 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 2966 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 2860 Definition* left = call->ArgumentAt(0); | 2967 Definition* left = call->ArgumentAt(0); |
| 2861 Definition* instantiator = call->ArgumentAt(1); | 2968 Definition* instantiator = call->ArgumentAt(1); |
| 2862 Definition* type_args = call->ArgumentAt(2); | 2969 Definition* type_args = call->ArgumentAt(2); |
| 2863 const AbstractType& type = | 2970 const AbstractType& type = |
| 2864 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 2971 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
| 2865 const bool negate = | 2972 const bool negate = Bool::Cast( |
| 2866 Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value(); | 2973 OriginalDefinition(call->ArgumentAt(4))->AsConstant()->value()).value(); |
| 2867 const ICData& unary_checks = | 2974 const ICData& unary_checks = |
| 2868 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 2975 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 2869 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 2976 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 2870 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); | 2977 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); |
| 2871 if (!as_bool.IsNull()) { | 2978 if (!as_bool.IsNull()) { |
| 2872 AddReceiverCheck(call); | 2979 AddReceiverCheck(call); |
| 2873 if (negate) { | 2980 if (negate) { |
| 2874 as_bool = Bool::Get(!as_bool.value()).raw(); | 2981 as_bool = Bool::Get(!as_bool.value()).raw(); |
| 2875 } | 2982 } |
| 2876 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); | 2983 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2955 } | 3062 } |
| 2956 | 3063 |
| 2957 if (Token::IsTypeCastOperator(op_kind)) { | 3064 if (Token::IsTypeCastOperator(op_kind)) { |
| 2958 ReplaceWithTypeCast(instr); | 3065 ReplaceWithTypeCast(instr); |
| 2959 return; | 3066 return; |
| 2960 } | 3067 } |
| 2961 | 3068 |
| 2962 const ICData& unary_checks = | 3069 const ICData& unary_checks = |
| 2963 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); | 3070 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); |
| 2964 | 3071 |
| 2965 if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) && | 3072 intptr_t max_checks = (op_kind == Token::kEQ) |
| 3073 ? FLAG_max_equality_polymorphic_checks |
| 3074 : FLAG_max_polymorphic_checks; |
| 3075 if ((unary_checks.NumberOfChecks() > max_checks) && |
| 2966 InstanceCallNeedsClassCheck(instr)) { | 3076 InstanceCallNeedsClassCheck(instr)) { |
| 2967 // Too many checks, it will be megamorphic which needs unary checks. | 3077 // Too many checks, it will be megamorphic which needs unary checks. |
| 2968 instr->set_ic_data(&unary_checks); | 3078 instr->set_ic_data(&unary_checks); |
| 2969 return; | 3079 return; |
| 2970 } | 3080 } |
| 2971 | 3081 |
| 2972 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithStoreIndexed(instr)) { | 3082 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithStoreIndexed(instr)) { |
| 2973 return; | 3083 return; |
| 2974 } | 3084 } |
| 2975 if ((op_kind == Token::kINDEX) && TryReplaceWithLoadIndexed(instr)) { | 3085 if ((op_kind == Token::kINDEX) && TryReplaceWithLoadIndexed(instr)) { |
| 2976 return; | 3086 return; |
| 2977 } | 3087 } |
| 2978 | 3088 |
| 3089 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) { |
| 3090 return; |
| 3091 } |
| 3092 |
| 2979 if (Token::IsRelationalOperator(op_kind) && | 3093 if (Token::IsRelationalOperator(op_kind) && |
| 2980 TryReplaceWithRelationalOp(instr, op_kind)) { | 3094 TryReplaceWithRelationalOp(instr, op_kind)) { |
| 2981 return; | 3095 return; |
| 2982 } | 3096 } |
| 2983 | 3097 |
| 2984 if (Token::IsBinaryOperator(op_kind) && | 3098 if (Token::IsBinaryOperator(op_kind) && |
| 2985 TryReplaceWithBinaryOp(instr, op_kind)) { | 3099 TryReplaceWithBinaryOp(instr, op_kind)) { |
| 2986 return; | 3100 return; |
| 2987 } | 3101 } |
| 2988 if (Token::IsPrefixOperator(op_kind) && | 3102 if (Token::IsPrefixOperator(op_kind) && |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3183 new Value(instr->ArgumentAt(1)), | 3297 new Value(instr->ArgumentAt(1)), |
| 3184 needs_store_barrier); | 3298 needs_store_barrier); |
| 3185 // Discard the environment from the original instruction because the store | 3299 // Discard the environment from the original instruction because the store |
| 3186 // can't deoptimize. | 3300 // can't deoptimize. |
| 3187 instr->RemoveEnvironment(); | 3301 instr->RemoveEnvironment(); |
| 3188 ReplaceCall(instr, store); | 3302 ReplaceCall(instr, store); |
| 3189 return true; | 3303 return true; |
| 3190 } | 3304 } |
| 3191 | 3305 |
| 3192 | 3306 |
| 3193 bool FlowGraphOptimizer::CanStrictifyEqualityCompare( | |
| 3194 EqualityCompareInstr* compare) { | |
| 3195 // If one of the inputs is null this is a strict comparison. | |
| 3196 if (compare->left()->BindsToConstantNull() || | |
| 3197 compare->right()->BindsToConstantNull()) { | |
| 3198 return true; | |
| 3199 } | |
| 3200 | |
| 3201 if (compare->left()->Type()->IsNone()) { | |
| 3202 return false; // We might be running prior to any type propagation passes. | |
| 3203 } | |
| 3204 | |
| 3205 // Try resolving target function using propagated cid for the receiver. | |
| 3206 // If receiver is either null or has default equality operator then | |
| 3207 // we can convert such comparison to a strict one. | |
| 3208 const intptr_t receiver_cid = | |
| 3209 compare->left()->Type()->ToNullableCid(); | |
| 3210 | |
| 3211 if (receiver_cid == kDynamicCid) { | |
| 3212 return false; | |
| 3213 } | |
| 3214 | |
| 3215 const Class& receiver_class = Class::Handle( | |
| 3216 Isolate::Current()->class_table()->At(receiver_cid)); | |
| 3217 | |
| 3218 // Resolve equality operator. | |
| 3219 const intptr_t kNumArgs = 2; | |
| 3220 ArgumentsDescriptor args_desc( | |
| 3221 Array::Handle(ArgumentsDescriptor::New(kNumArgs))); | |
| 3222 const Function& function = Function::Handle( | |
| 3223 Resolver::ResolveDynamicForReceiverClass( | |
| 3224 receiver_class, | |
| 3225 Symbols::EqualOperator(), | |
| 3226 args_desc)); | |
| 3227 | |
| 3228 if (function.IsNull()) { | |
| 3229 return false; | |
| 3230 } | |
| 3231 | |
| 3232 // Default equality operator declared on the Object class just calls | |
| 3233 // identical. | |
| 3234 return (Class::Handle(function.Owner()).id() == kInstanceCid); | |
| 3235 } | |
| 3236 | |
| 3237 | |
| 3238 template <typename T> | |
| 3239 bool FlowGraphOptimizer::StrictifyEqualityCompare( | |
| 3240 EqualityCompareInstr* compare, | |
| 3241 T current_instruction) const { | |
| 3242 if (CanStrictifyEqualityCompare(compare)) { | |
| 3243 Token::Kind strict_kind = (compare->kind() == Token::kEQ) ? | |
| 3244 Token::kEQ_STRICT : Token::kNE_STRICT; | |
| 3245 StrictCompareInstr* strict_comp = | |
| 3246 new StrictCompareInstr(compare->token_pos(), | |
| 3247 strict_kind, | |
| 3248 compare->left()->CopyWithType(), | |
| 3249 compare->right()->CopyWithType()); | |
| 3250 // Numbers override equality and are therefore not part of this conversion. | |
| 3251 strict_comp->set_needs_number_check(false); | |
| 3252 current_instruction->ReplaceWith(strict_comp, current_iterator()); | |
| 3253 return true; | |
| 3254 } | |
| 3255 return false; | |
| 3256 } | |
| 3257 | |
| 3258 | |
| 3259 // Returns true if we converted EqualityCompare to StrictCompare. | |
| 3260 template <typename T> | |
| 3261 bool FlowGraphOptimizer::StrictifyEqualityCompareWithICData( | |
| 3262 EqualityCompareInstr* compare, | |
| 3263 const ICData& unary_ic_data, | |
| 3264 T current_instruction) { | |
| 3265 ASSERT(unary_ic_data.num_args_tested() == 1); | |
| 3266 if (unary_ic_data.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | |
| 3267 // If possible classes do not override Object's equality then replace | |
| 3268 // with strict equality. | |
| 3269 Function& target = Function::Handle(); | |
| 3270 Class& targets_class = Class::Handle(); | |
| 3271 for (intptr_t i = 0; i < unary_ic_data.NumberOfChecks(); i++) { | |
| 3272 intptr_t cid = kIllegalCid; | |
| 3273 unary_ic_data.GetOneClassCheckAt(i, &cid, &target); | |
| 3274 targets_class = target.Owner(); | |
| 3275 if (targets_class.id() != kInstanceCid) { | |
| 3276 // Overriden equality operator. | |
| 3277 return false; | |
| 3278 } | |
| 3279 } | |
| 3280 AddCheckClass(compare->left()->definition(), | |
| 3281 unary_ic_data, | |
| 3282 compare->deopt_id(), | |
| 3283 current_instruction->env(), | |
| 3284 current_instruction); | |
| 3285 ASSERT((compare->kind() == Token::kEQ) || (compare->kind() == Token::kNE)); | |
| 3286 Token::Kind strict_kind = (compare->kind() == Token::kEQ) ? | |
| 3287 Token::kEQ_STRICT : Token::kNE_STRICT; | |
| 3288 StrictCompareInstr* strict_comp = | |
| 3289 new StrictCompareInstr(compare->token_pos(), | |
| 3290 strict_kind, | |
| 3291 compare->left()->Copy(), | |
| 3292 compare->right()->Copy()); | |
| 3293 // Numbers override equality and are therefore not part of this conversion. | |
| 3294 strict_comp->set_needs_number_check(false); | |
| 3295 current_instruction->ReplaceWith(strict_comp, current_iterator()); | |
| 3296 return true; | |
| 3297 } | |
| 3298 return false; | |
| 3299 } | |
| 3300 | |
| 3301 | |
| 3302 template <typename T> | |
| 3303 void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp, | |
| 3304 T current_instruction) { | |
| 3305 if (StrictifyEqualityCompare(comp, current_instruction)) { | |
| 3306 // Based on input types, equality converted to strict-equality. | |
| 3307 return; | |
| 3308 } | |
| 3309 | |
| 3310 if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) { | |
| 3311 return; | |
| 3312 } | |
| 3313 | |
| 3314 const ICData& ic_data = *comp->ic_data(); | |
| 3315 ASSERT(ic_data.num_args_tested() == 2); | |
| 3316 ASSERT(comp->operation_cid() == kIllegalCid); | |
| 3317 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | |
| 3318 InsertBefore(current_instruction, | |
| 3319 new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()), | |
| 3320 current_instruction->env(), | |
| 3321 Definition::kEffect); | |
| 3322 InsertBefore(current_instruction, | |
| 3323 new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()), | |
| 3324 current_instruction->env(), | |
| 3325 Definition::kEffect); | |
| 3326 comp->set_operation_cid(kSmiCid); | |
| 3327 } else if (HasTwoMintOrSmi(ic_data) && | |
| 3328 FlowGraphCompiler::SupportsUnboxedMints()) { | |
| 3329 comp->set_operation_cid(kMintCid); | |
| 3330 } else if (HasTwoDoubleOrSmi(ic_data)) { | |
| 3331 // Use double comparison. | |
| 3332 if (SmiFitsInDouble()) { | |
| 3333 comp->set_operation_cid(kDoubleCid); | |
| 3334 } else { | |
| 3335 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | |
| 3336 // We cannot use double comparison on two smis. | |
| 3337 ASSERT(comp->operation_cid() == kIllegalCid); | |
| 3338 } else { | |
| 3339 InsertBefore(current_instruction, | |
| 3340 new CheckEitherNonSmiInstr(comp->left()->Copy(), | |
| 3341 comp->right()->Copy(), | |
| 3342 comp->deopt_id()), | |
| 3343 current_instruction->env(), | |
| 3344 Definition::kEffect); | |
| 3345 comp->set_operation_cid(kDoubleCid); | |
| 3346 } | |
| 3347 } | |
| 3348 } | |
| 3349 | |
| 3350 if (comp->operation_cid() != kIllegalCid) { | |
| 3351 // Done. | |
| 3352 return; | |
| 3353 } | |
| 3354 | |
| 3355 const ICData& unary_checks_0 = | |
| 3356 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks()); | |
| 3357 if (StrictifyEqualityCompareWithICData( | |
| 3358 comp, unary_checks_0, current_instruction)) { | |
| 3359 // Based on ICData, equality converted to strict-equality. | |
| 3360 return; | |
| 3361 } | |
| 3362 | |
| 3363 // Check if ICDData contains checks with Smi/Null combinations. In that case | |
| 3364 // we can still emit the optimized Smi equality operation but need to add | |
| 3365 // checks for null or Smi. | |
| 3366 // TODO(srdjan): Add it for Double and Mint. | |
| 3367 GrowableArray<intptr_t> smi_or_null(2); | |
| 3368 smi_or_null.Add(kSmiCid); | |
| 3369 smi_or_null.Add(kNullCid); | |
| 3370 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, | |
| 3371 smi_or_null, | |
| 3372 smi_or_null)) { | |
| 3373 AddCheckClass(comp->left()->definition(), | |
| 3374 unary_checks_0, | |
| 3375 comp->deopt_id(), | |
| 3376 current_instruction->env(), | |
| 3377 current_instruction); | |
| 3378 | |
| 3379 const ICData& unary_checks_1 = | |
| 3380 ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1)); | |
| 3381 AddCheckClass(comp->right()->definition(), | |
| 3382 unary_checks_1, | |
| 3383 comp->deopt_id(), | |
| 3384 current_instruction->env(), | |
| 3385 current_instruction); | |
| 3386 comp->set_operation_cid(kSmiCid); | |
| 3387 } | |
| 3388 } | |
| 3389 | |
| 3390 | |
| 3391 | |
| 3392 | |
| 3393 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) { | |
| 3394 HandleEqualityCompare(instr, instr); | |
| 3395 } | |
| 3396 | |
| 3397 | |
| 3398 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) { | |
| 3399 ComparisonInstr* comparison = instr->comparison(); | |
| 3400 if (comparison->IsEqualityCompare()) { | |
| 3401 HandleEqualityCompare(comparison->AsEqualityCompare(), instr); | |
| 3402 } else { | |
| 3403 ASSERT(comparison->IsStrictCompare()); | |
| 3404 // Nothing to do. | |
| 3405 } | |
| 3406 } | |
| 3407 | |
| 3408 | |
| 3409 // Range analysis for smi values. | 3307 // Range analysis for smi values. |
| 3410 class RangeAnalysis : public ValueObject { | 3308 class RangeAnalysis : public ValueObject { |
| 3411 public: | 3309 public: |
| 3412 explicit RangeAnalysis(FlowGraph* flow_graph) | 3310 explicit RangeAnalysis(FlowGraph* flow_graph) |
| 3413 : flow_graph_(flow_graph), | 3311 : flow_graph_(flow_graph), |
| 3414 marked_defns_(NULL) { } | 3312 marked_defns_(NULL) { } |
| 3415 | 3313 |
| 3416 // Infer ranges for all values and remove overflow checks from binary smi | 3314 // Infer ranges for all values and remove overflow checks from binary smi |
| 3417 // operations when proven redundant. | 3315 // operations when proven redundant. |
| 3418 void Analyze(); | 3316 void Analyze(); |
| (...skipping 1075 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4494 return (kind_ == other->kind_) && | 4392 return (kind_ == other->kind_) && |
| 4495 (representation_ == other->representation_) && | 4393 (representation_ == other->representation_) && |
| 4496 (instance_ == other->instance_) && | 4394 (instance_ == other->instance_) && |
| 4497 SameField(other); | 4395 SameField(other); |
| 4498 } | 4396 } |
| 4499 | 4397 |
| 4500 // Create a zone allocated copy of this place. | 4398 // Create a zone allocated copy of this place. |
| 4501 static Place* Wrap(const Place& place); | 4399 static Place* Wrap(const Place& place); |
| 4502 | 4400 |
| 4503 private: | 4401 private: |
| 4504 static Definition* OriginalDefinition(Definition* defn) { | |
| 4505 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { | |
| 4506 if (defn->IsRedefinition()) { | |
| 4507 defn = defn->AsRedefinition()->value()->definition(); | |
| 4508 } else { | |
| 4509 defn = defn->AsAssertAssignable()->value()->definition(); | |
| 4510 } | |
| 4511 } | |
| 4512 return defn; | |
| 4513 } | |
| 4514 | |
| 4515 bool SameField(Place* other) const { | 4402 bool SameField(Place* other) const { |
| 4516 return (kind_ == kField) ? (field().raw() == other->field().raw()) | 4403 return (kind_ == kField) ? (field().raw() == other->field().raw()) |
| 4517 : (offset_in_bytes_ == other->offset_in_bytes_); | 4404 : (offset_in_bytes_ == other->offset_in_bytes_); |
| 4518 } | 4405 } |
| 4519 | 4406 |
| 4520 intptr_t FieldHashcode() const { | 4407 intptr_t FieldHashcode() const { |
| 4521 return (kind_ == kField) ? reinterpret_cast<intptr_t>(field().raw()) | 4408 return (kind_ == kField) ? reinterpret_cast<intptr_t>(field().raw()) |
| 4522 : offset_in_bytes_; | 4409 : offset_in_bytes_; |
| 4523 } | 4410 } |
| 4524 | 4411 |
| (...skipping 1822 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6347 return false; | 6234 return false; |
| 6348 } | 6235 } |
| 6349 } | 6236 } |
| 6350 | 6237 |
| 6351 | 6238 |
| 6352 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { | 6239 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { |
| 6353 const Object& left = instr->left()->definition()->constant_value(); | 6240 const Object& left = instr->left()->definition()->constant_value(); |
| 6354 const Object& right = instr->right()->definition()->constant_value(); | 6241 const Object& right = instr->right()->definition()->constant_value(); |
| 6355 | 6242 |
| 6356 if (instr->left()->definition() == instr->right()->definition()) { | 6243 if (instr->left()->definition() == instr->right()->definition()) { |
| 6357 // Fold x == x, and x != x to true/false for numbers and checked strict | 6244 // Fold x == x, and x != x to true/false for numbers comparisons. |
| 6358 // comparisons. | 6245 if (RawObject::IsIntegerClassId(instr->operation_cid())) { |
| 6359 if (instr->IsCheckedStrictEqual() || | |
| 6360 RawObject::IsIntegerClassId(instr->operation_cid())) { | |
| 6361 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); | 6246 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); |
| 6362 } | 6247 } |
| 6363 } | 6248 } |
| 6364 | 6249 |
| 6365 if (IsNonConstant(left) || IsNonConstant(right)) { | 6250 if (IsNonConstant(left) || IsNonConstant(right)) { |
| 6366 SetValue(instr, non_constant_); | 6251 SetValue(instr, non_constant_); |
| 6367 } else if (IsConstant(left) && IsConstant(right)) { | 6252 } else if (IsConstant(left) && IsConstant(right)) { |
| 6368 if (left.IsInteger() && right.IsInteger()) { | 6253 if (left.IsInteger() && right.IsInteger()) { |
| 6369 const bool result = CompareIntegers(instr->kind(), | 6254 const bool result = CompareIntegers(instr->kind(), |
| 6370 Integer::Cast(left), | 6255 Integer::Cast(left), |
| (...skipping 948 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7319 comparison->kind(), | 7204 comparison->kind(), |
| 7320 left, | 7205 left, |
| 7321 right); | 7206 right); |
| 7322 } else if (comparison->IsEqualityCompare()) { | 7207 } else if (comparison->IsEqualityCompare()) { |
| 7323 EqualityCompareInstr* equality_compare = comparison->AsEqualityCompare(); | 7208 EqualityCompareInstr* equality_compare = comparison->AsEqualityCompare(); |
| 7324 EqualityCompareInstr* new_equality_compare = | 7209 EqualityCompareInstr* new_equality_compare = |
| 7325 new EqualityCompareInstr(equality_compare->token_pos(), | 7210 new EqualityCompareInstr(equality_compare->token_pos(), |
| 7326 comparison->kind(), | 7211 comparison->kind(), |
| 7327 left, | 7212 left, |
| 7328 right, | 7213 right, |
| 7329 Object::null_array()); | 7214 equality_compare->operation_cid(), |
| 7330 new_equality_compare->set_ic_data(equality_compare->ic_data()); | 7215 equality_compare->deopt_id()); |
| 7331 new_equality_compare->set_operation_cid(equality_compare->operation_cid()); | |
| 7332 new_comparison = new_equality_compare; | 7216 new_comparison = new_equality_compare; |
| 7333 } else { | 7217 } else { |
| 7334 ASSERT(comparison->IsRelationalOp()); | 7218 ASSERT(comparison->IsRelationalOp()); |
| 7335 RelationalOpInstr* relational_op = comparison->AsRelationalOp(); | 7219 RelationalOpInstr* relational_op = comparison->AsRelationalOp(); |
| 7336 RelationalOpInstr* new_relational_op = | 7220 RelationalOpInstr* new_relational_op = |
| 7337 new RelationalOpInstr(relational_op->token_pos(), | 7221 new RelationalOpInstr(relational_op->token_pos(), |
| 7338 comparison->kind(), | 7222 comparison->kind(), |
| 7339 left, | 7223 left, |
| 7340 right, | 7224 right, |
| 7341 relational_op->operation_cid(), | 7225 relational_op->operation_cid(), |
| (...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7865 } | 7749 } |
| 7866 | 7750 |
| 7867 // Insert materializations at environment uses. | 7751 // Insert materializations at environment uses. |
| 7868 for (intptr_t i = 0; i < exits.length(); i++) { | 7752 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7869 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 7753 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 7870 } | 7754 } |
| 7871 } | 7755 } |
| 7872 | 7756 |
| 7873 | 7757 |
| 7874 } // namespace dart | 7758 } // namespace dart |
| OLD | NEW |