| 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 #ifndef DART_PRECOMPILED_RUNTIME | 4 #ifndef DART_PRECOMPILED_RUNTIME |
| 5 #include "vm/jit_optimizer.h" | 5 #include "vm/jit_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 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 Instruction* insert_before) { | 382 Instruction* insert_before) { |
| 383 if (to_check->Type()->ToCid() != kSmiCid) { | 383 if (to_check->Type()->ToCid() != kSmiCid) { |
| 384 InsertBefore(insert_before, | 384 InsertBefore(insert_before, |
| 385 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, | 385 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, |
| 386 insert_before->token_pos()), | 386 insert_before->token_pos()), |
| 387 deopt_environment, FlowGraph::kEffect); | 387 deopt_environment, FlowGraph::kEffect); |
| 388 } | 388 } |
| 389 } | 389 } |
| 390 | 390 |
| 391 | 391 |
| 392 Instruction* JitOptimizer::GetCheckClass(Definition* to_check, | |
| 393 const ICData& unary_checks, | |
| 394 intptr_t deopt_id, | |
| 395 TokenPosition token_pos) { | |
| 396 if ((unary_checks.NumberOfUsedChecks() == 1) && | |
| 397 unary_checks.HasReceiverClassId(kSmiCid)) { | |
| 398 return new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, token_pos); | |
| 399 } | |
| 400 return new (Z) CheckClassInstr(new (Z) Value(to_check), deopt_id, | |
| 401 unary_checks, token_pos); | |
| 402 } | |
| 403 | |
| 404 | |
| 405 void JitOptimizer::AddCheckClass(Definition* to_check, | 392 void JitOptimizer::AddCheckClass(Definition* to_check, |
| 406 const ICData& unary_checks, | 393 const Cids& cids, |
| 407 intptr_t deopt_id, | 394 intptr_t deopt_id, |
| 408 Environment* deopt_environment, | 395 Environment* deopt_environment, |
| 409 Instruction* insert_before) { | 396 Instruction* insert_before) { |
| 410 // Type propagation has not run yet, we cannot eliminate the check. | 397 // Type propagation has not run yet, we cannot eliminate the check. |
| 411 Instruction* check = GetCheckClass(to_check, unary_checks, deopt_id, | 398 Instruction* check = flow_graph_->CreateCheckClass( |
| 412 insert_before->token_pos()); | 399 to_check, cids, deopt_id, insert_before->token_pos()); |
| 413 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); | 400 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); |
| 414 } | 401 } |
| 415 | 402 |
| 416 | 403 |
| 417 void JitOptimizer::AddReceiverCheck(InstanceCallInstr* call) { | 404 void JitOptimizer::AddChecksToArgNr(InstanceCallInstr* call, |
| 418 AddCheckClass(call->ArgumentAt(0), | 405 Definition* instr, |
| 419 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), | 406 int argument_number) { |
| 420 call->deopt_id(), call->env(), call); | 407 const Cids* cids = Cids::Create(Z, *call->ic_data(), argument_number); |
| 408 AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call); |
| 421 } | 409 } |
| 422 | 410 |
| 423 | 411 |
| 424 static bool ArgIsAlways(intptr_t cid, | 412 static bool ArgIsAlways(intptr_t cid, |
| 425 const ICData& ic_data, | 413 const ICData& ic_data, |
| 426 intptr_t arg_number) { | 414 intptr_t arg_number) { |
| 427 ASSERT(ic_data.NumArgsTested() > arg_number); | 415 ASSERT(ic_data.NumArgsTested() > arg_number); |
| 428 if (ic_data.NumberOfUsedChecks() == 0) { | 416 if (ic_data.NumberOfUsedChecks() == 0) { |
| 429 return false; | 417 return false; |
| 430 } | 418 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 | 497 |
| 510 Definition* to_remove_right = NULL; | 498 Definition* to_remove_right = NULL; |
| 511 Value* right_val = NULL; | 499 Value* right_val = NULL; |
| 512 if (right->IsOneByteStringFromCharCode()) { | 500 if (right->IsOneByteStringFromCharCode()) { |
| 513 // Skip string-from-char-code, and use its input as right value. | 501 // Skip string-from-char-code, and use its input as right value. |
| 514 OneByteStringFromCharCodeInstr* right_instr = | 502 OneByteStringFromCharCodeInstr* right_instr = |
| 515 right->AsOneByteStringFromCharCode(); | 503 right->AsOneByteStringFromCharCode(); |
| 516 right_val = new (Z) Value(right_instr->char_code()->definition()); | 504 right_val = new (Z) Value(right_instr->char_code()->definition()); |
| 517 to_remove_right = right_instr; | 505 to_remove_right = right_instr; |
| 518 } else { | 506 } else { |
| 519 const ICData& unary_checks_1 = | 507 AddChecksToArgNr(call, right, 1); |
| 520 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); | |
| 521 AddCheckClass(right, unary_checks_1, call->deopt_id(), call->env(), call); | |
| 522 // String-to-char-code instructions returns -1 (illegal charcode) if | 508 // String-to-char-code instructions returns -1 (illegal charcode) if |
| 523 // string is not of length one. | 509 // string is not of length one. |
| 524 StringToCharCodeInstr* char_code_right = new (Z) | 510 StringToCharCodeInstr* char_code_right = new (Z) |
| 525 StringToCharCodeInstr(new (Z) Value(right), kOneByteStringCid); | 511 StringToCharCodeInstr(new (Z) Value(right), kOneByteStringCid); |
| 526 InsertBefore(call, char_code_right, call->env(), FlowGraph::kValue); | 512 InsertBefore(call, char_code_right, call->env(), FlowGraph::kValue); |
| 527 right_val = new (Z) Value(char_code_right); | 513 right_val = new (Z) Value(char_code_right); |
| 528 } | 514 } |
| 529 | 515 |
| 530 // Comparing char-codes instead of strings. | 516 // Comparing char-codes instead of strings. |
| 531 EqualityCompareInstr* comp = | 517 EqualityCompareInstr* comp = |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 602 } | 588 } |
| 603 } else { | 589 } else { |
| 604 // Check if ICDData contains checks with Smi/Null combinations. In that case | 590 // Check if ICDData contains checks with Smi/Null combinations. In that case |
| 605 // we can still emit the optimized Smi equality operation but need to add | 591 // we can still emit the optimized Smi equality operation but need to add |
| 606 // checks for null or Smi. | 592 // checks for null or Smi. |
| 607 GrowableArray<intptr_t> smi_or_null(2); | 593 GrowableArray<intptr_t> smi_or_null(2); |
| 608 smi_or_null.Add(kSmiCid); | 594 smi_or_null.Add(kSmiCid); |
| 609 smi_or_null.Add(kNullCid); | 595 smi_or_null.Add(kNullCid); |
| 610 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, smi_or_null, | 596 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, smi_or_null, |
| 611 smi_or_null)) { | 597 smi_or_null)) { |
| 612 const ICData& unary_checks_0 = | 598 AddChecksToArgNr(call, left, 0); |
| 613 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); | 599 AddChecksToArgNr(call, right, 0); |
| 614 AddCheckClass(left, unary_checks_0, call->deopt_id(), call->env(), call); | |
| 615 | |
| 616 const ICData& unary_checks_1 = | |
| 617 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); | |
| 618 AddCheckClass(right, unary_checks_1, call->deopt_id(), call->env(), call); | |
| 619 cid = kSmiCid; | 600 cid = kSmiCid; |
| 620 } else { | 601 } else { |
| 621 // Shortcut for equality with null. | 602 // Shortcut for equality with null. |
| 622 ConstantInstr* right_const = right->AsConstant(); | 603 ConstantInstr* right_const = right->AsConstant(); |
| 623 ConstantInstr* left_const = left->AsConstant(); | 604 ConstantInstr* left_const = left->AsConstant(); |
| 624 if ((right_const != NULL && right_const->value().IsNull()) || | 605 if ((right_const != NULL && right_const->value().IsNull()) || |
| 625 (left_const != NULL && left_const->value().IsNull())) { | 606 (left_const != NULL && left_const->value().IsNull())) { |
| 626 StrictCompareInstr* comp = new (Z) | 607 StrictCompareInstr* comp = new (Z) |
| 627 StrictCompareInstr(call->token_pos(), Token::kEQ_STRICT, | 608 StrictCompareInstr(call->token_pos(), Token::kEQ_STRICT, |
| 628 new (Z) Value(left), new (Z) Value(right), | 609 new (Z) Value(left), new (Z) Value(right), |
| (...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 | 953 |
| 973 | 954 |
| 974 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, | 955 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, |
| 975 Token::Kind op_kind) { | 956 Token::Kind op_kind) { |
| 976 if (!ShouldInlineSimd()) { | 957 if (!ShouldInlineSimd()) { |
| 977 return false; | 958 return false; |
| 978 } | 959 } |
| 979 ASSERT(call->ArgumentCount() == 2); | 960 ASSERT(call->ArgumentCount() == 2); |
| 980 Definition* left = call->ArgumentAt(0); | 961 Definition* left = call->ArgumentAt(0); |
| 981 Definition* right = call->ArgumentAt(1); | 962 Definition* right = call->ArgumentAt(1); |
| 982 // Type check left. | 963 // Type check left and right. |
| 983 AddCheckClass(left, ICData::ZoneHandle( | 964 AddChecksToArgNr(call, left, 0); |
| 984 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 965 AddChecksToArgNr(call, right, 1); |
| 985 call->deopt_id(), call->env(), call); | |
| 986 // Type check right. | |
| 987 AddCheckClass(right, ICData::ZoneHandle( | |
| 988 Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)), | |
| 989 call->deopt_id(), call->env(), call); | |
| 990 // Replace call. | 966 // Replace call. |
| 991 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr( | 967 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr( |
| 992 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 968 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 993 ReplaceCall(call, float32x4_bin_op); | 969 ReplaceCall(call, float32x4_bin_op); |
| 994 | 970 |
| 995 return true; | 971 return true; |
| 996 } | 972 } |
| 997 | 973 |
| 998 | 974 |
| 999 bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, | 975 bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, |
| 1000 Token::Kind op_kind) { | 976 Token::Kind op_kind) { |
| 1001 if (!ShouldInlineSimd()) { | 977 if (!ShouldInlineSimd()) { |
| 1002 return false; | 978 return false; |
| 1003 } | 979 } |
| 1004 ASSERT(call->ArgumentCount() == 2); | 980 ASSERT(call->ArgumentCount() == 2); |
| 1005 Definition* left = call->ArgumentAt(0); | 981 Definition* left = call->ArgumentAt(0); |
| 1006 Definition* right = call->ArgumentAt(1); | 982 Definition* right = call->ArgumentAt(1); |
| 1007 // Type check left. | 983 // Type check left and right. |
| 1008 AddCheckClass(left, ICData::ZoneHandle( | 984 AddChecksToArgNr(call, left, 0); |
| 1009 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 985 AddChecksToArgNr(call, right, 1); |
| 1010 call->deopt_id(), call->env(), call); | |
| 1011 // Type check right. | |
| 1012 AddCheckClass(right, ICData::ZoneHandle( | |
| 1013 Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)), | |
| 1014 call->deopt_id(), call->env(), call); | |
| 1015 // Replace call. | 986 // Replace call. |
| 1016 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr( | 987 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr( |
| 1017 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 988 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 1018 ReplaceCall(call, int32x4_bin_op); | 989 ReplaceCall(call, int32x4_bin_op); |
| 1019 return true; | 990 return true; |
| 1020 } | 991 } |
| 1021 | 992 |
| 1022 | 993 |
| 1023 bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, | 994 bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, |
| 1024 Token::Kind op_kind) { | 995 Token::Kind op_kind) { |
| 1025 if (!ShouldInlineSimd()) { | 996 if (!ShouldInlineSimd()) { |
| 1026 return false; | 997 return false; |
| 1027 } | 998 } |
| 1028 ASSERT(call->ArgumentCount() == 2); | 999 ASSERT(call->ArgumentCount() == 2); |
| 1029 Definition* left = call->ArgumentAt(0); | 1000 Definition* left = call->ArgumentAt(0); |
| 1030 Definition* right = call->ArgumentAt(1); | 1001 Definition* right = call->ArgumentAt(1); |
| 1031 // Type check left. | 1002 // Type check left and right. |
| 1032 AddCheckClass( | 1003 AddChecksToArgNr(call, left, 0); |
| 1033 left, ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1004 AddChecksToArgNr(call, right, 1); |
| 1034 call->deopt_id(), call->env(), call); | |
| 1035 // Type check right. | |
| 1036 AddCheckClass( | |
| 1037 right, ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1)), | |
| 1038 call->deopt_id(), call->env(), call); | |
| 1039 // Replace call. | 1005 // Replace call. |
| 1040 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr( | 1006 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr( |
| 1041 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 1007 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
| 1042 ReplaceCall(call, float64x2_bin_op); | 1008 ReplaceCall(call, float64x2_bin_op); |
| 1043 return true; | 1009 return true; |
| 1044 } | 1010 } |
| 1045 | 1011 |
| 1046 | 1012 |
| 1047 // Only unique implicit instance getters can be currently handled. | 1013 // Only unique implicit instance getters can be currently handled. |
| 1048 bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { | 1014 bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 return; | 1468 return; |
| 1503 } | 1469 } |
| 1504 if ((op_kind == Token::kSET) && | 1470 if ((op_kind == Token::kSET) && |
| 1505 TryInlineInstanceSetter(instr, unary_checks)) { | 1471 TryInlineInstanceSetter(instr, unary_checks)) { |
| 1506 return; | 1472 return; |
| 1507 } | 1473 } |
| 1508 if (TryInlineInstanceMethod(instr)) { | 1474 if (TryInlineInstanceMethod(instr)) { |
| 1509 return; | 1475 return; |
| 1510 } | 1476 } |
| 1511 | 1477 |
| 1512 CallTargets* targets = CallTargets::Create(Z, unary_checks); | 1478 const CallTargets& targets = *CallTargets::CreateAndExpand(Z, unary_checks); |
| 1513 | 1479 |
| 1514 bool has_one_target = targets->HasSingleTarget(); | 1480 bool has_one_target = targets.HasSingleTarget(); |
| 1515 | 1481 |
| 1516 if (has_one_target) { | 1482 if (has_one_target) { |
| 1517 // Check if the single target is a polymorphic target, if it is, | 1483 // Check if the single target is a polymorphic target, if it is, |
| 1518 // we don't have one target. | 1484 // we don't have one target. |
| 1519 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); | 1485 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); |
| 1520 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { | 1486 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { |
| 1521 has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType( | 1487 has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType( |
| 1522 *targets) != Type::null(); | 1488 targets) != Type::null(); |
| 1523 } else { | 1489 } else { |
| 1524 const bool polymorphic_target = | 1490 const bool polymorphic_target = |
| 1525 MethodRecognizer::PolymorphicTarget(target); | 1491 MethodRecognizer::PolymorphicTarget(target); |
| 1526 has_one_target = !polymorphic_target; | 1492 has_one_target = !polymorphic_target; |
| 1527 } | 1493 } |
| 1528 } | 1494 } |
| 1529 | 1495 |
| 1530 if (has_one_target) { | 1496 if (has_one_target) { |
| 1531 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); | 1497 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); |
| 1532 const RawFunction::Kind function_kind = target.kind(); | 1498 const RawFunction::Kind function_kind = target.kind(); |
| 1533 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { | 1499 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { |
| 1534 PolymorphicInstanceCallInstr* call = | 1500 PolymorphicInstanceCallInstr* call = |
| 1535 new (Z) PolymorphicInstanceCallInstr(instr, *targets, | 1501 new (Z) PolymorphicInstanceCallInstr(instr, targets, |
| 1536 /* call_with_checks = */ false, | 1502 /* call_with_checks = */ false, |
| 1537 /* complete = */ false); | 1503 /* complete = */ false); |
| 1538 instr->ReplaceWith(call, current_iterator()); | 1504 instr->ReplaceWith(call, current_iterator()); |
| 1539 return; | 1505 return; |
| 1540 } | 1506 } |
| 1541 } | 1507 } |
| 1542 | 1508 |
| 1543 // If there is only one target we can make this into a deopting class check, | 1509 // If there is only one target we can make this into a deopting class check, |
| 1544 // followed by a call instruction that does not check the class of the | 1510 // followed by a call instruction that does not check the class of the |
| 1545 // receiver. This enables a lot of optimizations because after the class | 1511 // receiver. This enables a lot of optimizations because after the class |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1557 // Type propagation has not run yet, we cannot eliminate the check. | 1523 // Type propagation has not run yet, we cannot eliminate the check. |
| 1558 // TODO(erikcorry): The receiver check should use the off-heap targets | 1524 // TODO(erikcorry): The receiver check should use the off-heap targets |
| 1559 // array, not the IC array. | 1525 // array, not the IC array. |
| 1560 AddReceiverCheck(instr); | 1526 AddReceiverCheck(instr); |
| 1561 // Call can still deoptimize, do not detach environment from instr. | 1527 // Call can still deoptimize, do not detach environment from instr. |
| 1562 call_with_checks = false; | 1528 call_with_checks = false; |
| 1563 } else { | 1529 } else { |
| 1564 call_with_checks = true; | 1530 call_with_checks = true; |
| 1565 } | 1531 } |
| 1566 PolymorphicInstanceCallInstr* call = | 1532 PolymorphicInstanceCallInstr* call = |
| 1567 new (Z) PolymorphicInstanceCallInstr(instr, *targets, call_with_checks, | 1533 new (Z) PolymorphicInstanceCallInstr(instr, targets, call_with_checks, |
| 1568 /* complete = */ false); | 1534 /* complete = */ false); |
| 1569 instr->ReplaceWith(call, current_iterator()); | 1535 instr->ReplaceWith(call, current_iterator()); |
| 1570 } | 1536 } |
| 1571 | 1537 |
| 1572 | 1538 |
| 1573 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { | 1539 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 1574 MethodRecognizer::Kind recognized_kind = | 1540 MethodRecognizer::Kind recognized_kind = |
| 1575 MethodRecognizer::RecognizeKind(call->function()); | 1541 MethodRecognizer::RecognizeKind(call->function()); |
| 1576 switch (recognized_kind) { | 1542 switch (recognized_kind) { |
| 1577 case MethodRecognizer::kObjectConstructor: | 1543 case MethodRecognizer::kObjectConstructor: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1610 kDoubleCid)) { | 1576 kDoubleCid)) { |
| 1611 result_cid = kDoubleCid; | 1577 result_cid = kDoubleCid; |
| 1612 } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, | 1578 } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, |
| 1613 kSmiCid)) { | 1579 kSmiCid)) { |
| 1614 result_cid = kSmiCid; | 1580 result_cid = kSmiCid; |
| 1615 } | 1581 } |
| 1616 if (result_cid != kIllegalCid) { | 1582 if (result_cid != kIllegalCid) { |
| 1617 MathMinMaxInstr* min_max = new (Z) MathMinMaxInstr( | 1583 MathMinMaxInstr* min_max = new (Z) MathMinMaxInstr( |
| 1618 recognized_kind, new (Z) Value(call->ArgumentAt(0)), | 1584 recognized_kind, new (Z) Value(call->ArgumentAt(0)), |
| 1619 new (Z) Value(call->ArgumentAt(1)), call->deopt_id(), result_cid); | 1585 new (Z) Value(call->ArgumentAt(1)), call->deopt_id(), result_cid); |
| 1620 const ICData& unary_checks = | 1586 const Cids* cids = Cids::Create(Z, ic_data, 0); |
| 1621 ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks()); | 1587 AddCheckClass(min_max->left()->definition(), *cids, call->deopt_id(), |
| 1622 AddCheckClass(min_max->left()->definition(), unary_checks, | 1588 call->env(), call); |
| 1623 call->deopt_id(), call->env(), call); | 1589 AddCheckClass(min_max->right()->definition(), *cids, call->deopt_id(), |
| 1624 AddCheckClass(min_max->right()->definition(), unary_checks, | 1590 call->env(), call); |
| 1625 call->deopt_id(), call->env(), call); | |
| 1626 ReplaceCall(call, min_max); | 1591 ReplaceCall(call, min_max); |
| 1627 } | 1592 } |
| 1628 } | 1593 } |
| 1629 break; | 1594 break; |
| 1630 } | 1595 } |
| 1631 | 1596 |
| 1632 case MethodRecognizer::kDoubleFromInteger: { | 1597 case MethodRecognizer::kDoubleFromInteger: { |
| 1633 if (call->HasICData() && call->ic_data()->NumberOfChecksIs(1)) { | 1598 if (call->HasICData() && call->ic_data()->NumberOfChecksIs(1)) { |
| 1634 const ICData& ic_data = *call->ic_data(); | 1599 const ICData& ic_data = *call->ic_data(); |
| 1635 if (CanUnboxDouble()) { | 1600 if (CanUnboxDouble()) { |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1813 // Discard the environment from the original instruction because the store | 1778 // Discard the environment from the original instruction because the store |
| 1814 // can't deoptimize. | 1779 // can't deoptimize. |
| 1815 instr->RemoveEnvironment(); | 1780 instr->RemoveEnvironment(); |
| 1816 ReplaceCall(instr, store); | 1781 ReplaceCall(instr, store); |
| 1817 return true; | 1782 return true; |
| 1818 } | 1783 } |
| 1819 | 1784 |
| 1820 | 1785 |
| 1821 } // namespace dart | 1786 } // namespace dart |
| 1822 #endif // DART_PRECOMPILED_RUNTIME | 1787 #endif // DART_PRECOMPILED_RUNTIME |
| OLD | NEW |