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 |