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 |