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 |