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 |