Index: src/arm64/code-stubs-arm64.cc |
diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc |
index a42f5cd34da87677a2f8fd4d59c417c82fbb4ee5..127588267d791170d0a88f56e32374f5a94026b0 100644 |
--- a/src/arm64/code-stubs-arm64.cc |
+++ b/src/arm64/code-stubs-arm64.cc |
@@ -1477,15 +1477,78 @@ void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { |
} |
-void CEntryStub::GenerateCore(MacroAssembler* masm, |
- Label* throw_normal, |
- Label* throw_termination, |
- bool do_gc, |
- bool always_allocate) { |
- // x0 : Result parameter for PerformGC, if do_gc is true. |
+void CEntryStub::Generate(MacroAssembler* masm) { |
+ // The Abort mechanism relies on CallRuntime, which in turn relies on |
+ // CEntryStub, so until this stub has been generated, we have to use a |
+ // fall-back Abort mechanism. |
+ // |
+ // Note that this stub must be generated before any use of Abort. |
+ MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm); |
+ |
+ ASM_LOCATION("CEntryStub::Generate entry"); |
+ ProfileEntryHookStub::MaybeCallEntryHook(masm); |
+ |
+ // Register parameters: |
+ // x0: argc (including receiver, untagged) |
+ // x1: target |
+ // |
+ // The stack on entry holds the arguments and the receiver, with the receiver |
+ // at the highest address: |
+ // |
+ // jssp]argc-1]: receiver |
+ // jssp[argc-2]: arg[argc-2] |
+ // ... ... |
+ // jssp[1]: arg[1] |
+ // jssp[0]: arg[0] |
+ // |
+ // The arguments are in reverse order, so that arg[argc-2] is actually the |
+ // first argument to the target function and arg[0] is the last. |
+ ASSERT(jssp.Is(__ StackPointer())); |
+ const Register& argc_input = x0; |
+ const Register& target_input = x1; |
+ |
+ // Calculate argv, argc and the target address, and store them in |
+ // callee-saved registers so we can retry the call without having to reload |
+ // these arguments. |
+ // TODO(jbramley): If the first call attempt succeeds in the common case (as |
+ // it should), then we might be better off putting these parameters directly |
+ // into their argument registers, rather than using callee-saved registers and |
+ // preserving them on the stack. |
+ const Register& argv = x21; |
+ const Register& argc = x22; |
+ const Register& target = x23; |
+ |
+ // Derive argv from the stack pointer so that it points to the first argument |
+ // (arg[argc-2]), or just below the receiver in case there are no arguments. |
+ // - Adjust for the arg[] array. |
+ Register temp_argv = x11; |
+ __ Add(temp_argv, jssp, Operand(x0, LSL, kPointerSizeLog2)); |
+ // - Adjust for the receiver. |
+ __ Sub(temp_argv, temp_argv, 1 * kPointerSize); |
+ |
+ // Enter the exit frame. Reserve three slots to preserve x21-x23 callee-saved |
+ // registers. |
+ FrameScope scope(masm, StackFrame::MANUAL); |
+ __ EnterExitFrame(save_doubles_, x10, 3); |
+ ASSERT(csp.Is(__ StackPointer())); |
+ |
+ // Poke callee-saved registers into reserved space. |
+ __ Poke(argv, 1 * kPointerSize); |
+ __ Poke(argc, 2 * kPointerSize); |
+ __ Poke(target, 3 * kPointerSize); |
+ |
+ // We normally only keep tagged values in callee-saved registers, as they |
+ // could be pushed onto the stack by called stubs and functions, and on the |
+ // stack they can confuse the GC. However, we're only calling C functions |
+ // which can push arbitrary data onto the stack anyway, and so the GC won't |
+ // examine that part of the stack. |
+ __ Mov(argc, argc_input); |
+ __ Mov(target, target_input); |
+ __ Mov(argv, temp_argv); |
+ |
// x21 : argv |
// x22 : argc |
- // x23 : target |
+ // x23 : call target |
// |
// The stack (on entry) holds the arguments and the receiver, with the |
// receiver at the highest address: |
@@ -1515,44 +1578,21 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, |
// |
// After an unsuccessful call, the exit frame and suchlike are left |
// untouched, and the stub either throws an exception by jumping to one of |
- // the provided throw_ labels, or it falls through. The failure details are |
- // passed through in x0. |
+ // the exception_returned label. |
+ |
ASSERT(csp.Is(__ StackPointer())); |
Isolate* isolate = masm->isolate(); |
- const Register& argv = x21; |
- const Register& argc = x22; |
- const Register& target = x23; |
- |
- if (do_gc) { |
- // Call Runtime::PerformGC, passing x0 (the result parameter for |
- // PerformGC) and x1 (the isolate). |
- __ Mov(x1, ExternalReference::isolate_address(masm->isolate())); |
- __ CallCFunction( |
- ExternalReference::perform_gc_function(isolate), 2, 0); |
- } |
- |
- ExternalReference scope_depth = |
- ExternalReference::heap_always_allocate_scope_depth(isolate); |
- if (always_allocate) { |
- __ Mov(x10, Operand(scope_depth)); |
- __ Ldr(x11, MemOperand(x10)); |
- __ Add(x11, x11, 1); |
- __ Str(x11, MemOperand(x10)); |
- } |
- |
// Prepare AAPCS64 arguments to pass to the builtin. |
__ Mov(x0, argc); |
__ Mov(x1, argv); |
__ Mov(x2, ExternalReference::isolate_address(isolate)); |
- // Store the return address on the stack, in the space previously allocated |
- // by EnterExitFrame. The return address is queried by |
- // ExitFrame::GetStateForFramePointer. |
Label return_location; |
__ Adr(x12, &return_location); |
__ Poke(x12, 0); |
+ |
if (__ emit_debug_code()) { |
// Verify that the slot below fp[kSPOffset]-8 points to the return location |
// (currently in x12). |
@@ -1567,27 +1607,17 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, |
// Call the builtin. |
__ Blr(target); |
__ Bind(&return_location); |
- const Register& result = x0; |
- |
- if (always_allocate) { |
- __ Mov(x10, Operand(scope_depth)); |
- __ Ldr(x11, MemOperand(x10)); |
- __ Sub(x11, x11, 1); |
- __ Str(x11, MemOperand(x10)); |
- } |
// x0 result The return code from the call. |
// x21 argv |
// x22 argc |
// x23 target |
- // |
- // If all of the result bits matching kFailureTagMask are '1', the result is |
- // a failure. Otherwise, it's an ordinary tagged object and the call was a |
- // success. |
- Label failure; |
- __ And(x10, result, kFailureTagMask); |
- __ Cmp(x10, kFailureTagMask); |
- __ B(&failure, eq); |
+ const Register& result = x0; |
+ |
+ // Check result for exception sentinel. |
+ Label exception_returned; |
+ __ CompareRoot(result, Heap::kExceptionRootIndex); |
+ __ B(eq, &exception_returned); |
// The call succeeded, so unwind the stack and return. |
@@ -1612,27 +1642,15 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, |
// hasn't changed (except for the return address). |
__ SetStackPointer(csp); |
- __ Bind(&failure); |
- // The call failed, so check if we need to throw an exception, and fall |
- // through (to retry) otherwise. |
- |
- Label retry; |
- // x0 result The return code from the call, including the failure |
- // code and details. |
- // x21 argv |
- // x22 argc |
- // x23 target |
- // Refer to the Failure class for details of the bit layout. |
- STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); |
- __ Tst(result, kFailureTypeTagMask << kFailureTagSize); |
- __ B(eq, &retry); // RETRY_AFTER_GC |
+ // Handling of exception. |
+ __ Bind(&exception_returned); |
// Retrieve the pending exception. |
+ ExternalReference pending_exception_address( |
+ Isolate::kPendingExceptionAddress, isolate); |
const Register& exception = result; |
const Register& exception_address = x11; |
- __ Mov(exception_address, |
- Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
- isolate))); |
+ __ Mov(exception_address, Operand(pending_exception_address)); |
__ Ldr(exception, MemOperand(exception_address)); |
// Clear the pending exception. |
@@ -1646,118 +1664,9 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, |
// Special handling of termination exceptions, which are uncatchable by |
// JavaScript code. |
+ Label throw_termination_exception; |
__ Cmp(exception, Operand(isolate->factory()->termination_exception())); |
- __ B(eq, throw_termination); |
- |
- // Handle normal exception. |
- __ B(throw_normal); |
- |
- __ Bind(&retry); |
- // The result (x0) is passed through as the next PerformGC parameter. |
-} |
- |
- |
-void CEntryStub::Generate(MacroAssembler* masm) { |
- // The Abort mechanism relies on CallRuntime, which in turn relies on |
- // CEntryStub, so until this stub has been generated, we have to use a |
- // fall-back Abort mechanism. |
- // |
- // Note that this stub must be generated before any use of Abort. |
- MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm); |
- |
- ASM_LOCATION("CEntryStub::Generate entry"); |
- ProfileEntryHookStub::MaybeCallEntryHook(masm); |
- |
- // Register parameters: |
- // x0: argc (including receiver, untagged) |
- // x1: target |
- // |
- // The stack on entry holds the arguments and the receiver, with the receiver |
- // at the highest address: |
- // |
- // jssp]argc-1]: receiver |
- // jssp[argc-2]: arg[argc-2] |
- // ... ... |
- // jssp[1]: arg[1] |
- // jssp[0]: arg[0] |
- // |
- // The arguments are in reverse order, so that arg[argc-2] is actually the |
- // first argument to the target function and arg[0] is the last. |
- ASSERT(jssp.Is(__ StackPointer())); |
- const Register& argc_input = x0; |
- const Register& target_input = x1; |
- |
- // Calculate argv, argc and the target address, and store them in |
- // callee-saved registers so we can retry the call without having to reload |
- // these arguments. |
- // TODO(jbramley): If the first call attempt succeeds in the common case (as |
- // it should), then we might be better off putting these parameters directly |
- // into their argument registers, rather than using callee-saved registers and |
- // preserving them on the stack. |
- const Register& argv = x21; |
- const Register& argc = x22; |
- const Register& target = x23; |
- |
- // Derive argv from the stack pointer so that it points to the first argument |
- // (arg[argc-2]), or just below the receiver in case there are no arguments. |
- // - Adjust for the arg[] array. |
- Register temp_argv = x11; |
- __ Add(temp_argv, jssp, Operand(x0, LSL, kPointerSizeLog2)); |
- // - Adjust for the receiver. |
- __ Sub(temp_argv, temp_argv, 1 * kPointerSize); |
- |
- // Enter the exit frame. Reserve three slots to preserve x21-x23 callee-saved |
- // registers. |
- FrameScope scope(masm, StackFrame::MANUAL); |
- __ EnterExitFrame(save_doubles_, x10, 3); |
- ASSERT(csp.Is(__ StackPointer())); |
- |
- // Poke callee-saved registers into reserved space. |
- __ Poke(argv, 1 * kPointerSize); |
- __ Poke(argc, 2 * kPointerSize); |
- __ Poke(target, 3 * kPointerSize); |
- |
- // We normally only keep tagged values in callee-saved registers, as they |
- // could be pushed onto the stack by called stubs and functions, and on the |
- // stack they can confuse the GC. However, we're only calling C functions |
- // which can push arbitrary data onto the stack anyway, and so the GC won't |
- // examine that part of the stack. |
- __ Mov(argc, argc_input); |
- __ Mov(target, target_input); |
- __ Mov(argv, temp_argv); |
- |
- Label throw_normal; |
- Label throw_termination; |
- |
- // Call the runtime function. |
- GenerateCore(masm, |
- &throw_normal, |
- &throw_termination, |
- false, |
- false); |
- |
- // If successful, the previous GenerateCore will have returned to the |
- // calling code. Otherwise, we fall through into the following. |
- |
- // Do space-specific GC and retry runtime call. |
- GenerateCore(masm, |
- &throw_normal, |
- &throw_termination, |
- true, |
- false); |
- |
- // Do full GC and retry runtime call one final time. |
- __ Mov(x0, reinterpret_cast<uint64_t>(Failure::InternalError())); |
- GenerateCore(masm, |
- &throw_normal, |
- &throw_termination, |
- true, |
- true); |
- |
- { FrameScope scope(masm, StackFrame::MANUAL); |
- __ CallCFunction( |
- ExternalReference::out_of_memory_function(masm->isolate()), 0); |
- } |
+ __ B(eq, &throw_termination_exception); |
// We didn't execute a return case, so the stack frame hasn't been updated |
// (except for the return address slot). However, we don't need to initialize |
@@ -1765,24 +1674,18 @@ void CEntryStub::Generate(MacroAssembler* masm) { |
// unwinds the stack. |
__ SetStackPointer(jssp); |
- // Throw exceptions. |
- // If we throw an exception, we can end up re-entering CEntryStub before we |
- // pop the exit frame, so need to ensure that x21-x23 contain GC-safe values |
- // here. |
- |
- __ Bind(&throw_termination); |
- ASM_LOCATION("Throw termination"); |
+ ASM_LOCATION("Throw normal"); |
__ Mov(argv, 0); |
__ Mov(argc, 0); |
__ Mov(target, 0); |
- __ ThrowUncatchable(x0, x10, x11, x12, x13); |
+ __ Throw(x0, x10, x11, x12, x13); |
- __ Bind(&throw_normal); |
- ASM_LOCATION("Throw normal"); |
+ __ Bind(&throw_termination_exception); |
+ ASM_LOCATION("Throw termination"); |
__ Mov(argv, 0); |
__ Mov(argc, 0); |
__ Mov(target, 0); |
- __ Throw(x0, x10, x11, x12, x13); |
+ __ ThrowUncatchable(x0, x10, x11, x12, x13); |
} |
@@ -1882,7 +1785,7 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { |
isolate))); |
} |
__ Str(code_entry, MemOperand(x10)); |
- __ Mov(x0, Operand(reinterpret_cast<int64_t>(Failure::Exception()))); |
+ __ LoadRoot(x0, Heap::kExceptionRootIndex); |
__ B(&exit); |
// Invoke: Link this frame into the handler chain. There's only one |