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 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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, Register left, | 206 static void EmitIdenticalObjectComparison(MacroAssembler* masm, Register left, |
207 Register right, Register scratch, | 207 Register right, Register scratch, |
208 FPRegister double_scratch, | 208 FPRegister double_scratch, |
209 Label* slow, Condition cond, | 209 Label* slow, Condition cond, |
210 bool strong) { | 210 Strength strength) { |
211 DCHECK(!AreAliased(left, right, scratch)); | 211 DCHECK(!AreAliased(left, right, scratch)); |
212 Label not_identical, return_equal, heap_number; | 212 Label not_identical, return_equal, heap_number; |
213 Register result = x0; | 213 Register result = x0; |
214 | 214 |
215 __ Cmp(right, left); | 215 __ Cmp(right, left); |
216 __ B(ne, ¬_identical); | 216 __ B(ne, ¬_identical); |
217 | 217 |
218 // 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(), |
219 // so we do the second best thing - test it ourselves. | 219 // so we do the second best thing - test it ourselves. |
220 // 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 |
221 // Smis. If it's not a heap number, then return equal. | 221 // Smis. If it's not a heap number, then return equal. |
222 Register right_type = scratch; | 222 Register right_type = scratch; |
223 if ((cond == lt) || (cond == gt)) { | 223 if ((cond == lt) || (cond == gt)) { |
224 // Call runtime on identical JSObjects. Otherwise return equal. | 224 // Call runtime on identical JSObjects. Otherwise return equal. |
225 __ JumpIfObjectType(right, right_type, right_type, FIRST_SPEC_OBJECT_TYPE, | 225 __ JumpIfObjectType(right, right_type, right_type, FIRST_SPEC_OBJECT_TYPE, |
226 slow, ge); | 226 slow, ge); |
227 // 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. |
228 __ Cmp(right_type, SYMBOL_TYPE); | 228 __ Cmp(right_type, SYMBOL_TYPE); |
229 __ B(eq, slow); | 229 __ B(eq, slow); |
230 if (strong) { | 230 if (is_strong(strength)) { |
231 // Call the runtime on anything that is converted in the semantics, since | 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. | 232 // we need to throw a TypeError. Smis have already been ruled out. |
233 __ Cmp(right_type, Operand(HEAP_NUMBER_TYPE)); | 233 __ Cmp(right_type, Operand(HEAP_NUMBER_TYPE)); |
234 __ B(eq, &return_equal); | 234 __ B(eq, &return_equal); |
235 __ Tst(right_type, Operand(kIsNotStringMask)); | 235 __ Tst(right_type, Operand(kIsNotStringMask)); |
236 __ B(ne, slow); | 236 __ B(ne, slow); |
237 } | 237 } |
238 } else if (cond == eq) { | 238 } else if (cond == eq) { |
239 __ JumpIfHeapNumber(right, &heap_number); | 239 __ JumpIfHeapNumber(right, &heap_number); |
240 } else { | 240 } else { |
241 __ JumpIfObjectType(right, right_type, right_type, HEAP_NUMBER_TYPE, | 241 __ JumpIfObjectType(right, right_type, right_type, HEAP_NUMBER_TYPE, |
242 &heap_number); | 242 &heap_number); |
243 // Comparing JS objects with <=, >= is complicated. | 243 // Comparing JS objects with <=, >= is complicated. |
244 __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE); | 244 __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE); |
245 __ B(ge, slow); | 245 __ B(ge, slow); |
246 // Call runtime on identical symbols since we need to throw a TypeError. | 246 // Call runtime on identical symbols since we need to throw a TypeError. |
247 __ Cmp(right_type, SYMBOL_TYPE); | 247 __ Cmp(right_type, SYMBOL_TYPE); |
248 __ B(eq, slow); | 248 __ B(eq, slow); |
249 if (strong) { | 249 if (is_strong(strength)) { |
250 // Call the runtime on anything that is converted in the semantics, | 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 | 251 // since we need to throw a TypeError. Smis and heap numbers have |
252 // already been ruled out. | 252 // already been ruled out. |
253 __ Tst(right_type, Operand(kIsNotStringMask)); | 253 __ Tst(right_type, Operand(kIsNotStringMask)); |
254 __ B(ne, slow); | 254 __ B(ne, slow); |
255 } | 255 } |
256 // Normally here we fall through to return_equal, but undefined is | 256 // Normally here we fall through to return_equal, but undefined is |
257 // special: (undefined == undefined) == true, but | 257 // special: (undefined == undefined) == true, but |
258 // (undefined <= undefined) == false! See ECMAScript 11.8.5. | 258 // (undefined <= undefined) == false! See ECMAScript 11.8.5. |
259 if ((cond == le) || (cond == ge)) { | 259 if ((cond == le) || (cond == ge)) { |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 __ Sub(result, lhs, Operand::UntagSmi(rhs)); | 522 __ Sub(result, lhs, Operand::UntagSmi(rhs)); |
523 __ Ret(); | 523 __ Ret(); |
524 | 524 |
525 __ Bind(¬_two_smis); | 525 __ Bind(¬_two_smis); |
526 | 526 |
527 // 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 |
528 // certain that at least one operand isn't a smi. | 528 // certain that at least one operand isn't a smi. |
529 | 529 |
530 // 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 |
531 // 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. |
532 EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond, strong()); | 532 EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond, |
| 533 strength()); |
533 | 534 |
534 // If either is a smi (we know that at least one is not a smi), then they can | 535 // If either is a smi (we know that at least one is not a smi), then they can |
535 // only be strictly equal if the other is a HeapNumber. | 536 // only be strictly equal if the other is a HeapNumber. |
536 __ JumpIfBothNotSmi(lhs, rhs, ¬_smis); | 537 __ JumpIfBothNotSmi(lhs, rhs, ¬_smis); |
537 | 538 |
538 // Exactly one operand is a smi. EmitSmiNonsmiComparison generates code that | 539 // Exactly one operand is a smi. EmitSmiNonsmiComparison generates code that |
539 // can: | 540 // can: |
540 // 1) Return the answer. | 541 // 1) Return the answer. |
541 // 2) Branch to the slow case. | 542 // 2) Branch to the slow case. |
542 // 3) Fall through to both_loaded_as_doubles. | 543 // 3) Fall through to both_loaded_as_doubles. |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 } | 642 } |
642 | 643 |
643 __ Bind(&slow); | 644 __ Bind(&slow); |
644 | 645 |
645 __ Push(lhs, rhs); | 646 __ Push(lhs, rhs); |
646 // Figure out which native to call and setup the arguments. | 647 // Figure out which native to call and setup the arguments. |
647 Builtins::JavaScript native; | 648 Builtins::JavaScript native; |
648 if (cond == eq) { | 649 if (cond == eq) { |
649 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 650 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
650 } else { | 651 } else { |
651 native = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE; | 652 native = |
| 653 is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE; |
652 int ncr; // NaN compare result | 654 int ncr; // NaN compare result |
653 if ((cond == lt) || (cond == le)) { | 655 if ((cond == lt) || (cond == le)) { |
654 ncr = GREATER; | 656 ncr = GREATER; |
655 } else { | 657 } else { |
656 DCHECK((cond == gt) || (cond == ge)); // remaining cases | 658 DCHECK((cond == gt) || (cond == ge)); // remaining cases |
657 ncr = LESS; | 659 ncr = LESS; |
658 } | 660 } |
659 __ Mov(x10, Smi::FromInt(ncr)); | 661 __ Mov(x10, Smi::FromInt(ncr)); |
660 __ Push(x10); | 662 __ Push(x10); |
661 } | 663 } |
(...skipping 2833 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3495 | 3497 |
3496 __ Bind(&values_in_d_regs); | 3498 __ Bind(&values_in_d_regs); |
3497 __ Fcmp(lhs_d, rhs_d); | 3499 __ Fcmp(lhs_d, rhs_d); |
3498 __ B(vs, &unordered); // Overflow flag set if either is NaN. | 3500 __ B(vs, &unordered); // Overflow flag set if either is NaN. |
3499 STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1)); | 3501 STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1)); |
3500 __ Cset(result, gt); // gt => 1, otherwise (lt, eq) => 0 (EQUAL). | 3502 __ Cset(result, gt); // gt => 1, otherwise (lt, eq) => 0 (EQUAL). |
3501 __ Csinv(result, result, xzr, ge); // lt => -1, gt => 1, eq => 0. | 3503 __ Csinv(result, result, xzr, ge); // lt => -1, gt => 1, eq => 0. |
3502 __ Ret(); | 3504 __ Ret(); |
3503 | 3505 |
3504 __ Bind(&unordered); | 3506 __ Bind(&unordered); |
3505 CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC, | 3507 CompareICStub stub(isolate(), op(), strength(), CompareICState::GENERIC, |
3506 CompareICState::GENERIC, CompareICState::GENERIC); | 3508 CompareICState::GENERIC, CompareICState::GENERIC); |
3507 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 3509 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
3508 | 3510 |
3509 __ Bind(&maybe_undefined1); | 3511 __ Bind(&maybe_undefined1); |
3510 if (Token::IsOrderedRelationalCompareOp(op())) { | 3512 if (Token::IsOrderedRelationalCompareOp(op())) { |
3511 __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss); | 3513 __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss); |
3512 __ JumpIfSmi(lhs, &unordered); | 3514 __ JumpIfSmi(lhs, &unordered); |
3513 __ JumpIfNotHeapNumber(lhs, &maybe_undefined2); | 3515 __ JumpIfNotHeapNumber(lhs, &maybe_undefined2); |
3514 __ B(&unordered); | 3516 __ B(&unordered); |
3515 } | 3517 } |
(...skipping 2313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5829 MemOperand(fp, 6 * kPointerSize), NULL); | 5831 MemOperand(fp, 6 * kPointerSize), NULL); |
5830 } | 5832 } |
5831 | 5833 |
5832 | 5834 |
5833 #undef __ | 5835 #undef __ |
5834 | 5836 |
5835 } // namespace internal | 5837 } // namespace internal |
5836 } // namespace v8 | 5838 } // namespace v8 |
5837 | 5839 |
5838 #endif // V8_TARGET_ARCH_ARM64 | 5840 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |