| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
| 6 | 6 |
| 7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
| 8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
| 9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
| 10 #include "src/ic/handler-compiler.h" | 10 #include "src/ic/handler-compiler.h" |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 } | 200 } |
| 201 __ Pop(scratch2, scratch1); | 201 __ Pop(scratch2, scratch1); |
| 202 __ Ret(); | 202 __ Ret(); |
| 203 } | 203 } |
| 204 | 204 |
| 205 | 205 |
| 206 // See call site for description. | 206 // See call site for description. |
| 207 static void EmitIdenticalObjectComparison(MacroAssembler* masm, Register left, | 207 static void EmitIdenticalObjectComparison(MacroAssembler* masm, Register left, |
| 208 Register right, Register scratch, | 208 Register right, Register scratch, |
| 209 FPRegister double_scratch, | 209 FPRegister double_scratch, |
| 210 Label* slow, Condition cond, | 210 Label* slow, Condition cond) { |
| 211 Strength strength) { | |
| 212 DCHECK(!AreAliased(left, right, scratch)); | 211 DCHECK(!AreAliased(left, right, scratch)); |
| 213 Label not_identical, return_equal, heap_number; | 212 Label not_identical, return_equal, heap_number; |
| 214 Register result = x0; | 213 Register result = x0; |
| 215 | 214 |
| 216 __ Cmp(right, left); | 215 __ Cmp(right, left); |
| 217 __ B(ne, ¬_identical); | 216 __ B(ne, ¬_identical); |
| 218 | 217 |
| 219 // Test for NaN. Sadly, we can't just compare to factory::nan_value(), | 218 // Test for NaN. Sadly, we can't just compare to factory::nan_value(), |
| 220 // so we do the second best thing - test it ourselves. | 219 // so we do the second best thing - test it ourselves. |
| 221 // They are both equal and they are not both Smis so both of them are not | 220 // They are both equal and they are not both Smis so both of them are not |
| 222 // Smis. If it's not a heap number, then return equal. | 221 // Smis. If it's not a heap number, then return equal. |
| 223 Register right_type = scratch; | 222 Register right_type = scratch; |
| 224 if ((cond == lt) || (cond == gt)) { | 223 if ((cond == lt) || (cond == gt)) { |
| 225 // Call runtime on identical JSObjects. Otherwise return equal. | 224 // Call runtime on identical JSObjects. Otherwise return equal. |
| 226 __ JumpIfObjectType(right, right_type, right_type, FIRST_JS_RECEIVER_TYPE, | 225 __ JumpIfObjectType(right, right_type, right_type, FIRST_JS_RECEIVER_TYPE, |
| 227 slow, ge); | 226 slow, ge); |
| 228 // Call runtime on identical symbols since we need to throw a TypeError. | 227 // Call runtime on identical symbols since we need to throw a TypeError. |
| 229 __ Cmp(right_type, SYMBOL_TYPE); | 228 __ Cmp(right_type, SYMBOL_TYPE); |
| 230 __ B(eq, slow); | 229 __ B(eq, slow); |
| 231 // Call runtime on identical SIMD values since we must throw a TypeError. | 230 // Call runtime on identical SIMD values since we must throw a TypeError. |
| 232 __ Cmp(right_type, SIMD128_VALUE_TYPE); | 231 __ Cmp(right_type, SIMD128_VALUE_TYPE); |
| 233 __ B(eq, slow); | 232 __ B(eq, slow); |
| 234 if (is_strong(strength)) { | |
| 235 // Call the runtime on anything that is converted in the semantics, since | |
| 236 // we need to throw a TypeError. Smis have already been ruled out. | |
| 237 __ Cmp(right_type, Operand(HEAP_NUMBER_TYPE)); | |
| 238 __ B(eq, &return_equal); | |
| 239 __ Tst(right_type, Operand(kIsNotStringMask)); | |
| 240 __ B(ne, slow); | |
| 241 } | |
| 242 } else if (cond == eq) { | 233 } else if (cond == eq) { |
| 243 __ JumpIfHeapNumber(right, &heap_number); | 234 __ JumpIfHeapNumber(right, &heap_number); |
| 244 } else { | 235 } else { |
| 245 __ JumpIfObjectType(right, right_type, right_type, HEAP_NUMBER_TYPE, | 236 __ JumpIfObjectType(right, right_type, right_type, HEAP_NUMBER_TYPE, |
| 246 &heap_number); | 237 &heap_number); |
| 247 // Comparing JS objects with <=, >= is complicated. | 238 // Comparing JS objects with <=, >= is complicated. |
| 248 __ Cmp(right_type, FIRST_JS_RECEIVER_TYPE); | 239 __ Cmp(right_type, FIRST_JS_RECEIVER_TYPE); |
| 249 __ B(ge, slow); | 240 __ B(ge, slow); |
| 250 // Call runtime on identical symbols since we need to throw a TypeError. | 241 // Call runtime on identical symbols since we need to throw a TypeError. |
| 251 __ Cmp(right_type, SYMBOL_TYPE); | 242 __ Cmp(right_type, SYMBOL_TYPE); |
| 252 __ B(eq, slow); | 243 __ B(eq, slow); |
| 253 // Call runtime on identical SIMD values since we must throw a TypeError. | 244 // Call runtime on identical SIMD values since we must throw a TypeError. |
| 254 __ Cmp(right_type, SIMD128_VALUE_TYPE); | 245 __ Cmp(right_type, SIMD128_VALUE_TYPE); |
| 255 __ B(eq, slow); | 246 __ B(eq, slow); |
| 256 if (is_strong(strength)) { | |
| 257 // Call the runtime on anything that is converted in the semantics, | |
| 258 // since we need to throw a TypeError. Smis and heap numbers have | |
| 259 // already been ruled out. | |
| 260 __ Tst(right_type, Operand(kIsNotStringMask)); | |
| 261 __ B(ne, slow); | |
| 262 } | |
| 263 // Normally here we fall through to return_equal, but undefined is | 247 // Normally here we fall through to return_equal, but undefined is |
| 264 // special: (undefined == undefined) == true, but | 248 // special: (undefined == undefined) == true, but |
| 265 // (undefined <= undefined) == false! See ECMAScript 11.8.5. | 249 // (undefined <= undefined) == false! See ECMAScript 11.8.5. |
| 266 if ((cond == le) || (cond == ge)) { | 250 if ((cond == le) || (cond == ge)) { |
| 267 __ Cmp(right_type, ODDBALL_TYPE); | 251 __ Cmp(right_type, ODDBALL_TYPE); |
| 268 __ B(ne, &return_equal); | 252 __ B(ne, &return_equal); |
| 269 __ JumpIfNotRoot(right, Heap::kUndefinedValueRootIndex, &return_equal); | 253 __ JumpIfNotRoot(right, Heap::kUndefinedValueRootIndex, &return_equal); |
| 270 if (cond == le) { | 254 if (cond == le) { |
| 271 // undefined <= undefined should fail. | 255 // undefined <= undefined should fail. |
| 272 __ Mov(result, GREATER); | 256 __ Mov(result, GREATER); |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 524 __ Sub(result, lhs, Operand::UntagSmi(rhs)); | 508 __ Sub(result, lhs, Operand::UntagSmi(rhs)); |
| 525 __ Ret(); | 509 __ Ret(); |
| 526 | 510 |
| 527 __ Bind(¬_two_smis); | 511 __ Bind(¬_two_smis); |
| 528 | 512 |
| 529 // NOTICE! This code is only reached after a smi-fast-case check, so it is | 513 // NOTICE! This code is only reached after a smi-fast-case check, so it is |
| 530 // certain that at least one operand isn't a smi. | 514 // certain that at least one operand isn't a smi. |
| 531 | 515 |
| 532 // Handle the case where the objects are identical. Either returns the answer | 516 // Handle the case where the objects are identical. Either returns the answer |
| 533 // or goes to slow. Only falls through if the objects were not identical. | 517 // or goes to slow. Only falls through if the objects were not identical. |
| 534 EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond, | 518 EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond); |
| 535 strength()); | |
| 536 | 519 |
| 537 // If either is a smi (we know that at least one is not a smi), then they can | 520 // If either is a smi (we know that at least one is not a smi), then they can |
| 538 // only be strictly equal if the other is a HeapNumber. | 521 // only be strictly equal if the other is a HeapNumber. |
| 539 __ JumpIfBothNotSmi(lhs, rhs, ¬_smis); | 522 __ JumpIfBothNotSmi(lhs, rhs, ¬_smis); |
| 540 | 523 |
| 541 // Exactly one operand is a smi. EmitSmiNonsmiComparison generates code that | 524 // Exactly one operand is a smi. EmitSmiNonsmiComparison generates code that |
| 542 // can: | 525 // can: |
| 543 // 1) Return the answer. | 526 // 1) Return the answer. |
| 544 // 2) Branch to the slow case. | 527 // 2) Branch to the slow case. |
| 545 // 3) Fall through to both_loaded_as_doubles. | 528 // 3) Fall through to both_loaded_as_doubles. |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 ncr = GREATER; | 638 ncr = GREATER; |
| 656 } else { | 639 } else { |
| 657 DCHECK((cond == gt) || (cond == ge)); // remaining cases | 640 DCHECK((cond == gt) || (cond == ge)); // remaining cases |
| 658 ncr = LESS; | 641 ncr = LESS; |
| 659 } | 642 } |
| 660 __ Mov(x10, Smi::FromInt(ncr)); | 643 __ Mov(x10, Smi::FromInt(ncr)); |
| 661 __ Push(x10); | 644 __ Push(x10); |
| 662 | 645 |
| 663 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 646 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
| 664 // tagged as a small integer. | 647 // tagged as a small integer. |
| 665 __ TailCallRuntime(is_strong(strength()) ? Runtime::kCompare_Strong | 648 __ TailCallRuntime(Runtime::kCompare); |
| 666 : Runtime::kCompare); | |
| 667 } | 649 } |
| 668 | 650 |
| 669 __ Bind(&miss); | 651 __ Bind(&miss); |
| 670 GenerateMiss(masm); | 652 GenerateMiss(masm); |
| 671 } | 653 } |
| 672 | 654 |
| 673 | 655 |
| 674 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 656 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
| 675 CPURegList saved_regs = kCallerSaved; | 657 CPURegList saved_regs = kCallerSaved; |
| 676 CPURegList saved_fp_regs = kCallerSavedFP; | 658 CPURegList saved_fp_regs = kCallerSavedFP; |
| (...skipping 1945 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2622 | 2604 |
| 2623 | 2605 |
| 2624 void CompareICStub::GenerateBooleans(MacroAssembler* masm) { | 2606 void CompareICStub::GenerateBooleans(MacroAssembler* masm) { |
| 2625 // Inputs are in x0 (lhs) and x1 (rhs). | 2607 // Inputs are in x0 (lhs) and x1 (rhs). |
| 2626 DCHECK_EQ(CompareICState::BOOLEAN, state()); | 2608 DCHECK_EQ(CompareICState::BOOLEAN, state()); |
| 2627 ASM_LOCATION("CompareICStub[Booleans]"); | 2609 ASM_LOCATION("CompareICStub[Booleans]"); |
| 2628 Label miss; | 2610 Label miss; |
| 2629 | 2611 |
| 2630 __ CheckMap(x1, x2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK); | 2612 __ CheckMap(x1, x2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK); |
| 2631 __ CheckMap(x0, x3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK); | 2613 __ CheckMap(x0, x3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK); |
| 2632 if (op() != Token::EQ_STRICT && is_strong(strength())) { | 2614 if (!Token::IsEqualityOp(op())) { |
| 2633 __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion); | 2615 __ Ldr(x1, FieldMemOperand(x1, Oddball::kToNumberOffset)); |
| 2634 } else { | 2616 __ AssertSmi(x1); |
| 2635 if (!Token::IsEqualityOp(op())) { | 2617 __ Ldr(x0, FieldMemOperand(x0, Oddball::kToNumberOffset)); |
| 2636 __ Ldr(x1, FieldMemOperand(x1, Oddball::kToNumberOffset)); | 2618 __ AssertSmi(x0); |
| 2637 __ AssertSmi(x1); | |
| 2638 __ Ldr(x0, FieldMemOperand(x0, Oddball::kToNumberOffset)); | |
| 2639 __ AssertSmi(x0); | |
| 2640 } | |
| 2641 __ Sub(x0, x1, x0); | |
| 2642 __ Ret(); | |
| 2643 } | 2619 } |
| 2620 __ Sub(x0, x1, x0); |
| 2621 __ Ret(); |
| 2644 | 2622 |
| 2645 __ Bind(&miss); | 2623 __ Bind(&miss); |
| 2646 GenerateMiss(masm); | 2624 GenerateMiss(masm); |
| 2647 } | 2625 } |
| 2648 | 2626 |
| 2649 | 2627 |
| 2650 void CompareICStub::GenerateSmis(MacroAssembler* masm) { | 2628 void CompareICStub::GenerateSmis(MacroAssembler* masm) { |
| 2651 // Inputs are in x0 (lhs) and x1 (rhs). | 2629 // Inputs are in x0 (lhs) and x1 (rhs). |
| 2652 DCHECK(state() == CompareICState::SMI); | 2630 DCHECK(state() == CompareICState::SMI); |
| 2653 ASM_LOCATION("CompareICStub[Smis]"); | 2631 ASM_LOCATION("CompareICStub[Smis]"); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2707 | 2685 |
| 2708 __ Bind(&values_in_d_regs); | 2686 __ Bind(&values_in_d_regs); |
| 2709 __ Fcmp(lhs_d, rhs_d); | 2687 __ Fcmp(lhs_d, rhs_d); |
| 2710 __ B(vs, &unordered); // Overflow flag set if either is NaN. | 2688 __ B(vs, &unordered); // Overflow flag set if either is NaN. |
| 2711 STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1)); | 2689 STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1)); |
| 2712 __ Cset(result, gt); // gt => 1, otherwise (lt, eq) => 0 (EQUAL). | 2690 __ Cset(result, gt); // gt => 1, otherwise (lt, eq) => 0 (EQUAL). |
| 2713 __ Csinv(result, result, xzr, ge); // lt => -1, gt => 1, eq => 0. | 2691 __ Csinv(result, result, xzr, ge); // lt => -1, gt => 1, eq => 0. |
| 2714 __ Ret(); | 2692 __ Ret(); |
| 2715 | 2693 |
| 2716 __ Bind(&unordered); | 2694 __ Bind(&unordered); |
| 2717 CompareICStub stub(isolate(), op(), strength(), CompareICState::GENERIC, | 2695 CompareICStub stub(isolate(), op(), CompareICState::GENERIC, |
| 2718 CompareICState::GENERIC, CompareICState::GENERIC); | 2696 CompareICState::GENERIC, CompareICState::GENERIC); |
| 2719 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 2697 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 2720 | 2698 |
| 2721 __ Bind(&maybe_undefined1); | 2699 __ Bind(&maybe_undefined1); |
| 2722 if (Token::IsOrderedRelationalCompareOp(op())) { | 2700 if (Token::IsOrderedRelationalCompareOp(op())) { |
| 2723 __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss); | 2701 __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss); |
| 2724 __ JumpIfSmi(lhs, &unordered); | 2702 __ JumpIfSmi(lhs, &unordered); |
| 2725 __ JumpIfNotHeapNumber(lhs, &maybe_undefined2); | 2703 __ JumpIfNotHeapNumber(lhs, &maybe_undefined2); |
| 2726 __ B(&unordered); | 2704 __ B(&unordered); |
| 2727 } | 2705 } |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2938 __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset)); | 2916 __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset)); |
| 2939 __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset)); | 2917 __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset)); |
| 2940 __ Cmp(rhs_map, map); | 2918 __ Cmp(rhs_map, map); |
| 2941 __ B(ne, &miss); | 2919 __ B(ne, &miss); |
| 2942 __ Cmp(lhs_map, map); | 2920 __ Cmp(lhs_map, map); |
| 2943 __ B(ne, &miss); | 2921 __ B(ne, &miss); |
| 2944 | 2922 |
| 2945 if (Token::IsEqualityOp(op())) { | 2923 if (Token::IsEqualityOp(op())) { |
| 2946 __ Sub(result, rhs, lhs); | 2924 __ Sub(result, rhs, lhs); |
| 2947 __ Ret(); | 2925 __ Ret(); |
| 2948 } else if (is_strong(strength())) { | |
| 2949 __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion); | |
| 2950 } else { | 2926 } else { |
| 2951 Register ncr = x2; | 2927 Register ncr = x2; |
| 2952 if (op() == Token::LT || op() == Token::LTE) { | 2928 if (op() == Token::LT || op() == Token::LTE) { |
| 2953 __ Mov(ncr, Smi::FromInt(GREATER)); | 2929 __ Mov(ncr, Smi::FromInt(GREATER)); |
| 2954 } else { | 2930 } else { |
| 2955 __ Mov(ncr, Smi::FromInt(LESS)); | 2931 __ Mov(ncr, Smi::FromInt(LESS)); |
| 2956 } | 2932 } |
| 2957 __ Push(lhs, rhs, ncr); | 2933 __ Push(lhs, rhs, ncr); |
| 2958 __ TailCallRuntime(Runtime::kCompare); | 2934 __ TailCallRuntime(Runtime::kCompare); |
| 2959 } | 2935 } |
| (...skipping 2932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5892 return_value_operand, NULL); | 5868 return_value_operand, NULL); |
| 5893 } | 5869 } |
| 5894 | 5870 |
| 5895 | 5871 |
| 5896 #undef __ | 5872 #undef __ |
| 5897 | 5873 |
| 5898 } // namespace internal | 5874 } // namespace internal |
| 5899 } // namespace v8 | 5875 } // namespace v8 |
| 5900 | 5876 |
| 5901 #endif // V8_TARGET_ARCH_ARM64 | 5877 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |