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_X64 | 7 #if V8_TARGET_ARCH_X64 |
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 1515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1526 __ movp(scratch, FieldOperand(object, HeapObject::kMapOffset)); | 1526 __ movp(scratch, FieldOperand(object, HeapObject::kMapOffset)); |
1527 __ movzxbp(scratch, | 1527 __ movzxbp(scratch, |
1528 FieldOperand(scratch, Map::kInstanceTypeOffset)); | 1528 FieldOperand(scratch, Map::kInstanceTypeOffset)); |
1529 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); | 1529 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
1530 __ testb(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); | 1530 __ testb(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask)); |
1531 __ j(not_zero, label); | 1531 __ j(not_zero, label); |
1532 } | 1532 } |
1533 | 1533 |
1534 | 1534 |
1535 void CompareICStub::GenerateGeneric(MacroAssembler* masm) { | 1535 void CompareICStub::GenerateGeneric(MacroAssembler* masm) { |
1536 Label check_unequal_objects, done; | 1536 Label runtime_call, check_unequal_objects, done; |
1537 Condition cc = GetCondition(); | 1537 Condition cc = GetCondition(); |
1538 Factory* factory = isolate()->factory(); | 1538 Factory* factory = isolate()->factory(); |
1539 | 1539 |
1540 Label miss; | 1540 Label miss; |
1541 CheckInputType(masm, rdx, left(), &miss); | 1541 CheckInputType(masm, rdx, left(), &miss); |
1542 CheckInputType(masm, rax, right(), &miss); | 1542 CheckInputType(masm, rax, right(), &miss); |
1543 | 1543 |
1544 // Compare two smis. | 1544 // Compare two smis. |
1545 Label non_smi, smi_done; | 1545 Label non_smi, smi_done; |
1546 __ JumpIfNotBothSmi(rax, rdx, &non_smi); | 1546 __ JumpIfNotBothSmi(rax, rdx, &non_smi); |
(...skipping 12 matching lines...) Expand all Loading... |
1559 | 1559 |
1560 // Two identical objects are equal unless they are both NaN or undefined. | 1560 // Two identical objects are equal unless they are both NaN or undefined. |
1561 { | 1561 { |
1562 Label not_identical; | 1562 Label not_identical; |
1563 __ cmpp(rax, rdx); | 1563 __ cmpp(rax, rdx); |
1564 __ j(not_equal, ¬_identical, Label::kNear); | 1564 __ j(not_equal, ¬_identical, Label::kNear); |
1565 | 1565 |
1566 if (cc != equal) { | 1566 if (cc != equal) { |
1567 // Check for undefined. undefined OP undefined is false even though | 1567 // Check for undefined. undefined OP undefined is false even though |
1568 // undefined == undefined. | 1568 // undefined == undefined. |
1569 Label check_for_nan; | |
1570 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 1569 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
1571 __ j(not_equal, &check_for_nan, Label::kNear); | 1570 if (strong()) { |
1572 __ Set(rax, NegativeComparisonResult(cc)); | 1571 // In strong mode, this comparison must throw, so call the runtime. |
1573 __ ret(0); | 1572 __ j(equal, &runtime_call, Label::kFar); |
1574 __ bind(&check_for_nan); | 1573 } else { |
| 1574 Label check_for_nan; |
| 1575 __ j(not_equal, &check_for_nan, Label::kNear); |
| 1576 __ Set(rax, NegativeComparisonResult(cc)); |
| 1577 __ ret(0); |
| 1578 __ bind(&check_for_nan); |
| 1579 } |
1575 } | 1580 } |
1576 | 1581 |
1577 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), | 1582 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), |
1578 // so we do the second best thing - test it ourselves. | 1583 // so we do the second best thing - test it ourselves. |
1579 Label heap_number; | 1584 Label heap_number; |
1580 // If it's not a heap number, then return equal for (in)equality operator. | 1585 // If it's not a heap number, then return equal for (in)equality operator. |
1581 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), | 1586 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), |
1582 factory->heap_number_map()); | 1587 factory->heap_number_map()); |
1583 __ j(equal, &heap_number, Label::kNear); | 1588 __ j(equal, &heap_number, Label::kNear); |
1584 if (cc != equal) { | 1589 if (cc != equal) { |
| 1590 __ movp(rcx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 1591 __ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); |
1585 // Call runtime on identical objects. Otherwise return equal. | 1592 // Call runtime on identical objects. Otherwise return equal. |
1586 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); | 1593 __ cmpb(rcx, Immediate(static_cast<uint8_t>(FIRST_SPEC_OBJECT_TYPE))); |
1587 __ j(above_equal, ¬_identical, Label::kNear); | 1594 __ j(above_equal, &runtime_call, Label::kFar); |
1588 // Call runtime on identical symbols since we need to throw a TypeError. | 1595 // Call runtime on identical symbols since we need to throw a TypeError. |
1589 __ CmpObjectType(rax, SYMBOL_TYPE, rcx); | 1596 __ cmpb(rcx, Immediate(static_cast<uint8_t>(SYMBOL_TYPE))); |
1590 __ j(equal, ¬_identical, Label::kNear); | 1597 __ j(equal, &runtime_call, Label::kFar); |
| 1598 if (strong()) { |
| 1599 // We have already tested for smis and heap numbers, so if both |
| 1600 // arguments are not strings we must proceed to the slow case. |
| 1601 __ testb(rcx, Immediate(kIsNotStringMask)); |
| 1602 __ j(not_zero, &runtime_call, Label::kFar); |
| 1603 } |
1591 } | 1604 } |
1592 __ Set(rax, EQUAL); | 1605 __ Set(rax, EQUAL); |
1593 __ ret(0); | 1606 __ ret(0); |
1594 | 1607 |
1595 __ bind(&heap_number); | 1608 __ bind(&heap_number); |
1596 // It is a heap number, so return equal if it's not NaN. | 1609 // It is a heap number, so return equal if it's not NaN. |
1597 // For NaN, return 1 for every condition except greater and | 1610 // For NaN, return 1 for every condition except greater and |
1598 // greater-equal. Return -1 for them, so the comparison yields | 1611 // greater-equal. Return -1 for them, so the comparison yields |
1599 // false for all conditions except not-equal. | 1612 // false for all conditions except not-equal. |
1600 __ Set(rax, EQUAL); | 1613 __ Set(rax, EQUAL); |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1727 | 1740 |
1728 #ifdef DEBUG | 1741 #ifdef DEBUG |
1729 __ Abort(kUnexpectedFallThroughFromStringComparison); | 1742 __ Abort(kUnexpectedFallThroughFromStringComparison); |
1730 #endif | 1743 #endif |
1731 | 1744 |
1732 __ bind(&check_unequal_objects); | 1745 __ bind(&check_unequal_objects); |
1733 if (cc == equal && !strict()) { | 1746 if (cc == equal && !strict()) { |
1734 // Not strict equality. Objects are unequal if | 1747 // Not strict equality. Objects are unequal if |
1735 // they are both JSObjects and not undetectable, | 1748 // they are both JSObjects and not undetectable, |
1736 // and their pointers are different. | 1749 // and their pointers are different. |
1737 Label not_both_objects, return_unequal; | 1750 Label return_unequal; |
1738 // At most one is a smi, so we can test for smi by adding the two. | 1751 // At most one is a smi, so we can test for smi by adding the two. |
1739 // A smi plus a heap object has the low bit set, a heap object plus | 1752 // A smi plus a heap object has the low bit set, a heap object plus |
1740 // a heap object has the low bit clear. | 1753 // a heap object has the low bit clear. |
1741 STATIC_ASSERT(kSmiTag == 0); | 1754 STATIC_ASSERT(kSmiTag == 0); |
1742 STATIC_ASSERT(kSmiTagMask == 1); | 1755 STATIC_ASSERT(kSmiTagMask == 1); |
1743 __ leap(rcx, Operand(rax, rdx, times_1, 0)); | 1756 __ leap(rcx, Operand(rax, rdx, times_1, 0)); |
1744 __ testb(rcx, Immediate(kSmiTagMask)); | 1757 __ testb(rcx, Immediate(kSmiTagMask)); |
1745 __ j(not_zero, ¬_both_objects, Label::kNear); | 1758 __ j(not_zero, &runtime_call, Label::kNear); |
1746 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx); | 1759 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx); |
1747 __ j(below, ¬_both_objects, Label::kNear); | 1760 __ j(below, &runtime_call, Label::kNear); |
1748 __ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx); | 1761 __ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx); |
1749 __ j(below, ¬_both_objects, Label::kNear); | 1762 __ j(below, &runtime_call, Label::kNear); |
1750 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 1763 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
1751 Immediate(1 << Map::kIsUndetectable)); | 1764 Immediate(1 << Map::kIsUndetectable)); |
1752 __ j(zero, &return_unequal, Label::kNear); | 1765 __ j(zero, &return_unequal, Label::kNear); |
1753 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | 1766 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), |
1754 Immediate(1 << Map::kIsUndetectable)); | 1767 Immediate(1 << Map::kIsUndetectable)); |
1755 __ j(zero, &return_unequal, Label::kNear); | 1768 __ j(zero, &return_unequal, Label::kNear); |
1756 // The objects are both undetectable, so they both compare as the value | 1769 // The objects are both undetectable, so they both compare as the value |
1757 // undefined, and are equal. | 1770 // undefined, and are equal. |
1758 __ Set(rax, EQUAL); | 1771 __ Set(rax, EQUAL); |
1759 __ bind(&return_unequal); | 1772 __ bind(&return_unequal); |
1760 // Return non-equal by returning the non-zero object pointer in rax, | 1773 // Return non-equal by returning the non-zero object pointer in rax, |
1761 // or return equal if we fell through to here. | 1774 // or return equal if we fell through to here. |
1762 __ ret(0); | 1775 __ ret(0); |
1763 __ bind(¬_both_objects); | |
1764 } | 1776 } |
| 1777 __ bind(&runtime_call); |
1765 | 1778 |
1766 // Push arguments below the return address to prepare jump to builtin. | 1779 // Push arguments below the return address to prepare jump to builtin. |
1767 __ PopReturnAddressTo(rcx); | 1780 __ PopReturnAddressTo(rcx); |
1768 __ Push(rdx); | 1781 __ Push(rdx); |
1769 __ Push(rax); | 1782 __ Push(rax); |
1770 | 1783 |
1771 // Figure out which native to call and setup the arguments. | 1784 // Figure out which native to call and setup the arguments. |
1772 Builtins::JavaScript builtin; | 1785 Builtins::JavaScript builtin; |
1773 if (cc == equal) { | 1786 if (cc == equal) { |
1774 builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 1787 builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
1775 } else { | 1788 } else { |
1776 builtin = Builtins::COMPARE; | 1789 builtin = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE; |
1777 __ Push(Smi::FromInt(NegativeComparisonResult(cc))); | 1790 __ Push(Smi::FromInt(NegativeComparisonResult(cc))); |
1778 } | 1791 } |
1779 | 1792 |
1780 __ PushReturnAddressFrom(rcx); | 1793 __ PushReturnAddressFrom(rcx); |
1781 | 1794 |
1782 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 1795 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
1783 // tagged as a small integer. | 1796 // tagged as a small integer. |
1784 __ InvokeBuiltin(builtin, JUMP_FUNCTION); | 1797 __ InvokeBuiltin(builtin, JUMP_FUNCTION); |
1785 | 1798 |
1786 __ bind(&miss); | 1799 __ bind(&miss); |
(...skipping 1804 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3591 // Return a result of -1, 0, or 1, based on EFLAGS. | 3604 // Return a result of -1, 0, or 1, based on EFLAGS. |
3592 // Performing mov, because xor would destroy the flag register. | 3605 // Performing mov, because xor would destroy the flag register. |
3593 __ movl(rax, Immediate(0)); | 3606 __ movl(rax, Immediate(0)); |
3594 __ movl(rcx, Immediate(0)); | 3607 __ movl(rcx, Immediate(0)); |
3595 __ setcc(above, rax); // Add one to zero if carry clear and not equal. | 3608 __ setcc(above, rax); // Add one to zero if carry clear and not equal. |
3596 __ sbbp(rax, rcx); // Subtract one if below (aka. carry set). | 3609 __ sbbp(rax, rcx); // Subtract one if below (aka. carry set). |
3597 __ ret(0); | 3610 __ ret(0); |
3598 | 3611 |
3599 __ bind(&unordered); | 3612 __ bind(&unordered); |
3600 __ bind(&generic_stub); | 3613 __ bind(&generic_stub); |
3601 CompareICStub stub(isolate(), op(), CompareICState::GENERIC, | 3614 CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC, |
3602 CompareICState::GENERIC, CompareICState::GENERIC); | 3615 CompareICState::GENERIC, CompareICState::GENERIC); |
3603 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); | 3616 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); |
3604 | 3617 |
3605 __ bind(&maybe_undefined1); | 3618 __ bind(&maybe_undefined1); |
3606 if (Token::IsOrderedRelationalCompareOp(op())) { | 3619 if (Token::IsOrderedRelationalCompareOp(op())) { |
3607 __ Cmp(rax, isolate()->factory()->undefined_value()); | 3620 __ Cmp(rax, isolate()->factory()->undefined_value()); |
3608 __ j(not_equal, &miss); | 3621 __ j(not_equal, &miss); |
3609 __ JumpIfSmi(rdx, &unordered); | 3622 __ JumpIfSmi(rdx, &unordered); |
3610 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); | 3623 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx); |
3611 __ j(not_equal, &maybe_undefined2, Label::kNear); | 3624 __ j(not_equal, &maybe_undefined2, Label::kNear); |
(...skipping 1750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5362 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, getter_arg, | 5375 CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, getter_arg, |
5363 kStackSpace, nullptr, return_value_operand, NULL); | 5376 kStackSpace, nullptr, return_value_operand, NULL); |
5364 } | 5377 } |
5365 | 5378 |
5366 | 5379 |
5367 #undef __ | 5380 #undef __ |
5368 | 5381 |
5369 } } // namespace v8::internal | 5382 } } // namespace v8::internal |
5370 | 5383 |
5371 #endif // V8_TARGET_ARCH_X64 | 5384 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |