| Index: src/x64/macro-assembler-x64.cc
|
| diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
|
| index a5634a794da1650878f50e6f1eb999ac6c22e61c..88f61d4725751b647b3a8b7ad40a156011db2bd5 100644
|
| --- a/src/x64/macro-assembler-x64.cc
|
| +++ b/src/x64/macro-assembler-x64.cc
|
| @@ -336,12 +336,32 @@ void MacroAssembler::CallStub(CodeStub* stub) {
|
| }
|
|
|
|
|
| +Object* MacroAssembler::TryCallStub(CodeStub* stub) {
|
| + ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
|
| + Object* result = stub->TryGetCode();
|
| + if (!result->IsFailure()) {
|
| + call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| void MacroAssembler::TailCallStub(CodeStub* stub) {
|
| ASSERT(allow_stub_calls()); // calls are not allowed in some stubs
|
| Jump(stub->GetCode(), RelocInfo::CODE_TARGET);
|
| }
|
|
|
|
|
| +Object* MacroAssembler::TryTailCallStub(CodeStub* stub) {
|
| + ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs.
|
| + Object* result = stub->TryGetCode();
|
| + if (!result->IsFailure()) {
|
| + jmp(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET);
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| void MacroAssembler::StubReturn(int argc) {
|
| ASSERT(argc >= 1 && generating_stub());
|
| ret((argc - 1) * kPointerSize);
|
| @@ -361,6 +381,12 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
|
| }
|
|
|
|
|
| +Object* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
|
| + int num_arguments) {
|
| + return TryCallRuntime(Runtime::FunctionForId(id), num_arguments);
|
| +}
|
| +
|
| +
|
| void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
|
| // If the expected number of arguments of the runtime function is
|
| // constant, we check that the actual number of arguments match the
|
| @@ -381,6 +407,26 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
|
| }
|
|
|
|
|
| +Object* MacroAssembler::TryCallRuntime(Runtime::Function* f,
|
| + int num_arguments) {
|
| + if (f->nargs >= 0 && f->nargs != num_arguments) {
|
| + IllegalOperation(num_arguments);
|
| + // Since we did not call the stub, there was no allocation failure.
|
| + // Return some non-failure object.
|
| + return Heap::undefined_value();
|
| + }
|
| +
|
| + // TODO(1236192): Most runtime routines don't need the number of
|
| + // arguments passed in because it is constant. At some point we
|
| + // should remove this need and make the runtime routine entry code
|
| + // smarter.
|
| + Set(rax, num_arguments);
|
| + movq(rbx, ExternalReference(f));
|
| + CEntryStub ces(f->result_size);
|
| + return TryCallStub(&ces);
|
| +}
|
| +
|
| +
|
| void MacroAssembler::CallExternalReference(const ExternalReference& ext,
|
| int num_arguments) {
|
| Set(rax, num_arguments);
|
| @@ -417,6 +463,87 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
|
| }
|
|
|
|
|
| +static int Offset(ExternalReference ref0, ExternalReference ref1) {
|
| + int64_t offset = (ref0.address() - ref1.address());
|
| + // Check that fits into int.
|
| + ASSERT(static_cast<int>(offset) == offset);
|
| + return static_cast<int>(offset);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::PushHandleScope(Register scratch) {
|
| + ExternalReference extensions_address =
|
| + ExternalReference::handle_scope_extensions_address();
|
| + const int kExtensionsOffset = 0;
|
| + const int kNextOffset = Offset(
|
| + ExternalReference::handle_scope_next_address(),
|
| + extensions_address);
|
| + const int kLimitOffset = Offset(
|
| + ExternalReference::handle_scope_limit_address(),
|
| + extensions_address);
|
| +
|
| + // Push the number of extensions, smi-tagged so the gc will ignore it.
|
| + movq(kScratchRegister, extensions_address);
|
| + movq(scratch, Operand(kScratchRegister, kExtensionsOffset));
|
| + movq(Operand(kScratchRegister, kExtensionsOffset), Immediate(0));
|
| + Integer32ToSmi(scratch, scratch);
|
| + push(scratch);
|
| + // Push next and limit pointers which will be wordsize aligned and
|
| + // hence automatically smi tagged.
|
| + push(Operand(kScratchRegister, kNextOffset));
|
| + push(Operand(kScratchRegister, kLimitOffset));
|
| +}
|
| +
|
| +
|
| +Object* MacroAssembler::PopHandleScopeHelper(Register saved,
|
| + Register scratch,
|
| + bool gc_allowed) {
|
| + ExternalReference extensions_address =
|
| + ExternalReference::handle_scope_extensions_address();
|
| + const int kExtensionsOffset = 0;
|
| + const int kNextOffset = Offset(
|
| + ExternalReference::handle_scope_next_address(),
|
| + extensions_address);
|
| + const int kLimitOffset = Offset(
|
| + ExternalReference::handle_scope_limit_address(),
|
| + extensions_address);
|
| +
|
| + Object* result = NULL;
|
| + Label write_back;
|
| + movq(kScratchRegister, extensions_address);
|
| + cmpq(Operand(kScratchRegister, kExtensionsOffset), Immediate(0));
|
| + j(equal, &write_back);
|
| + push(saved);
|
| + if (gc_allowed) {
|
| + CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
|
| + } else {
|
| + result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
|
| + if (result->IsFailure()) return result;
|
| + }
|
| + pop(saved);
|
| + movq(kScratchRegister, extensions_address);
|
| +
|
| + bind(&write_back);
|
| + pop(Operand(kScratchRegister, kLimitOffset));
|
| + pop(Operand(kScratchRegister, kNextOffset));
|
| + pop(scratch);
|
| + SmiToInteger32(scratch, scratch);
|
| + movq(Operand(kScratchRegister, kExtensionsOffset), scratch);
|
| +
|
| + return result;
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::PopHandleScope(Register saved, Register scratch) {
|
| + PopHandleScopeHelper(saved, scratch, true);
|
| +}
|
| +
|
| +
|
| +Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) {
|
| + return PopHandleScopeHelper(saved, scratch, false);
|
| +}
|
| +
|
| +
|
| void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
|
| int result_size) {
|
| // Set the entry point and jump to the C entry runtime stub.
|
| @@ -2208,7 +2335,8 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
|
| }
|
|
|
|
|
| -void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) {
|
| +void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode,
|
| + bool save_rax) {
|
| // Setup the frame structure on the stack.
|
| // All constants are relative to the frame pointer of the exit frame.
|
| ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
|
| @@ -2226,18 +2354,19 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) {
|
| // Save the frame pointer and the context in top.
|
| ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
|
| ExternalReference context_address(Top::k_context_address);
|
| - movq(r14, rax); // Backup rax before we use it.
|
| + if (save_rax) {
|
| + movq(r14, rax); // Backup rax before we use it.
|
| + }
|
|
|
| movq(rax, rbp);
|
| store_rax(c_entry_fp_address);
|
| movq(rax, rsi);
|
| store_rax(context_address);
|
| +}
|
|
|
| - // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
|
| - // so it must be retained across the C-call.
|
| - int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
|
| - lea(r12, Operand(rbp, r14, times_pointer_size, offset));
|
| -
|
| +void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode,
|
| + int result_size,
|
| + int argc) {
|
| #ifdef ENABLE_DEBUGGER_SUPPORT
|
| // Save the state of all registers to the stack from the memory
|
| // location. This is needed to allow nested break points.
|
| @@ -2258,7 +2387,7 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) {
|
| // Reserve space for the Arguments object. The Windows 64-bit ABI
|
| // requires us to pass this structure as a pointer to its location on
|
| // the stack. The structure contains 2 values.
|
| - int argument_stack_space = 2 * kPointerSize;
|
| + int argument_stack_space = argc * kPointerSize;
|
| // We also need backing space for 4 parameters, even though
|
| // we only pass one or two parameter, and it is in a register.
|
| int argument_mirror_space = 4 * kPointerSize;
|
| @@ -2280,6 +2409,33 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) {
|
| }
|
|
|
|
|
| +void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) {
|
| + EnterExitFramePrologue(mode, true);
|
| +
|
| + // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
|
| + // so it must be retained across the C-call.
|
| + int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
|
| + lea(r12, Operand(rbp, r14, times_pointer_size, offset));
|
| +
|
| + EnterExitFrameEpilogue(mode, result_size, 2);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode,
|
| + int stack_space,
|
| + int argc,
|
| + int result_size) {
|
| + EnterExitFramePrologue(mode, false);
|
| +
|
| + // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame,
|
| + // so it must be retained across the C-call.
|
| + int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
|
| + lea(r12, Operand(rbp, (stack_space * kPointerSize) + offset));
|
| +
|
| + EnterExitFrameEpilogue(mode, result_size, argc);
|
| +}
|
| +
|
| +
|
| void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode, int result_size) {
|
| // Registers:
|
| // r12 : argv
|
|
|