Commit 9d6fd082 authored by antonm@chromium.org's avatar antonm@chromium.org

Port faster callbacks invocation to x64.

It's a port of http://code.google.com/p/v8/source/detail?r=3209 to x64 platform.
That allows invocation of callbacks without going into runtime.

Review URL: http://codereview.chromium.org/2801008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5141 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent cf21615b
...@@ -12275,7 +12275,7 @@ static const bool kPassHandlesDirectly = false; ...@@ -12275,7 +12275,7 @@ static const bool kPassHandlesDirectly = false;
void ApiGetterEntryStub::Generate(MacroAssembler* masm) { void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
Label get_result; Label empty_handle;
Label prologue; Label prologue;
Label promote_scheduled_exception; Label promote_scheduled_exception;
__ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, kArgc); __ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, kArgc);
...@@ -12318,20 +12318,20 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) { ...@@ -12318,20 +12318,20 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
// Dereference this to get to the location. // Dereference this to get to the location.
__ mov(eax, Operand(eax, 0)); __ mov(eax, Operand(eax, 0));
} }
// Check if the result handle holds 0 // Check if the result handle holds 0.
__ test(eax, Operand(eax)); __ test(eax, Operand(eax));
__ j(not_zero, &get_result, taken); __ j(zero, &empty_handle, not_taken);
// It was zero; the result is undefined.
__ mov(eax, Factory::undefined_value());
__ jmp(&prologue);
// It was non-zero. Dereference to get the result value. // It was non-zero. Dereference to get the result value.
__ bind(&get_result);
__ mov(eax, Operand(eax, 0)); __ mov(eax, Operand(eax, 0));
__ bind(&prologue); __ bind(&prologue);
__ LeaveExitFrame(ExitFrame::MODE_NORMAL); __ LeaveExitFrame(ExitFrame::MODE_NORMAL);
__ ret(0); __ ret(0);
__ bind(&promote_scheduled_exception); __ bind(&promote_scheduled_exception);
__ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
__ bind(&empty_handle);
// It was zero; the result is undefined.
__ mov(eax, Factory::undefined_value());
__ jmp(&prologue);
} }
......
...@@ -1052,16 +1052,6 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { ...@@ -1052,16 +1052,6 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
} }
void MacroAssembler::CallExternalReference(ExternalReference ref,
int num_arguments) {
mov(eax, Immediate(num_arguments));
mov(ebx, Immediate(ref));
CEntryStub stub(1);
CallStub(&stub);
}
Object* MacroAssembler::TryCallRuntime(Runtime::Function* f, Object* MacroAssembler::TryCallRuntime(Runtime::Function* f,
int num_arguments) { int num_arguments) {
if (f->nargs >= 0 && f->nargs != num_arguments) { if (f->nargs >= 0 && f->nargs != num_arguments) {
...@@ -1082,6 +1072,16 @@ Object* MacroAssembler::TryCallRuntime(Runtime::Function* f, ...@@ -1082,6 +1072,16 @@ Object* MacroAssembler::TryCallRuntime(Runtime::Function* f,
} }
void MacroAssembler::CallExternalReference(ExternalReference ref,
int num_arguments) {
mov(eax, Immediate(num_arguments));
mov(ebx, Immediate(ref));
CEntryStub stub(1);
CallStub(&stub);
}
void MacroAssembler::TailCallExternalReference(const ExternalReference& ext, void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
int num_arguments, int num_arguments,
int result_size) { int result_size) {
...@@ -1106,8 +1106,7 @@ void MacroAssembler::PushHandleScope(Register scratch) { ...@@ -1106,8 +1106,7 @@ void MacroAssembler::PushHandleScope(Register scratch) {
ExternalReference extensions_address = ExternalReference extensions_address =
ExternalReference::handle_scope_extensions_address(); ExternalReference::handle_scope_extensions_address();
mov(scratch, Operand::StaticVariable(extensions_address)); mov(scratch, Operand::StaticVariable(extensions_address));
ASSERT_EQ(0, kSmiTag); SmiTag(scratch);
shl(scratch, kSmiTagSize);
push(scratch); push(scratch);
mov(Operand::StaticVariable(extensions_address), Immediate(0)); mov(Operand::StaticVariable(extensions_address), Immediate(0));
// Push next and limit pointers which will be wordsize aligned and // Push next and limit pointers which will be wordsize aligned and
...@@ -1131,16 +1130,14 @@ Object* MacroAssembler::PopHandleScopeHelper(Register saved, ...@@ -1131,16 +1130,14 @@ Object* MacroAssembler::PopHandleScopeHelper(Register saved,
mov(scratch, Operand::StaticVariable(extensions_address)); mov(scratch, Operand::StaticVariable(extensions_address));
cmp(Operand(scratch), Immediate(0)); cmp(Operand(scratch), Immediate(0));
j(equal, &write_back); j(equal, &write_back);
// Calling a runtime function messes with registers so we save and push(saved);
// restore any one we're asked not to change
if (saved.is_valid()) push(saved);
if (gc_allowed) { if (gc_allowed) {
CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0); CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
} else { } else {
result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0); result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
} }
if (saved.is_valid()) pop(saved); pop(saved);
bind(&write_back); bind(&write_back);
ExternalReference limit_address = ExternalReference limit_address =
...@@ -1150,7 +1147,7 @@ Object* MacroAssembler::PopHandleScopeHelper(Register saved, ...@@ -1150,7 +1147,7 @@ Object* MacroAssembler::PopHandleScopeHelper(Register saved,
ExternalReference::handle_scope_next_address(); ExternalReference::handle_scope_next_address();
pop(Operand::StaticVariable(next_address)); pop(Operand::StaticVariable(next_address));
pop(scratch); pop(scratch);
shr(scratch, kSmiTagSize); SmiUntag(scratch);
mov(Operand::StaticVariable(extensions_address), scratch); mov(Operand::StaticVariable(extensions_address), scratch);
return result; return result;
......
...@@ -393,12 +393,12 @@ class MacroAssembler: public Assembler { ...@@ -393,12 +393,12 @@ class MacroAssembler: public Assembler {
// Convenience function: Same as above, but takes the fid instead. // Convenience function: Same as above, but takes the fid instead.
void CallRuntime(Runtime::FunctionId id, int num_arguments); void CallRuntime(Runtime::FunctionId id, int num_arguments);
// Convenience function: call an external reference.
void CallExternalReference(ExternalReference ref, int num_arguments);
// Convenience function: Same as above, but takes the fid instead. // Convenience function: Same as above, but takes the fid instead.
Object* TryCallRuntime(Runtime::FunctionId id, int num_arguments); Object* TryCallRuntime(Runtime::FunctionId id, int num_arguments);
// Convenience function: call an external reference.
void CallExternalReference(ExternalReference ref, int num_arguments);
// Tail call of a runtime routine (jump). // Tail call of a runtime routine (jump).
// Like JumpToExternalReference, but also takes care of passing the number // Like JumpToExternalReference, but also takes care of passing the number
// of parameters. // of parameters.
...@@ -431,7 +431,7 @@ class MacroAssembler: public Assembler { ...@@ -431,7 +431,7 @@ class MacroAssembler: public Assembler {
void PushHandleScope(Register scratch); void PushHandleScope(Register scratch);
// Pops a handle scope using the specified scratch register and // Pops a handle scope using the specified scratch register and
// ensuring that saved register, it is not no_reg, is left unchanged. // ensuring that saved register is left unchanged.
void PopHandleScope(Register saved, Register scratch); void PopHandleScope(Register saved, Register scratch);
// As PopHandleScope, but does not perform a GC. Instead, returns a // As PopHandleScope, but does not perform a GC. Instead, returns a
......
...@@ -1033,24 +1033,23 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -1033,24 +1033,23 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
// Check that the maps haven't changed. // Check that the maps haven't changed.
Register reg = Register reg =
CheckPrototypes(object, receiver, holder, CheckPrototypes(object, receiver, holder, scratch1,
scratch1, scratch2, scratch3, name, miss); scratch2, scratch3, name, miss);
Handle<AccessorInfo> callback_handle(callback); Handle<AccessorInfo> callback_handle(callback);
Register other = reg.is(scratch1) ? scratch2 : scratch1;
__ EnterInternalFrame(); __ EnterInternalFrame();
__ PushHandleScope(other); __ PushHandleScope(scratch2);
// Push the stack address where the list of arguments ends // Push the stack address where the list of arguments ends.
__ mov(other, esp); __ mov(scratch2, esp);
__ sub(Operand(other), Immediate(2 * kPointerSize)); __ sub(Operand(scratch2), Immediate(2 * kPointerSize));
__ push(other); __ push(scratch2);
__ push(receiver); // receiver __ push(receiver); // receiver
__ push(reg); // holder __ push(reg); // holder
// Push data from AccessorInfo. // Push data from AccessorInfo.
if (Heap::InNewSpace(callback_handle->data())) { if (Heap::InNewSpace(callback_handle->data())) {
__ mov(other, Immediate(callback_handle)); __ mov(scratch2, Immediate(callback_handle));
__ push(FieldOperand(other, AccessorInfo::kDataOffset)); __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset));
} else { } else {
__ push(Immediate(Handle<Object>(callback_handle->data()))); __ push(Immediate(Handle<Object>(callback_handle->data())));
} }
...@@ -1077,7 +1076,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -1077,7 +1076,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
} }
// We need to avoid using eax since that now holds the result. // We need to avoid using eax since that now holds the result.
Register tmp = other.is(eax) ? reg : other; Register tmp = scratch2.is(eax) ? reg : scratch2;
// Emitting PopHandleScope may try to allocate. Do not allow the // Emitting PopHandleScope may try to allocate. Do not allow the
// assembler to perform a garbage collection but instead return a // assembler to perform a garbage collection but instead return a
// failure object. // failure object.
......
...@@ -1496,12 +1496,8 @@ void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) { ...@@ -1496,12 +1496,8 @@ void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) {
void Assembler::movq(Register dst, ExternalReference ref) { void Assembler::movq(Register dst, ExternalReference ref) {
EnsureSpace ensure_space(this); int64_t value = reinterpret_cast<int64_t>(ref.address());
last_pc_ = pc_; movq(dst, value, RelocInfo::EXTERNAL_REFERENCE);
emit_rex_64(dst);
emit(0xB8 | dst.low_bits());
emitq(reinterpret_cast<uintptr_t>(ref.address()),
RelocInfo::EXTERNAL_REFERENCE);
} }
......
...@@ -509,7 +509,6 @@ class Assembler : public Malloced { ...@@ -509,7 +509,6 @@ class Assembler : public Malloced {
void push(Immediate value); void push(Immediate value);
void push(Register src); void push(Register src);
void push(const Operand& src); void push(const Operand& src);
void push(Label* label, RelocInfo::Mode relocation_mode);
void pop(Register dst); void pop(Register dst);
void pop(const Operand& dst); void pop(const Operand& dst);
......
...@@ -10890,7 +10890,48 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { ...@@ -10890,7 +10890,48 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
void ApiGetterEntryStub::Generate(MacroAssembler* masm) { void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
UNREACHABLE(); Label empty_result;
Label prologue;
Label promote_scheduled_exception;
__ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, 0);
ASSERT_EQ(kArgc, 4);
#ifdef _WIN64
// All the parameters should be set up by a caller.
#else
// Set 1st parameter register with property name.
__ movq(rsi, rdx);
// Second parameter register rdi should be set with pointer to AccessorInfo
// by a caller.
#endif
// Call the api function!
__ movq(rax,
reinterpret_cast<int64_t>(fun()->address()),
RelocInfo::RUNTIME_ENTRY);
__ call(rax);
// Check if the function scheduled an exception.
ExternalReference scheduled_exception_address =
ExternalReference::scheduled_exception_address();
__ movq(rsi, scheduled_exception_address);
__ Cmp(Operand(rsi, 0), Factory::the_hole_value());
__ j(not_equal, &promote_scheduled_exception);
#ifdef _WIN64
// rax keeps a pointer to v8::Handle, unpack it.
__ movq(rax, Operand(rax, 0));
#endif
// Check if the result handle holds 0.
__ testq(rax, rax);
__ j(zero, &empty_result);
// It was non-zero. Dereference to get the result value.
__ movq(rax, Operand(rax, 0));
__ bind(&prologue);
__ LeaveExitFrame(ExitFrame::MODE_NORMAL);
__ ret(0);
__ bind(&promote_scheduled_exception);
__ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
__ bind(&empty_result);
// It was zero; the result is undefined.
__ Move(rax, Factory::undefined_value());
__ jmp(&prologue);
} }
......
...@@ -336,12 +336,32 @@ void MacroAssembler::CallStub(CodeStub* stub) { ...@@ -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) { void MacroAssembler::TailCallStub(CodeStub* stub) {
ASSERT(allow_stub_calls()); // calls are not allowed in some stubs ASSERT(allow_stub_calls()); // calls are not allowed in some stubs
Jump(stub->GetCode(), RelocInfo::CODE_TARGET); 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) { void MacroAssembler::StubReturn(int argc) {
ASSERT(argc >= 1 && generating_stub()); ASSERT(argc >= 1 && generating_stub());
ret((argc - 1) * kPointerSize); ret((argc - 1) * kPointerSize);
...@@ -361,6 +381,12 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { ...@@ -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) { void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
// If the expected number of arguments of the runtime function is // If the expected number of arguments of the runtime function is
// constant, we check that the actual number of arguments match the // constant, we check that the actual number of arguments match the
...@@ -381,6 +407,26 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { ...@@ -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, void MacroAssembler::CallExternalReference(const ExternalReference& ext,
int num_arguments) { int num_arguments) {
Set(rax, num_arguments); Set(rax, num_arguments);
...@@ -417,6 +463,87 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, ...@@ -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, void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
int result_size) { int result_size) {
// Set the entry point and jump to the C entry runtime stub. // Set the entry point and jump to the C entry runtime stub.
...@@ -2208,7 +2335,8 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { ...@@ -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. // Setup the frame structure on the stack.
// All constants are relative to the frame pointer of the exit frame. // All constants are relative to the frame pointer of the exit frame.
ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize); ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
...@@ -2226,18 +2354,19 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { ...@@ -2226,18 +2354,19 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) {
// Save the frame pointer and the context in top. // Save the frame pointer and the context in top.
ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
ExternalReference context_address(Top::k_context_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); movq(rax, rbp);
store_rax(c_entry_fp_address); store_rax(c_entry_fp_address);
movq(rax, rsi); movq(rax, rsi);
store_rax(context_address); store_rax(context_address);
}
// Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode,
// so it must be retained across the C-call. int result_size,
int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; int argc) {
lea(r12, Operand(rbp, r14, times_pointer_size, offset));
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
// Save the state of all registers to the stack from the memory // Save the state of all registers to the stack from the memory
// location. This is needed to allow nested break points. // location. This is needed to allow nested break points.
...@@ -2258,7 +2387,7 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { ...@@ -2258,7 +2387,7 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) {
// Reserve space for the Arguments object. The Windows 64-bit ABI // Reserve space for the Arguments object. The Windows 64-bit ABI
// requires us to pass this structure as a pointer to its location on // requires us to pass this structure as a pointer to its location on
// the stack. The structure contains 2 values. // 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 also need backing space for 4 parameters, even though
// we only pass one or two parameter, and it is in a register. // we only pass one or two parameter, and it is in a register.
int argument_mirror_space = 4 * kPointerSize; int argument_mirror_space = 4 * kPointerSize;
...@@ -2280,6 +2409,33 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { ...@@ -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) { void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode, int result_size) {
// Registers: // Registers:
// r12 : argv // r12 : argv
......
...@@ -163,6 +163,11 @@ class MacroAssembler: public Assembler { ...@@ -163,6 +163,11 @@ class MacroAssembler: public Assembler {
// to the first argument in register rsi. // to the first argument in register rsi.
void EnterExitFrame(ExitFrame::Mode mode, int result_size = 1); void EnterExitFrame(ExitFrame::Mode mode, int result_size = 1);
void EnterApiExitFrame(ExitFrame::Mode mode,
int stack_space,
int argc,
int result_size = 1);
// Leave the current exit frame. Expects/provides the return value in // Leave the current exit frame. Expects/provides the return value in
// register rax:rdx (untouched) and the pointer to the first // register rax:rdx (untouched) and the pointer to the first
// argument in register rsi. // argument in register rsi.
...@@ -719,18 +724,36 @@ class MacroAssembler: public Assembler { ...@@ -719,18 +724,36 @@ class MacroAssembler: public Assembler {
// Call a code stub. // Call a code stub.
void CallStub(CodeStub* stub); void CallStub(CodeStub* stub);
// Call a code stub and return the code object called. Try to generate
// the code if necessary. Do not perform a GC but instead return a retry
// after GC failure.
Object* TryCallStub(CodeStub* stub);
// Tail call a code stub (jump). // Tail call a code stub (jump).
void TailCallStub(CodeStub* stub); void TailCallStub(CodeStub* stub);
// Tail call a code stub (jump) and return the code object called. Try to
// generate the code if necessary. Do not perform a GC but instead return
// a retry after GC failure.
Object* TryTailCallStub(CodeStub* stub);
// Return from a code stub after popping its arguments. // Return from a code stub after popping its arguments.
void StubReturn(int argc); void StubReturn(int argc);
// Call a runtime routine. // Call a runtime routine.
void CallRuntime(Runtime::Function* f, int num_arguments); void CallRuntime(Runtime::Function* f, int num_arguments);
// Call a runtime function, returning the CodeStub object called.
// Try to generate the stub code if necessary. Do not perform a GC
// but instead return a retry after GC failure.
Object* TryCallRuntime(Runtime::Function* f, int num_arguments);
// Convenience function: Same as above, but takes the fid instead. // Convenience function: Same as above, but takes the fid instead.
void CallRuntime(Runtime::FunctionId id, int num_arguments); void CallRuntime(Runtime::FunctionId id, int num_arguments);
// Convenience function: Same as above, but takes the fid instead.
Object* TryCallRuntime(Runtime::FunctionId id, int num_arguments);
// Convenience function: call an external reference. // Convenience function: call an external reference.
void CallExternalReference(const ExternalReference& ext, void CallExternalReference(const ExternalReference& ext,
int num_arguments); int num_arguments);
...@@ -747,6 +770,16 @@ class MacroAssembler: public Assembler { ...@@ -747,6 +770,16 @@ class MacroAssembler: public Assembler {
int num_arguments, int num_arguments,
int result_size); int result_size);
void PushHandleScope(Register scratch);
// Pops a handle scope using the specified scratch register and
// ensuring that saved register is left unchanged.
void PopHandleScope(Register saved, Register scratch);
// As PopHandleScope, but does not perform a GC. Instead, returns a
// retry after GC failure object if GC is necessary.
Object* TryPopHandleScope(Register saved, Register scratch);
// Jump to a runtime routine. // Jump to a runtime routine.
void JumpToExternalReference(const ExternalReference& ext, int result_size); void JumpToExternalReference(const ExternalReference& ext, int result_size);
...@@ -835,6 +868,9 @@ class MacroAssembler: public Assembler { ...@@ -835,6 +868,9 @@ class MacroAssembler: public Assembler {
void EnterFrame(StackFrame::Type type); void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type); void LeaveFrame(StackFrame::Type type);
void EnterExitFramePrologue(ExitFrame::Mode mode, bool save_rax);
void EnterExitFrameEpilogue(ExitFrame::Mode mode, int result_size, int argc);
// Allocation support helpers. // Allocation support helpers.
// Loads the top of new-space into the result register. // Loads the top of new-space into the result register.
// If flags contains RESULT_CONTAINS_TOP then result_end is valid and // If flags contains RESULT_CONTAINS_TOP then result_end is valid and
...@@ -848,6 +884,13 @@ class MacroAssembler: public Assembler { ...@@ -848,6 +884,13 @@ class MacroAssembler: public Assembler {
// Update allocation top with value in result_end register. // Update allocation top with value in result_end register.
// If scratch is valid, it contains the address of the allocation top. // If scratch is valid, it contains the address of the allocation top.
void UpdateAllocationTopHelper(Register result_end, Register scratch); void UpdateAllocationTopHelper(Register result_end, Register scratch);
// Helper for PopHandleScope. Allowed to perform a GC and returns
// NULL if gc_allowed. Does not perform a GC if !gc_allowed, and
// possibly returns a failure object indicating an allocation failure.
Object* PopHandleScopeHelper(Register saved,
Register scratch,
bool gc_allowed);
}; };
......
...@@ -2211,23 +2211,80 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -2211,23 +2211,80 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
// Check that the maps haven't changed. // Check that the maps haven't changed.
Register reg = Register reg =
CheckPrototypes(object, receiver, holder, CheckPrototypes(object, receiver, holder, scratch1,
scratch1, scratch2, scratch3, name, miss); scratch2, scratch3, name, miss);
// Push the arguments on the JS stack of the caller. Handle<AccessorInfo> callback_handle(callback);
__ pop(scratch2); // remove return address
__ EnterInternalFrame();
__ PushHandleScope(scratch2);
// Push the stack address where the list of arguments ends.
__ movq(scratch2, rsp);
__ subq(scratch2, Immediate(2 * kPointerSize));
__ push(scratch2);
__ push(receiver); // receiver __ push(receiver); // receiver
__ push(reg); // holder __ push(reg); // holder
__ Move(reg, Handle<AccessorInfo>(callback)); // callback data if (Heap::InNewSpace(callback_handle->data())) {
__ push(reg); __ Move(scratch2, callback_handle);
__ push(FieldOperand(reg, AccessorInfo::kDataOffset)); __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset)); // data
} else {
__ Push(Handle<Object>(callback_handle->data()));
}
__ push(name_reg); // name __ push(name_reg); // name
__ push(scratch2); // restore return address // Save a pointer to where we pushed the arguments pointer.
// This will be passed as the const AccessorInfo& to the C++ callback.
#ifdef _WIN64
// Win64 uses first register--rcx--for returned value.
Register accessor_info_arg = r8;
Register name_arg = rdx;
#else
Register accessor_info_arg = rdx; // temporary, copied to rsi by the stub.
Register name_arg = rdi;
#endif
// Do tail-call to the runtime system. __ movq(accessor_info_arg, rsp);
ExternalReference load_callback_property = __ addq(accessor_info_arg, Immediate(4 * kPointerSize));
ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); __ movq(name_arg, rsp);
__ TailCallExternalReference(load_callback_property, 5, 1);
// Do call through the api.
ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace);
Address getter_address = v8::ToCData<Address>(callback->getter());
ApiFunction fun(getter_address);
ApiGetterEntryStub stub(callback_handle, &fun);
#ifdef _WIN64
// We need to prepare a slot for result handle on stack and put
// a pointer to it into 1st arg register.
__ push(Immediate(0));
__ movq(rcx, rsp);
#endif
// Emitting a stub call may try to allocate (if the code is not
// already generated). Do not allow the assembler to perform a
// garbage collection but instead return the allocation failure
// object.
Object* result = masm()->TryCallStub(&stub);
if (result->IsFailure()) {
*failure = Failure::cast(result);
return false;
}
#ifdef _WIN64
// Discard allocated slot.
__ addq(rsp, Immediate(kPointerSize));
#endif
// We need to avoid using rax since that now holds the result.
Register tmp = scratch2.is(rax) ? reg : scratch2;
// Emitting PopHandleScope may try to allocate. Do not allow the
// assembler to perform a garbage collection but instead return a
// failure object.
result = masm()->TryPopHandleScope(rax, tmp);
if (result->IsFailure()) {
*failure = Failure::cast(result);
return false;
}
__ LeaveInternalFrame();
__ ret(0);
return true; return true;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment