| 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 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
| 8 | 8 |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 __ Bind(&done); | 196 __ Bind(&done); |
| 197 if (!skip_fastpath()) { | 197 if (!skip_fastpath()) { |
| 198 __ Pop(double_scratch); | 198 __ Pop(double_scratch); |
| 199 } | 199 } |
| 200 __ Pop(scratch2, scratch1); | 200 __ Pop(scratch2, scratch1); |
| 201 __ Ret(); | 201 __ Ret(); |
| 202 } | 202 } |
| 203 | 203 |
| 204 | 204 |
| 205 // See call site for description. | 205 // See call site for description. |
| 206 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 206 static void EmitIdenticalObjectComparison(MacroAssembler* masm, Register left, |
| 207 Register left, | 207 Register right, Register scratch, |
| 208 Register right, | |
| 209 Register scratch, | |
| 210 FPRegister double_scratch, | 208 FPRegister double_scratch, |
| 211 Label* slow, | 209 Label* slow, Condition cond, |
| 212 Condition cond) { | 210 bool strong) { |
| 213 DCHECK(!AreAliased(left, right, scratch)); | 211 DCHECK(!AreAliased(left, right, scratch)); |
| 214 Label not_identical, return_equal, heap_number; | 212 Label not_identical, return_equal, heap_number; |
| 215 Register result = x0; | 213 Register result = x0; |
| 216 | 214 |
| 217 __ Cmp(right, left); | 215 __ Cmp(right, left); |
| 218 __ B(ne, ¬_identical); | 216 __ B(ne, ¬_identical); |
| 219 | 217 |
| 220 // 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(), |
| 221 // so we do the second best thing - test it ourselves. | 219 // so we do the second best thing - test it ourselves. |
| 222 // 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 |
| 223 // Smis. If it's not a heap number, then return equal. | 221 // Smis. If it's not a heap number, then return equal. |
| 224 Register right_type = scratch; | 222 Register right_type = scratch; |
| 225 if ((cond == lt) || (cond == gt)) { | 223 if ((cond == lt) || (cond == gt)) { |
| 224 // Call runtime on identical JSObjects. Otherwise return equal. |
| 226 __ JumpIfObjectType(right, right_type, right_type, FIRST_SPEC_OBJECT_TYPE, | 225 __ JumpIfObjectType(right, right_type, right_type, FIRST_SPEC_OBJECT_TYPE, |
| 227 slow, ge); | 226 slow, ge); |
| 227 // Call runtime on identical symbols since we need to throw a TypeError. |
| 228 __ Cmp(right_type, SYMBOL_TYPE); | 228 __ Cmp(right_type, SYMBOL_TYPE); |
| 229 __ B(eq, slow); | 229 __ B(eq, slow); |
| 230 if (strong) { |
| 231 // Call the runtime on anything that is converted in the semantics, since |
| 232 // we need to throw a TypeError. Smis have already been ruled out. |
| 233 __ Cmp(right_type, Operand(HEAP_NUMBER_TYPE)); |
| 234 __ B(eq, &return_equal); |
| 235 __ Tst(right_type, Operand(kIsNotStringMask)); |
| 236 __ B(ne, slow); |
| 237 } |
| 230 } else if (cond == eq) { | 238 } else if (cond == eq) { |
| 231 __ JumpIfHeapNumber(right, &heap_number); | 239 __ JumpIfHeapNumber(right, &heap_number); |
| 232 } else { | 240 } else { |
| 233 __ JumpIfObjectType(right, right_type, right_type, HEAP_NUMBER_TYPE, | 241 __ JumpIfObjectType(right, right_type, right_type, HEAP_NUMBER_TYPE, |
| 234 &heap_number); | 242 &heap_number); |
| 235 // Comparing JS objects with <=, >= is complicated. | 243 // Comparing JS objects with <=, >= is complicated. |
| 236 __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE); | 244 __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE); |
| 237 __ B(ge, slow); | 245 __ B(ge, slow); |
| 246 // Call runtime on identical symbols since we need to throw a TypeError. |
| 238 __ Cmp(right_type, SYMBOL_TYPE); | 247 __ Cmp(right_type, SYMBOL_TYPE); |
| 239 __ B(eq, slow); | 248 __ B(eq, slow); |
| 249 if (strong) { |
| 250 // Call the runtime on anything that is converted in the semantics, |
| 251 // since we need to throw a TypeError. Smis and heap numbers have |
| 252 // already been ruled out. |
| 253 __ Tst(right_type, Operand(kIsNotStringMask)); |
| 254 __ B(ne, slow); |
| 255 } |
| 240 // Normally here we fall through to return_equal, but undefined is | 256 // Normally here we fall through to return_equal, but undefined is |
| 241 // special: (undefined == undefined) == true, but | 257 // special: (undefined == undefined) == true, but |
| 242 // (undefined <= undefined) == false! See ECMAScript 11.8.5. | 258 // (undefined <= undefined) == false! See ECMAScript 11.8.5. |
| 243 if ((cond == le) || (cond == ge)) { | 259 if ((cond == le) || (cond == ge)) { |
| 244 __ Cmp(right_type, ODDBALL_TYPE); | 260 __ Cmp(right_type, ODDBALL_TYPE); |
| 245 __ B(ne, &return_equal); | 261 __ B(ne, &return_equal); |
| 246 __ JumpIfNotRoot(right, Heap::kUndefinedValueRootIndex, &return_equal); | 262 __ JumpIfNotRoot(right, Heap::kUndefinedValueRootIndex, &return_equal); |
| 247 if (cond == le) { | 263 if (cond == le) { |
| 248 // undefined <= undefined should fail. | 264 // undefined <= undefined should fail. |
| 249 __ Mov(result, GREATER); | 265 __ Mov(result, GREATER); |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 __ Sub(result, lhs, Operand::UntagSmi(rhs)); | 522 __ Sub(result, lhs, Operand::UntagSmi(rhs)); |
| 507 __ Ret(); | 523 __ Ret(); |
| 508 | 524 |
| 509 __ Bind(¬_two_smis); | 525 __ Bind(¬_two_smis); |
| 510 | 526 |
| 511 // NOTICE! This code is only reached after a smi-fast-case check, so it is | 527 // NOTICE! This code is only reached after a smi-fast-case check, so it is |
| 512 // certain that at least one operand isn't a smi. | 528 // certain that at least one operand isn't a smi. |
| 513 | 529 |
| 514 // Handle the case where the objects are identical. Either returns the answer | 530 // Handle the case where the objects are identical. Either returns the answer |
| 515 // or goes to slow. Only falls through if the objects were not identical. | 531 // or goes to slow. Only falls through if the objects were not identical. |
| 516 EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond); | 532 EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond, strong()); |
| 517 | 533 |
| 518 // If either is a smi (we know that at least one is not a smi), then they can | 534 // If either is a smi (we know that at least one is not a smi), then they can |
| 519 // only be strictly equal if the other is a HeapNumber. | 535 // only be strictly equal if the other is a HeapNumber. |
| 520 __ JumpIfBothNotSmi(lhs, rhs, ¬_smis); | 536 __ JumpIfBothNotSmi(lhs, rhs, ¬_smis); |
| 521 | 537 |
| 522 // Exactly one operand is a smi. EmitSmiNonsmiComparison generates code that | 538 // Exactly one operand is a smi. EmitSmiNonsmiComparison generates code that |
| 523 // can: | 539 // can: |
| 524 // 1) Return the answer. | 540 // 1) Return the answer. |
| 525 // 2) Branch to the slow case. | 541 // 2) Branch to the slow case. |
| 526 // 3) Fall through to both_loaded_as_doubles. | 542 // 3) Fall through to both_loaded_as_doubles. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 } | 641 } |
| 626 | 642 |
| 627 __ Bind(&slow); | 643 __ Bind(&slow); |
| 628 | 644 |
| 629 __ Push(lhs, rhs); | 645 __ Push(lhs, rhs); |
| 630 // Figure out which native to call and setup the arguments. | 646 // Figure out which native to call and setup the arguments. |
| 631 Builtins::JavaScript native; | 647 Builtins::JavaScript native; |
| 632 if (cond == eq) { | 648 if (cond == eq) { |
| 633 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 649 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
| 634 } else { | 650 } else { |
| 635 native = Builtins::COMPARE; | 651 native = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE; |
| 636 int ncr; // NaN compare result | 652 int ncr; // NaN compare result |
| 637 if ((cond == lt) || (cond == le)) { | 653 if ((cond == lt) || (cond == le)) { |
| 638 ncr = GREATER; | 654 ncr = GREATER; |
| 639 } else { | 655 } else { |
| 640 DCHECK((cond == gt) || (cond == ge)); // remaining cases | 656 DCHECK((cond == gt) || (cond == ge)); // remaining cases |
| 641 ncr = LESS; | 657 ncr = LESS; |
| 642 } | 658 } |
| 643 __ Mov(x10, Smi::FromInt(ncr)); | 659 __ Mov(x10, Smi::FromInt(ncr)); |
| 644 __ Push(x10); | 660 __ Push(x10); |
| 645 } | 661 } |
| (...skipping 2832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3478 | 3494 |
| 3479 __ Bind(&values_in_d_regs); | 3495 __ Bind(&values_in_d_regs); |
| 3480 __ Fcmp(lhs_d, rhs_d); | 3496 __ Fcmp(lhs_d, rhs_d); |
| 3481 __ B(vs, &unordered); // Overflow flag set if either is NaN. | 3497 __ B(vs, &unordered); // Overflow flag set if either is NaN. |
| 3482 STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1)); | 3498 STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1)); |
| 3483 __ Cset(result, gt); // gt => 1, otherwise (lt, eq) => 0 (EQUAL). | 3499 __ Cset(result, gt); // gt => 1, otherwise (lt, eq) => 0 (EQUAL). |
| 3484 __ Csinv(result, result, xzr, ge); // lt => -1, gt => 1, eq => 0. | 3500 __ Csinv(result, result, xzr, ge); // lt => -1, gt => 1, eq => 0. |
| 3485 __ Ret(); | 3501 __ Ret(); |
| 3486 | 3502 |
| 3487 __ Bind(&unordered); | 3503 __ Bind(&unordered); |
| 3488 CompareICStub stub(isolate(), op(), CompareICState::GENERIC, | 3504 CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC, |
| 3489 CompareICState::GENERIC, CompareICState::GENERIC); | 3505 CompareICState::GENERIC, CompareICState::GENERIC); |
| 3490 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 3506 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 3491 | 3507 |
| 3492 __ Bind(&maybe_undefined1); | 3508 __ Bind(&maybe_undefined1); |
| 3493 if (Token::IsOrderedRelationalCompareOp(op())) { | 3509 if (Token::IsOrderedRelationalCompareOp(op())) { |
| 3494 __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss); | 3510 __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss); |
| 3495 __ JumpIfSmi(lhs, &unordered); | 3511 __ JumpIfSmi(lhs, &unordered); |
| 3496 __ JumpIfNotHeapNumber(lhs, &maybe_undefined2); | 3512 __ JumpIfNotHeapNumber(lhs, &maybe_undefined2); |
| 3497 __ B(&unordered); | 3513 __ B(&unordered); |
| 3498 } | 3514 } |
| (...skipping 2262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5761 kStackUnwindSpace, NULL, spill_offset, | 5777 kStackUnwindSpace, NULL, spill_offset, |
| 5762 MemOperand(fp, 6 * kPointerSize), NULL); | 5778 MemOperand(fp, 6 * kPointerSize), NULL); |
| 5763 } | 5779 } |
| 5764 | 5780 |
| 5765 | 5781 |
| 5766 #undef __ | 5782 #undef __ |
| 5767 | 5783 |
| 5768 } } // namespace v8::internal | 5784 } } // namespace v8::internal |
| 5769 | 5785 |
| 5770 #endif // V8_TARGET_ARCH_ARM64 | 5786 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |