| OLD | NEW | 
|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. | 
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without | 
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are | 
| 4 // met: | 4 // met: | 
| 5 // | 5 // | 
| 6 //     * Redistributions of source code must retain the above copyright | 6 //     * Redistributions of source code must retain the above copyright | 
| 7 //       notice, this list of conditions and the following disclaimer. | 7 //       notice, this list of conditions and the following disclaimer. | 
| 8 //     * Redistributions in binary form must reproduce the above | 8 //     * Redistributions in binary form must reproduce the above | 
| 9 //       copyright notice, this list of conditions and the following | 9 //       copyright notice, this list of conditions and the following | 
| 10 //       disclaimer in the documentation and/or other materials provided | 10 //       disclaimer in the documentation and/or other materials provided | 
| (...skipping 1488 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1499 | 1499 | 
| 1500 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | 1500 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | 
| 1501   __ pop(rcx); | 1501   __ pop(rcx); | 
| 1502   __ push(rdx); | 1502   __ push(rdx); | 
| 1503   __ push(rax); | 1503   __ push(rax); | 
| 1504   __ push(rcx); | 1504   __ push(rcx); | 
| 1505 } | 1505 } | 
| 1506 | 1506 | 
| 1507 | 1507 | 
| 1508 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 1508 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 
| 1509   // Input on stack: | 1509   // TAGGED case: | 
| 1510   // rsp[8]: argument (should be number). | 1510   //   Input: | 
| 1511   // rsp[0]: return address. | 1511   //     rsp[8]: argument (should be number). | 
|  | 1512   //     rsp[0]: return address. | 
|  | 1513   //   Output: | 
|  | 1514   //     rax: tagged double result. | 
|  | 1515   // UNTAGGED case: | 
|  | 1516   //   Input:: | 
|  | 1517   //     rsp[0]: return address. | 
|  | 1518   //     xmm1: untagged double input argument | 
|  | 1519   //   Output: | 
|  | 1520   //     xmm1: untagged double result. | 
|  | 1521 | 
| 1512   Label runtime_call; | 1522   Label runtime_call; | 
| 1513   Label runtime_call_clear_stack; | 1523   Label runtime_call_clear_stack; | 
| 1514   Label input_not_smi; | 1524   Label skip_cache; | 
| 1515   NearLabel loaded; | 1525   const bool tagged = (argument_type_ == TAGGED); | 
| 1516   // Test that rax is a number. | 1526   if (tagged) { | 
| 1517   __ movq(rax, Operand(rsp, kPointerSize)); | 1527     NearLabel input_not_smi; | 
| 1518   __ JumpIfNotSmi(rax, &input_not_smi); | 1528     NearLabel loaded; | 
| 1519   // Input is a smi. Untag and load it onto the FPU stack. | 1529     // Test that rax is a number. | 
| 1520   // Then load the bits of the double into rbx. | 1530     __ movq(rax, Operand(rsp, kPointerSize)); | 
| 1521   __ SmiToInteger32(rax, rax); | 1531     __ JumpIfNotSmi(rax, &input_not_smi); | 
| 1522   __ subq(rsp, Immediate(kPointerSize)); | 1532     // Input is a smi. Untag and load it onto the FPU stack. | 
| 1523   __ cvtlsi2sd(xmm1, rax); | 1533     // Then load the bits of the double into rbx. | 
| 1524   __ movsd(Operand(rsp, 0), xmm1); | 1534     __ SmiToInteger32(rax, rax); | 
| 1525   __ movq(rbx, xmm1); | 1535     __ subq(rsp, Immediate(kDoubleSize)); | 
| 1526   __ movq(rdx, xmm1); | 1536     __ cvtlsi2sd(xmm1, rax); | 
| 1527   __ fld_d(Operand(rsp, 0)); | 1537     __ movsd(Operand(rsp, 0), xmm1); | 
| 1528   __ addq(rsp, Immediate(kPointerSize)); | 1538     __ movq(rbx, xmm1); | 
| 1529   __ jmp(&loaded); | 1539     __ movq(rdx, xmm1); | 
|  | 1540     __ fld_d(Operand(rsp, 0)); | 
|  | 1541     __ addq(rsp, Immediate(kDoubleSize)); | 
|  | 1542     __ jmp(&loaded); | 
| 1530 | 1543 | 
| 1531   __ bind(&input_not_smi); | 1544     __ bind(&input_not_smi); | 
| 1532   // Check if input is a HeapNumber. | 1545     // Check if input is a HeapNumber. | 
| 1533   __ Move(rbx, Factory::heap_number_map()); | 1546     __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex); | 
| 1534   __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 1547     __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 
| 1535   __ j(not_equal, &runtime_call); | 1548     __ j(not_equal, &runtime_call); | 
| 1536   // Input is a HeapNumber. Push it on the FPU stack and load its | 1549     // Input is a HeapNumber. Push it on the FPU stack and load its | 
| 1537   // bits into rbx. | 1550     // bits into rbx. | 
| 1538   __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 1551     __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 
| 1539   __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); | 1552     __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); | 
| 1540   __ movq(rdx, rbx); | 1553     __ movq(rdx, rbx); | 
| 1541   __ bind(&loaded); | 1554 | 
| 1542   // ST[0] == double value | 1555     __ bind(&loaded); | 
|  | 1556   } else {  // UNTAGGED. | 
|  | 1557     __ movq(rbx, xmm1); | 
|  | 1558     __ movq(rdx, xmm1); | 
|  | 1559   } | 
|  | 1560 | 
|  | 1561   // ST[0] == double value, if TAGGED. | 
| 1543   // rbx = bits of double value. | 1562   // rbx = bits of double value. | 
| 1544   // rdx = also bits of double value. | 1563   // rdx = also bits of double value. | 
| 1545   // Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic): | 1564   // Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic): | 
| 1546   //   h = h0 = bits ^ (bits >> 32); | 1565   //   h = h0 = bits ^ (bits >> 32); | 
| 1547   //   h ^= h >> 16; | 1566   //   h ^= h >> 16; | 
| 1548   //   h ^= h >> 8; | 1567   //   h ^= h >> 8; | 
| 1549   //   h = h & (cacheSize - 1); | 1568   //   h = h & (cacheSize - 1); | 
| 1550   // or h = (h0 ^ (h0 >> 8) ^ (h0 >> 16) ^ (h0 >> 24)) & (cacheSize - 1) | 1569   // or h = (h0 ^ (h0 >> 8) ^ (h0 >> 16) ^ (h0 >> 24)) & (cacheSize - 1) | 
| 1551   __ sar(rdx, Immediate(32)); | 1570   __ sar(rdx, Immediate(32)); | 
| 1552   __ xorl(rdx, rbx); | 1571   __ xorl(rdx, rbx); | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 1564 | 1583 | 
| 1565   // ST[0] == double value. | 1584   // ST[0] == double value. | 
| 1566   // rbx = bits of double value. | 1585   // rbx = bits of double value. | 
| 1567   // rcx = TranscendentalCache::hash(double value). | 1586   // rcx = TranscendentalCache::hash(double value). | 
| 1568   __ movq(rax, ExternalReference::transcendental_cache_array_address()); | 1587   __ movq(rax, ExternalReference::transcendental_cache_array_address()); | 
| 1569   // rax points to cache array. | 1588   // rax points to cache array. | 
| 1570   __ movq(rax, Operand(rax, type_ * sizeof(TranscendentalCache::caches_[0]))); | 1589   __ movq(rax, Operand(rax, type_ * sizeof(TranscendentalCache::caches_[0]))); | 
| 1571   // rax points to the cache for the type type_. | 1590   // rax points to the cache for the type type_. | 
| 1572   // If NULL, the cache hasn't been initialized yet, so go through runtime. | 1591   // If NULL, the cache hasn't been initialized yet, so go through runtime. | 
| 1573   __ testq(rax, rax); | 1592   __ testq(rax, rax); | 
| 1574   __ j(zero, &runtime_call_clear_stack); | 1593   __ j(zero, &runtime_call_clear_stack);  // Only clears stack if TAGGED. | 
| 1575 #ifdef DEBUG | 1594 #ifdef DEBUG | 
| 1576   // Check that the layout of cache elements match expectations. | 1595   // Check that the layout of cache elements match expectations. | 
| 1577   {  // NOLINT - doesn't like a single brace on a line. | 1596   {  // NOLINT - doesn't like a single brace on a line. | 
| 1578     TranscendentalCache::Element test_elem[2]; | 1597     TranscendentalCache::Element test_elem[2]; | 
| 1579     char* elem_start = reinterpret_cast<char*>(&test_elem[0]); | 1598     char* elem_start = reinterpret_cast<char*>(&test_elem[0]); | 
| 1580     char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); | 1599     char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); | 
| 1581     char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0])); | 1600     char* elem_in0  = reinterpret_cast<char*>(&(test_elem[0].in[0])); | 
| 1582     char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1])); | 1601     char* elem_in1  = reinterpret_cast<char*>(&(test_elem[0].in[1])); | 
| 1583     char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); | 1602     char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); | 
| 1584     // Two uint_32's and a pointer per element. | 1603     // Two uint_32's and a pointer per element. | 
| 1585     CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); | 1604     CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); | 
| 1586     CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); | 1605     CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); | 
| 1587     CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); | 1606     CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); | 
| 1588     CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); | 1607     CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); | 
| 1589   } | 1608   } | 
| 1590 #endif | 1609 #endif | 
| 1591   // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. | 1610   // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. | 
| 1592   __ addl(rcx, rcx); | 1611   __ addl(rcx, rcx); | 
| 1593   __ lea(rcx, Operand(rax, rcx, times_8, 0)); | 1612   __ lea(rcx, Operand(rax, rcx, times_8, 0)); | 
| 1594   // Check if cache matches: Double value is stored in uint32_t[2] array. | 1613   // Check if cache matches: Double value is stored in uint32_t[2] array. | 
| 1595   NearLabel cache_miss; | 1614   NearLabel cache_miss; | 
| 1596   __ cmpq(rbx, Operand(rcx, 0)); | 1615   __ cmpq(rbx, Operand(rcx, 0)); | 
| 1597   __ j(not_equal, &cache_miss); | 1616   __ j(not_equal, &cache_miss); | 
| 1598   // Cache hit! | 1617   // Cache hit! | 
| 1599   __ movq(rax, Operand(rcx, 2 * kIntSize)); | 1618   __ movq(rax, Operand(rcx, 2 * kIntSize)); | 
| 1600   __ fstp(0);  // Clear FPU stack. | 1619   if (tagged) { | 
| 1601   __ ret(kPointerSize); | 1620     __ fstp(0);  // Clear FPU stack. | 
|  | 1621     __ ret(kPointerSize); | 
|  | 1622   } else {  // UNTAGGED. | 
|  | 1623     __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); | 
|  | 1624     __ Ret(); | 
|  | 1625   } | 
| 1602 | 1626 | 
| 1603   __ bind(&cache_miss); | 1627   __ bind(&cache_miss); | 
| 1604   // Update cache with new value. | 1628   // Update cache with new value. | 
| 1605   Label nan_result; | 1629   if (tagged) { | 
| 1606   GenerateOperation(masm, &nan_result); |  | 
| 1607   __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack); | 1630   __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack); | 
|  | 1631   } else {  // UNTAGGED. | 
|  | 1632     __ AllocateHeapNumber(rax, rdi, &skip_cache); | 
|  | 1633     __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1); | 
|  | 1634     __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 
|  | 1635   } | 
|  | 1636   GenerateOperation(masm); | 
| 1608   __ movq(Operand(rcx, 0), rbx); | 1637   __ movq(Operand(rcx, 0), rbx); | 
| 1609   __ movq(Operand(rcx, 2 * kIntSize), rax); | 1638   __ movq(Operand(rcx, 2 * kIntSize), rax); | 
| 1610   __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 1639   __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 
| 1611   __ ret(kPointerSize); | 1640   if (tagged) { | 
|  | 1641     __ ret(kPointerSize); | 
|  | 1642   } else {  // UNTAGGED. | 
|  | 1643     __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); | 
|  | 1644     __ Ret(); | 
| 1612 | 1645 | 
| 1613   __ bind(&runtime_call_clear_stack); | 1646     // Skip cache and return answer directly, only in untagged case. | 
| 1614   __ fstp(0); | 1647     __ bind(&skip_cache); | 
| 1615   __ bind(&runtime_call); | 1648     __ subq(rsp, Immediate(kDoubleSize)); | 
| 1616   __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); | 1649     __ movsd(Operand(rsp, 0), xmm1); | 
|  | 1650     __ fld_d(Operand(rsp, 0)); | 
|  | 1651     GenerateOperation(masm); | 
|  | 1652     __ fstp_d(Operand(rsp, 0)); | 
|  | 1653     __ movsd(xmm1, Operand(rsp, 0)); | 
|  | 1654     __ addq(rsp, Immediate(kDoubleSize)); | 
|  | 1655     // We return the value in xmm1 without adding it to the cache, but | 
|  | 1656     // we cause a scavenging GC so that future allocations will succeed. | 
|  | 1657     __ EnterInternalFrame(); | 
|  | 1658     // Allocate an unused object bigger than a HeapNumber. | 
|  | 1659     __ Push(Smi::FromInt(2 * kDoubleSize)); | 
|  | 1660     __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); | 
|  | 1661     __ LeaveInternalFrame(); | 
|  | 1662     __ Ret(); | 
|  | 1663   } | 
| 1617 | 1664 | 
| 1618   __ bind(&nan_result); | 1665   // Call runtime, doing whatever allocation and cleanup is necessary. | 
| 1619   __ fstp(0);  // Remove argument from FPU stack. | 1666   if (tagged) { | 
| 1620   __ LoadRoot(rax, Heap::kNanValueRootIndex); | 1667     __ bind(&runtime_call_clear_stack); | 
| 1621   __ movq(Operand(rcx, 0), rbx); | 1668     __ fstp(0); | 
| 1622   __ movq(Operand(rcx, 2 * kIntSize), rax); | 1669     __ bind(&runtime_call); | 
| 1623   __ ret(kPointerSize); | 1670     __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); | 
|  | 1671   } else {  // UNTAGGED. | 
|  | 1672     __ bind(&runtime_call_clear_stack); | 
|  | 1673     __ bind(&runtime_call); | 
|  | 1674     __ AllocateHeapNumber(rax, rdi, &skip_cache); | 
|  | 1675     __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1); | 
|  | 1676     __ EnterInternalFrame(); | 
|  | 1677     __ push(rax); | 
|  | 1678     __ CallRuntime(RuntimeFunction(), 1); | 
|  | 1679     __ LeaveInternalFrame(); | 
|  | 1680     __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset)); | 
|  | 1681     __ Ret(); | 
|  | 1682   } | 
| 1624 } | 1683 } | 
| 1625 | 1684 | 
| 1626 | 1685 | 
| 1627 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | 1686 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | 
| 1628   switch (type_) { | 1687   switch (type_) { | 
| 1629     // Add more cases when necessary. | 1688     // Add more cases when necessary. | 
| 1630     case TranscendentalCache::SIN: return Runtime::kMath_sin; | 1689     case TranscendentalCache::SIN: return Runtime::kMath_sin; | 
| 1631     case TranscendentalCache::COS: return Runtime::kMath_cos; | 1690     case TranscendentalCache::COS: return Runtime::kMath_cos; | 
| 1632     case TranscendentalCache::LOG: return Runtime::kMath_log; | 1691     case TranscendentalCache::LOG: return Runtime::kMath_log; | 
| 1633     default: | 1692     default: | 
| 1634       UNIMPLEMENTED(); | 1693       UNIMPLEMENTED(); | 
| 1635       return Runtime::kAbort; | 1694       return Runtime::kAbort; | 
| 1636   } | 1695   } | 
| 1637 } | 1696 } | 
| 1638 | 1697 | 
| 1639 | 1698 | 
| 1640 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm, | 1699 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { | 
| 1641                                                 Label* on_nan_result) { |  | 
| 1642   // Registers: | 1700   // Registers: | 
|  | 1701   // rax: Newly allocated HeapNumber, which must be preserved. | 
| 1643   // rbx: Bits of input double. Must be preserved. | 1702   // rbx: Bits of input double. Must be preserved. | 
| 1644   // rcx: Pointer to cache entry. Must be preserved. | 1703   // rcx: Pointer to cache entry. Must be preserved. | 
| 1645   // st(0): Input double | 1704   // st(0): Input double | 
| 1646   Label done; | 1705   Label done; | 
| 1647   if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { | 1706   if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { | 
| 1648     // Both fsin and fcos require arguments in the range +/-2^63 and | 1707     // Both fsin and fcos require arguments in the range +/-2^63 and | 
| 1649     // return NaN for infinities and NaN. They can share all code except | 1708     // return NaN for infinities and NaN. They can share all code except | 
| 1650     // the actual fsin/fcos operation. | 1709     // the actual fsin/fcos operation. | 
| 1651     Label in_range; | 1710     Label in_range; | 
| 1652     // If argument is outside the range -2^63..2^63, fsin/cos doesn't | 1711     // If argument is outside the range -2^63..2^63, fsin/cos doesn't | 
| 1653     // work. We must reduce it to the appropriate range. | 1712     // work. We must reduce it to the appropriate range. | 
| 1654     __ movq(rdi, rbx); | 1713     __ movq(rdi, rbx); | 
| 1655     // Move exponent and sign bits to low bits. | 1714     // Move exponent and sign bits to low bits. | 
| 1656     __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); | 1715     __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); | 
| 1657     // Remove sign bit. | 1716     // Remove sign bit. | 
| 1658     __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); | 1717     __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); | 
| 1659     int supported_exponent_limit = (63 + HeapNumber::kExponentBias); | 1718     int supported_exponent_limit = (63 + HeapNumber::kExponentBias); | 
| 1660     __ cmpl(rdi, Immediate(supported_exponent_limit)); | 1719     __ cmpl(rdi, Immediate(supported_exponent_limit)); | 
| 1661     __ j(below, &in_range); | 1720     __ j(below, &in_range); | 
| 1662     // Check for infinity and NaN. Both return NaN for sin. | 1721     // Check for infinity and NaN. Both return NaN for sin. | 
| 1663     __ cmpl(rdi, Immediate(0x7ff)); | 1722     __ cmpl(rdi, Immediate(0x7ff)); | 
| 1664     __ j(equal, on_nan_result); | 1723     NearLabel non_nan_result; | 
|  | 1724     __ j(not_equal, &non_nan_result); | 
|  | 1725     // Input is +/-Infinity or NaN. Result is NaN. | 
|  | 1726     __ fstp(0); | 
|  | 1727     __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex); | 
|  | 1728     __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset)); | 
|  | 1729     __ jmp(&done); | 
|  | 1730 | 
|  | 1731     __ bind(&non_nan_result); | 
| 1665 | 1732 | 
| 1666     // Use fpmod to restrict argument to the range +/-2*PI. | 1733     // Use fpmod to restrict argument to the range +/-2*PI. | 
|  | 1734     __ movq(rdi, rax);  // Save rax before using fnstsw_ax. | 
| 1667     __ fldpi(); | 1735     __ fldpi(); | 
| 1668     __ fadd(0); | 1736     __ fadd(0); | 
| 1669     __ fld(1); | 1737     __ fld(1); | 
| 1670     // FPU Stack: input, 2*pi, input. | 1738     // FPU Stack: input, 2*pi, input. | 
| 1671     { | 1739     { | 
| 1672       Label no_exceptions; | 1740       Label no_exceptions; | 
| 1673       __ fwait(); | 1741       __ fwait(); | 
| 1674       __ fnstsw_ax(); | 1742       __ fnstsw_ax(); | 
| 1675       // Clear if Illegal Operand or Zero Division exceptions are set. | 1743       // Clear if Illegal Operand or Zero Division exceptions are set. | 
| 1676       __ testl(rax, Immediate(5));  // #IO and #ZD flags of FPU status word. | 1744       __ testl(rax, Immediate(5));  // #IO and #ZD flags of FPU status word. | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 1689       __ testl(rax, Immediate(0x400));  // Check C2 bit of FPU status word. | 1757       __ testl(rax, Immediate(0x400));  // Check C2 bit of FPU status word. | 
| 1690       // If C2 is set, computation only has partial result. Loop to | 1758       // If C2 is set, computation only has partial result. Loop to | 
| 1691       // continue computation. | 1759       // continue computation. | 
| 1692       __ j(not_zero, &partial_remainder_loop); | 1760       __ j(not_zero, &partial_remainder_loop); | 
| 1693   } | 1761   } | 
| 1694     // FPU Stack: input, 2*pi, input % 2*pi | 1762     // FPU Stack: input, 2*pi, input % 2*pi | 
| 1695     __ fstp(2); | 1763     __ fstp(2); | 
| 1696     // FPU Stack: input % 2*pi, 2*pi, | 1764     // FPU Stack: input % 2*pi, 2*pi, | 
| 1697     __ fstp(0); | 1765     __ fstp(0); | 
| 1698     // FPU Stack: input % 2*pi | 1766     // FPU Stack: input % 2*pi | 
|  | 1767     __ movq(rax, rdi);  // Restore rax, pointer to the new HeapNumber. | 
| 1699     __ bind(&in_range); | 1768     __ bind(&in_range); | 
| 1700     switch (type_) { | 1769     switch (type_) { | 
| 1701       case TranscendentalCache::SIN: | 1770       case TranscendentalCache::SIN: | 
| 1702         __ fsin(); | 1771         __ fsin(); | 
| 1703         break; | 1772         break; | 
| 1704       case TranscendentalCache::COS: | 1773       case TranscendentalCache::COS: | 
| 1705         __ fcos(); | 1774         __ fcos(); | 
| 1706         break; | 1775         break; | 
| 1707       default: | 1776       default: | 
| 1708         UNREACHABLE(); | 1777         UNREACHABLE(); | 
| (...skipping 3157 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 4866           FieldOperand(elements, PixelArray::kExternalPointerOffset)); | 4935           FieldOperand(elements, PixelArray::kExternalPointerOffset)); | 
| 4867   __ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value); | 4936   __ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value); | 
| 4868   __ ret(0);  // Return value in eax. | 4937   __ ret(0);  // Return value in eax. | 
| 4869 } | 4938 } | 
| 4870 | 4939 | 
| 4871 #undef __ | 4940 #undef __ | 
| 4872 | 4941 | 
| 4873 } }  // namespace v8::internal | 4942 } }  // namespace v8::internal | 
| 4874 | 4943 | 
| 4875 #endif  // V8_TARGET_ARCH_X64 | 4944 #endif  // V8_TARGET_ARCH_X64 | 
| OLD | NEW | 
|---|