| Index: src/x64/codegen-x64.cc
|
| diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
|
| index 7e2e6ed2b1d097c86cdd5c7bc481264f4e8e2934..7d5e594945330b3ff09601be451fe46aa0daf90e 100644
|
| --- a/src/x64/codegen-x64.cc
|
| +++ b/src/x64/codegen-x64.cc
|
| @@ -50,7 +50,8 @@ CodeGenerator::CodeGenerator(int buffer_size,
|
| in_spilled_code_(false) {
|
| }
|
|
|
| -#define __ masm->
|
| +#define __ ACCESS_MASM(masm)
|
| +
|
|
|
|
|
| void CodeGenerator::DeclareGlobals(Handle<FixedArray> a) {
|
| @@ -228,8 +229,245 @@ void CodeGenerator::VisitThisFunction(ThisFunction* a) {
|
| }
|
|
|
|
|
| +void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
|
| + // Check that stack should contain frame pointer, code pointer, state and
|
| + // return address in that order.
|
| + ASSERT_EQ(StackHandlerConstants::kFPOffset + kPointerSize,
|
| + StackHandlerConstants::kCodeOffset);
|
| + ASSERT_EQ(StackHandlerConstants::kCodeOffset + kPointerSize,
|
| + StackHandlerConstants::kStateOffset);
|
| + ASSERT_EQ(StackHandlerConstants::kStateOffset + kPointerSize,
|
| + StackHandlerConstants::kPCOffset);
|
| +
|
| + ExternalReference handler_address(Top::k_handler_address);
|
| + __ movq(kScratchRegister, handler_address);
|
| + __ movq(rdx, Operand(kScratchRegister, 0));
|
| + // get next in chain
|
| + __ movq(rcx, Operand(rdx, StackHandlerConstants::kAddressDisplacement));
|
| + __ movq(Operand(kScratchRegister, 0), rcx);
|
| + __ movq(rsp, rdx);
|
| + __ pop(rbp); // pop frame pointer
|
| + __ pop(rdx); // remove code pointer
|
| + __ pop(rdx); // remove state
|
| +
|
| + // Before returning we restore the context from the frame pointer if not NULL.
|
| + // The frame pointer is NULL in the exception handler of a JS entry frame.
|
| + __ xor_(rsi, rsi); // tentatively set context pointer to NULL
|
| + Label skip;
|
| + __ cmp(rbp, Immediate(0));
|
| + __ j(equal, &skip);
|
| + __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
| + __ bind(&skip);
|
| +
|
| + __ ret(0);
|
| +}
|
| +
|
| +
|
| +
|
| +void CEntryStub::GenerateCore(MacroAssembler* masm,
|
| + Label* throw_normal_exception,
|
| + Label* throw_out_of_memory_exception,
|
| + StackFrame::Type frame_type,
|
| + bool do_gc,
|
| + bool always_allocate_scope) {
|
| + // rax: result parameter for PerformGC, if any
|
| + // rbx: pointer to C function (C callee-saved)
|
| + // rbp: frame pointer (restored after C call)
|
| + // rsp: stack pointer (restored after C call)
|
| + // rdi: number of arguments including receiver (C callee-saved)
|
| + // rsi: pointer to the first argument (C callee-saved)
|
| +
|
| + if (do_gc) {
|
| + __ movq(Operand(rsp, 0), rax); // Result.
|
| + __ movq(kScratchRegister,
|
| + FUNCTION_ADDR(Runtime::PerformGC),
|
| + RelocInfo::RUNTIME_ENTRY);
|
| + __ call(kScratchRegister);
|
| + }
|
| +
|
| + ExternalReference scope_depth =
|
| + ExternalReference::heap_always_allocate_scope_depth();
|
| + if (always_allocate_scope) {
|
| + __ movq(kScratchRegister, scope_depth);
|
| + __ inc(Operand(kScratchRegister, 0));
|
| + }
|
| +
|
| + // Call C function.
|
| + __ movq(Operand(rsp, 0 * kPointerSize), rdi); // argc.
|
| + __ movq(Operand(rsp, 1 * kPointerSize), rsi); // argv.
|
| + __ call(rbx);
|
| + // Result is in rax - do not destroy this register!
|
| +
|
| + if (always_allocate_scope) {
|
| + __ movq(kScratchRegister, scope_depth);
|
| + __ dec(Operand(kScratchRegister, 0));
|
| + }
|
| +
|
| + // Check for failure result.
|
| + Label failure_returned;
|
| + ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
|
| + __ lea(rcx, Operand(rax, 1));
|
| + // Lower 2 bits of rcx are 0 iff rax has failure tag.
|
| + __ testl(rcx, Immediate(kFailureTagMask));
|
| + __ j(zero, &failure_returned);
|
| +
|
| + // Exit the JavaScript to C++ exit frame.
|
| + __ LeaveExitFrame(frame_type);
|
| + __ ret(0);
|
| +
|
| + // Handling of failure.
|
| + __ bind(&failure_returned);
|
| +
|
| + Label retry;
|
| + // If the returned exception is RETRY_AFTER_GC continue at retry label
|
| + ASSERT(Failure::RETRY_AFTER_GC == 0);
|
| + __ testq(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
|
| + __ j(zero, &retry);
|
| +
|
| + Label continue_exception;
|
| + // If the returned failure is EXCEPTION then promote Top::pending_exception().
|
| + __ movq(kScratchRegister, Failure::Exception(), RelocInfo::NONE);
|
| + __ cmp(rax, kScratchRegister);
|
| + __ j(not_equal, &continue_exception);
|
| +
|
| + // Retrieve the pending exception and clear the variable.
|
| + ExternalReference pending_exception_address(Top::k_pending_exception_address);
|
| + __ movq(kScratchRegister, pending_exception_address);
|
| + __ movq(rax, Operand(kScratchRegister, 0));
|
| + __ movq(rdx, ExternalReference::the_hole_value_location());
|
| + __ movq(rdx, Operand(rdx, 0));
|
| + __ movq(Operand(kScratchRegister, 0), rdx);
|
| +
|
| + __ bind(&continue_exception);
|
| + // Special handling of out of memory exception.
|
| + __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE);
|
| + __ cmp(rax, kScratchRegister);
|
| + __ j(equal, throw_out_of_memory_exception);
|
| +
|
| + // Handle normal exception.
|
| + __ jmp(throw_normal_exception);
|
| +
|
| + // Retry.
|
| + __ bind(&retry);
|
| +}
|
| +
|
| +
|
| +void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
|
| + // Fetch top stack handler.
|
| + ExternalReference handler_address(Top::k_handler_address);
|
| + __ movq(kScratchRegister, handler_address);
|
| + __ movq(rdx, Operand(kScratchRegister, 0));
|
| +
|
| + // Unwind the handlers until the ENTRY handler is found.
|
| + Label loop, done;
|
| + __ bind(&loop);
|
| + // Load the type of the current stack handler.
|
| + const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
|
| + StackHandlerConstants::kStateOffset;
|
| + __ cmp(Operand(rdx, kStateOffset), Immediate(StackHandler::ENTRY));
|
| + __ j(equal, &done);
|
| + // Fetch the next handler in the list.
|
| + const int kNextOffset = StackHandlerConstants::kAddressDisplacement +
|
| + StackHandlerConstants::kNextOffset;
|
| + __ movq(rdx, Operand(rdx, kNextOffset));
|
| + __ jmp(&loop);
|
| + __ bind(&done);
|
| +
|
| + // Set the top handler address to next handler past the current ENTRY handler.
|
| + __ movq(rax, Operand(rdx, kNextOffset));
|
| + __ store_rax(handler_address);
|
| +
|
| + // Set external caught exception to false.
|
| + __ movq(rax, Immediate(false));
|
| + ExternalReference external_caught(Top::k_external_caught_exception_address);
|
| + __ store_rax(external_caught);
|
| +
|
| + // Set pending exception and rax to out of memory exception.
|
| + __ movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
|
| + ExternalReference pending_exception(Top::k_pending_exception_address);
|
| + __ store_rax(pending_exception);
|
| +
|
| + // Restore the stack to the address of the ENTRY handler
|
| + __ movq(rsp, rdx);
|
| +
|
| + // Clear the context pointer;
|
| + __ xor_(rsi, rsi);
|
| +
|
| + // Restore registers from handler.
|
| + __ pop(rbp); // FP
|
| + __ pop(rdx); // Code
|
| + __ pop(rdx); // State
|
| +
|
| + __ ret(0);
|
| +}
|
| +
|
| +
|
| void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
|
| - masm->int3(); // TODO(X64): UNIMPLEMENTED.
|
| + // rax: number of arguments including receiver
|
| + // rbx: pointer to C function (C callee-saved)
|
| + // rbp: frame pointer (restored after C call)
|
| + // rsp: stack pointer (restored after C call)
|
| + // rsi: current context (C callee-saved)
|
| + // rdi: caller's parameter pointer pp (C callee-saved)
|
| +
|
| + // NOTE: Invocations of builtins may return failure objects
|
| + // instead of a proper result. The builtin entry handles
|
| + // this by performing a garbage collection and retrying the
|
| + // builtin once.
|
| +
|
| + StackFrame::Type frame_type = is_debug_break ?
|
| + StackFrame::EXIT_DEBUG :
|
| + StackFrame::EXIT;
|
| +
|
| + // Enter the exit frame that transitions from JavaScript to C++.
|
| + __ EnterExitFrame(frame_type);
|
| +
|
| + // rax: result parameter for PerformGC, if any (setup below)
|
| + // rbx: pointer to builtin function (C callee-saved)
|
| + // rbp: frame pointer (restored after C call)
|
| + // rsp: stack pointer (restored after C call)
|
| + // rdi: number of arguments including receiver (C callee-saved)
|
| + // rsi: argv pointer (C callee-saved)
|
| +
|
| + Label throw_out_of_memory_exception;
|
| + Label throw_normal_exception;
|
| +
|
| + // Call into the runtime system. Collect garbage before the call if
|
| + // running with --gc-greedy set.
|
| + if (FLAG_gc_greedy) {
|
| + Failure* failure = Failure::RetryAfterGC(0);
|
| + __ movq(rax, failure, RelocInfo::NONE);
|
| + }
|
| + GenerateCore(masm, &throw_normal_exception,
|
| + &throw_out_of_memory_exception,
|
| + frame_type,
|
| + FLAG_gc_greedy,
|
| + false);
|
| +
|
| + // Do space-specific GC and retry runtime call.
|
| + GenerateCore(masm,
|
| + &throw_normal_exception,
|
| + &throw_out_of_memory_exception,
|
| + frame_type,
|
| + true,
|
| + false);
|
| +
|
| + // Do full GC and retry runtime call one final time.
|
| + Failure* failure = Failure::InternalError();
|
| + __ movq(rax, failure, RelocInfo::NONE);
|
| + GenerateCore(masm,
|
| + &throw_normal_exception,
|
| + &throw_out_of_memory_exception,
|
| + frame_type,
|
| + true,
|
| + true);
|
| +
|
| + __ bind(&throw_out_of_memory_exception);
|
| + GenerateThrowOutOfMemory(masm);
|
| + // control flow for generated will not return.
|
| +
|
| + __ bind(&throw_normal_exception);
|
| + GenerateThrowTOS(masm);
|
| }
|
|
|
|
|
|
|