| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #if defined(V8_TARGET_ARCH_MIPS) | 30 #if V8_TARGET_ARCH_MIPS |
| 31 | 31 |
| 32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "codegen.h" | 34 #include "codegen.h" |
| 35 #include "regexp-macro-assembler.h" | 35 #include "regexp-macro-assembler.h" |
| 36 #include "stub-cache.h" | 36 #include "stub-cache.h" |
| 37 | 37 |
| 38 namespace v8 { | 38 namespace v8 { |
| 39 namespace internal { | 39 namespace internal { |
| 40 | 40 |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 } | 220 } |
| 221 | 221 |
| 222 | 222 |
| 223 void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( | 223 void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( |
| 224 Isolate* isolate, | 224 Isolate* isolate, |
| 225 CodeStubInterfaceDescriptor* descriptor) { | 225 CodeStubInterfaceDescriptor* descriptor) { |
| 226 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1); | 226 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1); |
| 227 } | 227 } |
| 228 | 228 |
| 229 | 229 |
| 230 void UnaryOpStub::InitializeInterfaceDescriptor( |
| 231 Isolate* isolate, |
| 232 CodeStubInterfaceDescriptor* descriptor) { |
| 233 static Register registers[] = { a0 }; |
| 234 descriptor->register_param_count_ = 1; |
| 235 descriptor->register_params_ = registers; |
| 236 descriptor->deoptimization_handler_ = |
| 237 FUNCTION_ADDR(UnaryOpIC_Miss); |
| 238 } |
| 239 |
| 240 |
| 241 void StoreGlobalStub::InitializeInterfaceDescriptor( |
| 242 Isolate* isolate, |
| 243 CodeStubInterfaceDescriptor* descriptor) { |
| 244 static Register registers[] = { a1, a2, a0 }; |
| 245 descriptor->register_param_count_ = 3; |
| 246 descriptor->register_params_ = registers; |
| 247 descriptor->deoptimization_handler_ = |
| 248 FUNCTION_ADDR(StoreIC_MissFromStubFailure); |
| 249 } |
| 250 |
| 251 |
| 230 #define __ ACCESS_MASM(masm) | 252 #define __ ACCESS_MASM(masm) |
| 231 | 253 |
| 254 |
| 232 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 255 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
| 233 Label* slow, | 256 Label* slow, |
| 234 Condition cc); | 257 Condition cc); |
| 235 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 258 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
| 236 Register lhs, | 259 Register lhs, |
| 237 Register rhs, | 260 Register rhs, |
| 238 Label* rhs_not_nan, | 261 Label* rhs_not_nan, |
| 239 Label* slow, | 262 Label* slow, |
| 240 bool strict); | 263 bool strict); |
| 241 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 264 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
| (...skipping 932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1174 __ Branch(&return_not_equal, eq, a2, Operand(ODDBALL_TYPE)); | 1197 __ Branch(&return_not_equal, eq, a2, Operand(ODDBALL_TYPE)); |
| 1175 | 1198 |
| 1176 __ GetObjectType(rhs, a3, a3); | 1199 __ GetObjectType(rhs, a3, a3); |
| 1177 __ Branch(&return_not_equal, greater, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); | 1200 __ Branch(&return_not_equal, greater, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 1178 | 1201 |
| 1179 // Check for oddballs: true, false, null, undefined. | 1202 // Check for oddballs: true, false, null, undefined. |
| 1180 __ Branch(&return_not_equal, eq, a3, Operand(ODDBALL_TYPE)); | 1203 __ Branch(&return_not_equal, eq, a3, Operand(ODDBALL_TYPE)); |
| 1181 | 1204 |
| 1182 // Now that we have the types we might as well check for | 1205 // Now that we have the types we might as well check for |
| 1183 // internalized-internalized. | 1206 // internalized-internalized. |
| 1184 // Ensure that no non-strings have the internalized bit set. | 1207 Label not_internalized; |
| 1185 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsInternalizedMask); | |
| 1186 STATIC_ASSERT(kInternalizedTag != 0); | 1208 STATIC_ASSERT(kInternalizedTag != 0); |
| 1187 __ And(t2, a2, Operand(a3)); | 1209 __ And(t2, a2, Operand(kIsNotStringMask | kIsInternalizedMask)); |
| 1188 __ And(t0, t2, Operand(kIsInternalizedMask)); | 1210 __ Branch(¬_internalized, ne, t2, |
| 1189 __ Branch(&return_not_equal, ne, t0, Operand(zero_reg)); | 1211 Operand(kInternalizedTag | kStringTag)); |
| 1212 |
| 1213 __ And(a3, a3, Operand(kIsNotStringMask | kIsInternalizedMask)); |
| 1214 __ Branch(&return_not_equal, eq, a3, |
| 1215 Operand(kInternalizedTag | kStringTag)); |
| 1216 |
| 1217 __ bind(¬_internalized); |
| 1190 } | 1218 } |
| 1191 | 1219 |
| 1192 | 1220 |
| 1193 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, | 1221 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, |
| 1194 Register lhs, | 1222 Register lhs, |
| 1195 Register rhs, | 1223 Register rhs, |
| 1196 Label* both_loaded_as_doubles, | 1224 Label* both_loaded_as_doubles, |
| 1197 Label* not_heap_numbers, | 1225 Label* not_heap_numbers, |
| 1198 Label* slow) { | 1226 Label* slow) { |
| 1199 __ GetObjectType(lhs, a3, a2); | 1227 __ GetObjectType(lhs, a3, a2); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1213 | 1241 |
| 1214 // Fast negative check for internalized-to-internalized equality. | 1242 // Fast negative check for internalized-to-internalized equality. |
| 1215 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, | 1243 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, |
| 1216 Register lhs, | 1244 Register lhs, |
| 1217 Register rhs, | 1245 Register rhs, |
| 1218 Label* possible_strings, | 1246 Label* possible_strings, |
| 1219 Label* not_both_strings) { | 1247 Label* not_both_strings) { |
| 1220 ASSERT((lhs.is(a0) && rhs.is(a1)) || | 1248 ASSERT((lhs.is(a0) && rhs.is(a1)) || |
| 1221 (lhs.is(a1) && rhs.is(a0))); | 1249 (lhs.is(a1) && rhs.is(a0))); |
| 1222 | 1250 |
| 1223 // a2 is object type of lhs. | 1251 // a2 is object type of rhs. |
| 1224 // Ensure that no non-strings have the internalized bit set. | |
| 1225 Label object_test; | 1252 Label object_test; |
| 1226 STATIC_ASSERT(kInternalizedTag != 0); | 1253 STATIC_ASSERT(kInternalizedTag != 0); |
| 1227 __ And(at, a2, Operand(kIsNotStringMask)); | 1254 __ And(at, a2, Operand(kIsNotStringMask)); |
| 1228 __ Branch(&object_test, ne, at, Operand(zero_reg)); | 1255 __ Branch(&object_test, ne, at, Operand(zero_reg)); |
| 1229 __ And(at, a2, Operand(kIsInternalizedMask)); | 1256 __ And(at, a2, Operand(kIsInternalizedMask)); |
| 1230 __ Branch(possible_strings, eq, at, Operand(zero_reg)); | 1257 __ Branch(possible_strings, eq, at, Operand(zero_reg)); |
| 1231 __ GetObjectType(rhs, a3, a3); | 1258 __ GetObjectType(rhs, a3, a3); |
| 1232 __ Branch(not_both_strings, ge, a3, Operand(FIRST_NONSTRING_TYPE)); | 1259 __ Branch(not_both_strings, ge, a3, Operand(FIRST_NONSTRING_TYPE)); |
| 1233 __ And(at, a3, Operand(kIsInternalizedMask)); | 1260 __ And(at, a3, Operand(kIsInternalizedMask)); |
| 1234 __ Branch(possible_strings, eq, at, Operand(zero_reg)); | 1261 __ Branch(possible_strings, eq, at, Operand(zero_reg)); |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1575 argument_count); | 1602 argument_count); |
| 1576 if (save_doubles_ == kSaveFPRegs) { | 1603 if (save_doubles_ == kSaveFPRegs) { |
| 1577 __ MultiPopFPU(kCallerSavedFPU); | 1604 __ MultiPopFPU(kCallerSavedFPU); |
| 1578 } | 1605 } |
| 1579 | 1606 |
| 1580 __ MultiPop(kJSCallerSaved | ra.bit()); | 1607 __ MultiPop(kJSCallerSaved | ra.bit()); |
| 1581 __ Ret(); | 1608 __ Ret(); |
| 1582 } | 1609 } |
| 1583 | 1610 |
| 1584 | 1611 |
| 1585 void UnaryOpStub::PrintName(StringStream* stream) { | |
| 1586 const char* op_name = Token::Name(op_); | |
| 1587 const char* overwrite_name = NULL; // Make g++ happy. | |
| 1588 switch (mode_) { | |
| 1589 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | |
| 1590 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; | |
| 1591 } | |
| 1592 stream->Add("UnaryOpStub_%s_%s_%s", | |
| 1593 op_name, | |
| 1594 overwrite_name, | |
| 1595 UnaryOpIC::GetName(operand_type_)); | |
| 1596 } | |
| 1597 | |
| 1598 | |
| 1599 // TODO(svenpanne): Use virtual functions instead of switch. | |
| 1600 void UnaryOpStub::Generate(MacroAssembler* masm) { | |
| 1601 switch (operand_type_) { | |
| 1602 case UnaryOpIC::UNINITIALIZED: | |
| 1603 GenerateTypeTransition(masm); | |
| 1604 break; | |
| 1605 case UnaryOpIC::SMI: | |
| 1606 GenerateSmiStub(masm); | |
| 1607 break; | |
| 1608 case UnaryOpIC::NUMBER: | |
| 1609 GenerateNumberStub(masm); | |
| 1610 break; | |
| 1611 case UnaryOpIC::GENERIC: | |
| 1612 GenerateGenericStub(masm); | |
| 1613 break; | |
| 1614 } | |
| 1615 } | |
| 1616 | |
| 1617 | |
| 1618 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | |
| 1619 // Argument is in a0 and v0 at this point, so we can overwrite a0. | |
| 1620 __ li(a2, Operand(Smi::FromInt(op_))); | |
| 1621 __ li(a1, Operand(Smi::FromInt(mode_))); | |
| 1622 __ li(a0, Operand(Smi::FromInt(operand_type_))); | |
| 1623 __ Push(v0, a2, a1, a0); | |
| 1624 | |
| 1625 __ TailCallExternalReference( | |
| 1626 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); | |
| 1627 } | |
| 1628 | |
| 1629 | |
| 1630 // TODO(svenpanne): Use virtual functions instead of switch. | |
| 1631 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | |
| 1632 switch (op_) { | |
| 1633 case Token::SUB: | |
| 1634 GenerateSmiStubSub(masm); | |
| 1635 break; | |
| 1636 case Token::BIT_NOT: | |
| 1637 GenerateSmiStubBitNot(masm); | |
| 1638 break; | |
| 1639 default: | |
| 1640 UNREACHABLE(); | |
| 1641 } | |
| 1642 } | |
| 1643 | |
| 1644 | |
| 1645 void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { | |
| 1646 Label non_smi, slow; | |
| 1647 GenerateSmiCodeSub(masm, &non_smi, &slow); | |
| 1648 __ bind(&non_smi); | |
| 1649 __ bind(&slow); | |
| 1650 GenerateTypeTransition(masm); | |
| 1651 } | |
| 1652 | |
| 1653 | |
| 1654 void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { | |
| 1655 Label non_smi; | |
| 1656 GenerateSmiCodeBitNot(masm, &non_smi); | |
| 1657 __ bind(&non_smi); | |
| 1658 GenerateTypeTransition(masm); | |
| 1659 } | |
| 1660 | |
| 1661 | |
| 1662 void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, | |
| 1663 Label* non_smi, | |
| 1664 Label* slow) { | |
| 1665 __ JumpIfNotSmi(a0, non_smi); | |
| 1666 | |
| 1667 // The result of negating zero or the smallest negative smi is not a smi. | |
| 1668 __ And(t0, a0, ~0x80000000); | |
| 1669 __ Branch(slow, eq, t0, Operand(zero_reg)); | |
| 1670 | |
| 1671 // Return '0 - value'. | |
| 1672 __ Ret(USE_DELAY_SLOT); | |
| 1673 __ subu(v0, zero_reg, a0); | |
| 1674 } | |
| 1675 | |
| 1676 | |
| 1677 void UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm, | |
| 1678 Label* non_smi) { | |
| 1679 __ JumpIfNotSmi(a0, non_smi); | |
| 1680 | |
| 1681 // Flip bits and revert inverted smi-tag. | |
| 1682 __ Neg(v0, a0); | |
| 1683 __ And(v0, v0, ~kSmiTagMask); | |
| 1684 __ Ret(); | |
| 1685 } | |
| 1686 | |
| 1687 | |
| 1688 // TODO(svenpanne): Use virtual functions instead of switch. | |
| 1689 void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) { | |
| 1690 switch (op_) { | |
| 1691 case Token::SUB: | |
| 1692 GenerateNumberStubSub(masm); | |
| 1693 break; | |
| 1694 case Token::BIT_NOT: | |
| 1695 GenerateNumberStubBitNot(masm); | |
| 1696 break; | |
| 1697 default: | |
| 1698 UNREACHABLE(); | |
| 1699 } | |
| 1700 } | |
| 1701 | |
| 1702 | |
| 1703 void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) { | |
| 1704 Label non_smi, slow, call_builtin; | |
| 1705 GenerateSmiCodeSub(masm, &non_smi, &call_builtin); | |
| 1706 __ bind(&non_smi); | |
| 1707 GenerateHeapNumberCodeSub(masm, &slow); | |
| 1708 __ bind(&slow); | |
| 1709 GenerateTypeTransition(masm); | |
| 1710 __ bind(&call_builtin); | |
| 1711 GenerateGenericCodeFallback(masm); | |
| 1712 } | |
| 1713 | |
| 1714 | |
| 1715 void UnaryOpStub::GenerateNumberStubBitNot(MacroAssembler* masm) { | |
| 1716 Label non_smi, slow; | |
| 1717 GenerateSmiCodeBitNot(masm, &non_smi); | |
| 1718 __ bind(&non_smi); | |
| 1719 GenerateHeapNumberCodeBitNot(masm, &slow); | |
| 1720 __ bind(&slow); | |
| 1721 GenerateTypeTransition(masm); | |
| 1722 } | |
| 1723 | |
| 1724 | |
| 1725 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, | |
| 1726 Label* slow) { | |
| 1727 EmitCheckForHeapNumber(masm, a0, a1, t2, slow); | |
| 1728 // a0 is a heap number. Get a new heap number in a1. | |
| 1729 if (mode_ == UNARY_OVERWRITE) { | |
| 1730 __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); | |
| 1731 __ Xor(a2, a2, Operand(HeapNumber::kSignMask)); // Flip sign. | |
| 1732 __ Ret(USE_DELAY_SLOT); | |
| 1733 __ sw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); | |
| 1734 } else { | |
| 1735 Label slow_allocate_heapnumber, heapnumber_allocated; | |
| 1736 __ AllocateHeapNumber(a1, a2, a3, t2, &slow_allocate_heapnumber); | |
| 1737 __ jmp(&heapnumber_allocated); | |
| 1738 | |
| 1739 __ bind(&slow_allocate_heapnumber); | |
| 1740 { | |
| 1741 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1742 __ push(a0); | |
| 1743 __ CallRuntime(Runtime::kNumberAlloc, 0); | |
| 1744 __ mov(a1, v0); | |
| 1745 __ pop(a0); | |
| 1746 } | |
| 1747 | |
| 1748 __ bind(&heapnumber_allocated); | |
| 1749 __ lw(a3, FieldMemOperand(a0, HeapNumber::kMantissaOffset)); | |
| 1750 __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); | |
| 1751 __ sw(a3, FieldMemOperand(a1, HeapNumber::kMantissaOffset)); | |
| 1752 __ Xor(a2, a2, Operand(HeapNumber::kSignMask)); // Flip sign. | |
| 1753 __ sw(a2, FieldMemOperand(a1, HeapNumber::kExponentOffset)); | |
| 1754 __ Ret(USE_DELAY_SLOT); | |
| 1755 __ mov(v0, a1); | |
| 1756 } | |
| 1757 } | |
| 1758 | |
| 1759 | |
| 1760 void UnaryOpStub::GenerateHeapNumberCodeBitNot( | |
| 1761 MacroAssembler* masm, | |
| 1762 Label* slow) { | |
| 1763 Label impossible; | |
| 1764 | |
| 1765 EmitCheckForHeapNumber(masm, a0, a1, t2, slow); | |
| 1766 // Convert the heap number in a0 to an untagged integer in a1. | |
| 1767 __ ConvertToInt32(a0, a1, a2, a3, f0, slow); | |
| 1768 | |
| 1769 // Do the bitwise operation and check if the result fits in a smi. | |
| 1770 Label try_float; | |
| 1771 __ Neg(a1, a1); | |
| 1772 __ Addu(a2, a1, Operand(0x40000000)); | |
| 1773 __ Branch(&try_float, lt, a2, Operand(zero_reg)); | |
| 1774 | |
| 1775 // Tag the result as a smi and we're done. | |
| 1776 __ Ret(USE_DELAY_SLOT); // SmiTag emits one instruction in delay slot. | |
| 1777 __ SmiTag(v0, a1); | |
| 1778 | |
| 1779 // Try to store the result in a heap number. | |
| 1780 __ bind(&try_float); | |
| 1781 if (mode_ == UNARY_NO_OVERWRITE) { | |
| 1782 Label slow_allocate_heapnumber, heapnumber_allocated; | |
| 1783 // Allocate a new heap number without zapping v0, which we need if it fails. | |
| 1784 __ AllocateHeapNumber(a2, a3, t0, t2, &slow_allocate_heapnumber); | |
| 1785 __ jmp(&heapnumber_allocated); | |
| 1786 | |
| 1787 __ bind(&slow_allocate_heapnumber); | |
| 1788 { | |
| 1789 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1790 __ push(v0); // Push the heap number, not the untagged int32. | |
| 1791 __ CallRuntime(Runtime::kNumberAlloc, 0); | |
| 1792 __ mov(a2, v0); // Move the new heap number into a2. | |
| 1793 // Get the heap number into v0, now that the new heap number is in a2. | |
| 1794 __ pop(v0); | |
| 1795 } | |
| 1796 | |
| 1797 // Convert the heap number in v0 to an untagged integer in a1. | |
| 1798 // This can't go slow-case because it's the same number we already | |
| 1799 // converted once again. | |
| 1800 __ ConvertToInt32(v0, a1, a3, t0, f0, &impossible); | |
| 1801 // Negate the result. | |
| 1802 __ Xor(a1, a1, -1); | |
| 1803 | |
| 1804 __ bind(&heapnumber_allocated); | |
| 1805 __ mov(v0, a2); // Move newly allocated heap number to v0. | |
| 1806 } | |
| 1807 | |
| 1808 // Convert the int32 in a1 to the heap number in v0. a2 is corrupted. | |
| 1809 __ mtc1(a1, f0); | |
| 1810 __ cvt_d_w(f0, f0); | |
| 1811 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); | |
| 1812 __ Ret(); | |
| 1813 | |
| 1814 __ bind(&impossible); | |
| 1815 if (FLAG_debug_code) { | |
| 1816 __ stop("Incorrect assumption in bit-not stub"); | |
| 1817 } | |
| 1818 } | |
| 1819 | |
| 1820 | |
| 1821 // TODO(svenpanne): Use virtual functions instead of switch. | |
| 1822 void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { | |
| 1823 switch (op_) { | |
| 1824 case Token::SUB: | |
| 1825 GenerateGenericStubSub(masm); | |
| 1826 break; | |
| 1827 case Token::BIT_NOT: | |
| 1828 GenerateGenericStubBitNot(masm); | |
| 1829 break; | |
| 1830 default: | |
| 1831 UNREACHABLE(); | |
| 1832 } | |
| 1833 } | |
| 1834 | |
| 1835 | |
| 1836 void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { | |
| 1837 Label non_smi, slow; | |
| 1838 GenerateSmiCodeSub(masm, &non_smi, &slow); | |
| 1839 __ bind(&non_smi); | |
| 1840 GenerateHeapNumberCodeSub(masm, &slow); | |
| 1841 __ bind(&slow); | |
| 1842 GenerateGenericCodeFallback(masm); | |
| 1843 } | |
| 1844 | |
| 1845 | |
| 1846 void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { | |
| 1847 Label non_smi, slow; | |
| 1848 GenerateSmiCodeBitNot(masm, &non_smi); | |
| 1849 __ bind(&non_smi); | |
| 1850 GenerateHeapNumberCodeBitNot(masm, &slow); | |
| 1851 __ bind(&slow); | |
| 1852 GenerateGenericCodeFallback(masm); | |
| 1853 } | |
| 1854 | |
| 1855 | |
| 1856 void UnaryOpStub::GenerateGenericCodeFallback( | |
| 1857 MacroAssembler* masm) { | |
| 1858 // Handle the slow case by jumping to the JavaScript builtin. | |
| 1859 __ push(a0); | |
| 1860 switch (op_) { | |
| 1861 case Token::SUB: | |
| 1862 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); | |
| 1863 break; | |
| 1864 case Token::BIT_NOT: | |
| 1865 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); | |
| 1866 break; | |
| 1867 default: | |
| 1868 UNREACHABLE(); | |
| 1869 } | |
| 1870 } | |
| 1871 | |
| 1872 | |
| 1873 void BinaryOpStub::Initialize() { | 1612 void BinaryOpStub::Initialize() { |
| 1874 platform_specific_bit_ = true; // FPU is a base requirement for V8. | 1613 platform_specific_bit_ = true; // FPU is a base requirement for V8. |
| 1875 } | 1614 } |
| 1876 | 1615 |
| 1877 | 1616 |
| 1878 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 1617 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 1879 Label get_result; | 1618 Label get_result; |
| 1880 | 1619 |
| 1881 __ Push(a1, a0); | 1620 __ Push(a1, a0); |
| 1882 | 1621 |
| (...skipping 1636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3519 | 3258 |
| 3520 void CEntryStub::Generate(MacroAssembler* masm) { | 3259 void CEntryStub::Generate(MacroAssembler* masm) { |
| 3521 // Called from JavaScript; parameters are on stack as if calling JS function | 3260 // Called from JavaScript; parameters are on stack as if calling JS function |
| 3522 // s0: number of arguments including receiver | 3261 // s0: number of arguments including receiver |
| 3523 // s1: size of arguments excluding receiver | 3262 // s1: size of arguments excluding receiver |
| 3524 // s2: pointer to builtin function | 3263 // s2: pointer to builtin function |
| 3525 // fp: frame pointer (restored after C call) | 3264 // fp: frame pointer (restored after C call) |
| 3526 // sp: stack pointer (restored as callee's sp after C call) | 3265 // sp: stack pointer (restored as callee's sp after C call) |
| 3527 // cp: current context (C callee-saved) | 3266 // cp: current context (C callee-saved) |
| 3528 | 3267 |
| 3268 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
| 3269 |
| 3529 // NOTE: Invocations of builtins may return failure objects | 3270 // NOTE: Invocations of builtins may return failure objects |
| 3530 // instead of a proper result. The builtin entry handles | 3271 // instead of a proper result. The builtin entry handles |
| 3531 // this by performing a garbage collection and retrying the | 3272 // this by performing a garbage collection and retrying the |
| 3532 // builtin once. | 3273 // builtin once. |
| 3533 | 3274 |
| 3534 // NOTE: s0-s2 hold the arguments of this function instead of a0-a2. | 3275 // NOTE: s0-s2 hold the arguments of this function instead of a0-a2. |
| 3535 // The reason for this is that these arguments would need to be saved anyway | 3276 // The reason for this is that these arguments would need to be saved anyway |
| 3536 // so it's faster to set them up directly. | 3277 // so it's faster to set them up directly. |
| 3537 // See MacroAssembler::PrepareCEntryArgs and PrepareCEntryFunction. | 3278 // See MacroAssembler::PrepareCEntryArgs and PrepareCEntryFunction. |
| 3538 | 3279 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3612 // Registers: | 3353 // Registers: |
| 3613 // a0: entry address | 3354 // a0: entry address |
| 3614 // a1: function | 3355 // a1: function |
| 3615 // a2: receiver | 3356 // a2: receiver |
| 3616 // a3: argc | 3357 // a3: argc |
| 3617 // | 3358 // |
| 3618 // Stack: | 3359 // Stack: |
| 3619 // 4 args slots | 3360 // 4 args slots |
| 3620 // args | 3361 // args |
| 3621 | 3362 |
| 3363 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
| 3364 |
| 3622 // Save callee saved registers on the stack. | 3365 // Save callee saved registers on the stack. |
| 3623 __ MultiPush(kCalleeSaved | ra.bit()); | 3366 __ MultiPush(kCalleeSaved | ra.bit()); |
| 3624 | 3367 |
| 3625 // Save callee-saved FPU registers. | 3368 // Save callee-saved FPU registers. |
| 3626 __ MultiPushFPU(kCalleeSavedFPU); | 3369 __ MultiPushFPU(kCalleeSavedFPU); |
| 3627 // Set up the reserved register for 0.0. | 3370 // Set up the reserved register for 0.0. |
| 3628 __ Move(kDoubleRegZero, 0.0); | 3371 __ Move(kDoubleRegZero, 0.0); |
| 3629 | 3372 |
| 3630 | 3373 |
| 3631 // Load argv in s0 register. | 3374 // Load argv in s0 register. |
| (...skipping 1402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5034 | 4777 |
| 5035 // A monomorphic cache hit or an already megamorphic state: invoke the | 4778 // A monomorphic cache hit or an already megamorphic state: invoke the |
| 5036 // function without changing the state. | 4779 // function without changing the state. |
| 5037 __ Branch(&done, eq, a3, Operand(a1)); | 4780 __ Branch(&done, eq, a3, Operand(a1)); |
| 5038 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); | 4781 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
| 5039 __ Branch(&done, eq, a3, Operand(at)); | 4782 __ Branch(&done, eq, a3, Operand(at)); |
| 5040 | 4783 |
| 5041 // Special handling of the Array() function, which caches not only the | 4784 // Special handling of the Array() function, which caches not only the |
| 5042 // monomorphic Array function but the initial ElementsKind with special | 4785 // monomorphic Array function but the initial ElementsKind with special |
| 5043 // sentinels | 4786 // sentinels |
| 5044 Handle<Object> terminal_kind_sentinel = | |
| 5045 TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(), | |
| 5046 LAST_FAST_ELEMENTS_KIND); | |
| 5047 __ JumpIfNotSmi(a3, &miss); | 4787 __ JumpIfNotSmi(a3, &miss); |
| 5048 __ Branch(&miss, gt, a3, Operand(terminal_kind_sentinel)); | 4788 if (FLAG_debug_code) { |
| 4789 Handle<Object> terminal_kind_sentinel = |
| 4790 TypeFeedbackCells::MonomorphicArraySentinel(masm->isolate(), |
| 4791 LAST_FAST_ELEMENTS_KIND); |
| 4792 __ Assert(le, "Array function sentinel is not an ElementsKind", |
| 4793 a3, Operand(terminal_kind_sentinel)); |
| 4794 } |
| 4795 |
| 5049 // Make sure the function is the Array() function | 4796 // Make sure the function is the Array() function |
| 5050 __ LoadArrayFunction(a3); | 4797 __ LoadArrayFunction(a3); |
| 5051 __ Branch(&megamorphic, ne, a1, Operand(a3)); | 4798 __ Branch(&megamorphic, ne, a1, Operand(a3)); |
| 5052 __ jmp(&done); | 4799 __ jmp(&done); |
| 5053 | 4800 |
| 5054 __ bind(&miss); | 4801 __ bind(&miss); |
| 5055 | 4802 |
| 5056 // A monomorphic miss (i.e, here the cache is not uninitialized) goes | 4803 // A monomorphic miss (i.e, here the cache is not uninitialized) goes |
| 5057 // megamorphic. | 4804 // megamorphic. |
| 5058 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 4805 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| (...skipping 1546 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6605 | 6352 |
| 6606 // Check that both operands are heap objects. | 6353 // Check that both operands are heap objects. |
| 6607 __ JumpIfEitherSmi(left, right, &miss); | 6354 __ JumpIfEitherSmi(left, right, &miss); |
| 6608 | 6355 |
| 6609 // Check that both operands are internalized strings. | 6356 // Check that both operands are internalized strings. |
| 6610 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 6357 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
| 6611 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 6358 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
| 6612 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 6359 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
| 6613 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 6360 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
| 6614 STATIC_ASSERT(kInternalizedTag != 0); | 6361 STATIC_ASSERT(kInternalizedTag != 0); |
| 6615 __ And(tmp1, tmp1, Operand(tmp2)); | 6362 |
| 6616 __ And(tmp1, tmp1, kIsInternalizedMask); | 6363 __ And(tmp1, tmp1, Operand(kIsNotStringMask | kIsInternalizedMask)); |
| 6617 __ Branch(&miss, eq, tmp1, Operand(zero_reg)); | 6364 __ Branch(&miss, ne, tmp1, Operand(kInternalizedTag | kStringTag)); |
| 6365 |
| 6366 __ And(tmp2, tmp2, Operand(kIsNotStringMask | kIsInternalizedMask)); |
| 6367 __ Branch(&miss, ne, tmp2, Operand(kInternalizedTag | kStringTag)); |
| 6368 |
| 6618 // Make sure a0 is non-zero. At this point input operands are | 6369 // Make sure a0 is non-zero. At this point input operands are |
| 6619 // guaranteed to be non-zero. | 6370 // guaranteed to be non-zero. |
| 6620 ASSERT(right.is(a0)); | 6371 ASSERT(right.is(a0)); |
| 6621 STATIC_ASSERT(EQUAL == 0); | 6372 STATIC_ASSERT(EQUAL == 0); |
| 6622 STATIC_ASSERT(kSmiTag == 0); | 6373 STATIC_ASSERT(kSmiTag == 0); |
| 6623 __ mov(v0, right); | 6374 __ mov(v0, right); |
| 6624 // Internalized strings are compared by identity. | 6375 // Internalized strings are compared by identity. |
| 6625 __ Ret(ne, left, Operand(right)); | 6376 __ Ret(ne, left, Operand(right)); |
| 6626 ASSERT(is_int16(EQUAL)); | 6377 ASSERT(is_int16(EQUAL)); |
| 6627 __ Ret(USE_DELAY_SLOT); | 6378 __ Ret(USE_DELAY_SLOT); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 6647 __ JumpIfEitherSmi(left, right, &miss); | 6398 __ JumpIfEitherSmi(left, right, &miss); |
| 6648 | 6399 |
| 6649 // Check that both operands are unique names. This leaves the instance | 6400 // Check that both operands are unique names. This leaves the instance |
| 6650 // types loaded in tmp1 and tmp2. | 6401 // types loaded in tmp1 and tmp2. |
| 6651 STATIC_ASSERT(kInternalizedTag != 0); | 6402 STATIC_ASSERT(kInternalizedTag != 0); |
| 6652 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 6403 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
| 6653 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 6404 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
| 6654 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 6405 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
| 6655 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 6406 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
| 6656 | 6407 |
| 6657 Label succeed1; | 6408 __ JumpIfNotUniqueName(tmp1, &miss); |
| 6658 __ And(at, tmp1, Operand(kIsInternalizedMask)); | 6409 __ JumpIfNotUniqueName(tmp2, &miss); |
| 6659 __ Branch(&succeed1, ne, at, Operand(zero_reg)); | |
| 6660 __ Branch(&miss, ne, tmp1, Operand(SYMBOL_TYPE)); | |
| 6661 __ bind(&succeed1); | |
| 6662 | |
| 6663 Label succeed2; | |
| 6664 __ And(at, tmp2, Operand(kIsInternalizedMask)); | |
| 6665 __ Branch(&succeed2, ne, at, Operand(zero_reg)); | |
| 6666 __ Branch(&miss, ne, tmp2, Operand(SYMBOL_TYPE)); | |
| 6667 __ bind(&succeed2); | |
| 6668 | 6410 |
| 6669 // Use a0 as result | 6411 // Use a0 as result |
| 6670 __ mov(v0, a0); | 6412 __ mov(v0, a0); |
| 6671 | 6413 |
| 6672 // Unique names are compared by identity. | 6414 // Unique names are compared by identity. |
| 6673 Label done; | 6415 Label done; |
| 6674 __ Branch(&done, ne, left, Operand(right)); | 6416 __ Branch(&done, ne, left, Operand(right)); |
| 6675 // Make sure a0 is non-zero. At this point input operands are | 6417 // Make sure a0 is non-zero. At this point input operands are |
| 6676 // guaranteed to be non-zero. | 6418 // guaranteed to be non-zero. |
| 6677 ASSERT(right.is(a0)); | 6419 ASSERT(right.is(a0)); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6720 STATIC_ASSERT(EQUAL == 0); | 6462 STATIC_ASSERT(EQUAL == 0); |
| 6721 STATIC_ASSERT(kSmiTag == 0); | 6463 STATIC_ASSERT(kSmiTag == 0); |
| 6722 __ Branch(&left_ne_right, ne, left, Operand(right)); | 6464 __ Branch(&left_ne_right, ne, left, Operand(right)); |
| 6723 __ Ret(USE_DELAY_SLOT); | 6465 __ Ret(USE_DELAY_SLOT); |
| 6724 __ mov(v0, zero_reg); // In the delay slot. | 6466 __ mov(v0, zero_reg); // In the delay slot. |
| 6725 __ bind(&left_ne_right); | 6467 __ bind(&left_ne_right); |
| 6726 | 6468 |
| 6727 // Handle not identical strings. | 6469 // Handle not identical strings. |
| 6728 | 6470 |
| 6729 // Check that both strings are internalized strings. If they are, we're done | 6471 // Check that both strings are internalized strings. If they are, we're done |
| 6730 // because we already know they are not identical. | 6472 // because we already know they are not identical. We know they are both |
| 6473 // strings. |
| 6731 if (equality) { | 6474 if (equality) { |
| 6732 ASSERT(GetCondition() == eq); | 6475 ASSERT(GetCondition() == eq); |
| 6733 STATIC_ASSERT(kInternalizedTag != 0); | 6476 STATIC_ASSERT(kInternalizedTag != 0); |
| 6734 __ And(tmp3, tmp1, Operand(tmp2)); | 6477 __ And(tmp3, tmp1, Operand(tmp2)); |
| 6735 __ And(tmp5, tmp3, Operand(kIsInternalizedMask)); | 6478 __ And(tmp5, tmp3, Operand(kIsInternalizedMask)); |
| 6736 Label is_symbol; | 6479 Label is_symbol; |
| 6737 __ Branch(&is_symbol, eq, tmp5, Operand(zero_reg)); | 6480 __ Branch(&is_symbol, eq, tmp5, Operand(zero_reg)); |
| 6738 // Make sure a0 is non-zero. At this point input operands are | 6481 // Make sure a0 is non-zero. At this point input operands are |
| 6739 // guaranteed to be non-zero. | 6482 // guaranteed to be non-zero. |
| 6740 ASSERT(right.is(a0)); | 6483 ASSERT(right.is(a0)); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6800 __ Branch(&miss, ne, a2, Operand(known_map_)); | 6543 __ Branch(&miss, ne, a2, Operand(known_map_)); |
| 6801 __ Branch(&miss, ne, a3, Operand(known_map_)); | 6544 __ Branch(&miss, ne, a3, Operand(known_map_)); |
| 6802 | 6545 |
| 6803 __ Ret(USE_DELAY_SLOT); | 6546 __ Ret(USE_DELAY_SLOT); |
| 6804 __ subu(v0, a0, a1); | 6547 __ subu(v0, a0, a1); |
| 6805 | 6548 |
| 6806 __ bind(&miss); | 6549 __ bind(&miss); |
| 6807 GenerateMiss(masm); | 6550 GenerateMiss(masm); |
| 6808 } | 6551 } |
| 6809 | 6552 |
| 6553 |
| 6810 void ICCompareStub::GenerateMiss(MacroAssembler* masm) { | 6554 void ICCompareStub::GenerateMiss(MacroAssembler* masm) { |
| 6811 { | 6555 { |
| 6812 // Call the runtime system in a fresh internal frame. | 6556 // Call the runtime system in a fresh internal frame. |
| 6813 ExternalReference miss = | 6557 ExternalReference miss = |
| 6814 ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate()); | 6558 ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate()); |
| 6815 FrameScope scope(masm, StackFrame::INTERNAL); | 6559 FrameScope scope(masm, StackFrame::INTERNAL); |
| 6816 __ Push(a1, a0); | 6560 __ Push(a1, a0); |
| 6817 __ push(ra); | 6561 __ push(ra); |
| 6818 __ Push(a1, a0); | 6562 __ Push(a1, a0); |
| 6819 __ li(t0, Operand(Smi::FromInt(op_))); | 6563 __ li(t0, Operand(Smi::FromInt(op_))); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6925 // Stop if found the property. | 6669 // Stop if found the property. |
| 6926 __ Branch(miss, eq, entity_name, Operand(Handle<Name>(name))); | 6670 __ Branch(miss, eq, entity_name, Operand(Handle<Name>(name))); |
| 6927 | 6671 |
| 6928 Label good; | 6672 Label good; |
| 6929 __ Branch(&good, eq, entity_name, Operand(tmp)); | 6673 __ Branch(&good, eq, entity_name, Operand(tmp)); |
| 6930 | 6674 |
| 6931 // Check if the entry name is not a unique name. | 6675 // Check if the entry name is not a unique name. |
| 6932 __ lw(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); | 6676 __ lw(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); |
| 6933 __ lbu(entity_name, | 6677 __ lbu(entity_name, |
| 6934 FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); | 6678 FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); |
| 6935 __ And(scratch0, entity_name, Operand(kIsInternalizedMask)); | 6679 __ JumpIfNotUniqueName(entity_name, miss); |
| 6936 __ Branch(&good, ne, scratch0, Operand(zero_reg)); | |
| 6937 __ Branch(miss, ne, entity_name, Operand(SYMBOL_TYPE)); | |
| 6938 | |
| 6939 __ bind(&good); | 6680 __ bind(&good); |
| 6940 | 6681 |
| 6941 // Restore the properties. | 6682 // Restore the properties. |
| 6942 __ lw(properties, | 6683 __ lw(properties, |
| 6943 FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 6684 FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 6944 } | 6685 } |
| 6945 | 6686 |
| 6946 const int spill_mask = | 6687 const int spill_mask = |
| 6947 (ra.bit() | t2.bit() | t1.bit() | t0.bit() | a3.bit() | | 6688 (ra.bit() | t2.bit() | t1.bit() | t0.bit() | a3.bit() | |
| 6948 a2.bit() | a1.bit() | a0.bit() | v0.bit()); | 6689 a2.bit() | a1.bit() | a0.bit() | v0.bit()); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7102 __ lw(entry_key, FieldMemOperand(index, kElementsStartOffset)); | 6843 __ lw(entry_key, FieldMemOperand(index, kElementsStartOffset)); |
| 7103 | 6844 |
| 7104 // Having undefined at this place means the name is not contained. | 6845 // Having undefined at this place means the name is not contained. |
| 7105 __ Branch(¬_in_dictionary, eq, entry_key, Operand(undefined)); | 6846 __ Branch(¬_in_dictionary, eq, entry_key, Operand(undefined)); |
| 7106 | 6847 |
| 7107 // Stop if found the property. | 6848 // Stop if found the property. |
| 7108 __ Branch(&in_dictionary, eq, entry_key, Operand(key)); | 6849 __ Branch(&in_dictionary, eq, entry_key, Operand(key)); |
| 7109 | 6850 |
| 7110 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { | 6851 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 7111 // Check if the entry name is not a unique name. | 6852 // Check if the entry name is not a unique name. |
| 7112 Label cont; | |
| 7113 __ lw(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); | 6853 __ lw(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset)); |
| 7114 __ lbu(entry_key, | 6854 __ lbu(entry_key, |
| 7115 FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); | 6855 FieldMemOperand(entry_key, Map::kInstanceTypeOffset)); |
| 7116 __ And(result, entry_key, Operand(kIsInternalizedMask)); | 6856 __ JumpIfNotUniqueName(entry_key, &maybe_in_dictionary); |
| 7117 __ Branch(&cont, ne, result, Operand(zero_reg)); | |
| 7118 __ Branch(&maybe_in_dictionary, ne, entry_key, Operand(SYMBOL_TYPE)); | |
| 7119 __ bind(&cont); | |
| 7120 } | 6857 } |
| 7121 } | 6858 } |
| 7122 | 6859 |
| 7123 __ bind(&maybe_in_dictionary); | 6860 __ bind(&maybe_in_dictionary); |
| 7124 // If we are doing negative lookup then probing failure should be | 6861 // If we are doing negative lookup then probing failure should be |
| 7125 // treated as a lookup success. For positive lookup probing failure | 6862 // treated as a lookup success. For positive lookup probing failure |
| 7126 // should be treated as lookup failure. | 6863 // should be treated as lookup failure. |
| 7127 if (mode_ == POSITIVE_LOOKUP) { | 6864 if (mode_ == POSITIVE_LOOKUP) { |
| 7128 __ Ret(USE_DELAY_SLOT); | 6865 __ Ret(USE_DELAY_SLOT); |
| 7129 __ mov(result, zero_reg); | 6866 __ mov(result, zero_reg); |
| 7130 } | 6867 } |
| 7131 | 6868 |
| 7132 __ bind(&in_dictionary); | 6869 __ bind(&in_dictionary); |
| 7133 __ Ret(USE_DELAY_SLOT); | 6870 __ Ret(USE_DELAY_SLOT); |
| 7134 __ li(result, 1); | 6871 __ li(result, 1); |
| 7135 | 6872 |
| 7136 __ bind(¬_in_dictionary); | 6873 __ bind(¬_in_dictionary); |
| 7137 __ Ret(USE_DELAY_SLOT); | 6874 __ Ret(USE_DELAY_SLOT); |
| 7138 __ mov(result, zero_reg); | 6875 __ mov(result, zero_reg); |
| 7139 } | 6876 } |
| 7140 | 6877 |
| 7141 | 6878 |
| 7142 struct AheadOfTimeWriteBarrierStubList { | 6879 struct AheadOfTimeWriteBarrierStubList { |
| 7143 Register object, value, address; | 6880 Register object, value, address; |
| 7144 RememberedSetAction action; | 6881 RememberedSetAction action; |
| 7145 }; | 6882 }; |
| 7146 | 6883 |
| 6884 |
| 7147 #define REG(Name) { kRegister_ ## Name ## _Code } | 6885 #define REG(Name) { kRegister_ ## Name ## _Code } |
| 7148 | 6886 |
| 7149 static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { | 6887 static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { |
| 7150 // Used in RegExpExecStub. | 6888 // Used in RegExpExecStub. |
| 7151 { REG(s2), REG(s0), REG(t3), EMIT_REMEMBERED_SET }, | 6889 { REG(s2), REG(s0), REG(t3), EMIT_REMEMBERED_SET }, |
| 7152 // Used in CompileArrayPushCall. | 6890 // Used in CompileArrayPushCall. |
| 7153 // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore. | 6891 // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore. |
| 7154 // Also used in KeyedStoreIC::GenerateGeneric. | 6892 // Also used in KeyedStoreIC::GenerateGeneric. |
| 7155 { REG(a3), REG(t0), REG(t1), EMIT_REMEMBERED_SET }, | 6893 { REG(a3), REG(t0), REG(t1), EMIT_REMEMBERED_SET }, |
| 7156 // Used in CompileStoreGlobal. | 6894 // Used in CompileStoreGlobal. |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7506 __ Addu(a1, a1, Operand(1)); | 7244 __ Addu(a1, a1, Operand(1)); |
| 7507 } | 7245 } |
| 7508 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); | 7246 masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE); |
| 7509 __ sll(a1, a1, kPointerSizeLog2); | 7247 __ sll(a1, a1, kPointerSizeLog2); |
| 7510 __ Ret(USE_DELAY_SLOT); | 7248 __ Ret(USE_DELAY_SLOT); |
| 7511 __ Addu(sp, sp, a1); | 7249 __ Addu(sp, sp, a1); |
| 7512 } | 7250 } |
| 7513 | 7251 |
| 7514 | 7252 |
| 7515 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { | 7253 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { |
| 7516 if (entry_hook_ != NULL) { | 7254 if (masm->isolate()->function_entry_hook() != NULL) { |
| 7255 AllowStubCallsScope allow_stub_calls(masm, true); |
| 7517 ProfileEntryHookStub stub; | 7256 ProfileEntryHookStub stub; |
| 7518 __ push(ra); | 7257 __ push(ra); |
| 7519 __ CallStub(&stub); | 7258 __ CallStub(&stub); |
| 7520 __ pop(ra); | 7259 __ pop(ra); |
| 7521 } | 7260 } |
| 7522 } | 7261 } |
| 7523 | 7262 |
| 7524 | 7263 |
| 7525 void ProfileEntryHookStub::Generate(MacroAssembler* masm) { | 7264 void ProfileEntryHookStub::Generate(MacroAssembler* masm) { |
| 7526 // The entry hook is a "push ra" instruction, followed by a call. | 7265 // The entry hook is a "push ra" instruction, followed by a call. |
| 7527 // Note: on MIPS "push" is 2 instruction | 7266 // Note: on MIPS "push" is 2 instruction |
| 7528 const int32_t kReturnAddressDistanceFromFunctionStart = | 7267 const int32_t kReturnAddressDistanceFromFunctionStart = |
| 7529 Assembler::kCallTargetAddressOffset + (2 * Assembler::kInstrSize); | 7268 Assembler::kCallTargetAddressOffset + (2 * Assembler::kInstrSize); |
| 7530 | 7269 |
| 7531 // Save live volatile registers. | 7270 // This should contain all kJSCallerSaved registers. |
| 7532 __ Push(ra, t1, a1); | 7271 const RegList kSavedRegs = |
| 7533 const int32_t kNumSavedRegs = 3; | 7272 kJSCallerSaved | // Caller saved registers. |
| 7273 s5.bit(); // Saved stack pointer. |
| 7274 |
| 7275 // We also save ra, so the count here is one higher than the mask indicates. |
| 7276 const int32_t kNumSavedRegs = kNumJSCallerSaved + 2; |
| 7277 |
| 7278 // Save all caller-save registers as this may be called from anywhere. |
| 7279 __ MultiPush(kSavedRegs | ra.bit()); |
| 7534 | 7280 |
| 7535 // Compute the function's address for the first argument. | 7281 // Compute the function's address for the first argument. |
| 7536 __ Subu(a0, ra, Operand(kReturnAddressDistanceFromFunctionStart)); | 7282 __ Subu(a0, ra, Operand(kReturnAddressDistanceFromFunctionStart)); |
| 7537 | 7283 |
| 7538 // The caller's return address is above the saved temporaries. | 7284 // The caller's return address is above the saved temporaries. |
| 7539 // Grab that for the second argument to the hook. | 7285 // Grab that for the second argument to the hook. |
| 7540 __ Addu(a1, sp, Operand(kNumSavedRegs * kPointerSize)); | 7286 __ Addu(a1, sp, Operand(kNumSavedRegs * kPointerSize)); |
| 7541 | 7287 |
| 7542 // Align the stack if necessary. | 7288 // Align the stack if necessary. |
| 7543 int frame_alignment = masm->ActivationFrameAlignment(); | 7289 int frame_alignment = masm->ActivationFrameAlignment(); |
| 7544 if (frame_alignment > kPointerSize) { | 7290 if (frame_alignment > kPointerSize) { |
| 7545 __ mov(t1, sp); | 7291 __ mov(s5, sp); |
| 7546 ASSERT(IsPowerOf2(frame_alignment)); | 7292 ASSERT(IsPowerOf2(frame_alignment)); |
| 7547 __ And(sp, sp, Operand(-frame_alignment)); | 7293 __ And(sp, sp, Operand(-frame_alignment)); |
| 7548 } | 7294 } |
| 7549 | 7295 |
| 7550 #if defined(V8_HOST_ARCH_MIPS) | 7296 #if defined(V8_HOST_ARCH_MIPS) |
| 7551 __ li(at, Operand(reinterpret_cast<int32_t>(&entry_hook_))); | 7297 int32_t entry_hook = |
| 7552 __ lw(at, MemOperand(at)); | 7298 reinterpret_cast<int32_t>(masm->isolate()->function_entry_hook()); |
| 7299 __ li(at, Operand(entry_hook)); |
| 7553 #else | 7300 #else |
| 7554 // Under the simulator we need to indirect the entry hook through a | 7301 // Under the simulator we need to indirect the entry hook through a |
| 7555 // trampoline function at a known address. | 7302 // trampoline function at a known address. |
| 7556 Address trampoline_address = reinterpret_cast<Address>( | 7303 ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline)); |
| 7557 reinterpret_cast<intptr_t>(EntryHookTrampoline)); | |
| 7558 ApiFunction dispatcher(trampoline_address); | |
| 7559 __ li(at, Operand(ExternalReference(&dispatcher, | 7304 __ li(at, Operand(ExternalReference(&dispatcher, |
| 7560 ExternalReference::BUILTIN_CALL, | 7305 ExternalReference::BUILTIN_CALL, |
| 7561 masm->isolate()))); | 7306 masm->isolate()))); |
| 7562 #endif | 7307 #endif |
| 7563 __ Call(at); | 7308 __ Call(at); |
| 7564 | 7309 |
| 7565 // Restore the stack pointer if needed. | 7310 // Restore the stack pointer if needed. |
| 7566 if (frame_alignment > kPointerSize) { | 7311 if (frame_alignment > kPointerSize) { |
| 7567 __ mov(sp, t1); | 7312 __ mov(sp, s5); |
| 7568 } | 7313 } |
| 7569 | 7314 |
| 7570 __ Pop(ra, t1, a1); | 7315 // Also pop ra to get Ret(0). |
| 7316 __ MultiPop(kSavedRegs | ra.bit()); |
| 7571 __ Ret(); | 7317 __ Ret(); |
| 7572 } | 7318 } |
| 7573 | 7319 |
| 7574 | 7320 |
| 7575 template<class T> | 7321 template<class T> |
| 7576 static void CreateArrayDispatch(MacroAssembler* masm) { | 7322 static void CreateArrayDispatch(MacroAssembler* masm) { |
| 7577 int last_index = GetSequenceIndexFromFastElementsKind( | 7323 int last_index = GetSequenceIndexFromFastElementsKind( |
| 7578 TERMINAL_FAST_ELEMENTS_KIND); | 7324 TERMINAL_FAST_ELEMENTS_KIND); |
| 7579 for (int i = 0; i <= last_index; ++i) { | 7325 for (int i = 0; i <= last_index; ++i) { |
| 7580 Label next; | 7326 Label next; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7614 | 7360 |
| 7615 // look at the first argument | 7361 // look at the first argument |
| 7616 __ lw(t1, MemOperand(sp, 0)); | 7362 __ lw(t1, MemOperand(sp, 0)); |
| 7617 __ Branch(&normal_sequence, eq, t1, Operand(zero_reg)); | 7363 __ Branch(&normal_sequence, eq, t1, Operand(zero_reg)); |
| 7618 | 7364 |
| 7619 // We are going to create a holey array, but our kind is non-holey. | 7365 // We are going to create a holey array, but our kind is non-holey. |
| 7620 // Fix kind and retry | 7366 // Fix kind and retry |
| 7621 __ Addu(a3, a3, Operand(1)); | 7367 __ Addu(a3, a3, Operand(1)); |
| 7622 __ Branch(&normal_sequence, eq, a2, Operand(undefined_sentinel)); | 7368 __ Branch(&normal_sequence, eq, a2, Operand(undefined_sentinel)); |
| 7623 | 7369 |
| 7370 // The type cell may have gone megamorphic, don't overwrite if so. |
| 7371 __ lw(t1, FieldMemOperand(a2, kPointerSize)); |
| 7372 __ JumpIfNotSmi(t1, &normal_sequence); |
| 7373 |
| 7624 // Save the resulting elements kind in type info | 7374 // Save the resulting elements kind in type info |
| 7625 __ SmiTag(a3); | 7375 __ SmiTag(a3); |
| 7626 __ sw(a3, FieldMemOperand(a2, kPointerSize)); | 7376 __ sw(a3, FieldMemOperand(a2, kPointerSize)); |
| 7627 __ SmiUntag(a3); | 7377 __ SmiUntag(a3); |
| 7628 | 7378 |
| 7629 __ bind(&normal_sequence); | 7379 __ bind(&normal_sequence); |
| 7630 int last_index = GetSequenceIndexFromFastElementsKind( | 7380 int last_index = GetSequenceIndexFromFastElementsKind( |
| 7631 TERMINAL_FAST_ELEMENTS_KIND); | 7381 TERMINAL_FAST_ELEMENTS_KIND); |
| 7632 for (int i = 0; i <= last_index; ++i) { | 7382 for (int i = 0; i <= last_index; ++i) { |
| 7633 Label next; | 7383 Label next; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 7645 | 7395 |
| 7646 template<class T> | 7396 template<class T> |
| 7647 static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { | 7397 static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { |
| 7648 int to_index = GetSequenceIndexFromFastElementsKind( | 7398 int to_index = GetSequenceIndexFromFastElementsKind( |
| 7649 TERMINAL_FAST_ELEMENTS_KIND); | 7399 TERMINAL_FAST_ELEMENTS_KIND); |
| 7650 for (int i = 0; i <= to_index; ++i) { | 7400 for (int i = 0; i <= to_index; ++i) { |
| 7651 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); | 7401 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); |
| 7652 T stub(kind); | 7402 T stub(kind); |
| 7653 stub.GetCode(isolate)->set_is_pregenerated(true); | 7403 stub.GetCode(isolate)->set_is_pregenerated(true); |
| 7654 if (AllocationSiteInfo::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) { | 7404 if (AllocationSiteInfo::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) { |
| 7655 T stub1(kind, true); | 7405 T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES); |
| 7656 stub1.GetCode(isolate)->set_is_pregenerated(true); | 7406 stub1.GetCode(isolate)->set_is_pregenerated(true); |
| 7657 } | 7407 } |
| 7658 } | 7408 } |
| 7659 } | 7409 } |
| 7660 | 7410 |
| 7661 | 7411 |
| 7662 void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { | 7412 void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) { |
| 7663 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>( | 7413 ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>( |
| 7664 isolate); | 7414 isolate); |
| 7665 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>( | 7415 ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>( |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7836 __ bind(&fast_elements_case); | 7586 __ bind(&fast_elements_case); |
| 7837 GenerateCase(masm, FAST_ELEMENTS); | 7587 GenerateCase(masm, FAST_ELEMENTS); |
| 7838 } | 7588 } |
| 7839 | 7589 |
| 7840 | 7590 |
| 7841 #undef __ | 7591 #undef __ |
| 7842 | 7592 |
| 7843 } } // namespace v8::internal | 7593 } } // namespace v8::internal |
| 7844 | 7594 |
| 7845 #endif // V8_TARGET_ARCH_MIPS | 7595 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |