Chromium Code Reviews| 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..61339e2cb4b8f78507b16b26effdc1f65155b28a 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 |
|
Yang
2014/04/22 11:28:55
@jbramley: now that we don't have a retry loop any
jbramley
2014/04/22 11:37:03
Yep, I'll have a look. We're gradually working thr
|
| + // 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: |
| @@ -1517,42 +1580,20 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, |
| // 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. |
| + |
| 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 +1608,16 @@ 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; |
| + |
| + Label failure_returned; |
| + __ CompareRoot(result, Heap::kExceptionRootIndex); |
| + __ B(eq, &failure_returned); |
| // The call succeeded, so unwind the stack and return. |
| @@ -1612,27 +1642,16 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, |
| // hasn't changed (except for the return address). |
| __ SetStackPointer(csp); |
| - __ Bind(&failure); |
| + __ Bind(&failure_returned); |
| // 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 |
| + ExternalReference pending_exception_address( |
| + Isolate::kPendingExceptionAddress, isolate); |
| - // Retrieve the pending exception. |
| 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 +1665,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 +1675,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 +1786,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 |