Commit 7a63bf77 authored by arv's avatar arv Committed by Commit bot

[es6] Make new.target work in functions

This makes new.target work in [[Call]] and [[Construct]] of ordinary
functions.

We achieve this by introducing a new construct stub for functions that
uses the new.target variable. The construct stub pushes the original
constructor just above the receiver in the construct frame.

BUG=v8:3887
LOG=N
R=adamk@chromium.org, dslomov@chromium.org

Review URL: https://codereview.chromium.org/1203813002

Cr-Commit-Position: refs/heads/master@{#29358}
parent 473badf5
...@@ -343,6 +343,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm, ...@@ -343,6 +343,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm,
static void Generate_JSConstructStubHelper(MacroAssembler* masm, static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function, bool is_api_function,
bool use_new_target,
bool create_memento) { bool create_memento) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : number of arguments // -- r0 : number of arguments
...@@ -367,10 +368,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -367,10 +368,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ push(r2); __ push(r2);
} }
// Preserve the two incoming parameters on the stack. // Preserve the incoming parameters on the stack.
__ SmiTag(r0); __ SmiTag(r0);
__ push(r0); // Smi-tagged arguments count. __ push(r0);
__ push(r1); // Constructor function. __ push(r1);
if (use_new_target) {
__ push(r3);
}
Label rt_call, allocated, normal_new, count_incremented; Label rt_call, allocated, normal_new, count_incremented;
__ cmp(r1, r3); __ cmp(r1, r3);
...@@ -610,7 +614,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -610,7 +614,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&allocated); __ bind(&allocated);
if (create_memento) { if (create_memento) {
__ ldr(r2, MemOperand(sp, kPointerSize * 2)); int offset = (use_new_target ? 3 : 2) * kPointerSize;
__ ldr(r2, MemOperand(sp, offset));
__ LoadRoot(r5, Heap::kUndefinedValueRootIndex); __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
__ cmp(r2, r5); __ cmp(r2, r5);
__ b(eq, &count_incremented); __ b(eq, &count_incremented);
...@@ -624,23 +629,27 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -624,23 +629,27 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&count_incremented); __ bind(&count_incremented);
} }
__ pop(r1); // Constructor function. // Restore the parameters.
if (use_new_target) {
__ pop(r3);
}
__ pop(r1);
// Retrieve smi-tagged arguments count from the stack.
__ ldr(r0, MemOperand(sp));
__ SmiUntag(r0);
// Push new.target onto the construct frame. This is stored just below the
// receiver on the stack.
if (use_new_target) {
__ push(r3);
}
__ push(r4); __ push(r4);
__ push(r4); __ push(r4);
// Reload the number of arguments from the stack.
// sp[0]: receiver
// sp[1]: receiver
// sp[2]: number of arguments (smi-tagged)
__ ldr(r3, MemOperand(sp, 2 * kPointerSize));
// Set up pointer to last argument. // Set up pointer to last argument.
__ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
// Set up number of arguments for function call below
__ SmiUntag(r0, r3);
// Copy arguments and receiver to the expression stack. // Copy arguments and receiver to the expression stack.
// r0: number of arguments // r0: number of arguments
// r1: constructor function // r1: constructor function
...@@ -648,8 +657,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -648,8 +657,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// r3: number of arguments (smi-tagged) // r3: number of arguments (smi-tagged)
// sp[0]: receiver // sp[0]: receiver
// sp[1]: receiver // sp[1]: receiver
// sp[2]: number of arguments (smi-tagged) // sp[2]: new.target (if used)
// sp[2/3]: number of arguments (smi-tagged)
Label loop, entry; Label loop, entry;
__ SmiTag(r3, r0);
__ b(&entry); __ b(&entry);
__ bind(&loop); __ bind(&loop);
__ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1)); __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1));
...@@ -672,14 +683,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -672,14 +683,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
} }
// Store offset of return address for deoptimizer. // Store offset of return address for deoptimizer.
if (!is_api_function) { // TODO(arv): Remove the "!use_new_target" before supporting optimization
// of functions that reference new.target
if (!is_api_function && !use_new_target) {
masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
} }
// Restore context from the frame. // Restore context from the frame.
// r0: result // r0: result
// sp[0]: receiver // sp[0]: receiver
// sp[1]: number of arguments (smi-tagged) // sp[1]: new.target (if used)
// sp[1/2]: number of arguments (smi-tagged)
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// If the result is an object (in the ECMA sense), we should get rid // If the result is an object (in the ECMA sense), we should get rid
...@@ -690,7 +704,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -690,7 +704,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// If the result is a smi, it is *not* an object in the ECMA sense. // If the result is a smi, it is *not* an object in the ECMA sense.
// r0: result // r0: result
// sp[0]: receiver (newly allocated object) // sp[0]: receiver (newly allocated object)
// sp[1]: number of arguments (smi-tagged) // sp[1]: new.target (if used)
// sp[1/2]: number of arguments (smi-tagged)
__ JumpIfSmi(r0, &use_receiver); __ JumpIfSmi(r0, &use_receiver);
// If the type of the result (stored in its map) is less than // If the type of the result (stored in its map) is less than
...@@ -708,8 +723,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -708,8 +723,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&exit); __ bind(&exit);
// r0: result // r0: result
// sp[0]: receiver (newly allocated object) // sp[0]: receiver (newly allocated object)
// sp[1]: number of arguments (smi-tagged) // sp[1]: new.target (if used)
__ ldr(r1, MemOperand(sp, kPointerSize)); // sp[1/2]: number of arguments (smi-tagged)
int offset = (use_new_target ? 2 : 1) * kPointerSize;
__ ldr(r1, MemOperand(sp, offset));
// Leave construct frame. // Leave construct frame.
} }
...@@ -722,12 +739,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -722,12 +739,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new);
} }
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, true, false); Generate_JSConstructStubHelper(masm, true, false, false);
}
void Builtins::Generate_JSConstructStubNewTarget(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, true, FLAG_pretenuring_call_new);
} }
......
...@@ -331,6 +331,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm, ...@@ -331,6 +331,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm,
static void Generate_JSConstructStubHelper(MacroAssembler* masm, static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function, bool is_api_function,
bool use_new_target,
bool create_memento) { bool create_memento) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- x0 : number of arguments // -- x0 : number of arguments
...@@ -360,11 +361,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -360,11 +361,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
Register argc = x0; Register argc = x0;
Register constructor = x1; Register constructor = x1;
Register original_constructor = x3; Register original_constructor = x3;
// x1: constructor function
// Preserve the incoming parameters on the stack.
__ SmiTag(argc); __ SmiTag(argc);
__ Push(argc, constructor); if (use_new_target) {
// sp[0] : Constructor function. __ Push(argc, constructor, original_constructor);
// sp[1]: number of arguments (smi-tagged) } else {
__ Push(argc, constructor);
}
// sp[0]: new.target (if used)
// sp[0/1]: Constructor function.
// sp[1/2]: number of arguments (smi-tagged)
Label rt_call, count_incremented, allocated, normal_new; Label rt_call, count_incremented, allocated, normal_new;
__ Cmp(constructor, original_constructor); __ Cmp(constructor, original_constructor);
...@@ -580,7 +587,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -580,7 +587,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Bind(&allocated); __ Bind(&allocated);
if (create_memento) { if (create_memento) {
__ Peek(x10, 2 * kXRegSize); int offset = (use_new_target ? 3 : 2) * kXRegSize;
__ Peek(x10, offset);
__ JumpIfRoot(x10, Heap::kUndefinedValueRootIndex, &count_incremented); __ JumpIfRoot(x10, Heap::kUndefinedValueRootIndex, &count_incremented);
// r2 is an AllocationSite. We are creating a memento from it, so we // r2 is an AllocationSite. We are creating a memento from it, so we
// need to increment the memento create count. // need to increment the memento create count.
...@@ -592,18 +600,24 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -592,18 +600,24 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&count_incremented); __ bind(&count_incremented);
} }
// Restore the parameters.
if (use_new_target) {
__ Pop(original_constructor);
}
__ Pop(constructor); __ Pop(constructor);
__ Push(x4, x4);
// Reload the number of arguments from the stack. // Reload the number of arguments from the stack.
// Set it up in x0 for the function call below. // Set it up in x0 for the function call below.
// jssp[0]: receiver // jssp[0]: number of arguments (smi-tagged)
// jssp[1]: receiver __ Peek(argc, 0); // Load number of arguments.
// jssp[2]: number of arguments (smi-tagged)
__ Peek(argc, 2 * kXRegSize); // Load number of arguments.
__ SmiUntag(argc); __ SmiUntag(argc);
if (use_new_target) {
__ Push(original_constructor, x4, x4);
} else {
__ Push(x4, x4);
}
// Set up pointer to last argument. // Set up pointer to last argument.
__ Add(x2, fp, StandardFrameConstants::kCallerSPOffset); __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
...@@ -614,7 +628,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -614,7 +628,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// x2: address of last argument (caller sp) // x2: address of last argument (caller sp)
// jssp[0]: receiver // jssp[0]: receiver
// jssp[1]: receiver // jssp[1]: receiver
// jssp[2]: number of arguments (smi-tagged) // jssp[2]: new.target (if used)
// jssp[2/3]: number of arguments (smi-tagged)
// Compute the start address of the copy in x3. // Compute the start address of the copy in x3.
__ Add(x3, x2, Operand(argc, LSL, kPointerSizeLog2)); __ Add(x3, x2, Operand(argc, LSL, kPointerSizeLog2));
Label loop, entry, done_copying_arguments; Label loop, entry, done_copying_arguments;
...@@ -645,14 +660,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -645,14 +660,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
} }
// Store offset of return address for deoptimizer. // Store offset of return address for deoptimizer.
if (!is_api_function) { // TODO(arv): Remove the "!use_new_target" before supporting optimization
// of functions that reference new.target
if (!is_api_function && !use_new_target) {
masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
} }
// Restore the context from the frame. // Restore the context from the frame.
// x0: result // x0: result
// jssp[0]: receiver // jssp[0]: receiver
// jssp[1]: number of arguments (smi-tagged) // jssp[1]: new.target (if used)
// jssp[1/2]: number of arguments (smi-tagged)
__ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// If the result is an object (in the ECMA sense), we should get rid // If the result is an object (in the ECMA sense), we should get rid
...@@ -680,8 +698,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -680,8 +698,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Bind(&exit); __ Bind(&exit);
// x0: result // x0: result
// jssp[0]: receiver (newly allocated object) // jssp[0]: receiver (newly allocated object)
// jssp[1]: number of arguments (smi-tagged) // jssp[1]: new.target (if used)
__ Peek(x1, kXRegSize); // jssp[1/2]: number of arguments (smi-tagged)
int offset = (use_new_target ? 2 : 1) * kXRegSize;
__ Peek(x1, offset);
// Leave construct frame. // Leave construct frame.
} }
...@@ -694,12 +714,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -694,12 +714,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new);
} }
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, true, false); Generate_JSConstructStubHelper(masm, true, false, false);
}
void Builtins::Generate_JSConstructStubNewTarget(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, true, FLAG_pretenuring_call_new);
} }
......
...@@ -273,7 +273,7 @@ void FullCodeGenerator::Generate() { ...@@ -273,7 +273,7 @@ void FullCodeGenerator::Generate() {
__ LoadRoot(x0, Heap::kUndefinedValueRootIndex); __ LoadRoot(x0, Heap::kUndefinedValueRootIndex);
__ Bind(&done); __ Bind(&done);
// new.target is parameter -2.
SetVar(new_target_var, x0, x2, x3); SetVar(new_target_var, x0, x2, x3);
} }
......
...@@ -70,6 +70,7 @@ enum BuiltinExtraArguments { ...@@ -70,6 +70,7 @@ enum BuiltinExtraArguments {
V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(JSConstructStubForDerived, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(JSConstructStubForDerived, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(JSConstructStubApi, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(JSConstructStubApi, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(JSConstructStubNewTarget, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(CompileLazy, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(CompileLazy, BUILTIN, UNINITIALIZED, kNoExtraICState) \
...@@ -322,6 +323,7 @@ class Builtins { ...@@ -322,6 +323,7 @@ class Builtins {
static void Generate_JSConstructStubGeneric(MacroAssembler* masm); static void Generate_JSConstructStubGeneric(MacroAssembler* masm);
static void Generate_JSConstructStubForDerived(MacroAssembler* masm); static void Generate_JSConstructStubForDerived(MacroAssembler* masm);
static void Generate_JSConstructStubApi(MacroAssembler* masm); static void Generate_JSConstructStubApi(MacroAssembler* masm);
static void Generate_JSConstructStubNewTarget(MacroAssembler* masm);
static void Generate_JSEntryTrampoline(MacroAssembler* masm); static void Generate_JSEntryTrampoline(MacroAssembler* masm);
static void Generate_JSConstructEntryTrampoline(MacroAssembler* masm); static void Generate_JSConstructEntryTrampoline(MacroAssembler* masm);
static void Generate_NotifyDeoptimized(MacroAssembler* masm); static void Generate_NotifyDeoptimized(MacroAssembler* masm);
......
...@@ -1440,6 +1440,11 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( ...@@ -1440,6 +1440,11 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
// first time. It may have already been compiled previously. // first time. It may have already been compiled previously.
result->set_never_compiled(outer_info->is_first_compile() && lazy); result->set_never_compiled(outer_info->is_first_compile() && lazy);
if (literal->scope()->new_target_var() != nullptr) {
Handle<Code> stub(isolate->builtins()->JSConstructStubNewTarget());
result->set_construct_stub(*stub);
}
RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result); RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
result->set_allows_lazy_compilation(literal->AllowsLazyCompilation()); result->set_allows_lazy_compilation(literal->AllowsLazyCompilation());
result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx); result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx);
......
...@@ -138,6 +138,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm, ...@@ -138,6 +138,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm,
static void Generate_JSConstructStubHelper(MacroAssembler* masm, static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function, bool is_api_function,
bool use_new_target,
bool create_memento) { bool create_memento) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax: number of arguments // -- eax: number of arguments
...@@ -158,12 +159,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -158,12 +159,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ push(ebx); __ push(ebx);
} }
// Store a smi-tagged arguments count on the stack. // Preserve the incoming parameters on the stack.
__ SmiTag(eax); __ SmiTag(eax);
__ push(eax); __ push(eax);
// Push the function to invoke on the stack.
__ push(edi); __ push(edi);
if (use_new_target) {
__ push(edx);
}
__ cmp(edx, edi); __ cmp(edx, edi);
Label normal_new; Label normal_new;
...@@ -391,7 +393,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -391,7 +393,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&allocated); __ bind(&allocated);
if (create_memento) { if (create_memento) {
__ mov(ecx, Operand(esp, kPointerSize * 2)); int offset = (use_new_target ? 3 : 2) * kPointerSize;
__ mov(ecx, Operand(esp, offset));
__ cmp(ecx, masm->isolate()->factory()->undefined_value()); __ cmp(ecx, masm->isolate()->factory()->undefined_value());
__ j(equal, &count_incremented); __ j(equal, &count_incremented);
// ecx is an AllocationSite. We are creating a memento from it, so we // ecx is an AllocationSite. We are creating a memento from it, so we
...@@ -401,13 +404,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -401,13 +404,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&count_incremented); __ bind(&count_incremented);
} }
// Retrieve the function from the stack. // Restore the parameters.
__ pop(edi); if (use_new_target) {
__ pop(edx); // new.target
}
__ pop(edi); // Constructor function.
// Retrieve smi-tagged arguments count from the stack. // Retrieve smi-tagged arguments count from the stack.
__ mov(eax, Operand(esp, 0)); __ mov(eax, Operand(esp, 0));
__ SmiUntag(eax); __ SmiUntag(eax);
// Push new.target onto the construct frame. This is stored just below the
// receiver on the stack.
if (use_new_target) {
__ push(edx);
}
// Push the allocated receiver to the stack. We need two copies // Push the allocated receiver to the stack. We need two copies
// because we may have to return the original one and the calling // because we may have to return the original one and the calling
// conventions dictate that the called function pops the receiver. // conventions dictate that the called function pops the receiver.
...@@ -440,7 +452,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -440,7 +452,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
} }
// Store offset of return address for deoptimizer. // Store offset of return address for deoptimizer.
if (!is_api_function) { // TODO(arv): Remove the "!use_new_target" before supporting optimization
// of functions that reference new.target
if (!is_api_function && !use_new_target) {
masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
} }
...@@ -465,9 +479,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -465,9 +479,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&use_receiver); __ bind(&use_receiver);
__ mov(eax, Operand(esp, 0)); __ mov(eax, Operand(esp, 0));
// Restore the arguments count and leave the construct frame. // Restore the arguments count and leave the construct frame. The arguments
// count is stored below the reciever and the new.target.
__ bind(&exit); __ bind(&exit);
__ mov(ebx, Operand(esp, kPointerSize)); // Get arguments count. int offset = (use_new_target ? 2 : 1) * kPointerSize;
__ mov(ebx, Operand(esp, offset));
// Leave construct frame. // Leave construct frame.
} }
...@@ -483,12 +499,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -483,12 +499,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new);
} }
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, true, false); Generate_JSConstructStubHelper(masm, true, false, false);
}
void Builtins::Generate_JSConstructStubNewTarget(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, true, FLAG_pretenuring_call_new);
} }
......
...@@ -348,6 +348,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm, ...@@ -348,6 +348,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm,
static void Generate_JSConstructStubHelper(MacroAssembler* masm, static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function, bool is_api_function,
bool use_new_target,
bool create_memento) { bool create_memento) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : number of arguments // -- a0 : number of arguments
...@@ -379,9 +380,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -379,9 +380,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ push(a2); __ push(a2);
} }
// Preserve the two incoming parameters on the stack. // Preserve the incoming parameters on the stack.
__ sll(a0, a0, kSmiTagSize); // Tag arguments count. __ SmiTag(a0);
__ MultiPushReversed(a0.bit() | a1.bit()); if (use_new_target) {
__ Push(a0, a1, a3);
} else {
__ Push(a0, a1);
}
Label rt_call, allocated, normal_new, count_incremented; Label rt_call, allocated, normal_new, count_incremented;
__ Branch(&normal_new, eq, a1, Operand(a3)); __ Branch(&normal_new, eq, a1, Operand(a3));
...@@ -628,7 +633,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -628,7 +633,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&allocated); __ bind(&allocated);
if (create_memento) { if (create_memento) {
__ lw(a2, MemOperand(sp, kPointerSize * 2)); int offset = (use_new_target ? 3 : 2) * kPointerSize;
__ lw(a2, MemOperand(sp, offset));
__ LoadRoot(t5, Heap::kUndefinedValueRootIndex); __ LoadRoot(t5, Heap::kUndefinedValueRootIndex);
__ Branch(&count_incremented, eq, a2, Operand(t5)); __ Branch(&count_incremented, eq, a2, Operand(t5));
// a2 is an AllocationSite. We are creating a memento from it, so we // a2 is an AllocationSite. We are creating a memento from it, so we
...@@ -641,22 +647,25 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -641,22 +647,25 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&count_incremented); __ bind(&count_incremented);
} }
// Restore the parameters.
if (use_new_target) {
__ Pop(a3); // new.target
}
__ Pop(a1); __ Pop(a1);
__ Push(t4, t4); // Retrieve smi-tagged arguments count from the stack.
__ lw(a0, MemOperand(sp));
__ SmiUntag(a0);
// Reload the number of arguments from the stack. if (use_new_target) {
// sp[0]: receiver __ Push(a3, t4, t4);
// sp[1]: receiver } else {
// sp[2]: number of arguments (smi-tagged) __ Push(t4, t4);
__ lw(a3, MemOperand(sp, 2 * kPointerSize)); }
// Set up pointer to last argument. // Set up pointer to last argument.
__ Addu(a2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); __ Addu(a2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
// Set up number of arguments for function call below.
__ srl(a0, a3, kSmiTagSize);
// Copy arguments and receiver to the expression stack. // Copy arguments and receiver to the expression stack.
// a0: number of arguments // a0: number of arguments
// a1: constructor function // a1: constructor function
...@@ -664,8 +673,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -664,8 +673,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// a3: number of arguments (smi-tagged) // a3: number of arguments (smi-tagged)
// sp[0]: receiver // sp[0]: receiver
// sp[1]: receiver // sp[1]: receiver
// sp[2]: number of arguments (smi-tagged) // sp[2]: new.target (if used)
// sp[2/3]: number of arguments (smi-tagged)
Label loop, entry; Label loop, entry;
__ SmiTag(a3, a0);
__ jmp(&entry); __ jmp(&entry);
__ bind(&loop); __ bind(&loop);
__ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize); __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
...@@ -690,7 +701,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -690,7 +701,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
} }
// Store offset of return address for deoptimizer. // Store offset of return address for deoptimizer.
if (!is_api_function) { // TODO(arv): Remove the "!use_new_target" before supporting optimization
// of functions that reference new.target
if (!is_api_function && !use_new_target) {
masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
} }
...@@ -705,7 +718,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -705,7 +718,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// If the result is a smi, it is *not* an object in the ECMA sense. // If the result is a smi, it is *not* an object in the ECMA sense.
// v0: result // v0: result
// sp[0]: receiver (newly allocated object) // sp[0]: receiver (newly allocated object)
// sp[1]: number of arguments (smi-tagged) // sp[1]: new.target (if used)
// sp[1/2]: number of arguments (smi-tagged)
__ JumpIfSmi(v0, &use_receiver); __ JumpIfSmi(v0, &use_receiver);
// If the type of the result (stored in its map) is less than // If the type of the result (stored in its map) is less than
...@@ -723,8 +737,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -723,8 +737,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&exit); __ bind(&exit);
// v0: result // v0: result
// sp[0]: receiver (newly allocated object) // sp[0]: receiver (newly allocated object)
// sp[1]: number of arguments (smi-tagged) // sp[1]: new.target (if used)
__ lw(a1, MemOperand(sp, kPointerSize)); // sp[1/2]: number of arguments (smi-tagged)
int offset = (use_new_target ? 2 : 1) * kPointerSize;
__ lw(a1, MemOperand(sp, offset));
// Leave construct frame. // Leave construct frame.
} }
...@@ -738,12 +754,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -738,12 +754,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new);
} }
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, true, false); Generate_JSConstructStubHelper(masm, true, false, false);
}
void Builtins::Generate_JSConstructStubNewTarget(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, true, FLAG_pretenuring_call_new);
} }
......
...@@ -347,6 +347,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm, ...@@ -347,6 +347,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm,
static void Generate_JSConstructStubHelper(MacroAssembler* masm, static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function, bool is_api_function,
bool use_new_target,
bool create_memento) { bool create_memento) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : number of arguments // -- a0 : number of arguments
...@@ -378,10 +379,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -378,10 +379,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ push(a2); __ push(a2);
} }
// Preserve the two incoming parameters on the stack. // Preserve the incoming parameters on the stack.
// Tag arguments count. __ SmiTag(a0);
__ dsll32(a0, a0, 0); if (use_new_target) {
__ MultiPushReversed(a0.bit() | a1.bit()); __ Push(a0, a1, a3);
} else {
__ Push(a0, a1);
}
Label rt_call, allocated, normal_new, count_incremented; Label rt_call, allocated, normal_new, count_incremented;
__ Branch(&normal_new, eq, a1, Operand(a3)); __ Branch(&normal_new, eq, a1, Operand(a3));
...@@ -636,7 +640,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -636,7 +640,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&allocated); __ bind(&allocated);
if (create_memento) { if (create_memento) {
__ ld(a2, MemOperand(sp, kPointerSize * 2)); int offset = (use_new_target ? 3 : 2) * kPointerSize;
__ ld(a2, MemOperand(sp, offset));
__ LoadRoot(t1, Heap::kUndefinedValueRootIndex); __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
__ Branch(&count_incremented, eq, a2, Operand(t1)); __ Branch(&count_incremented, eq, a2, Operand(t1));
// a2 is an AllocationSite. We are creating a memento from it, so we // a2 is an AllocationSite. We are creating a memento from it, so we
...@@ -649,22 +654,24 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -649,22 +654,24 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&count_incremented); __ bind(&count_incremented);
} }
// Restore the parameters.
if (use_new_target) {
__ Pop(a3); // new.target
}
__ Pop(a1); __ Pop(a1);
__ Push(t0, t0); __ ld(a0, MemOperand(sp));
__ SmiUntag(a0);
// Reload the number of arguments from the stack. if (use_new_target) {
// sp[0]: receiver __ Push(a3, t0, t0);
// sp[1]: receiver } else {
// sp[2]: number of arguments (smi-tagged) __ Push(t0, t0);
__ ld(a3, MemOperand(sp, 2 * kPointerSize)); }
// Set up pointer to last argument. // Set up pointer to last argument.
__ Daddu(a2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); __ Daddu(a2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
// Set up number of arguments for function call below.
__ SmiUntag(a0, a3);
// Copy arguments and receiver to the expression stack. // Copy arguments and receiver to the expression stack.
// a0: number of arguments // a0: number of arguments
// a1: constructor function // a1: constructor function
...@@ -672,9 +679,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -672,9 +679,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// a3: number of arguments (smi-tagged) // a3: number of arguments (smi-tagged)
// sp[0]: receiver // sp[0]: receiver
// sp[1]: receiver // sp[1]: receiver
// sp[2]: number of arguments (smi-tagged) // sp[2]: new.target (if used)
// sp[2/3]: number of arguments (smi-tagged)
Label loop, entry; Label loop, entry;
__ SmiUntag(a3); __ mov(a3, a0);
__ jmp(&entry); __ jmp(&entry);
__ bind(&loop); __ bind(&loop);
__ dsll(a4, a3, kPointerSizeLog2); __ dsll(a4, a3, kPointerSizeLog2);
...@@ -699,7 +707,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -699,7 +707,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
} }
// Store offset of return address for deoptimizer. // Store offset of return address for deoptimizer.
if (!is_api_function) { // TODO(arv): Remove the "!use_new_target" before supporting optimization
// of functions that reference new.target
if (!is_api_function && !use_new_target) {
masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
} }
...@@ -714,7 +724,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -714,7 +724,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// If the result is a smi, it is *not* an object in the ECMA sense. // If the result is a smi, it is *not* an object in the ECMA sense.
// v0: result // v0: result
// sp[0]: receiver (newly allocated object) // sp[0]: receiver (newly allocated object)
// sp[1]: number of arguments (smi-tagged) // sp[1]: new.target (if used)
// sp[1/2]: number of arguments (smi-tagged)
__ JumpIfSmi(v0, &use_receiver); __ JumpIfSmi(v0, &use_receiver);
// If the type of the result (stored in its map) is less than // If the type of the result (stored in its map) is less than
...@@ -732,8 +743,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -732,8 +743,10 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&exit); __ bind(&exit);
// v0: result // v0: result
// sp[0]: receiver (newly allocated object) // sp[0]: receiver (newly allocated object)
// sp[1]: number of arguments (smi-tagged) // sp[1]: new.target (if used)
__ ld(a1, MemOperand(sp, kPointerSize)); // sp[1/2]: number of arguments (smi-tagged)
int offset = (use_new_target ? 2 : 1) * kPointerSize;
__ ld(a1, MemOperand(sp, offset));
// Leave construct frame. // Leave construct frame.
} }
...@@ -747,12 +760,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -747,12 +760,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new);
} }
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, true, false); Generate_JSConstructStubHelper(masm, true, false, false);
}
void Builtins::Generate_JSConstructStubNewTarget(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, true, FLAG_pretenuring_call_new);
} }
......
...@@ -319,24 +319,20 @@ void Scope::Initialize() { ...@@ -319,24 +319,20 @@ void Scope::Initialize() {
receiver_ = var; receiver_ = var;
} }
if (is_function_scope()) { if (is_function_scope() && !is_arrow_scope()) {
if (!is_arrow_scope()) { // Declare 'arguments' variable which exists in all non arrow functions.
// Declare 'arguments' variable which exists in all non arrow functions. // Note that it might never be accessed, in which case it won't be
// Note that it might never be accessed, in which case it won't be // allocated during variable allocation.
// allocated during variable allocation. variables_.Declare(this, ast_value_factory_->arguments_string(), VAR,
variables_.Declare(this, ast_value_factory_->arguments_string(), VAR, Variable::ARGUMENTS, kCreatedInitialized);
Variable::ARGUMENTS, kCreatedInitialized);
} if (subclass_constructor || FLAG_harmony_new_target) {
if (subclass_constructor) {
DCHECK(!is_arrow_scope());
variables_.Declare(this, ast_value_factory_->new_target_string(), CONST, variables_.Declare(this, ast_value_factory_->new_target_string(), CONST,
Variable::NORMAL, kCreatedInitialized); Variable::NORMAL, kCreatedInitialized);
} }
if (IsConciseMethod(function_kind_) || IsConstructor(function_kind_) || if (IsConciseMethod(function_kind_) || IsConstructor(function_kind_) ||
IsAccessorFunction(function_kind_)) { IsAccessorFunction(function_kind_)) {
DCHECK(!is_arrow_scope());
variables_.Declare(this, ast_value_factory_->this_function_string(), variables_.Declare(this, ast_value_factory_->this_function_string(),
CONST, Variable::NORMAL, kCreatedInitialized); CONST, Variable::NORMAL, kCreatedInitialized);
} }
......
...@@ -136,6 +136,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm, ...@@ -136,6 +136,7 @@ static void Generate_Runtime_NewObject(MacroAssembler* masm,
static void Generate_JSConstructStubHelper(MacroAssembler* masm, static void Generate_JSConstructStubHelper(MacroAssembler* masm,
bool is_api_function, bool is_api_function,
bool use_new_target,
bool create_memento) { bool create_memento) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax: number of arguments // -- rax: number of arguments
...@@ -156,12 +157,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -156,12 +157,13 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ Push(rbx); __ Push(rbx);
} }
// Store a smi-tagged arguments count on the stack. // Preserve the incoming parameters on the stack.
__ Integer32ToSmi(rax, rax); __ Integer32ToSmi(rax, rax);
__ Push(rax); __ Push(rax);
// Push the function to invoke on the stack.
__ Push(rdi); __ Push(rdi);
if (use_new_target) {
__ Push(rdx);
}
Label rt_call, normal_new, allocated, count_incremented; Label rt_call, normal_new, allocated, count_incremented;
__ cmpp(rdx, rdi); __ cmpp(rdx, rdi);
...@@ -388,7 +390,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -388,7 +390,8 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&allocated); __ bind(&allocated);
if (create_memento) { if (create_memento) {
__ movp(rcx, Operand(rsp, kPointerSize*2)); int offset = (use_new_target ? 3 : 2) * kPointerSize;
__ movp(rcx, Operand(rsp, offset));
__ Cmp(rcx, masm->isolate()->factory()->undefined_value()); __ Cmp(rcx, masm->isolate()->factory()->undefined_value());
__ j(equal, &count_incremented); __ j(equal, &count_incremented);
// rcx is an AllocationSite. We are creating a memento from it, so we // rcx is an AllocationSite. We are creating a memento from it, so we
...@@ -399,13 +402,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -399,13 +402,22 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&count_incremented); __ bind(&count_incremented);
} }
// Retrieve the function from the stack. // Restore the parameters.
if (use_new_target) {
__ Pop(rdx);
}
__ Pop(rdi); __ Pop(rdi);
// Retrieve smi-tagged arguments count from the stack. // Retrieve smi-tagged arguments count from the stack.
__ movp(rax, Operand(rsp, 0)); __ movp(rax, Operand(rsp, 0));
__ SmiToInteger32(rax, rax); __ SmiToInteger32(rax, rax);
// Push new.target onto the construct frame. This is stored just below the
// receiver on the stack.
if (use_new_target) {
__ Push(rdx);
}
// Push the allocated receiver to the stack. We need two copies // Push the allocated receiver to the stack. We need two copies
// because we may have to return the original one and the calling // because we may have to return the original one and the calling
// conventions dictate that the called function pops the receiver. // conventions dictate that the called function pops the receiver.
...@@ -437,7 +449,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -437,7 +449,9 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
} }
// Store offset of return address for deoptimizer. // Store offset of return address for deoptimizer.
if (!is_api_function) { // TODO(arv): Remove the "!use_new_target" before supporting optimization
// of functions that reference new.target
if (!is_api_function && !use_new_target) {
masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
} }
...@@ -462,9 +476,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -462,9 +476,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ bind(&use_receiver); __ bind(&use_receiver);
__ movp(rax, Operand(rsp, 0)); __ movp(rax, Operand(rsp, 0));
// Restore the arguments count and leave the construct frame. // Restore the arguments count and leave the construct frame. The arguments
// count is stored below the reciever and the new.target.
__ bind(&exit); __ bind(&exit);
__ movp(rbx, Operand(rsp, kPointerSize)); // Get arguments count. int offset = (use_new_target ? 2 : 1) * kPointerSize;
__ movp(rbx, Operand(rsp, offset));
// Leave construct frame. // Leave construct frame.
} }
...@@ -481,12 +497,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm, ...@@ -481,12 +497,17 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new);
} }
void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, true, false); Generate_JSConstructStubHelper(masm, true, false, false);
}
void Builtins::Generate_JSConstructStubNewTarget(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, true, FLAG_pretenuring_call_new);
} }
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-classes --harmony-new-target --harmony-reflect
// Flags: --harmony-rest-parameters --harmony-arrow-functions
(function TestClass() {
'use strict';
var calls = 0;
class Base {
constructor(_) {
assertEquals(Base, new.target);
calls++;
}
}
assertInstanceof(new Base(1), Base);
assertInstanceof(new Base(1, 2), Base);
assertInstanceof(new Base(), Base);
assertEquals(3, calls);
})();
(function TestDerivedClass() {
'use strict';
var calls = 0;
class Base {
constructor(expected) {
assertEquals(expected, new.target);
}
}
class Derived extends Base {
constructor(expected) {
super(expected);
assertEquals(expected, new.target);
calls++;
}
}
new Derived(Derived, 'extra');
new Derived(Derived);
assertEquals(2, calls);
class Derived2 extends Derived {}
calls = 0;
new Derived2(Derived2);
new Derived2(Derived2, 'extra');
assertEquals(2, calls);
})();
(function TestFunctionCall() {
var calls;
function f(expected) {
calls++;
assertEquals(expected, new.target);
}
calls = 0;
f(undefined);
f(undefined, 'extra');
f();
assertEquals(3, calls);
calls = 0;
f.call({}, undefined);
f.call({}, undefined, 'extra');
f.call({});
assertEquals(3, calls);
calls = 0;
f.apply({}, [undefined]);
f.apply({}, [undefined, 'extra']);
f.apply({}, []);
assertEquals(3, calls);
})();
(function TestFunctionConstruct() {
var calls;
function f(expected) {
calls++;
assertEquals(expected, new.target);
}
calls = 0;
new f(f);
new f(f, 'extra');
assertEquals(2, calls);
})();
(function TestClassExtendsFunction() {
'use strict';
var calls = 0;
function f(expected) {
assertEquals(expected, new.target);
}
class Derived extends f {
constructor(expected) {
super(expected);
assertEquals(expected, new.target);
calls++;
}
}
new Derived(Derived);
new Derived(Derived, 'extra');
assertEquals(2, calls);
})();
(function TestFunctionReturnObject() {
function f(expected) {
assertEquals(expected, new.target);
return /abc/;
}
assertInstanceof(new f(f), RegExp);
assertInstanceof(new f(f, 'extra'), RegExp);
assertInstanceof(f(undefined), RegExp);
assertInstanceof(f(), RegExp);
assertInstanceof(f(undefined, 'extra'), RegExp);
})();
(function TestClassReturnObject() {
'use strict';
class Base {
constructor(expected) {
assertEquals(expected, new.target);
return /abc/;
}
}
assertInstanceof(new Base(Base), RegExp);
assertInstanceof(new Base(Base, 'extra'), RegExp);
class Derived extends Base {}
assertInstanceof(new Derived(Derived), RegExp);
assertInstanceof(new Derived(Derived, 'extra'), RegExp);
class Derived2 extends Base {
constructor(expected) {
super(expected);
assertInstanceof(this, RegExp);
}
}
assertInstanceof(new Derived2(Derived2), RegExp);
assertInstanceof(new Derived2(Derived2, 'extra'), RegExp);
})();
/*
// TODO(arv): Reflect.construct does not work correctly with a third argument.
(function TestReflectConstruct() {
var calls = 0;
function f(expected) {
calls++;
assertEquals(expected, new.target);
}
var o = Reflect.construct(f, [f]);
assertEquals(Object.getPrototypeOf(o), f.prototype);
o = Reflect.construct(f, [f, 'extra']);
assertEquals(Object.getPrototypeOf(o), f.prototype);
assertEquals(2, calls);
calls = 0;
o = Reflect.construct(f, [f], f);
assertEquals(Object.getPrototypeOf(o), f.prototype);
o = Reflect.construct(f, [f, 'extra'], f);
assertEquals(Object.getPrototypeOf(o), f.prototype);
assertEquals(2, calls);
function g() {}
calls = 0;
o = Reflect.construct(f, [g], g);
assertEquals(Object.getPrototypeOf(o), g.prototype);
o = Reflect.construct(f, [g, 'extra'], g);
assertEquals(Object.getPrototypeOf(o), g.prototype);
assertEquals(2, calls);
})();
*/
(function TestRestParametersFunction() {
function f(...rest) {
assertEquals(rest[0], new.target);
}
assertInstanceof(new f(f), f);
assertInstanceof(new f(f, 'extra'), f);
})();
(function TestRestParametersClass() {
'use strict';
class Base {
constructor(...rest) {
assertEquals(rest[0], new.target);
}
}
assertInstanceof(new Base(Base), Base);
assertInstanceof(new Base(Base, 'extra'), Base);
class Derived extends Base {}
assertInstanceof(new Derived(Derived), Derived);
assertInstanceof(new Derived(Derived, 'extra'), Derived);
})();
(function TestArrowFunction() {
function f(expected) {
(() => {
assertEquals(expected, new.target);
})();
}
assertInstanceof(new f(f), f);
assertInstanceof(new f(f, 'extra'), f);
})();
(function TestRestParametersClass() {
'use strict';
class Base {
constructor(expected) {
(() => {
assertEquals(expected, new.target);
})();
}
}
assertInstanceof(new Base(Base), Base);
assertInstanceof(new Base(Base, 'extra'), Base);
class Derived extends Base {}
assertInstanceof(new Derived(Derived), Derived);
assertInstanceof(new Derived(Derived, 'extra'), Derived);
})();
(function TestSloppyArguments() {
var length, a0, a1, a2, nt;
function f(x) {
assertEquals(length, arguments.length);
assertEquals(a0, arguments[0]);
assertEquals(a1, arguments[1]);
assertEquals(a2, arguments[2]);
assertEquals(nt, new.target);
if (length > 0) {
x = 42;
assertEquals(42, x);
assertEquals(42, arguments[0]);
arguments[0] = 33;
assertEquals(33, x);
assertEquals(33, arguments[0]);
}
}
nt = f;
length = 0;
new f();
length = 1;
a0 = 1;
new f(1);
length = 2;
a0 = 1;
a1 = 2;
new f(1, 2);
length = 3;
a0 = 1;
a1 = 2;
a2 = 3;
new f(1, 2, 3);
nt = undefined;
a0 = a1 = a2 = undefined;
length = 0;
f();
length = 1;
a0 = 1;
f(1);
length = 2;
a0 = 1;
a1 = 2;
f(1, 2);
length = 3;
a0 = 1;
a1 = 2;
a2 = 3;
f(1, 2, 3);
})();
(function TestStrictArguments() {
var length, a0, a1, a2, nt;
function f(x) {
'use strict';
assertEquals(length, arguments.length);
assertEquals(a0, arguments[0]);
assertEquals(a1, arguments[1]);
assertEquals(a2, arguments[2]);
assertEquals(nt, new.target);
if (length > 0) {
x = 42;
assertEquals(a0, arguments[0]);
arguments[0] = 33;
assertEquals(33, arguments[0]);
}
}
nt = f;
length = 0;
new f();
length = 1;
a0 = 1;
new f(1);
length = 2;
a0 = 1;
a1 = 2;
new f(1, 2);
length = 3;
a0 = 1;
a1 = 2;
a2 = 3;
new f(1, 2, 3);
nt = undefined;
a0 = a1 = a2 = undefined;
length = 0;
f();
length = 1;
a0 = 1;
f(1);
length = 2;
a0 = 1;
a1 = 2;
f(1, 2);
length = 3;
a0 = 1;
a1 = 2;
a2 = 3;
f(1, 2, 3);
})();
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