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 |
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 RememberedSetAction remembered_set_action, | 482 RememberedSetAction remembered_set_action, |
483 SmiCheck smi_check) { | 483 SmiCheck smi_check) { |
484 // The compiled code assumes that record write doesn't change the | 484 // The compiled code assumes that record write doesn't change the |
485 // context register, so we check that none of the clobbered | 485 // context register, so we check that none of the clobbered |
486 // registers are cp. | 486 // registers are cp. |
487 ASSERT(!address.is(cp) && !value.is(cp)); | 487 ASSERT(!address.is(cp) && !value.is(cp)); |
488 | 488 |
489 if (emit_debug_code()) { | 489 if (emit_debug_code()) { |
490 ldr(ip, MemOperand(address)); | 490 ldr(ip, MemOperand(address)); |
491 cmp(ip, value); | 491 cmp(ip, value); |
492 Check(eq, kWrongAddressOrValuePassedToRecordWrite); | 492 Check(eq, "Wrong address or value passed to RecordWrite"); |
493 } | 493 } |
494 | 494 |
495 Label done; | 495 Label done; |
496 | 496 |
497 if (smi_check == INLINE_SMI_CHECK) { | 497 if (smi_check == INLINE_SMI_CHECK) { |
498 JumpIfSmi(value, &done); | 498 JumpIfSmi(value, &done); |
499 } | 499 } |
500 | 500 |
501 CheckPageFlag(value, | 501 CheckPageFlag(value, |
502 value, // Used as scratch. | 502 value, // Used as scratch. |
(...skipping 980 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1483 | 1483 |
1484 ASSERT(!holder_reg.is(scratch)); | 1484 ASSERT(!holder_reg.is(scratch)); |
1485 ASSERT(!holder_reg.is(ip)); | 1485 ASSERT(!holder_reg.is(ip)); |
1486 ASSERT(!scratch.is(ip)); | 1486 ASSERT(!scratch.is(ip)); |
1487 | 1487 |
1488 // Load current lexical context from the stack frame. | 1488 // Load current lexical context from the stack frame. |
1489 ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1489 ldr(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
1490 // In debug mode, make sure the lexical context is set. | 1490 // In debug mode, make sure the lexical context is set. |
1491 #ifdef DEBUG | 1491 #ifdef DEBUG |
1492 cmp(scratch, Operand::Zero()); | 1492 cmp(scratch, Operand::Zero()); |
1493 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext); | 1493 Check(ne, "we should not have an empty lexical context"); |
1494 #endif | 1494 #endif |
1495 | 1495 |
1496 // Load the native context of the current context. | 1496 // Load the native context of the current context. |
1497 int offset = | 1497 int offset = |
1498 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize; | 1498 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize; |
1499 ldr(scratch, FieldMemOperand(scratch, offset)); | 1499 ldr(scratch, FieldMemOperand(scratch, offset)); |
1500 ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); | 1500 ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); |
1501 | 1501 |
1502 // Check the context is a native context. | 1502 // Check the context is a native context. |
1503 if (emit_debug_code()) { | 1503 if (emit_debug_code()) { |
1504 // Cannot use ip as a temporary in this verification code. Due to the fact | 1504 // Cannot use ip as a temporary in this verification code. Due to the fact |
1505 // that ip is clobbered as part of cmp with an object Operand. | 1505 // that ip is clobbered as part of cmp with an object Operand. |
1506 push(holder_reg); // Temporarily save holder on the stack. | 1506 push(holder_reg); // Temporarily save holder on the stack. |
1507 // Read the first word and compare to the native_context_map. | 1507 // Read the first word and compare to the native_context_map. |
1508 ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); | 1508 ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); |
1509 LoadRoot(ip, Heap::kNativeContextMapRootIndex); | 1509 LoadRoot(ip, Heap::kNativeContextMapRootIndex); |
1510 cmp(holder_reg, ip); | 1510 cmp(holder_reg, ip); |
1511 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); | 1511 Check(eq, "JSGlobalObject::native_context should be a native context."); |
1512 pop(holder_reg); // Restore holder. | 1512 pop(holder_reg); // Restore holder. |
1513 } | 1513 } |
1514 | 1514 |
1515 // Check if both contexts are the same. | 1515 // Check if both contexts are the same. |
1516 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); | 1516 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); |
1517 cmp(scratch, Operand(ip)); | 1517 cmp(scratch, Operand(ip)); |
1518 b(eq, &same_contexts); | 1518 b(eq, &same_contexts); |
1519 | 1519 |
1520 // Check the context is a native context. | 1520 // Check the context is a native context. |
1521 if (emit_debug_code()) { | 1521 if (emit_debug_code()) { |
1522 // Cannot use ip as a temporary in this verification code. Due to the fact | 1522 // Cannot use ip as a temporary in this verification code. Due to the fact |
1523 // that ip is clobbered as part of cmp with an object Operand. | 1523 // that ip is clobbered as part of cmp with an object Operand. |
1524 push(holder_reg); // Temporarily save holder on the stack. | 1524 push(holder_reg); // Temporarily save holder on the stack. |
1525 mov(holder_reg, ip); // Move ip to its holding place. | 1525 mov(holder_reg, ip); // Move ip to its holding place. |
1526 LoadRoot(ip, Heap::kNullValueRootIndex); | 1526 LoadRoot(ip, Heap::kNullValueRootIndex); |
1527 cmp(holder_reg, ip); | 1527 cmp(holder_reg, ip); |
1528 Check(ne, kJSGlobalProxyContextShouldNotBeNull); | 1528 Check(ne, "JSGlobalProxy::context() should not be null."); |
1529 | 1529 |
1530 ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); | 1530 ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); |
1531 LoadRoot(ip, Heap::kNativeContextMapRootIndex); | 1531 LoadRoot(ip, Heap::kNativeContextMapRootIndex); |
1532 cmp(holder_reg, ip); | 1532 cmp(holder_reg, ip); |
1533 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext); | 1533 Check(eq, "JSGlobalObject::native_context should be a native context."); |
1534 // Restore ip is not needed. ip is reloaded below. | 1534 // Restore ip is not needed. ip is reloaded below. |
1535 pop(holder_reg); // Restore holder. | 1535 pop(holder_reg); // Restore holder. |
1536 // Restore ip to holder's context. | 1536 // Restore ip to holder's context. |
1537 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); | 1537 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset)); |
1538 } | 1538 } |
1539 | 1539 |
1540 // Check that the security token in the calling global object is | 1540 // Check that the security token in the calling global object is |
1541 // compatible with the security token in the receiving global | 1541 // compatible with the security token in the receiving global |
1542 // object. | 1542 // object. |
1543 int token_offset = Context::kHeaderSize + | 1543 int token_offset = Context::kHeaderSize + |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1720 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 1720 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
1721 // Load allocation top into result and allocation limit into ip. | 1721 // Load allocation top into result and allocation limit into ip. |
1722 ldm(ia, topaddr, result.bit() | ip.bit()); | 1722 ldm(ia, topaddr, result.bit() | ip.bit()); |
1723 } else { | 1723 } else { |
1724 if (emit_debug_code()) { | 1724 if (emit_debug_code()) { |
1725 // Assert that result actually contains top on entry. ip is used | 1725 // Assert that result actually contains top on entry. ip is used |
1726 // immediately below so this use of ip does not cause difference with | 1726 // immediately below so this use of ip does not cause difference with |
1727 // respect to register content between debug and release mode. | 1727 // respect to register content between debug and release mode. |
1728 ldr(ip, MemOperand(topaddr)); | 1728 ldr(ip, MemOperand(topaddr)); |
1729 cmp(result, ip); | 1729 cmp(result, ip); |
1730 Check(eq, kUnexpectedAllocationTop); | 1730 Check(eq, "Unexpected allocation top"); |
1731 } | 1731 } |
1732 // Load allocation limit into ip. Result already contains allocation top. | 1732 // Load allocation limit into ip. Result already contains allocation top. |
1733 ldr(ip, MemOperand(topaddr, limit - top)); | 1733 ldr(ip, MemOperand(topaddr, limit - top)); |
1734 } | 1734 } |
1735 | 1735 |
1736 if ((flags & DOUBLE_ALIGNMENT) != 0) { | 1736 if ((flags & DOUBLE_ALIGNMENT) != 0) { |
1737 // Align the next allocation. Storing the filler map without checking top is | 1737 // Align the next allocation. Storing the filler map without checking top is |
1738 // always safe because the limit of the heap is always aligned. | 1738 // always safe because the limit of the heap is always aligned. |
1739 ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); | 1739 ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); |
1740 ASSERT(kPointerAlignment * 2 == kDoubleAlignment); | 1740 ASSERT(kPointerAlignment * 2 == kDoubleAlignment); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1818 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 1818 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
1819 // Load allocation top into result and allocation limit into ip. | 1819 // Load allocation top into result and allocation limit into ip. |
1820 ldm(ia, topaddr, result.bit() | ip.bit()); | 1820 ldm(ia, topaddr, result.bit() | ip.bit()); |
1821 } else { | 1821 } else { |
1822 if (emit_debug_code()) { | 1822 if (emit_debug_code()) { |
1823 // Assert that result actually contains top on entry. ip is used | 1823 // Assert that result actually contains top on entry. ip is used |
1824 // immediately below so this use of ip does not cause difference with | 1824 // immediately below so this use of ip does not cause difference with |
1825 // respect to register content between debug and release mode. | 1825 // respect to register content between debug and release mode. |
1826 ldr(ip, MemOperand(topaddr)); | 1826 ldr(ip, MemOperand(topaddr)); |
1827 cmp(result, ip); | 1827 cmp(result, ip); |
1828 Check(eq, kUnexpectedAllocationTop); | 1828 Check(eq, "Unexpected allocation top"); |
1829 } | 1829 } |
1830 // Load allocation limit into ip. Result already contains allocation top. | 1830 // Load allocation limit into ip. Result already contains allocation top. |
1831 ldr(ip, MemOperand(topaddr, limit - top)); | 1831 ldr(ip, MemOperand(topaddr, limit - top)); |
1832 } | 1832 } |
1833 | 1833 |
1834 if ((flags & DOUBLE_ALIGNMENT) != 0) { | 1834 if ((flags & DOUBLE_ALIGNMENT) != 0) { |
1835 // Align the next allocation. Storing the filler map without checking top is | 1835 // Align the next allocation. Storing the filler map without checking top is |
1836 // always safe because the limit of the heap is always aligned. | 1836 // always safe because the limit of the heap is always aligned. |
1837 ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); | 1837 ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); |
1838 ASSERT(kPointerAlignment * 2 == kDoubleAlignment); | 1838 ASSERT(kPointerAlignment * 2 == kDoubleAlignment); |
(...skipping 13 matching lines...) Expand all Loading... |
1852 } else { | 1852 } else { |
1853 add(scratch2, result, Operand(object_size), SetCC); | 1853 add(scratch2, result, Operand(object_size), SetCC); |
1854 } | 1854 } |
1855 b(cs, gc_required); | 1855 b(cs, gc_required); |
1856 cmp(scratch2, Operand(ip)); | 1856 cmp(scratch2, Operand(ip)); |
1857 b(hi, gc_required); | 1857 b(hi, gc_required); |
1858 | 1858 |
1859 // Update allocation top. result temporarily holds the new top. | 1859 // Update allocation top. result temporarily holds the new top. |
1860 if (emit_debug_code()) { | 1860 if (emit_debug_code()) { |
1861 tst(scratch2, Operand(kObjectAlignmentMask)); | 1861 tst(scratch2, Operand(kObjectAlignmentMask)); |
1862 Check(eq, kUnalignedAllocationInNewSpace); | 1862 Check(eq, "Unaligned allocation in new space"); |
1863 } | 1863 } |
1864 str(scratch2, MemOperand(topaddr)); | 1864 str(scratch2, MemOperand(topaddr)); |
1865 | 1865 |
1866 // Tag object if requested. | 1866 // Tag object if requested. |
1867 if ((flags & TAG_OBJECT) != 0) { | 1867 if ((flags & TAG_OBJECT) != 0) { |
1868 add(result, result, Operand(kHeapObjectTag)); | 1868 add(result, result, Operand(kHeapObjectTag)); |
1869 } | 1869 } |
1870 } | 1870 } |
1871 | 1871 |
1872 | 1872 |
1873 void MacroAssembler::UndoAllocationInNewSpace(Register object, | 1873 void MacroAssembler::UndoAllocationInNewSpace(Register object, |
1874 Register scratch) { | 1874 Register scratch) { |
1875 ExternalReference new_space_allocation_top = | 1875 ExternalReference new_space_allocation_top = |
1876 ExternalReference::new_space_allocation_top_address(isolate()); | 1876 ExternalReference::new_space_allocation_top_address(isolate()); |
1877 | 1877 |
1878 // Make sure the object has no tag before resetting top. | 1878 // Make sure the object has no tag before resetting top. |
1879 and_(object, object, Operand(~kHeapObjectTagMask)); | 1879 and_(object, object, Operand(~kHeapObjectTagMask)); |
1880 #ifdef DEBUG | 1880 #ifdef DEBUG |
1881 // Check that the object un-allocated is below the current top. | 1881 // Check that the object un-allocated is below the current top. |
1882 mov(scratch, Operand(new_space_allocation_top)); | 1882 mov(scratch, Operand(new_space_allocation_top)); |
1883 ldr(scratch, MemOperand(scratch)); | 1883 ldr(scratch, MemOperand(scratch)); |
1884 cmp(object, scratch); | 1884 cmp(object, scratch); |
1885 Check(lt, kUndoAllocationOfNonAllocatedMemory); | 1885 Check(lt, "Undo allocation of non allocated memory"); |
1886 #endif | 1886 #endif |
1887 // Write the address of the object to un-allocate as the current top. | 1887 // Write the address of the object to un-allocate as the current top. |
1888 mov(scratch, Operand(new_space_allocation_top)); | 1888 mov(scratch, Operand(new_space_allocation_top)); |
1889 str(object, MemOperand(scratch)); | 1889 str(object, MemOperand(scratch)); |
1890 } | 1890 } |
1891 | 1891 |
1892 | 1892 |
1893 void MacroAssembler::AllocateTwoByteString(Register result, | 1893 void MacroAssembler::AllocateTwoByteString(Register result, |
1894 Register length, | 1894 Register length, |
1895 Register scratch1, | 1895 Register scratch1, |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2124 scratch1, | 2124 scratch1, |
2125 isolate()->factory()->heap_number_map(), | 2125 isolate()->factory()->heap_number_map(), |
2126 fail, | 2126 fail, |
2127 DONT_DO_SMI_CHECK); | 2127 DONT_DO_SMI_CHECK); |
2128 | 2128 |
2129 vldr(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); | 2129 vldr(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); |
2130 // Force a canonical NaN. | 2130 // Force a canonical NaN. |
2131 if (emit_debug_code()) { | 2131 if (emit_debug_code()) { |
2132 vmrs(ip); | 2132 vmrs(ip); |
2133 tst(ip, Operand(kVFPDefaultNaNModeControlBit)); | 2133 tst(ip, Operand(kVFPDefaultNaNModeControlBit)); |
2134 Assert(ne, kDefaultNaNModeNotSet); | 2134 Assert(ne, "Default NaN mode not set"); |
2135 } | 2135 } |
2136 VFPCanonicalizeNaN(double_scratch); | 2136 VFPCanonicalizeNaN(double_scratch); |
2137 b(&store); | 2137 b(&store); |
2138 | 2138 |
2139 bind(&smi_value); | 2139 bind(&smi_value); |
2140 SmiToDouble(double_scratch, value_reg); | 2140 SmiToDouble(double_scratch, value_reg); |
2141 | 2141 |
2142 bind(&store); | 2142 bind(&store); |
2143 add(scratch1, elements_reg, Operand::DoubleOffsetFromSmiKey(key_reg)); | 2143 add(scratch1, elements_reg, Operand::DoubleOffsetFromSmiKey(key_reg)); |
2144 vstr(double_scratch, | 2144 vstr(double_scratch, |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2374 } | 2374 } |
2375 // load value from ReturnValue | 2375 // load value from ReturnValue |
2376 ldr(r0, MemOperand(fp, return_value_offset*kPointerSize)); | 2376 ldr(r0, MemOperand(fp, return_value_offset*kPointerSize)); |
2377 bind(&return_value_loaded); | 2377 bind(&return_value_loaded); |
2378 // No more valid handles (the result handle was the last one). Restore | 2378 // No more valid handles (the result handle was the last one). Restore |
2379 // previous handle scope. | 2379 // previous handle scope. |
2380 str(r4, MemOperand(r7, kNextOffset)); | 2380 str(r4, MemOperand(r7, kNextOffset)); |
2381 if (emit_debug_code()) { | 2381 if (emit_debug_code()) { |
2382 ldr(r1, MemOperand(r7, kLevelOffset)); | 2382 ldr(r1, MemOperand(r7, kLevelOffset)); |
2383 cmp(r1, r6); | 2383 cmp(r1, r6); |
2384 Check(eq, kUnexpectedLevelAfterReturnFromApiCall); | 2384 Check(eq, "Unexpected level after return from api call"); |
2385 } | 2385 } |
2386 sub(r6, r6, Operand(1)); | 2386 sub(r6, r6, Operand(1)); |
2387 str(r6, MemOperand(r7, kLevelOffset)); | 2387 str(r6, MemOperand(r7, kLevelOffset)); |
2388 ldr(ip, MemOperand(r7, kLimitOffset)); | 2388 ldr(ip, MemOperand(r7, kLimitOffset)); |
2389 cmp(r5, ip); | 2389 cmp(r5, ip); |
2390 b(ne, &delete_allocated_handles); | 2390 b(ne, &delete_allocated_handles); |
2391 | 2391 |
2392 // Check if the function scheduled an exception. | 2392 // Check if the function scheduled an exception. |
2393 bind(&leave_exit_frame); | 2393 bind(&leave_exit_frame); |
2394 LoadRoot(r4, Heap::kTheHoleValueRootIndex); | 2394 LoadRoot(r4, Heap::kTheHoleValueRootIndex); |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2775 ASSERT(value > 0); | 2775 ASSERT(value > 0); |
2776 if (FLAG_native_code_counters && counter->Enabled()) { | 2776 if (FLAG_native_code_counters && counter->Enabled()) { |
2777 mov(scratch2, Operand(ExternalReference(counter))); | 2777 mov(scratch2, Operand(ExternalReference(counter))); |
2778 ldr(scratch1, MemOperand(scratch2)); | 2778 ldr(scratch1, MemOperand(scratch2)); |
2779 sub(scratch1, scratch1, Operand(value)); | 2779 sub(scratch1, scratch1, Operand(value)); |
2780 str(scratch1, MemOperand(scratch2)); | 2780 str(scratch1, MemOperand(scratch2)); |
2781 } | 2781 } |
2782 } | 2782 } |
2783 | 2783 |
2784 | 2784 |
2785 void MacroAssembler::Assert(Condition cond, BailoutReason reason) { | 2785 void MacroAssembler::Assert(Condition cond, const char* msg) { |
2786 if (emit_debug_code()) | 2786 if (emit_debug_code()) |
2787 Check(cond, reason); | 2787 Check(cond, msg); |
2788 } | 2788 } |
2789 | 2789 |
2790 | 2790 |
2791 void MacroAssembler::AssertFastElements(Register elements) { | 2791 void MacroAssembler::AssertFastElements(Register elements) { |
2792 if (emit_debug_code()) { | 2792 if (emit_debug_code()) { |
2793 ASSERT(!elements.is(ip)); | 2793 ASSERT(!elements.is(ip)); |
2794 Label ok; | 2794 Label ok; |
2795 push(elements); | 2795 push(elements); |
2796 ldr(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); | 2796 ldr(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); |
2797 LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 2797 LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
2798 cmp(elements, ip); | 2798 cmp(elements, ip); |
2799 b(eq, &ok); | 2799 b(eq, &ok); |
2800 LoadRoot(ip, Heap::kFixedDoubleArrayMapRootIndex); | 2800 LoadRoot(ip, Heap::kFixedDoubleArrayMapRootIndex); |
2801 cmp(elements, ip); | 2801 cmp(elements, ip); |
2802 b(eq, &ok); | 2802 b(eq, &ok); |
2803 LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); | 2803 LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); |
2804 cmp(elements, ip); | 2804 cmp(elements, ip); |
2805 b(eq, &ok); | 2805 b(eq, &ok); |
2806 Abort(kJSObjectWithFastElementsMapHasSlowElements); | 2806 Abort("JSObject with fast elements map has slow elements"); |
2807 bind(&ok); | 2807 bind(&ok); |
2808 pop(elements); | 2808 pop(elements); |
2809 } | 2809 } |
2810 } | 2810 } |
2811 | 2811 |
2812 | 2812 |
2813 void MacroAssembler::Check(Condition cond, BailoutReason reason) { | 2813 void MacroAssembler::Check(Condition cond, const char* msg) { |
2814 Label L; | 2814 Label L; |
2815 b(cond, &L); | 2815 b(cond, &L); |
2816 Abort(reason); | 2816 Abort(msg); |
2817 // will not return here | 2817 // will not return here |
2818 bind(&L); | 2818 bind(&L); |
2819 } | 2819 } |
2820 | 2820 |
2821 | 2821 |
2822 void MacroAssembler::Abort(BailoutReason reason) { | 2822 void MacroAssembler::Abort(const char* msg) { |
2823 Label abort_start; | 2823 Label abort_start; |
2824 bind(&abort_start); | 2824 bind(&abort_start); |
2825 // We want to pass the msg string like a smi to avoid GC | 2825 // We want to pass the msg string like a smi to avoid GC |
2826 // problems, however msg is not guaranteed to be aligned | 2826 // problems, however msg is not guaranteed to be aligned |
2827 // properly. Instead, we pass an aligned pointer that is | 2827 // properly. Instead, we pass an aligned pointer that is |
2828 // a proper v8 smi, but also pass the alignment difference | 2828 // a proper v8 smi, but also pass the alignment difference |
2829 // from the real pointer as a smi. | 2829 // from the real pointer as a smi. |
2830 const char* msg = GetBailoutReason(reason); | |
2831 intptr_t p1 = reinterpret_cast<intptr_t>(msg); | 2830 intptr_t p1 = reinterpret_cast<intptr_t>(msg); |
2832 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; | 2831 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; |
2833 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); | 2832 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); |
2834 #ifdef DEBUG | 2833 #ifdef DEBUG |
2835 if (msg != NULL) { | 2834 if (msg != NULL) { |
2836 RecordComment("Abort message: "); | 2835 RecordComment("Abort message: "); |
2837 RecordComment(msg); | 2836 RecordComment(msg); |
2838 } | 2837 } |
2839 #endif | 2838 #endif |
2840 | 2839 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2963 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, | 2962 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, |
2964 Register map, | 2963 Register map, |
2965 Register scratch) { | 2964 Register scratch) { |
2966 // Load the initial map. The global functions all have initial maps. | 2965 // Load the initial map. The global functions all have initial maps. |
2967 ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 2966 ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
2968 if (emit_debug_code()) { | 2967 if (emit_debug_code()) { |
2969 Label ok, fail; | 2968 Label ok, fail; |
2970 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); | 2969 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK); |
2971 b(&ok); | 2970 b(&ok); |
2972 bind(&fail); | 2971 bind(&fail); |
2973 Abort(kGlobalFunctionsMustHaveInitialMap); | 2972 Abort("Global functions must have initial map"); |
2974 bind(&ok); | 2973 bind(&ok); |
2975 } | 2974 } |
2976 } | 2975 } |
2977 | 2976 |
2978 | 2977 |
2979 void MacroAssembler::JumpIfNotPowerOfTwoOrZero( | 2978 void MacroAssembler::JumpIfNotPowerOfTwoOrZero( |
2980 Register reg, | 2979 Register reg, |
2981 Register scratch, | 2980 Register scratch, |
2982 Label* not_power_of_two_or_zero) { | 2981 Label* not_power_of_two_or_zero) { |
2983 sub(scratch, reg, Operand(1), SetCC); | 2982 sub(scratch, reg, Operand(1), SetCC); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3032 tst(reg1, Operand(kSmiTagMask)); | 3031 tst(reg1, Operand(kSmiTagMask)); |
3033 tst(reg2, Operand(kSmiTagMask), ne); | 3032 tst(reg2, Operand(kSmiTagMask), ne); |
3034 b(eq, on_either_smi); | 3033 b(eq, on_either_smi); |
3035 } | 3034 } |
3036 | 3035 |
3037 | 3036 |
3038 void MacroAssembler::AssertNotSmi(Register object) { | 3037 void MacroAssembler::AssertNotSmi(Register object) { |
3039 if (emit_debug_code()) { | 3038 if (emit_debug_code()) { |
3040 STATIC_ASSERT(kSmiTag == 0); | 3039 STATIC_ASSERT(kSmiTag == 0); |
3041 tst(object, Operand(kSmiTagMask)); | 3040 tst(object, Operand(kSmiTagMask)); |
3042 Check(ne, kOperandIsASmi); | 3041 Check(ne, "Operand is a smi"); |
3043 } | 3042 } |
3044 } | 3043 } |
3045 | 3044 |
3046 | 3045 |
3047 void MacroAssembler::AssertSmi(Register object) { | 3046 void MacroAssembler::AssertSmi(Register object) { |
3048 if (emit_debug_code()) { | 3047 if (emit_debug_code()) { |
3049 STATIC_ASSERT(kSmiTag == 0); | 3048 STATIC_ASSERT(kSmiTag == 0); |
3050 tst(object, Operand(kSmiTagMask)); | 3049 tst(object, Operand(kSmiTagMask)); |
3051 Check(eq, kOperandIsNotSmi); | 3050 Check(eq, "Operand is not smi"); |
3052 } | 3051 } |
3053 } | 3052 } |
3054 | 3053 |
3055 | 3054 |
3056 void MacroAssembler::AssertString(Register object) { | 3055 void MacroAssembler::AssertString(Register object) { |
3057 if (emit_debug_code()) { | 3056 if (emit_debug_code()) { |
3058 STATIC_ASSERT(kSmiTag == 0); | 3057 STATIC_ASSERT(kSmiTag == 0); |
3059 tst(object, Operand(kSmiTagMask)); | 3058 tst(object, Operand(kSmiTagMask)); |
3060 Check(ne, kOperandIsASmiAndNotAString); | 3059 Check(ne, "Operand is a smi and not a string"); |
3061 push(object); | 3060 push(object); |
3062 ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); | 3061 ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); |
3063 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); | 3062 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); |
3064 pop(object); | 3063 pop(object); |
3065 Check(lo, kOperandIsNotAString); | 3064 Check(lo, "Operand is not a string"); |
3066 } | 3065 } |
3067 } | 3066 } |
3068 | 3067 |
3069 | 3068 |
3070 void MacroAssembler::AssertName(Register object) { | 3069 void MacroAssembler::AssertName(Register object) { |
3071 if (emit_debug_code()) { | 3070 if (emit_debug_code()) { |
3072 STATIC_ASSERT(kSmiTag == 0); | 3071 STATIC_ASSERT(kSmiTag == 0); |
3073 tst(object, Operand(kSmiTagMask)); | 3072 tst(object, Operand(kSmiTagMask)); |
3074 Check(ne, kOperandIsASmiAndNotAName); | 3073 Check(ne, "Operand is a smi and not a name"); |
3075 push(object); | 3074 push(object); |
3076 ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); | 3075 ldr(object, FieldMemOperand(object, HeapObject::kMapOffset)); |
3077 CompareInstanceType(object, object, LAST_NAME_TYPE); | 3076 CompareInstanceType(object, object, LAST_NAME_TYPE); |
3078 pop(object); | 3077 pop(object); |
3079 Check(le, kOperandIsNotAName); | 3078 Check(le, "Operand is not a name"); |
3080 } | 3079 } |
3081 } | 3080 } |
3082 | 3081 |
3083 | 3082 |
3084 | 3083 |
3085 void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) { | 3084 void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) { |
3086 if (emit_debug_code()) { | 3085 if (emit_debug_code()) { |
3087 CompareRoot(reg, index); | 3086 CompareRoot(reg, index); |
3088 Check(eq, kHeapNumberMapRegisterClobbered); | 3087 Check(eq, "HeapNumberMap register clobbered."); |
3089 } | 3088 } |
3090 } | 3089 } |
3091 | 3090 |
3092 | 3091 |
3093 void MacroAssembler::JumpIfNotHeapNumber(Register object, | 3092 void MacroAssembler::JumpIfNotHeapNumber(Register object, |
3094 Register heap_number_map, | 3093 Register heap_number_map, |
3095 Register scratch, | 3094 Register scratch, |
3096 Label* on_not_heap_number) { | 3095 Label* on_not_heap_number) { |
3097 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); | 3096 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); |
3098 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 3097 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3224 b(eq, &word_loop); | 3223 b(eq, &word_loop); |
3225 ldrb(scratch, MemOperand(src, 1, PostIndex)); | 3224 ldrb(scratch, MemOperand(src, 1, PostIndex)); |
3226 strb(scratch, MemOperand(dst, 1, PostIndex)); | 3225 strb(scratch, MemOperand(dst, 1, PostIndex)); |
3227 sub(length, length, Operand(1), SetCC); | 3226 sub(length, length, Operand(1), SetCC); |
3228 b(ne, &byte_loop_1); | 3227 b(ne, &byte_loop_1); |
3229 | 3228 |
3230 // Copy bytes in word size chunks. | 3229 // Copy bytes in word size chunks. |
3231 bind(&word_loop); | 3230 bind(&word_loop); |
3232 if (emit_debug_code()) { | 3231 if (emit_debug_code()) { |
3233 tst(src, Operand(kPointerSize - 1)); | 3232 tst(src, Operand(kPointerSize - 1)); |
3234 Assert(eq, kExpectingAlignmentForCopyBytes); | 3233 Assert(eq, "Expecting alignment for CopyBytes"); |
3235 } | 3234 } |
3236 cmp(length, Operand(kPointerSize)); | 3235 cmp(length, Operand(kPointerSize)); |
3237 b(lt, &byte_loop); | 3236 b(lt, &byte_loop); |
3238 ldr(scratch, MemOperand(src, kPointerSize, PostIndex)); | 3237 ldr(scratch, MemOperand(src, kPointerSize, PostIndex)); |
3239 if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) { | 3238 if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) { |
3240 str(scratch, MemOperand(dst, kPointerSize, PostIndex)); | 3239 str(scratch, MemOperand(dst, kPointerSize, PostIndex)); |
3241 } else { | 3240 } else { |
3242 strb(scratch, MemOperand(dst, 1, PostIndex)); | 3241 strb(scratch, MemOperand(dst, 1, PostIndex)); |
3243 mov(scratch, Operand(scratch, LSR, 8)); | 3242 mov(scratch, Operand(scratch, LSR, 8)); |
3244 strb(scratch, MemOperand(dst, 1, PostIndex)); | 3243 strb(scratch, MemOperand(dst, 1, PostIndex)); |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3488 | 3487 |
3489 void MacroAssembler::GetRelocatedValueLocation(Register ldr_location, | 3488 void MacroAssembler::GetRelocatedValueLocation(Register ldr_location, |
3490 Register result) { | 3489 Register result) { |
3491 const uint32_t kLdrOffsetMask = (1 << 12) - 1; | 3490 const uint32_t kLdrOffsetMask = (1 << 12) - 1; |
3492 const int32_t kPCRegOffset = 2 * kPointerSize; | 3491 const int32_t kPCRegOffset = 2 * kPointerSize; |
3493 ldr(result, MemOperand(ldr_location)); | 3492 ldr(result, MemOperand(ldr_location)); |
3494 if (emit_debug_code()) { | 3493 if (emit_debug_code()) { |
3495 // Check that the instruction is a ldr reg, [pc + offset] . | 3494 // Check that the instruction is a ldr reg, [pc + offset] . |
3496 and_(result, result, Operand(kLdrPCPattern)); | 3495 and_(result, result, Operand(kLdrPCPattern)); |
3497 cmp(result, Operand(kLdrPCPattern)); | 3496 cmp(result, Operand(kLdrPCPattern)); |
3498 Check(eq, kTheInstructionToPatchShouldBeALoadFromPc); | 3497 Check(eq, "The instruction to patch should be a load from pc."); |
3499 // Result was clobbered. Restore it. | 3498 // Result was clobbered. Restore it. |
3500 ldr(result, MemOperand(ldr_location)); | 3499 ldr(result, MemOperand(ldr_location)); |
3501 } | 3500 } |
3502 // Get the address of the constant. | 3501 // Get the address of the constant. |
3503 and_(result, result, Operand(kLdrOffsetMask)); | 3502 and_(result, result, Operand(kLdrOffsetMask)); |
3504 add(result, ldr_location, Operand(result)); | 3503 add(result, ldr_location, Operand(result)); |
3505 add(result, result, Operand(kPCRegOffset)); | 3504 add(result, result, Operand(kPCRegOffset)); |
3506 } | 3505 } |
3507 | 3506 |
3508 | 3507 |
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3877 void CodePatcher::EmitCondition(Condition cond) { | 3876 void CodePatcher::EmitCondition(Condition cond) { |
3878 Instr instr = Assembler::instr_at(masm_.pc_); | 3877 Instr instr = Assembler::instr_at(masm_.pc_); |
3879 instr = (instr & ~kCondMask) | cond; | 3878 instr = (instr & ~kCondMask) | cond; |
3880 masm_.emit(instr); | 3879 masm_.emit(instr); |
3881 } | 3880 } |
3882 | 3881 |
3883 | 3882 |
3884 } } // namespace v8::internal | 3883 } } // namespace v8::internal |
3885 | 3884 |
3886 #endif // V8_TARGET_ARCH_ARM | 3885 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |