Index: src/x64/builtins-x64.cc |
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc |
index 91db4c61f962fd032506dd0e4f2a9f9563f60624..e8cc4381bf26bb958e3f55d2fd6d4eeaf8cb75f6 100644 |
--- a/src/x64/builtins-x64.cc |
+++ b/src/x64/builtins-x64.cc |
@@ -23,13 +23,20 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm, |
// -- rax : number of arguments excluding receiver |
// -- rdi : called function (only guaranteed when |
// extra_args requires it) |
- // -- rsi : context |
// -- rsp[0] : return address |
// -- rsp[8] : last argument |
// -- ... |
// -- rsp[8 * argc] : first argument (argc == rax) |
// -- rsp[8 * (argc + 1)] : receiver |
// ----------------------------------- |
+ __ AssertFunction(rdi); |
+ |
+ // Make sure we operate in the context of the called function (for example |
+ // ConstructStubs implemented in C++ will be run in the context of the caller |
+ // instead of the callee, due to the way that [[Construct]] is defined for |
+ // ordinary functions). |
+ // TODO(bmeurer): Can we make this more robust? |
+ __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
// Insert extra arguments. |
int num_extra_args = 0; |
@@ -441,7 +448,7 @@ void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) { |
enum IsTagged { kRaxIsSmiTagged, kRaxIsUntaggedInt }; |
-// Clobbers rcx, rdx, kScratchRegister; preserves all other registers. |
+// Clobbers rcx, r11, kScratchRegister; preserves all other registers. |
static void Generate_CheckStackOverflow(MacroAssembler* masm, |
const int calleeOffset, |
IsTagged rax_is_tagged) { |
@@ -456,17 +463,17 @@ static void Generate_CheckStackOverflow(MacroAssembler* masm, |
// Make rcx the space we have left. The stack might already be overflowed |
// here which will cause rcx to become negative. |
__ subp(rcx, kScratchRegister); |
- // Make rdx the space we need for the array when it is unrolled onto the |
+ // Make r11 the space we need for the array when it is unrolled onto the |
// stack. |
if (rax_is_tagged == kRaxIsSmiTagged) { |
- __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2); |
+ __ PositiveSmiTimesPowerOfTwoToInteger64(r11, rax, kPointerSizeLog2); |
} else { |
DCHECK(rax_is_tagged == kRaxIsUntaggedInt); |
- __ movp(rdx, rax); |
- __ shlq(rdx, Immediate(kPointerSizeLog2)); |
+ __ movp(r11, rax); |
+ __ shlq(r11, Immediate(kPointerSizeLog2)); |
} |
// Check if the arguments will overflow the stack. |
- __ cmpp(rcx, rdx); |
+ __ cmpp(rcx, r11); |
__ j(greater, &okay); // Signed comparison. |
// Out of stack space. |
@@ -486,8 +493,8 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
ProfileEntryHookStub::MaybeCallEntryHook(masm); |
// Expects five C++ function parameters. |
- // - Address entry (ignored) |
- // - JSFunction* function ( |
+ // - Object* new_target |
+ // - JSFunction* function |
// - Object* receiver |
// - int argc |
// - Object*** argv |
@@ -498,11 +505,12 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
// Platform specific argument handling. After this, the stack contains |
// an internal frame and the pushed function and receiver, and |
// register rax and rbx holds the argument count and argument array, |
- // while rdi holds the function pointer and rsi the context. |
+ // while rdi holds the function pointer, rsi the context, and rdx the |
+ // new.target. |
#ifdef _WIN64 |
// MSVC parameters in: |
- // rcx : entry (ignored) |
+ // rcx : new_target |
// rdx : function |
// r8 : receiver |
// r9 : argc |
@@ -510,11 +518,14 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
// Clear the context before we push it when entering the internal frame. |
__ Set(rsi, 0); |
+ |
// Enter an internal frame. |
FrameScope scope(masm, StackFrame::INTERNAL); |
- // Load the function context into rsi. |
- __ movp(rsi, FieldOperand(rdx, JSFunction::kContextOffset)); |
+ // Setup the context (we need to use the caller context from the isolate). |
+ ExternalReference context_address(Isolate::kContextAddress, |
+ masm->isolate()); |
+ __ movp(rsi, masm->ExternalOperand(context_address)); |
// Push the function and the receiver onto the stack. |
__ Push(rdx); |
@@ -527,30 +538,42 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
__ movp(rbx, Operand(kScratchRegister, EntryFrameConstants::kArgvOffset)); |
// Load the function pointer into rdi. |
__ movp(rdi, rdx); |
+ // Load the new.target into rdx. |
+ __ movp(rdx, rcx); |
#else // _WIN64 |
// GCC parameters in: |
- // rdi : entry (ignored) |
+ // rdi : new_target |
// rsi : function |
// rdx : receiver |
// rcx : argc |
// r8 : argv |
+ __ movp(r11, rdi); |
__ movp(rdi, rsi); |
// rdi : function |
+ // r11 : new_target |
// Clear the context before we push it when entering the internal frame. |
__ Set(rsi, 0); |
+ |
// Enter an internal frame. |
FrameScope scope(masm, StackFrame::INTERNAL); |
- // Push the function and receiver and setup the context. |
+ // Setup the context (we need to use the caller context from the isolate). |
+ ExternalReference context_address(Isolate::kContextAddress, |
+ masm->isolate()); |
+ __ movp(rsi, masm->ExternalOperand(context_address)); |
+ |
+ // Push the function and receiver onto the stack. |
__ Push(rdi); |
__ Push(rdx); |
- __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
// Load the number of arguments and setup pointer to the arguments. |
__ movp(rax, rcx); |
__ movp(rbx, r8); |
+ |
+ // Load the new.target into rdx. |
+ __ movp(rdx, r11); |
#endif // _WIN64 |
// Current stack contents: |
@@ -562,13 +585,14 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
// rbx : argv |
// rsi : context |
// rdi : function |
+ // rdx : new.target |
// Check if we have enough stack space to push all arguments. |
// The function is the first thing that was pushed above after entering |
// the internal frame. |
const int kFunctionOffset = |
InternalFrameConstants::kCodeOffset - kRegisterSize; |
- // Expects argument count in rax. Clobbers rcx, rdx. |
+ // Expects argument count in rax. Clobbers rcx, r11. |
Generate_CheckStackOverflow(masm, kFunctionOffset, kRaxIsUntaggedInt); |
// Copy arguments to the stack in a loop. |
@@ -576,7 +600,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
// Push the values of these handles. |
Label loop, entry; |
__ Set(rcx, 0); // Set loop variable to 0. |
- __ jmp(&entry); |
+ __ jmp(&entry, Label::kNear); |
__ bind(&loop); |
__ movp(kScratchRegister, Operand(rbx, rcx, times_pointer_size, 0)); |
__ Push(Operand(kScratchRegister, 0)); // dereference handle |
@@ -585,16 +609,12 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
__ cmpp(rcx, rax); |
__ j(not_equal, &loop); |
- // Invoke the code. |
- if (is_construct) { |
- // No type feedback cell is available |
- __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); |
- // Expects rdi to hold function pointer. |
- CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS); |
- __ CallStub(&stub); |
- } else { |
- __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
- } |
+ // Invoke the builtin code. |
+ Handle<Code> builtin = is_construct |
+ ? masm->isolate()->builtins()->Construct() |
+ : masm->isolate()->builtins()->Call(); |
+ __ Call(builtin, RelocInfo::CODE_TARGET); |
+ |
// Exit the internal frame. Notice that this also removes the empty |
// context and the function left on the stack by the code |
// invocation. |
@@ -1695,7 +1715,7 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm) { |
void Builtins::Generate_Call(MacroAssembler* masm) { |
// ----------- S t a t e ------------- |
// -- rax : the number of arguments (not including the receiver) |
- // -- rdi : the target to call (can be any Object). |
+ // -- rdi : the target to call (can be any Object) |
// ----------------------------------- |
Label non_smi, non_function; |
@@ -1743,6 +1763,68 @@ void Builtins::Generate_Call(MacroAssembler* masm) { |
// static |
+void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { |
+ // ----------- S t a t e ------------- |
+ // -- rax : the number of arguments (not including the receiver) |
+ // -- rdx : the original constructor (checked to be a JSFunction) |
+ // -- rdi : the constructor to call (checked to be a JSFunction) |
+ // ----------------------------------- |
+ __ AssertFunction(rdx); |
+ __ AssertFunction(rdi); |
+ |
+ // Calling convention for function specific ConstructStubs require |
+ // rbx to contain either an AllocationSite or undefined. |
+ __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); |
+ |
+ // Tail call to the function-specific construct stub (still in the caller |
+ // context at this point). |
+ __ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
+ __ movp(rcx, FieldOperand(rcx, SharedFunctionInfo::kConstructStubOffset)); |
+ __ leap(rcx, FieldOperand(rcx, Code::kHeaderSize)); |
+ __ jmp(rcx); |
+} |
+ |
+ |
+// static |
+void Builtins::Generate_Construct(MacroAssembler* masm) { |
+ // ----------- S t a t e ------------- |
+ // -- rax : the number of arguments (not including the receiver) |
+ // -- rdx : the original constructor (either the same as the constructor or |
+ // the JSFunction on which new was invoked initially) |
+ // -- rdi : the constructor to call (can be any Object) |
+ // ----------------------------------- |
+ |
+ Label slow; |
+ __ JumpIfSmi(rdi, &slow, Label::kNear); |
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
+ __ j(equal, masm->isolate()->builtins()->ConstructFunction(), |
+ RelocInfo::CODE_TARGET); |
+ __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); |
+ __ j(not_equal, &slow, Label::kNear); |
+ |
+ // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies. |
+ __ movp(rdi, FieldOperand(rdi, JSFunctionProxy::kConstructTrapOffset)); |
+ __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
+ |
+ __ bind(&slow); |
+ { |
+ // Determine the delegate for the target (if any). |
+ FrameScope scope(masm, StackFrame::INTERNAL); |
+ __ Integer32ToSmi(rax, rax); |
+ __ Push(rax); |
+ __ Push(rdi); |
+ __ CallRuntime(Runtime::kGetConstructorDelegate, 1); |
+ __ movp(rdi, rax); |
+ __ Pop(rax); |
+ __ SmiToInteger32(rax, rax); |
+ } |
+ // The delegate is always a regular function. |
+ __ AssertFunction(rdi); |
+ __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET); |
+} |
+ |
+ |
+// static |
void Builtins::Generate_PushArgsAndCall(MacroAssembler* masm) { |
// ----------- S t a t e ------------- |
// -- rax : the number of arguments (not including the receiver) |