OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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/globals.h" // Needed here to get TARGET_ARCH_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
7 | 7 |
8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
9 | 9 |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 2430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2441 __ CompareImmediate(temp, threshold, PP); | 2441 __ CompareImmediate(temp, threshold, PP); |
2442 __ b(slow_path->osr_entry_label(), GE); | 2442 __ b(slow_path->osr_entry_label(), GE); |
2443 } | 2443 } |
2444 if (compiler->ForceSlowPathForStackOverflow()) { | 2444 if (compiler->ForceSlowPathForStackOverflow()) { |
2445 __ b(slow_path->entry_label()); | 2445 __ b(slow_path->entry_label()); |
2446 } | 2446 } |
2447 __ Bind(slow_path->exit_label()); | 2447 __ Bind(slow_path->exit_label()); |
2448 } | 2448 } |
2449 | 2449 |
2450 | 2450 |
| 2451 static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler, |
| 2452 Range* range, |
| 2453 Label* overflow, |
| 2454 Register result) { |
| 2455 if (!range->IsWithin(-0x20000000000000LL, 0x20000000000000LL)) { |
| 2456 ASSERT(overflow != NULL); |
| 2457 __ CompareImmediate(result, -0x20000000000000LL, PP); |
| 2458 __ b(overflow, LT); |
| 2459 __ CompareImmediate(result, 0x20000000000000LL, PP); |
| 2460 __ b(overflow, GT); |
| 2461 } |
| 2462 } |
| 2463 |
| 2464 |
2451 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, | 2465 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler, |
2452 BinarySmiOpInstr* shift_left) { | 2466 BinarySmiOpInstr* shift_left) { |
2453 const bool is_truncating = shift_left->is_truncating(); | 2467 const bool is_truncating = shift_left->is_truncating(); |
2454 const LocationSummary& locs = *shift_left->locs(); | 2468 const LocationSummary& locs = *shift_left->locs(); |
2455 Register left = locs.in(0).reg(); | 2469 Register left = locs.in(0).reg(); |
2456 Register result = locs.out(0).reg(); | 2470 Register result = locs.out(0).reg(); |
2457 Label* deopt = shift_left->CanDeoptimize() ? | 2471 Label* deopt = shift_left->CanDeoptimize() ? |
2458 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) | 2472 compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp) |
2459 : NULL; | 2473 : NULL; |
2460 if (locs.in(1).IsConstant()) { | 2474 if (locs.in(1).IsConstant()) { |
(...skipping 16 matching lines...) Expand all Loading... |
2477 } else { | 2491 } else { |
2478 if (!is_truncating) { | 2492 if (!is_truncating) { |
2479 // Check for overflow (preserve left). | 2493 // Check for overflow (preserve left). |
2480 __ Lsl(TMP, left, value); | 2494 __ Lsl(TMP, left, value); |
2481 __ cmp(left, Operand(TMP, ASR, value)); | 2495 __ cmp(left, Operand(TMP, ASR, value)); |
2482 __ b(deopt, NE); // Overflow. | 2496 __ b(deopt, NE); // Overflow. |
2483 } | 2497 } |
2484 // Shift for result now we know there is no overflow. | 2498 // Shift for result now we know there is no overflow. |
2485 __ Lsl(result, left, value); | 2499 __ Lsl(result, left, value); |
2486 } | 2500 } |
| 2501 if (FLAG_throw_on_javascript_int_overflow) { |
| 2502 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2503 } |
2487 return; | 2504 return; |
2488 } | 2505 } |
2489 | 2506 |
2490 // Right (locs.in(1)) is not constant. | 2507 // Right (locs.in(1)) is not constant. |
2491 Register right = locs.in(1).reg(); | 2508 Register right = locs.in(1).reg(); |
2492 Range* right_range = shift_left->right()->definition()->range(); | 2509 Range* right_range = shift_left->right()->definition()->range(); |
2493 if (shift_left->left()->BindsToConstant() && !is_truncating) { | 2510 if (shift_left->left()->BindsToConstant() && !is_truncating) { |
2494 // TODO(srdjan): Implement code below for is_truncating(). | 2511 // TODO(srdjan): Implement code below for is_truncating(). |
2495 // If left is constant, we know the maximal allowed size for right. | 2512 // If left is constant, we know the maximal allowed size for right. |
2496 const Object& obj = shift_left->left()->BoundConstant(); | 2513 const Object& obj = shift_left->left()->BoundConstant(); |
(...skipping 10 matching lines...) Expand all Loading... |
2507 (right_range == NULL) || | 2524 (right_range == NULL) || |
2508 !right_range->IsWithin(0, max_right - 1); | 2525 !right_range->IsWithin(0, max_right - 1); |
2509 if (right_needs_check) { | 2526 if (right_needs_check) { |
2510 __ CompareImmediate(right, | 2527 __ CompareImmediate(right, |
2511 reinterpret_cast<int64_t>(Smi::New(max_right)), PP); | 2528 reinterpret_cast<int64_t>(Smi::New(max_right)), PP); |
2512 __ b(deopt, CS); | 2529 __ b(deopt, CS); |
2513 } | 2530 } |
2514 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP. | 2531 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into TMP. |
2515 __ lslv(result, left, TMP); | 2532 __ lslv(result, left, TMP); |
2516 } | 2533 } |
| 2534 if (FLAG_throw_on_javascript_int_overflow) { |
| 2535 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2536 } |
2517 return; | 2537 return; |
2518 } | 2538 } |
2519 | 2539 |
2520 const bool right_needs_check = | 2540 const bool right_needs_check = |
2521 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); | 2541 (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1)); |
2522 if (is_truncating) { | 2542 if (is_truncating) { |
2523 if (right_needs_check) { | 2543 if (right_needs_check) { |
2524 const bool right_may_be_negative = | 2544 const bool right_may_be_negative = |
2525 (right_range == NULL) || | 2545 (right_range == NULL) || |
2526 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); | 2546 !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); |
(...skipping 25 matching lines...) Expand all Loading... |
2552 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP. | 2572 __ Asr(TMP, right, kSmiTagSize); // SmiUntag right into IP. |
2553 // Overflow test (preserve left, right, and IP); | 2573 // Overflow test (preserve left, right, and IP); |
2554 Register temp = locs.temp(0).reg(); | 2574 Register temp = locs.temp(0).reg(); |
2555 __ lslv(temp, left, TMP); | 2575 __ lslv(temp, left, TMP); |
2556 __ asrv(TMP2, temp, TMP); | 2576 __ asrv(TMP2, temp, TMP); |
2557 __ CompareRegisters(left, TMP2); | 2577 __ CompareRegisters(left, TMP2); |
2558 __ b(deopt, NE); // Overflow. | 2578 __ b(deopt, NE); // Overflow. |
2559 // Shift for result now we know there is no overflow. | 2579 // Shift for result now we know there is no overflow. |
2560 __ lslv(result, left, TMP); | 2580 __ lslv(result, left, TMP); |
2561 } | 2581 } |
| 2582 if (FLAG_throw_on_javascript_int_overflow) { |
| 2583 EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result); |
| 2584 } |
2562 } | 2585 } |
2563 | 2586 |
2564 | 2587 |
2565 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const { | 2588 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const { |
2566 const intptr_t kNumInputs = 2; | 2589 const intptr_t kNumInputs = 2; |
2567 const intptr_t kNumTemps = 0; | 2590 const intptr_t kNumTemps = 0; |
2568 LocationSummary* summary = | 2591 LocationSummary* summary = |
2569 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2592 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
2570 if (op_kind() == Token::kTRUNCDIV) { | 2593 if (op_kind() == Token::kTRUNCDIV) { |
2571 summary->set_in(0, Location::RequiresRegister()); | 2594 summary->set_in(0, Location::RequiresRegister()); |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2726 } | 2749 } |
2727 | 2750 |
2728 __ Asr(result, left, value); | 2751 __ Asr(result, left, value); |
2729 __ SmiTag(result); | 2752 __ SmiTag(result); |
2730 break; | 2753 break; |
2731 } | 2754 } |
2732 default: | 2755 default: |
2733 UNREACHABLE(); | 2756 UNREACHABLE(); |
2734 break; | 2757 break; |
2735 } | 2758 } |
| 2759 if (FLAG_throw_on_javascript_int_overflow) { |
| 2760 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2761 } |
2736 return; | 2762 return; |
2737 } | 2763 } |
2738 | 2764 |
2739 Register right = locs()->in(1).reg(); | 2765 Register right = locs()->in(1).reg(); |
2740 Range* right_range = this->right()->definition()->range(); | 2766 Range* right_range = this->right()->definition()->range(); |
2741 switch (op_kind()) { | 2767 switch (op_kind()) { |
2742 case Token::kADD: { | 2768 case Token::kADD: { |
2743 if (deopt == NULL) { | 2769 if (deopt == NULL) { |
2744 __ add(result, left, Operand(right)); | 2770 __ add(result, left, Operand(right)); |
2745 } else { | 2771 } else { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2868 case Token::kAND: { | 2894 case Token::kAND: { |
2869 // Flow graph builder has dissected this operation to guarantee correct | 2895 // Flow graph builder has dissected this operation to guarantee correct |
2870 // behavior (short-circuit evaluation). | 2896 // behavior (short-circuit evaluation). |
2871 UNREACHABLE(); | 2897 UNREACHABLE(); |
2872 break; | 2898 break; |
2873 } | 2899 } |
2874 default: | 2900 default: |
2875 UNREACHABLE(); | 2901 UNREACHABLE(); |
2876 break; | 2902 break; |
2877 } | 2903 } |
| 2904 if (FLAG_throw_on_javascript_int_overflow) { |
| 2905 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 2906 } |
2878 } | 2907 } |
2879 | 2908 |
2880 | 2909 |
2881 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const { | 2910 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const { |
2882 intptr_t left_cid = left()->Type()->ToCid(); | 2911 intptr_t left_cid = left()->Type()->ToCid(); |
2883 intptr_t right_cid = right()->Type()->ToCid(); | 2912 intptr_t right_cid = right()->Type()->ToCid(); |
2884 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); | 2913 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid)); |
2885 const intptr_t kNumInputs = 2; | 2914 const intptr_t kNumInputs = 2; |
2886 const intptr_t kNumTemps = 0; | 2915 const intptr_t kNumTemps = 0; |
2887 LocationSummary* summary = | 2916 LocationSummary* summary = |
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3555 | 3584 |
3556 | 3585 |
3557 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3586 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3558 Register value = locs()->in(0).reg(); | 3587 Register value = locs()->in(0).reg(); |
3559 Register result = locs()->out(0).reg(); | 3588 Register result = locs()->out(0).reg(); |
3560 switch (op_kind()) { | 3589 switch (op_kind()) { |
3561 case Token::kNEGATE: { | 3590 case Token::kNEGATE: { |
3562 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp); | 3591 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp); |
3563 __ subs(result, ZR, Operand(value)); | 3592 __ subs(result, ZR, Operand(value)); |
3564 __ b(deopt, VS); | 3593 __ b(deopt, VS); |
| 3594 if (FLAG_throw_on_javascript_int_overflow) { |
| 3595 EmitJavascriptOverflowCheck(compiler, range(), deopt, value); |
| 3596 } |
3565 break; | 3597 break; |
3566 } | 3598 } |
3567 case Token::kBIT_NOT: | 3599 case Token::kBIT_NOT: |
3568 __ mvn(result, value); | 3600 __ mvn(result, value); |
3569 // Remove inverted smi-tag. | 3601 // Remove inverted smi-tag. |
3570 __ andi(result, result, ~kSmiTagMask); | 3602 __ andi(result, result, ~kSmiTagMask); |
3571 break; | 3603 break; |
3572 default: | 3604 default: |
3573 UNREACHABLE(); | 3605 UNREACHABLE(); |
3574 } | 3606 } |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3636 __ fcmpd(VTMP, VTMP); | 3668 __ fcmpd(VTMP, VTMP); |
3637 __ b(&do_call, VS); | 3669 __ b(&do_call, VS); |
3638 | 3670 |
3639 __ fcvtzds(result, VTMP); | 3671 __ fcvtzds(result, VTMP); |
3640 // Overflow is signaled with minint. | 3672 // Overflow is signaled with minint. |
3641 | 3673 |
3642 // Check for overflow and that it fits into Smi. | 3674 // Check for overflow and that it fits into Smi. |
3643 __ CompareImmediate(result, 0xC000000000000000, PP); | 3675 __ CompareImmediate(result, 0xC000000000000000, PP); |
3644 __ b(&do_call, MI); | 3676 __ b(&do_call, MI); |
3645 __ SmiTag(result); | 3677 __ SmiTag(result); |
| 3678 if (FLAG_throw_on_javascript_int_overflow) { |
| 3679 EmitJavascriptOverflowCheck(compiler, range(), &do_call, result); |
| 3680 } |
3646 __ b(&done); | 3681 __ b(&done); |
3647 __ Bind(&do_call); | 3682 __ Bind(&do_call); |
3648 __ Push(value_obj); | 3683 __ Push(value_obj); |
3649 ASSERT(instance_call()->HasICData()); | 3684 ASSERT(instance_call()->HasICData()); |
3650 const ICData& ic_data = *instance_call()->ic_data(); | 3685 const ICData& ic_data = *instance_call()->ic_data(); |
3651 ASSERT((ic_data.NumberOfChecks() == 1)); | 3686 ASSERT((ic_data.NumberOfChecks() == 1)); |
3652 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 3687 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
3653 | 3688 |
3654 const intptr_t kNumberOfArguments = 1; | 3689 const intptr_t kNumberOfArguments = 1; |
3655 compiler->GenerateStaticCall(deopt_id(), | 3690 compiler->GenerateStaticCall(deopt_id(), |
(...skipping 25 matching lines...) Expand all Loading... |
3681 // on ARM64 because fcvtzds gives 0 for NaN. | 3716 // on ARM64 because fcvtzds gives 0 for NaN. |
3682 // TODO(zra): Check spec that this is true. | 3717 // TODO(zra): Check spec that this is true. |
3683 __ fcmpd(value, value); | 3718 __ fcmpd(value, value); |
3684 __ b(deopt, VS); | 3719 __ b(deopt, VS); |
3685 | 3720 |
3686 __ fcvtzds(result, value); | 3721 __ fcvtzds(result, value); |
3687 // Check for overflow and that it fits into Smi. | 3722 // Check for overflow and that it fits into Smi. |
3688 __ CompareImmediate(result, 0xC000000000000000, PP); | 3723 __ CompareImmediate(result, 0xC000000000000000, PP); |
3689 __ b(deopt, MI); | 3724 __ b(deopt, MI); |
3690 __ SmiTag(result); | 3725 __ SmiTag(result); |
| 3726 if (FLAG_throw_on_javascript_int_overflow) { |
| 3727 EmitJavascriptOverflowCheck(compiler, range(), deopt, result); |
| 3728 } |
3691 } | 3729 } |
3692 | 3730 |
3693 | 3731 |
3694 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(bool opt) const { | 3732 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(bool opt) const { |
3695 UNIMPLEMENTED(); | 3733 UNIMPLEMENTED(); |
3696 return NULL; | 3734 return NULL; |
3697 } | 3735 } |
3698 | 3736 |
3699 | 3737 |
3700 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3738 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3987 // } | 4025 // } |
3988 Label done; | 4026 Label done; |
3989 __ CompareRegisters(result_mod, ZR);; | 4027 __ CompareRegisters(result_mod, ZR);; |
3990 __ b(&done, GE); | 4028 __ b(&done, GE); |
3991 // Result is negative, adjust it. | 4029 // Result is negative, adjust it. |
3992 __ CompareRegisters(right, ZR); | 4030 __ CompareRegisters(right, ZR); |
3993 __ sub(TMP2, result_mod, Operand(right)); | 4031 __ sub(TMP2, result_mod, Operand(right)); |
3994 __ add(TMP, result_mod, Operand(right)); | 4032 __ add(TMP, result_mod, Operand(right)); |
3995 __ csel(result_mod, TMP, TMP2, GE); | 4033 __ csel(result_mod, TMP, TMP2, GE); |
3996 __ Bind(&done); | 4034 __ Bind(&done); |
3997 | 4035 // FLAG_throw_on_javascript_int_overflow: not needed. |
| 4036 // Note that the result of an integer division/modulo of two |
| 4037 // in-range arguments, cannot create out-of-range result. |
3998 return; | 4038 return; |
3999 } | 4039 } |
4000 if (kind() == MergedMathInstr::kSinCos) { | 4040 if (kind() == MergedMathInstr::kSinCos) { |
4001 UNIMPLEMENTED(); | 4041 UNIMPLEMENTED(); |
4002 } | 4042 } |
4003 UNIMPLEMENTED(); | 4043 UNIMPLEMENTED(); |
4004 } | 4044 } |
4005 | 4045 |
4006 | 4046 |
4007 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( | 4047 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( |
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4447 compiler->GenerateCall(token_pos(), | 4487 compiler->GenerateCall(token_pos(), |
4448 &label, | 4488 &label, |
4449 PcDescriptors::kOther, | 4489 PcDescriptors::kOther, |
4450 locs()); | 4490 locs()); |
4451 __ Drop(ArgumentCount()); // Discard arguments. | 4491 __ Drop(ArgumentCount()); // Discard arguments. |
4452 } | 4492 } |
4453 | 4493 |
4454 } // namespace dart | 4494 } // namespace dart |
4455 | 4495 |
4456 #endif // defined TARGET_ARCH_ARM64 | 4496 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |