| 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 1484 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1495 isolate->set_fp_stubs_generated(true); | 1495 isolate->set_fp_stubs_generated(true); |
| 1496 } | 1496 } |
| 1497 | 1497 |
| 1498 | 1498 |
| 1499 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { | 1499 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { |
| 1500 CEntryStub stub(1, kDontSaveFPRegs); | 1500 CEntryStub stub(1, kDontSaveFPRegs); |
| 1501 stub.GetCode(isolate); | 1501 stub.GetCode(isolate); |
| 1502 } | 1502 } |
| 1503 | 1503 |
| 1504 | 1504 |
| 1505 void CEntryStub::GenerateCore(MacroAssembler* masm, | 1505 void CEntryStub::Generate(MacroAssembler* masm) { |
| 1506 Label* throw_normal_exception, | 1506 // Called from JavaScript; parameters are on stack as if calling JS function. |
| 1507 Label* throw_termination_exception, | 1507 // r0: number of arguments including receiver |
| 1508 bool do_gc, | 1508 // r1: pointer to builtin function |
| 1509 bool always_allocate) { | 1509 // fp: frame pointer (restored after C call) |
| 1510 // r0: result parameter for PerformGC, if any | 1510 // sp: stack pointer (restored as callee's sp after C call) |
| 1511 // r4: number of arguments including receiver (C callee-saved) | 1511 // cp: current context (C callee-saved) |
| 1512 |
| 1513 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
| 1514 |
| 1515 __ mov(r5, Operand(r1)); |
| 1516 |
| 1517 // Compute the argv pointer in a callee-saved register. |
| 1518 __ add(r1, sp, Operand(r0, LSL, kPointerSizeLog2)); |
| 1519 __ sub(r1, r1, Operand(kPointerSize)); |
| 1520 |
| 1521 // Enter the exit frame that transitions from JavaScript to C++. |
| 1522 FrameScope scope(masm, StackFrame::MANUAL); |
| 1523 __ EnterExitFrame(save_doubles_); |
| 1524 |
| 1525 // Store a copy of argc in callee-saved registers for later. |
| 1526 __ mov(r4, Operand(r0)); |
| 1527 |
| 1528 // r0, r4: number of arguments including receiver (C callee-saved) |
| 1529 // r1: pointer to the first argument (C callee-saved) |
| 1512 // r5: pointer to builtin function (C callee-saved) | 1530 // r5: pointer to builtin function (C callee-saved) |
| 1513 // r6: pointer to the first argument (C callee-saved) | 1531 |
| 1532 // Result returned in r0 or r0+r1 by default. |
| 1533 |
| 1514 Isolate* isolate = masm->isolate(); | 1534 Isolate* isolate = masm->isolate(); |
| 1515 | 1535 |
| 1516 if (do_gc) { | |
| 1517 // Passing r0. | |
| 1518 __ PrepareCallCFunction(2, 0, r1); | |
| 1519 __ mov(r1, Operand(ExternalReference::isolate_address(masm->isolate()))); | |
| 1520 __ CallCFunction(ExternalReference::perform_gc_function(isolate), | |
| 1521 2, 0); | |
| 1522 } | |
| 1523 | |
| 1524 ExternalReference scope_depth = | |
| 1525 ExternalReference::heap_always_allocate_scope_depth(isolate); | |
| 1526 if (always_allocate) { | |
| 1527 __ mov(r0, Operand(scope_depth)); | |
| 1528 __ ldr(r1, MemOperand(r0)); | |
| 1529 __ add(r1, r1, Operand(1)); | |
| 1530 __ str(r1, MemOperand(r0)); | |
| 1531 } | |
| 1532 | |
| 1533 // Call C built-in. | |
| 1534 // r0 = argc, r1 = argv | |
| 1535 __ mov(r0, Operand(r4)); | |
| 1536 __ mov(r1, Operand(r6)); | |
| 1537 | |
| 1538 #if V8_HOST_ARCH_ARM | 1536 #if V8_HOST_ARCH_ARM |
| 1539 int frame_alignment = MacroAssembler::ActivationFrameAlignment(); | 1537 int frame_alignment = MacroAssembler::ActivationFrameAlignment(); |
| 1540 int frame_alignment_mask = frame_alignment - 1; | 1538 int frame_alignment_mask = frame_alignment - 1; |
| 1541 if (FLAG_debug_code) { | 1539 if (FLAG_debug_code) { |
| 1542 if (frame_alignment > kPointerSize) { | 1540 if (frame_alignment > kPointerSize) { |
| 1543 Label alignment_as_expected; | 1541 Label alignment_as_expected; |
| 1544 ASSERT(IsPowerOf2(frame_alignment)); | 1542 ASSERT(IsPowerOf2(frame_alignment)); |
| 1545 __ tst(sp, Operand(frame_alignment_mask)); | 1543 __ tst(sp, Operand(frame_alignment_mask)); |
| 1546 __ b(eq, &alignment_as_expected); | 1544 __ b(eq, &alignment_as_expected); |
| 1547 // Don't use Check here, as it will call Runtime_Abort re-entering here. | 1545 // Don't use Check here, as it will call Runtime_Abort re-entering here. |
| 1548 __ stop("Unexpected alignment"); | 1546 __ stop("Unexpected alignment"); |
| 1549 __ bind(&alignment_as_expected); | 1547 __ bind(&alignment_as_expected); |
| 1550 } | 1548 } |
| 1551 } | 1549 } |
| 1552 #endif | 1550 #endif |
| 1553 | 1551 |
| 1552 // Call C built-in. |
| 1553 // r0 = argc, r1 = argv |
| 1554 __ mov(r2, Operand(ExternalReference::isolate_address(isolate))); | 1554 __ mov(r2, Operand(ExternalReference::isolate_address(isolate))); |
| 1555 | 1555 |
| 1556 // To let the GC traverse the return address of the exit frames, we need to | 1556 // To let the GC traverse the return address of the exit frames, we need to |
| 1557 // know where the return address is. The CEntryStub is unmovable, so | 1557 // know where the return address is. The CEntryStub is unmovable, so |
| 1558 // we can store the address on the stack to be able to find it again and | 1558 // we can store the address on the stack to be able to find it again and |
| 1559 // we never have to restore it, because it will not change. | 1559 // we never have to restore it, because it will not change. |
| 1560 // Compute the return address in lr to return to after the jump below. Pc is | 1560 // Compute the return address in lr to return to after the jump below. Pc is |
| 1561 // already at '+ 8' from the current instruction but return is after three | 1561 // already at '+ 8' from the current instruction but return is after three |
| 1562 // instructions so add another 4 to pc to get the return address. | 1562 // instructions so add another 4 to pc to get the return address. |
| 1563 { | 1563 { |
| 1564 // Prevent literal pool emission before return address. | 1564 // Prevent literal pool emission before return address. |
| 1565 Assembler::BlockConstPoolScope block_const_pool(masm); | 1565 Assembler::BlockConstPoolScope block_const_pool(masm); |
| 1566 __ add(lr, pc, Operand(4)); | 1566 __ add(lr, pc, Operand(4)); |
| 1567 __ str(lr, MemOperand(sp, 0)); | 1567 __ str(lr, MemOperand(sp, 0)); |
| 1568 __ Call(r5); | 1568 __ Call(r5); |
| 1569 } | 1569 } |
| 1570 | 1570 |
| 1571 __ VFPEnsureFPSCRState(r2); | 1571 __ VFPEnsureFPSCRState(r2); |
| 1572 | 1572 |
| 1573 if (always_allocate) { | 1573 // Runtime functions should not return 'the hole'. Allowing it to escape may |
| 1574 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 | 1574 // lead to crashes in the IC code later. |
| 1575 // though (contain the result). | 1575 if (FLAG_debug_code) { |
| 1576 __ mov(r2, Operand(scope_depth)); | 1576 Label okay; |
| 1577 __ ldr(r3, MemOperand(r2)); | 1577 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); |
| 1578 __ sub(r3, r3, Operand(1)); | 1578 __ b(ne, &okay); |
| 1579 __ str(r3, MemOperand(r2)); | 1579 __ stop("The hole escaped"); |
| 1580 __ bind(&okay); |
| 1580 } | 1581 } |
| 1581 | 1582 |
| 1582 // check for failure result | 1583 // Check result for exception sentinel. |
| 1583 Label failure_returned; | 1584 Label exception_returned; |
| 1584 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); | 1585 __ CompareRoot(r0, Heap::kExceptionRootIndex); |
| 1585 // Lower 2 bits of r2 are 0 iff r0 has failure tag. | 1586 __ b(eq, &exception_returned); |
| 1586 __ add(r2, r0, Operand(1)); | 1587 |
| 1587 __ tst(r2, Operand(kFailureTagMask)); | 1588 ExternalReference pending_exception_address( |
| 1588 __ b(eq, &failure_returned); | 1589 Isolate::kPendingExceptionAddress, isolate); |
| 1590 |
| 1591 // Check that there is no pending exception, otherwise we |
| 1592 // should have returned the exception sentinel. |
| 1593 if (FLAG_debug_code) { |
| 1594 Label okay; |
| 1595 __ mov(r2, Operand(pending_exception_address)); |
| 1596 __ ldr(r2, MemOperand(r2)); |
| 1597 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); |
| 1598 // Cannot use check here as it attempts to generate call into runtime. |
| 1599 __ b(eq, &okay); |
| 1600 __ stop("Unexpected pending exception"); |
| 1601 __ bind(&okay); |
| 1602 } |
| 1589 | 1603 |
| 1590 // Exit C frame and return. | 1604 // Exit C frame and return. |
| 1591 // r0:r1: result | 1605 // r0:r1: result |
| 1592 // sp: stack pointer | 1606 // sp: stack pointer |
| 1593 // fp: frame pointer | 1607 // fp: frame pointer |
| 1594 // Callee-saved register r4 still holds argc. | 1608 // Callee-saved register r4 still holds argc. |
| 1595 __ LeaveExitFrame(save_doubles_, r4, true); | 1609 __ LeaveExitFrame(save_doubles_, r4, true); |
| 1596 __ mov(pc, lr); | 1610 __ mov(pc, lr); |
| 1597 | 1611 |
| 1598 // check if we should retry or throw exception | 1612 // Handling of exception. |
| 1599 Label retry; | 1613 __ bind(&exception_returned); |
| 1600 __ bind(&failure_returned); | |
| 1601 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); | |
| 1602 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | |
| 1603 __ b(eq, &retry); | |
| 1604 | 1614 |
| 1605 // Retrieve the pending exception. | 1615 // Retrieve the pending exception. |
| 1606 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 1616 __ mov(r2, Operand(pending_exception_address)); |
| 1607 isolate))); | 1617 __ ldr(r0, MemOperand(r2)); |
| 1608 __ ldr(r0, MemOperand(ip)); | |
| 1609 | 1618 |
| 1610 // Clear the pending exception. | 1619 // Clear the pending exception. |
| 1611 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); | 1620 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); |
| 1612 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 1621 __ str(r3, MemOperand(r2)); |
| 1613 isolate))); | |
| 1614 __ str(r3, MemOperand(ip)); | |
| 1615 | 1622 |
| 1616 // Special handling of termination exceptions which are uncatchable | 1623 // Special handling of termination exceptions which are uncatchable |
| 1617 // by javascript code. | 1624 // by javascript code. |
| 1618 __ LoadRoot(r3, Heap::kTerminationExceptionRootIndex); | 1625 Label throw_termination_exception; |
| 1619 __ cmp(r0, r3); | 1626 __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex); |
| 1620 __ b(eq, throw_termination_exception); | 1627 __ b(eq, &throw_termination_exception); |
| 1621 | 1628 |
| 1622 // Handle normal exception. | 1629 // Handle normal exception. |
| 1623 __ jmp(throw_normal_exception); | 1630 __ Throw(r0); |
| 1624 | 1631 |
| 1625 __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying | 1632 __ bind(&throw_termination_exception); |
| 1633 __ ThrowUncatchable(r0); |
| 1626 } | 1634 } |
| 1627 | 1635 |
| 1628 | 1636 |
| 1629 void CEntryStub::Generate(MacroAssembler* masm) { | |
| 1630 // Called from JavaScript; parameters are on stack as if calling JS function | |
| 1631 // r0: number of arguments including receiver | |
| 1632 // r1: pointer to builtin function | |
| 1633 // fp: frame pointer (restored after C call) | |
| 1634 // sp: stack pointer (restored as callee's sp after C call) | |
| 1635 // cp: current context (C callee-saved) | |
| 1636 | |
| 1637 ProfileEntryHookStub::MaybeCallEntryHook(masm); | |
| 1638 | |
| 1639 // Result returned in r0 or r0+r1 by default. | |
| 1640 | |
| 1641 // NOTE: Invocations of builtins may return failure objects | |
| 1642 // instead of a proper result. The builtin entry handles | |
| 1643 // this by performing a garbage collection and retrying the | |
| 1644 // builtin once. | |
| 1645 | |
| 1646 // Compute the argv pointer in a callee-saved register. | |
| 1647 __ add(r6, sp, Operand(r0, LSL, kPointerSizeLog2)); | |
| 1648 __ sub(r6, r6, Operand(kPointerSize)); | |
| 1649 | |
| 1650 // Enter the exit frame that transitions from JavaScript to C++. | |
| 1651 FrameScope scope(masm, StackFrame::MANUAL); | |
| 1652 __ EnterExitFrame(save_doubles_); | |
| 1653 | |
| 1654 // Set up argc and the builtin function in callee-saved registers. | |
| 1655 __ mov(r4, Operand(r0)); | |
| 1656 __ mov(r5, Operand(r1)); | |
| 1657 | |
| 1658 // r4: number of arguments (C callee-saved) | |
| 1659 // r5: pointer to builtin function (C callee-saved) | |
| 1660 // r6: pointer to first argument (C callee-saved) | |
| 1661 | |
| 1662 Label throw_normal_exception; | |
| 1663 Label throw_termination_exception; | |
| 1664 | |
| 1665 // Call into the runtime system. | |
| 1666 GenerateCore(masm, | |
| 1667 &throw_normal_exception, | |
| 1668 &throw_termination_exception, | |
| 1669 false, | |
| 1670 false); | |
| 1671 | |
| 1672 // Do space-specific GC and retry runtime call. | |
| 1673 GenerateCore(masm, | |
| 1674 &throw_normal_exception, | |
| 1675 &throw_termination_exception, | |
| 1676 true, | |
| 1677 false); | |
| 1678 | |
| 1679 // Do full GC and retry runtime call one final time. | |
| 1680 Failure* failure = Failure::InternalError(); | |
| 1681 __ mov(r0, Operand(reinterpret_cast<int32_t>(failure))); | |
| 1682 GenerateCore(masm, | |
| 1683 &throw_normal_exception, | |
| 1684 &throw_termination_exception, | |
| 1685 true, | |
| 1686 true); | |
| 1687 | |
| 1688 { FrameScope scope(masm, StackFrame::MANUAL); | |
| 1689 __ PrepareCallCFunction(0, r0); | |
| 1690 __ CallCFunction( | |
| 1691 ExternalReference::out_of_memory_function(masm->isolate()), 0, 0); | |
| 1692 } | |
| 1693 | |
| 1694 __ bind(&throw_termination_exception); | |
| 1695 __ ThrowUncatchable(r0); | |
| 1696 | |
| 1697 __ bind(&throw_normal_exception); | |
| 1698 __ Throw(r0); | |
| 1699 } | |
| 1700 | |
| 1701 | |
| 1702 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { | 1637 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { |
| 1703 // r0: code entry | 1638 // r0: code entry |
| 1704 // r1: function | 1639 // r1: function |
| 1705 // r2: receiver | 1640 // r2: receiver |
| 1706 // r3: argc | 1641 // r3: argc |
| 1707 // [sp+0]: argv | 1642 // [sp+0]: argv |
| 1708 | 1643 |
| 1709 Label invoke, handler_entry, exit; | 1644 Label invoke, handler_entry, exit; |
| 1710 | 1645 |
| 1711 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 1646 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1784 __ bind(&handler_entry); | 1719 __ bind(&handler_entry); |
| 1785 handler_offset_ = handler_entry.pos(); | 1720 handler_offset_ = handler_entry.pos(); |
| 1786 // Caught exception: Store result (exception) in the pending exception | 1721 // Caught exception: Store result (exception) in the pending exception |
| 1787 // field in the JSEnv and return a failure sentinel. Coming in here the | 1722 // field in the JSEnv and return a failure sentinel. Coming in here the |
| 1788 // fp will be invalid because the PushTryHandler below sets it to 0 to | 1723 // fp will be invalid because the PushTryHandler below sets it to 0 to |
| 1789 // signal the existence of the JSEntry frame. | 1724 // signal the existence of the JSEntry frame. |
| 1790 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 1725 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
| 1791 isolate))); | 1726 isolate))); |
| 1792 } | 1727 } |
| 1793 __ str(r0, MemOperand(ip)); | 1728 __ str(r0, MemOperand(ip)); |
| 1794 __ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception()))); | 1729 __ LoadRoot(r0, Heap::kExceptionRootIndex); |
| 1795 __ b(&exit); | 1730 __ b(&exit); |
| 1796 | 1731 |
| 1797 // Invoke: Link this frame into the handler chain. There's only one | 1732 // Invoke: Link this frame into the handler chain. There's only one |
| 1798 // handler block in this code object, so its index is 0. | 1733 // handler block in this code object, so its index is 0. |
| 1799 __ bind(&invoke); | 1734 __ bind(&invoke); |
| 1800 // Must preserve r0-r4, r5-r6 are available. | 1735 // Must preserve r0-r4, r5-r6 are available. |
| 1801 __ PushTryHandler(StackHandler::JS_ENTRY, 0); | 1736 __ PushTryHandler(StackHandler::JS_ENTRY, 0); |
| 1802 // If an exception not caught by another handler occurs, this handler | 1737 // If an exception not caught by another handler occurs, this handler |
| 1803 // returns control to the code after the bl(&invoke) above, which | 1738 // returns control to the code after the bl(&invoke) above, which |
| 1804 // restores all kCalleeSaved registers (including cp and fp) to their | 1739 // restores all kCalleeSaved registers (including cp and fp) to their |
| (...skipping 3450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5255 MemOperand(fp, 6 * kPointerSize), | 5190 MemOperand(fp, 6 * kPointerSize), |
| 5256 NULL); | 5191 NULL); |
| 5257 } | 5192 } |
| 5258 | 5193 |
| 5259 | 5194 |
| 5260 #undef __ | 5195 #undef __ |
| 5261 | 5196 |
| 5262 } } // namespace v8::internal | 5197 } } // namespace v8::internal |
| 5263 | 5198 |
| 5264 #endif // V8_TARGET_ARCH_ARM | 5199 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |