Reland: [ignition] Add call bytecodes for undefined receiver

Adds a collection of call bytecodes which have an implicit undefined
receiver argument, for cases such as global calls where we know that the
receiver has to be undefined. This way we can skip an LdaUndefined,
decrease bytecode register pressure, and set a more accurate
ConvertReceiverMode on the interpreter and TurboFan call.

As a side effect, the "normal" Call bytecode now becomes a rare case
(only with calls and super property calls), so we get rid of its 0-2
argument special cases and modify CallProperty[N] to use the
NotNullOrUndefined ConvertReceiverMode.

Reland of https://chromium-review.googlesource.com/c/463287 after fixing
tests in https://codereview.chromium.org/2813873002.

Change-Id: I314d69c7643ceec6a5750ffdab60dad38dad09e5
Reviewed-on: https://chromium-review.googlesource.com/474752
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44582}
This commit is contained in:
Leszek Swirski 2017-04-11 15:20:30 +01:00 committed by Commit Bot
parent 2e4a687338
commit 57afd0bb07
51 changed files with 986 additions and 732 deletions

View File

@ -324,7 +324,7 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
r0, // argument count (not including receiver)
@ -334,7 +334,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
r0, // argument count (not including receiver)
@ -346,8 +346,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
Register registers[] = {
r0, // argument count (not including receiver)
r1, // target to call checked to be Array function

View File

@ -353,7 +353,7 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
x0, // argument count (not including receiver)
@ -363,7 +363,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
x0, // argument count (not including receiver)
@ -375,8 +375,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
Register registers[] = {
x0, // argument count (not including receiver)
x1, // target to call checked to be Array function

View File

@ -1082,11 +1082,7 @@ static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register limit, Register scratch,
Label* stack_overflow) {
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, num_args, scratch, stack_overflow);
Register limit, Register scratch) {
// Find the address of the last argument.
__ mov(limit, num_args);
__ mov(limit, Operand(limit, LSL, kPointerSizeLog2));
@ -1103,9 +1099,9 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r2 : the address of the first argument to be pushed. Subsequent
@ -1117,8 +1113,16 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ add(r3, r0, Operand(1)); // Add one for receiver.
Generate_StackOverflowCheck(masm, r3, r4, &stack_overflow);
// Push "undefined" as the receiver arg if we need to.
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
__ mov(r3, r0); // Argument count is correct.
}
// Push the arguments. r2, r4, r5 will be modified.
Generate_InterpreterPushArgs(masm, r3, r2, r4, r5, &stack_overflow);
Generate_InterpreterPushArgs(masm, r3, r2, r4, r5);
// Call the target.
if (mode == InterpreterPushArgsMode::kJSFunction) {
@ -1143,7 +1147,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- r0 : argument count (not including receiver)
@ -1158,8 +1162,10 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
__ mov(ip, Operand::Zero());
__ push(ip);
Generate_StackOverflowCheck(masm, r0, r5, &stack_overflow);
// Push the arguments. r5, r4, r6 will be modified.
Generate_InterpreterPushArgs(masm, r0, r4, r5, r6, &stack_overflow);
Generate_InterpreterPushArgs(masm, r0, r4, r5, r6);
__ AssertUndefinedOrAllocationSite(r2, r5);
if (mode == InterpreterPushArgsMode::kJSFunction) {
@ -1190,7 +1196,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
void Builtins::Generate_InterpreterPushArgsThenConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : argument count (not including receiver)
@ -1200,11 +1206,14 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// -----------------------------------
Label stack_overflow;
__ add(r4, r0, Operand(1)); // Add one for receiver.
// Push a slot for the receiver to be constructed.
__ mov(ip, Operand::Zero());
__ push(ip);
Generate_StackOverflowCheck(masm, r0, r5, &stack_overflow);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments. r3, r5, r6 will be modified.
Generate_InterpreterPushArgs(masm, r4, r3, r5, r6, &stack_overflow);
Generate_InterpreterPushArgs(masm, r0, r3, r5, r6);
// Array constructor expects constructor in r3. It is same as r1 here.
__ mov(r3, r1);

View File

@ -1100,11 +1100,7 @@ static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register last_arg, Register stack_addr,
Register scratch,
Label* stack_overflow) {
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, num_args, scratch, stack_overflow);
Register scratch) {
__ Mov(scratch, num_args);
__ lsl(scratch, scratch, kPointerSizeLog2);
__ sub(last_arg, index, scratch);
@ -1126,9 +1122,9 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x2 : the address of the first argument to be pushed. Subsequent
@ -1141,8 +1137,17 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Add one for the receiver.
__ add(x3, x0, Operand(1));
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, x3, x6, &stack_overflow);
// Push "undefined" as the receiver arg if we need to.
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
__ Mov(x3, x0); // Argument count is correct.
}
// Push the arguments. x2, x4, x5, x6 will be modified.
Generate_InterpreterPushArgs(masm, x3, x2, x4, x5, x6, &stack_overflow);
Generate_InterpreterPushArgs(masm, x3, x2, x4, x5, x6);
// Call the target.
if (mode == InterpreterPushArgsMode::kJSFunction) {
@ -1166,7 +1171,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- x0 : argument count (not including receiver)
@ -1180,8 +1185,11 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Push a slot for the receiver.
__ Push(xzr);
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, x0, x7, &stack_overflow);
// Push the arguments. x5, x4, x6, x7 will be modified.
Generate_InterpreterPushArgs(masm, x0, x4, x5, x6, x7, &stack_overflow);
Generate_InterpreterPushArgs(masm, x0, x4, x5, x6, x7);
__ AssertUndefinedOrAllocationSite(x2, x6);
if (mode == InterpreterPushArgsMode::kJSFunction) {
@ -1211,7 +1219,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
void Builtins::Generate_InterpreterPushArgsThenConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : argument count (not including receiver)
@ -1221,10 +1229,14 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// -----------------------------------
Label stack_overflow;
__ add(x4, x0, Operand(1)); // Add one for the receiver.
// Push a slot for the receiver.
__ Push(xzr);
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, x0, x7, &stack_overflow);
// Push the arguments. x3, x5, x6, x7 will be modified.
Generate_InterpreterPushArgs(masm, x4, x3, x5, x6, x7, &stack_overflow);
Generate_InterpreterPushArgs(masm, x0, x3, x5, x6, x7);
// Array constructor expects constructor in x3. It is same as call target.
__ mov(x3, x1);

View File

@ -133,15 +133,17 @@ namespace internal {
\
/* Interpreter */ \
ASM(InterpreterEntryTrampoline) \
ASM(InterpreterPushArgsAndCall) \
ASM(InterpreterPushArgsAndCallFunction) \
ASM(InterpreterPushArgsAndCallWithFinalSpread) \
ASM(InterpreterPushArgsAndTailCall) \
ASM(InterpreterPushArgsAndTailCallFunction) \
ASM(InterpreterPushArgsAndConstruct) \
ASM(InterpreterPushArgsAndConstructFunction) \
ASM(InterpreterPushArgsAndConstructArray) \
ASM(InterpreterPushArgsAndConstructWithFinalSpread) \
ASM(InterpreterPushArgsThenCall) \
ASM(InterpreterPushUndefinedAndArgsThenCall) \
ASM(InterpreterPushArgsThenCallFunction) \
ASM(InterpreterPushUndefinedAndArgsThenCallFunction) \
ASM(InterpreterPushArgsThenCallWithFinalSpread) \
ASM(InterpreterPushArgsThenTailCall) \
ASM(InterpreterPushArgsThenTailCallFunction) \
ASM(InterpreterPushArgsThenConstruct) \
ASM(InterpreterPushArgsThenConstructFunction) \
ASM(InterpreterPushArgsThenConstructArray) \
ASM(InterpreterPushArgsThenConstructWithFinalSpread) \
ASM(InterpreterEnterBytecodeAdvance) \
ASM(InterpreterEnterBytecodeDispatch) \
ASM(InterpreterOnStackReplacement) \

View File

@ -9,48 +9,67 @@
namespace v8 {
namespace internal {
void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kDisallow, InterpreterPushArgsMode::kOther);
void Builtins::Generate_InterpreterPushArgsThenCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kDisallow,
InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsAndCallFunction(
void Builtins::Generate_InterpreterPushArgsThenCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kDisallow, InterpreterPushArgsMode::kJSFunction);
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kDisallow,
InterpreterPushArgsMode::kJSFunction);
}
void Builtins::Generate_InterpreterPushArgsAndCallWithFinalSpread(
void Builtins::Generate_InterpreterPushUndefinedAndArgsThenCall(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kDisallow, InterpreterPushArgsMode::kWithFinalSpread);
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kNullOrUndefined, TailCallMode::kDisallow,
InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsAndTailCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kAllow, InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsAndTailCallFunction(
void Builtins::Generate_InterpreterPushUndefinedAndArgsThenCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kAllow, InterpreterPushArgsMode::kJSFunction);
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kNullOrUndefined, TailCallMode::kDisallow,
InterpreterPushArgsMode::kJSFunction);
}
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenCallWithFinalSpread(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kDisallow,
InterpreterPushArgsMode::kWithFinalSpread);
}
void Builtins::Generate_InterpreterPushArgsThenTailCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kAllow,
InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsThenTailCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenCallImpl(
masm, ConvertReceiverMode::kAny, TailCallMode::kAllow,
InterpreterPushArgsMode::kJSFunction);
}
void Builtins::Generate_InterpreterPushArgsThenConstruct(MacroAssembler* masm) {
return Generate_InterpreterPushArgsThenConstructImpl(
masm, InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsAndConstructWithFinalSpread(
void Builtins::Generate_InterpreterPushArgsThenConstructWithFinalSpread(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(
return Generate_InterpreterPushArgsThenConstructImpl(
masm, InterpreterPushArgsMode::kWithFinalSpread);
}
void Builtins::Generate_InterpreterPushArgsAndConstructFunction(
void Builtins::Generate_InterpreterPushArgsThenConstructFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(
return Generate_InterpreterPushArgsThenConstructImpl(
masm, InterpreterPushArgsMode::kJSFunction);
}

View File

@ -11,38 +11,53 @@
namespace v8 {
namespace internal {
Handle<Code> Builtins::InterpreterPushArgsAndCall(
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
Handle<Code> Builtins::InterpreterPushArgsThenCall(
ConvertReceiverMode receiver_mode, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
switch (mode) {
case InterpreterPushArgsMode::kJSFunction:
if (tail_call_mode == TailCallMode::kDisallow) {
return InterpreterPushArgsAndCallFunction();
switch (receiver_mode) {
case ConvertReceiverMode::kNullOrUndefined:
return InterpreterPushUndefinedAndArgsThenCallFunction();
case ConvertReceiverMode::kNotNullOrUndefined:
case ConvertReceiverMode::kAny:
return InterpreterPushArgsThenCallFunction();
}
} else {
return InterpreterPushArgsAndTailCallFunction();
CHECK_EQ(receiver_mode, ConvertReceiverMode::kAny);
return InterpreterPushArgsThenTailCallFunction();
}
case InterpreterPushArgsMode::kWithFinalSpread:
CHECK(tail_call_mode == TailCallMode::kDisallow);
return InterpreterPushArgsAndCallWithFinalSpread();
return InterpreterPushArgsThenCallWithFinalSpread();
case InterpreterPushArgsMode::kOther:
if (tail_call_mode == TailCallMode::kDisallow) {
return InterpreterPushArgsAndCall();
switch (receiver_mode) {
case ConvertReceiverMode::kNullOrUndefined:
return InterpreterPushUndefinedAndArgsThenCall();
case ConvertReceiverMode::kNotNullOrUndefined:
case ConvertReceiverMode::kAny:
return InterpreterPushArgsThenCall();
}
} else {
return InterpreterPushArgsAndTailCall();
CHECK_EQ(receiver_mode, ConvertReceiverMode::kAny);
return InterpreterPushArgsThenTailCall();
}
}
UNREACHABLE();
return Handle<Code>::null();
}
Handle<Code> Builtins::InterpreterPushArgsAndConstruct(
Handle<Code> Builtins::InterpreterPushArgsThenConstruct(
InterpreterPushArgsMode mode) {
switch (mode) {
case InterpreterPushArgsMode::kJSFunction:
return InterpreterPushArgsAndConstructFunction();
return InterpreterPushArgsThenConstructFunction();
case InterpreterPushArgsMode::kWithFinalSpread:
return InterpreterPushArgsAndConstructWithFinalSpread();
return InterpreterPushArgsThenConstructWithFinalSpread();
case InterpreterPushArgsMode::kOther:
return InterpreterPushArgsAndConstruct();
return InterpreterPushArgsThenConstruct();
}
UNREACHABLE();
return Handle<Code>::null();

View File

@ -58,9 +58,10 @@ class Builtins {
Handle<Code> NonPrimitiveToPrimitive(
ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
Handle<Code> OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint);
Handle<Code> InterpreterPushArgsAndCall(TailCallMode tail_call_mode,
InterpreterPushArgsMode mode);
Handle<Code> InterpreterPushArgsAndConstruct(InterpreterPushArgsMode mode);
Handle<Code> InterpreterPushArgsThenCall(ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode,
InterpreterPushArgsMode mode);
Handle<Code> InterpreterPushArgsThenConstruct(InterpreterPushArgsMode mode);
Handle<Code> NewFunctionContext(ScopeType scope_type);
Handle<Code> NewCloneShallowArray(AllocationSiteMode allocation_mode);
Handle<Code> NewCloneShallowObject(int length);
@ -122,11 +123,11 @@ class Builtins {
static void Generate_CallForwardVarargs(MacroAssembler* masm,
Handle<Code> code);
static void Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode);
static void Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode);
static void Generate_InterpreterPushArgsAndConstructImpl(
static void Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode);
#define DECLARE_ASM(Name, ...) \

View File

@ -751,9 +751,9 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- ebx : the address of the first argument to be pushed. Subsequent
@ -776,6 +776,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Pop return address to allow tail-call after pushing arguments.
__ Pop(edx);
// Push "undefined" as the receiver arg if we need to.
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
__ sub(ecx, Immediate(1)); // Subtract one for receiver.
}
// Find the address of the last argument.
__ shl(ecx, kPointerSizeLog2);
__ neg(ecx);
@ -815,10 +821,10 @@ namespace {
// This function modified start_addr, and only reads the contents of num_args
// register. scratch1 and scratch2 are used as temporary registers. Their
// original values are restored after the use.
void Generate_InterpreterPushArgsAndReturnAddress(
void Generate_InterpreterPushZeroAndArgsAndReturnAddress(
MacroAssembler* masm, Register num_args, Register start_addr,
Register scratch1, Register scratch2, bool receiver_in_args,
int num_slots_above_ret_addr, Label* stack_overflow) {
Register scratch1, Register scratch2, int num_slots_above_ret_addr,
Label* stack_overflow) {
// We have to move return address and the temporary registers above it
// before we can copy arguments onto the stack. To achieve this:
// Step 1: Increment the stack pointer by num_args + 1 (for receiver).
@ -831,7 +837,7 @@ void Generate_InterpreterPushArgsAndReturnAddress(
// | | | return addr | (2)
// | | | arg N | (3)
// | scratch1 | <-- esp | .... |
// | .... | | arg 0 |
// | .... | | arg 1 |
// | scratch-n | | arg 0 |
// | return addr | | receiver slot |
@ -875,17 +881,12 @@ void Generate_InterpreterPushArgsAndReturnAddress(
}
// Step 3 copy arguments to correct locations.
if (receiver_in_args) {
__ mov(scratch1, num_args);
__ add(scratch1, Immediate(1));
} else {
// Slot meant for receiver contains return address. Reset it so that
// we will not incorrectly interpret return address as an object.
__ mov(Operand(esp, num_args, times_pointer_size,
(num_slots_above_ret_addr + 1) * kPointerSize),
Immediate(0));
__ mov(scratch1, num_args);
}
// Slot meant for receiver contains return address. Reset it so that
// we will not incorrectly interpret return address as an object.
__ mov(Operand(esp, num_args, times_pointer_size,
(num_slots_above_ret_addr + 1) * kPointerSize),
Immediate(0));
__ mov(scratch1, num_args);
Label loop_header, loop_check;
__ jmp(&loop_check);
@ -904,7 +905,7 @@ void Generate_InterpreterPushArgsAndReturnAddress(
} // end anonymous namespace
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
@ -923,8 +924,8 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Push arguments and move return address to the top of stack.
// The eax register is readonly. The ecx register will be modified. The edx
// and edi registers will be modified but restored to their original values.
Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false,
2, &stack_overflow);
Generate_InterpreterPushZeroAndArgsAndReturnAddress(masm, eax, ecx, edx, edi,
2, &stack_overflow);
// Restore edi and edx
__ Pop(edx);
@ -964,7 +965,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
void Builtins::Generate_InterpreterPushArgsThenConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
@ -982,8 +983,8 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// Push arguments and move return address to the top of stack.
// The eax register is readonly. The ecx register will be modified. The edx
// and edi registers will be modified but restored to their original values.
Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, true,
1, &stack_overflow);
Generate_InterpreterPushZeroAndArgsAndReturnAddress(masm, eax, ecx, edx, edi,
1, &stack_overflow);
// Restore edx.
__ Pop(edx);

View File

@ -1077,11 +1077,7 @@ static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register scratch, Register scratch2,
Label* stack_overflow) {
Generate_StackOverflowCheck(masm, num_args, scratch, scratch2,
stack_overflow);
Register scratch, Register scratch2) {
// Find the address of the last argument.
__ mov(scratch2, num_args);
__ sll(scratch2, scratch2, kPointerSizeLog2);
@ -1099,9 +1095,9 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a2 : the address of the first argument to be pushed. Subsequent
@ -1113,8 +1109,16 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ Addu(t0, a0, Operand(1)); // Add one for receiver.
Generate_StackOverflowCheck(masm, t0, t4, t1, &stack_overflow);
// Push "undefined" as the receiver arg if we need to.
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
__ mov(t0, a0); // No receiver.
}
// This function modifies a2, t4 and t1.
Generate_InterpreterPushArgs(masm, t0, a2, t4, t1, &stack_overflow);
Generate_InterpreterPushArgs(masm, t0, a2, t4, t1);
// Call the target.
if (mode == InterpreterPushArgsMode::kJSFunction) {
@ -1139,7 +1143,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- a0 : argument count (not including receiver)
@ -1153,8 +1157,10 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Push a slot for the receiver.
__ push(zero_reg);
Generate_StackOverflowCheck(masm, a0, t1, t0, &stack_overflow);
// This function modified t4, t1 and t0.
Generate_InterpreterPushArgs(masm, a0, t4, t1, t0, &stack_overflow);
Generate_InterpreterPushArgs(masm, a0, t4, t1, t0);
__ AssertUndefinedOrAllocationSite(a2, t0);
if (mode == InterpreterPushArgsMode::kJSFunction) {
@ -1185,7 +1191,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
void Builtins::Generate_InterpreterPushArgsThenConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
@ -1197,10 +1203,13 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// -----------------------------------
Label stack_overflow;
__ Addu(t0, a0, Operand(1)); // Add one for receiver.
// Push a slot for the receiver.
__ push(zero_reg);
// This function modifies a3, t4, and t1.
Generate_InterpreterPushArgs(masm, t0, a3, t1, t4, &stack_overflow);
Generate_StackOverflowCheck(masm, a0, t1, t4, &stack_overflow);
// This function modifies a3, t1, and t4.
Generate_InterpreterPushArgs(masm, a0, a3, t1, t4);
// ArrayConstructor stub expects constructor in a3. Set it here.
__ mov(a3, a1);

View File

@ -1070,11 +1070,7 @@ static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args,
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register scratch, Register scratch2,
Label* stack_overflow) {
// Generate_StackOverflowCheck(masm, num_args, scratch, scratch2,
// stack_overflow);
Register scratch, Register scratch2) {
// Find the address of the last argument.
__ mov(scratch2, num_args);
__ dsll(scratch2, scratch2, kPointerSizeLog2);
@ -1092,9 +1088,9 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a2 : the address of the first argument to be pushed. Subsequent
@ -1106,8 +1102,16 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ Daddu(a3, a0, Operand(1)); // Add one for receiver.
// Push "undefined" as the receiver arg if we need to.
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
__ Dsubu(a3, a3, Operand(1)); // Subtract one for receiver.
}
Generate_StackOverflowCheck(masm, a3, a4, t0, &stack_overflow);
// This function modifies a2, t0 and a4.
Generate_InterpreterPushArgs(masm, a3, a2, a4, t0, &stack_overflow);
Generate_InterpreterPushArgs(masm, a3, a2, a4, t0);
// Call the target.
if (mode == InterpreterPushArgsMode::kJSFunction) {
@ -1132,7 +1136,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- a0 : argument count (not including receiver)
@ -1146,8 +1150,10 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Push a slot for the receiver.
__ push(zero_reg);
Generate_StackOverflowCheck(masm, a0, a5, t0, &stack_overflow);
// This function modifies t0, a4 and a5.
Generate_InterpreterPushArgs(masm, a0, a4, a5, t0, &stack_overflow);
Generate_InterpreterPushArgs(masm, a0, a4, a5, t0);
__ AssertUndefinedOrAllocationSite(a2, t0);
if (mode == InterpreterPushArgsMode::kJSFunction) {
@ -1178,7 +1184,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
void Builtins::Generate_InterpreterPushArgsThenConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
@ -1190,10 +1196,13 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// -----------------------------------
Label stack_overflow;
__ Daddu(a4, a0, Operand(1)); // Add one for receiver.
// Push a slot for the receiver.
__ push(zero_reg);
Generate_StackOverflowCheck(masm, a4, a5, a6, &stack_overflow);
// This function modifies a3, a5 and a6.
Generate_InterpreterPushArgs(masm, a4, a3, a5, a6, &stack_overflow);
Generate_InterpreterPushArgs(masm, a4, a3, a5, a6);
// ArrayConstructor stub expects constructor in a3. Set it here.
__ mov(a3, a1);

View File

@ -1112,7 +1112,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
@ -1153,7 +1153,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- r3 : argument count (not including receiver)
@ -1206,7 +1206,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
void Builtins::Generate_InterpreterPushArgsThenConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r3 : argument count (not including receiver)

View File

@ -1118,7 +1118,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
@ -1159,7 +1159,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- r2 : argument count (not including receiver)
@ -1211,7 +1211,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
void Builtins::Generate_InterpreterPushArgsThenConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r2 : argument count (not including receiver)

View File

@ -823,9 +823,9 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rbx : the address of the first argument to be pushed. Subsequent
@ -845,6 +845,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister);
// Push "undefined" as the receiver arg if we need to.
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
__ PushRoot(Heap::kUndefinedValueRootIndex);
__ subp(rcx, Immediate(1)); // Subtract one for receiver.
}
// rbx and rdx will be modified.
Generate_InterpreterPushArgs(masm, rcx, rbx, rdx);
@ -852,15 +858,14 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ PushReturnAddressFrom(kScratchRegister); // Re-push return address.
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
__ Jump(masm->isolate()->builtins()->CallFunction(receiver_mode,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
__ Jump(masm->isolate()->builtins()->CallWithSpread(),
RelocInfo::CODE_TARGET);
} else {
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
__ Jump(masm->isolate()->builtins()->Call(receiver_mode, tail_call_mode),
RelocInfo::CODE_TARGET);
}
@ -874,7 +879,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
@ -934,7 +939,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
void Builtins::Generate_InterpreterPushArgsThenConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
@ -948,7 +953,6 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// Number of values to be pushed.
__ Move(r8, rax);
__ addp(r8, Immediate(1)); // Add one for receiver.
// Add a stack check before pushing arguments.
Generate_StackOverflowCheck(masm, r8, rdi, &stack_overflow);
@ -956,6 +960,9 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister);
// Push slot for the receiver to be constructed.
__ Push(Immediate(0));
// rcx and rdi will be modified.
Generate_InterpreterPushArgs(masm, r8, rcx, rdi);

View File

@ -694,7 +694,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
void Builtins::Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
@ -758,7 +758,7 @@ namespace {
// This function modified start_addr, and only reads the contents of num_args
// register. scratch1 and scratch2 are used as temporary registers. Their
// original values are restored after the use.
void Generate_InterpreterPushArgsAndReturnAddress(
void Generate_InterpreterPushArgsThenReturnAddress(
MacroAssembler* masm, Register num_args, Register start_addr,
Register scratch1, Register scratch2, bool receiver_in_args,
int num_slots_above_ret_addr, Label* stack_overflow) {
@ -847,7 +847,7 @@ void Generate_InterpreterPushArgsAndReturnAddress(
} // end anonymous namespace
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
@ -866,8 +866,8 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Push arguments and move return address to the top of stack.
// The eax register is readonly. The ecx register will be modified. The edx
// and edi registers will be modified but restored to their original values.
Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false,
2, &stack_overflow);
Generate_InterpreterPushArgsThenReturnAddress(masm, eax, ecx, edx, edi, false,
2, &stack_overflow);
// Restore edi and edx
__ Pop(edx);
@ -907,7 +907,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
void Builtins::Generate_InterpreterPushArgsThenConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
@ -925,8 +925,8 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray(
// Push arguments and move return address to the top of stack.
// The eax register is readonly. The ecx register will be modified. The edx
// and edi registers will be modified but restored to their original values.
Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, true,
1, &stack_overflow);
Generate_InterpreterPushArgsThenReturnAddress(masm, eax, ecx, edx, edi, true,
1, &stack_overflow);
// Restore edx.
__ Pop(edx);

View File

@ -464,25 +464,25 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) {
}
// static
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode,
InterpreterPushArgsMode mode) {
return Callable(
isolate->builtins()->InterpreterPushArgsAndCall(tail_call_mode, mode),
InterpreterPushArgsAndCallDescriptor(isolate));
Callable CodeFactory::InterpreterPushArgsThenCall(
Isolate* isolate, ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
return Callable(isolate->builtins()->InterpreterPushArgsThenCall(
receiver_mode, tail_call_mode, mode),
InterpreterPushArgsThenCallDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterPushArgsAndConstruct(
Callable CodeFactory::InterpreterPushArgsThenConstruct(
Isolate* isolate, InterpreterPushArgsMode mode) {
return Callable(isolate->builtins()->InterpreterPushArgsAndConstruct(mode),
InterpreterPushArgsAndConstructDescriptor(isolate));
return Callable(isolate->builtins()->InterpreterPushArgsThenConstruct(mode),
InterpreterPushArgsThenConstructDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterPushArgsAndConstructArray(Isolate* isolate) {
return Callable(isolate->builtins()->InterpreterPushArgsAndConstructArray(),
InterpreterPushArgsAndConstructArrayDescriptor(isolate));
Callable CodeFactory::InterpreterPushArgsThenConstructArray(Isolate* isolate) {
return Callable(isolate->builtins()->InterpreterPushArgsThenConstructArray(),
InterpreterPushArgsThenConstructArrayDescriptor(isolate));
}
// static

View File

@ -173,12 +173,13 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable HasProperty(Isolate* isolate);
static Callable ForInFilter(Isolate* isolate);
static Callable InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode,
InterpreterPushArgsMode mode);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate,
InterpreterPushArgsMode mode);
static Callable InterpreterPushArgsAndConstructArray(Isolate* isolate);
static Callable InterpreterPushArgsThenCall(Isolate* isolate,
ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode,
InterpreterPushArgsMode mode);
static Callable InterpreterPushArgsThenConstruct(
Isolate* isolate, InterpreterPushArgsMode mode);
static Callable InterpreterPushArgsThenConstructArray(Isolate* isolate);
static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1);
static Callable InterpreterOnStackReplacement(Isolate* isolate);

View File

@ -1342,37 +1342,55 @@ void BytecodeGraphBuilder::VisitCreateObjectLiteral() {
}
Node* const* BytecodeGraphBuilder::GetCallArgumentsFromRegister(
Node* callee, interpreter::Register receiver, size_t arity) {
Node** all = local_zone()->NewArray<Node*>(static_cast<int>(arity));
Node* callee, Node* receiver, interpreter::Register first_arg,
int arg_count) {
// The arity of the Call node -- includes the callee, receiver and function
// arguments.
int arity = 2 + arg_count;
Node** all = local_zone()->NewArray<Node*>(static_cast<size_t>(arity));
all[0] = callee;
all[1] = environment()->LookupRegister(receiver);
int receiver_index = receiver.index();
for (int i = 2; i < static_cast<int>(arity); ++i) {
all[i] = environment()->LookupRegister(
interpreter::Register(receiver_index + i - 1));
all[1] = receiver;
// The function arguments are in consecutive registers.
int arg_base = first_arg.index();
for (int i = 0; i < arg_count; ++i) {
all[2 + i] =
environment()->LookupRegister(interpreter::Register(arg_base + i));
}
return all;
}
Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
Node* const* args,
size_t arg_count) {
return MakeNode(call_op, static_cast<int>(arg_count), args, false);
int arg_count) {
return MakeNode(call_op, arg_count, args, false);
}
Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
Node* callee,
interpreter::Register receiver,
size_t arg_count) {
return ProcessCallArguments(
call_op, GetCallArgumentsFromRegister(callee, receiver, arg_count),
arg_count);
size_t reg_count) {
Node* receiver_node = environment()->LookupRegister(receiver);
// The receiver is followed by the arguments in the consecutive registers.
DCHECK_GE(reg_count, 1);
interpreter::Register first_arg = interpreter::Register(receiver.index() + 1);
int arg_count = static_cast<int>(reg_count) - 1;
Node* const* call_args =
GetCallArgumentsFromRegister(callee, receiver_node, first_arg, arg_count);
return ProcessCallArguments(call_op, call_args, 2 + arg_count);
}
void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_hint,
ConvertReceiverMode receiver_mode,
Node* const* args, size_t arg_count,
int slot_id) {
DCHECK_EQ(interpreter::Bytecodes::GetReceiverMode(
bytecode_iterator().current_bytecode()),
receiver_mode);
PrepareEagerCheckpoint();
// Slot index of 0 is used indicate no feedback slot is available. Assert
@ -1382,63 +1400,51 @@ void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode,
float const frequency = ComputeCallFrequency(slot_id);
const Operator* call = javascript()->Call(arg_count, frequency, feedback,
receiver_hint, tail_call_mode);
Node* value = ProcessCallArguments(call, args, arg_count);
receiver_mode, tail_call_mode);
Node* value = ProcessCallArguments(call, args, static_cast<int>(arg_count));
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::BuildCallVarArgs(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_hint) {
ConvertReceiverMode receiver_mode) {
DCHECK_EQ(interpreter::Bytecodes::GetReceiverMode(
bytecode_iterator().current_bytecode()),
receiver_mode);
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
int const slot_id = bytecode_iterator().GetIndexOperand(3);
BuildCall(tail_call_mode, receiver_hint,
GetCallArgumentsFromRegister(callee, receiver, arg_count + 1),
arg_count + 1, slot_id);
Node* receiver_node;
interpreter::Register first_arg;
int arg_count;
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
// The receiver is implicit (and undefined), the arguments are in
// consecutive registers.
receiver_node = jsgraph()->UndefinedConstant();
first_arg = first_reg;
arg_count = static_cast<int>(reg_count);
} else {
// The receiver is the first register, followed by the arguments in the
// consecutive registers.
DCHECK_GE(reg_count, 1);
receiver_node = environment()->LookupRegister(first_reg);
first_arg = interpreter::Register(first_reg.index() + 1);
arg_count = static_cast<int>(reg_count) - 1;
}
Node* const* call_args =
GetCallArgumentsFromRegister(callee, receiver_node, first_arg, arg_count);
BuildCall(tail_call_mode, receiver_mode, call_args,
static_cast<size_t>(2 + arg_count), slot_id);
}
void BytecodeGraphBuilder::VisitCall() {
void BytecodeGraphBuilder::VisitCallAnyReceiver() {
BuildCallVarArgs(TailCallMode::kDisallow, ConvertReceiverMode::kAny);
}
void BytecodeGraphBuilder::VisitCall0() {
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* receiver =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
int const slot_id = bytecode_iterator().GetIndexOperand(2);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kAny,
{callee, receiver}, slot_id);
}
void BytecodeGraphBuilder::VisitCall1() {
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* receiver =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
Node* arg0 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(2));
int const slot_id = bytecode_iterator().GetIndexOperand(3);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kAny,
{callee, receiver, arg0}, slot_id);
}
void BytecodeGraphBuilder::VisitCall2() {
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* receiver =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
Node* arg0 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(2));
Node* arg1 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(3));
int const slot_id = bytecode_iterator().GetIndexOperand(4);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kAny,
{callee, receiver, arg0, arg1}, slot_id);
}
void BytecodeGraphBuilder::VisitCallProperty() {
BuildCallVarArgs(TailCallMode::kDisallow,
ConvertReceiverMode::kNotNullOrUndefined);
@ -1480,16 +1486,54 @@ void BytecodeGraphBuilder::VisitCallProperty2() {
{callee, receiver, arg0, arg1}, slot_id);
}
void BytecodeGraphBuilder::VisitCallUndefinedReceiver() {
BuildCallVarArgs(TailCallMode::kDisallow,
ConvertReceiverMode::kNullOrUndefined);
}
void BytecodeGraphBuilder::VisitCallUndefinedReceiver0() {
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* receiver = jsgraph()->UndefinedConstant();
int const slot_id = bytecode_iterator().GetIndexOperand(1);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNullOrUndefined,
{callee, receiver}, slot_id);
}
void BytecodeGraphBuilder::VisitCallUndefinedReceiver1() {
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* receiver = jsgraph()->UndefinedConstant();
Node* arg0 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
int const slot_id = bytecode_iterator().GetIndexOperand(2);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNullOrUndefined,
{callee, receiver, arg0}, slot_id);
}
void BytecodeGraphBuilder::VisitCallUndefinedReceiver2() {
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* receiver = jsgraph()->UndefinedConstant();
Node* arg0 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
Node* arg1 =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(2));
int const slot_id = bytecode_iterator().GetIndexOperand(3);
BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNullOrUndefined,
{callee, receiver, arg0, arg1}, slot_id);
}
void BytecodeGraphBuilder::VisitCallWithSpread() {
PrepareEagerCheckpoint();
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
const Operator* call =
javascript()->CallWithSpread(static_cast<int>(arg_count + 1));
javascript()->CallWithSpread(static_cast<int>(reg_count + 1));
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1);
Node* value = ProcessCallArguments(call, callee, receiver, reg_count);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
@ -1506,118 +1550,127 @@ void BytecodeGraphBuilder::VisitCallJSRuntime() {
Node* callee =
BuildLoadNativeContextField(bytecode_iterator().GetIndexOperand(0));
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
// Create node to perform the JS runtime call.
const Operator* call = javascript()->Call(arg_count + 1);
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1);
const Operator* call = javascript()->Call(reg_count + 1);
Node* value = ProcessCallArguments(call, callee, receiver, reg_count);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
Node* BytecodeGraphBuilder::ProcessCallRuntimeArguments(
const Operator* call_runtime_op, interpreter::Register first_arg,
size_t arity) {
Node** all = local_zone()->NewArray<Node*>(arity);
int first_arg_index = first_arg.index();
for (int i = 0; i < static_cast<int>(arity); ++i) {
const Operator* call_runtime_op, interpreter::Register receiver,
size_t reg_count) {
int arg_count = static_cast<int>(reg_count);
// arity is args.
int arity = arg_count;
Node** all = local_zone()->NewArray<Node*>(static_cast<size_t>(arity));
int first_arg_index = receiver.index();
for (int i = 0; i < static_cast<int>(reg_count); ++i) {
all[i] = environment()->LookupRegister(
interpreter::Register(first_arg_index + i));
}
Node* value = MakeNode(call_runtime_op, static_cast<int>(arity), all, false);
Node* value = MakeNode(call_runtime_op, arity, all, false);
return value;
}
void BytecodeGraphBuilder::VisitCallRuntime() {
PrepareEagerCheckpoint();
Runtime::FunctionId functionId = bytecode_iterator().GetRuntimeIdOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
// Create node to perform the runtime call.
const Operator* call = javascript()->CallRuntime(functionId, arg_count);
Node* value = ProcessCallRuntimeArguments(call, first_arg, arg_count);
const Operator* call = javascript()->CallRuntime(functionId, reg_count);
Node* value = ProcessCallRuntimeArguments(call, receiver, reg_count);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitCallRuntimeForPair() {
PrepareEagerCheckpoint();
Runtime::FunctionId functionId = bytecode_iterator().GetRuntimeIdOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
interpreter::Register first_return =
bytecode_iterator().GetRegisterOperand(3);
// Create node to perform the runtime call.
const Operator* call = javascript()->CallRuntime(functionId, arg_count);
Node* return_pair = ProcessCallRuntimeArguments(call, first_arg, arg_count);
const Operator* call = javascript()->CallRuntime(functionId, reg_count);
Node* return_pair = ProcessCallRuntimeArguments(call, receiver, reg_count);
environment()->BindRegistersToProjections(first_return, return_pair,
Environment::kAttachFrameState);
}
Node* BytecodeGraphBuilder::ProcessConstructWithSpreadArguments(
const Operator* op, Node* callee, Node* new_target,
interpreter::Register first_arg, size_t arity) {
Node** all = local_zone()->NewArray<Node*>(arity);
interpreter::Register receiver, size_t reg_count) {
int arg_count = static_cast<int>(reg_count);
// arity is args + callee and new target.
int arity = arg_count + 2;
Node** all = local_zone()->NewArray<Node*>(static_cast<size_t>(arity));
all[0] = callee;
int first_arg_index = first_arg.index();
for (int i = 1; i < static_cast<int>(arity) - 1; ++i) {
all[i] = environment()->LookupRegister(
interpreter::Register(first_arg_index + i - 1));
int first_arg_index = receiver.index();
for (int i = 0; i < arg_count; ++i) {
all[1 + i] = environment()->LookupRegister(
interpreter::Register(first_arg_index + i));
}
all[arity - 1] = new_target;
Node* value = MakeNode(op, static_cast<int>(arity), all, false);
Node* value = MakeNode(op, arity, all, false);
return value;
}
void BytecodeGraphBuilder::VisitConstructWithSpread() {
PrepareEagerCheckpoint();
interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
Node* new_target = environment()->LookupAccumulator();
Node* callee = environment()->LookupRegister(callee_reg);
const Operator* op =
javascript()->ConstructWithSpread(static_cast<int>(arg_count) + 2);
javascript()->ConstructWithSpread(static_cast<uint32_t>(reg_count + 2));
Node* value = ProcessConstructWithSpreadArguments(op, callee, new_target,
first_arg, arg_count + 2);
receiver, reg_count);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitInvokeIntrinsic() {
PrepareEagerCheckpoint();
Runtime::FunctionId functionId = bytecode_iterator().GetIntrinsicIdOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
// Create node to perform the runtime call. Turbofan will take care of the
// lowering.
const Operator* call = javascript()->CallRuntime(functionId, arg_count);
Node* value = ProcessCallRuntimeArguments(call, first_arg, arg_count);
const Operator* call = javascript()->CallRuntime(functionId, reg_count);
Node* value = ProcessCallRuntimeArguments(call, receiver, reg_count);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
Node* BytecodeGraphBuilder::ProcessConstructArguments(
const Operator* call_new_op, Node* callee, Node* new_target,
interpreter::Register first_arg, size_t arity) {
Node** all = local_zone()->NewArray<Node*>(arity);
interpreter::Register receiver, size_t reg_count) {
int arg_count = static_cast<int>(reg_count);
// arity is args + callee and new target.
int arity = arg_count + 2;
Node** all = local_zone()->NewArray<Node*>(static_cast<size_t>(arity));
all[0] = callee;
int first_arg_index = first_arg.index();
for (int i = 1; i < static_cast<int>(arity) - 1; ++i) {
all[i] = environment()->LookupRegister(
interpreter::Register(first_arg_index + i - 1));
int first_arg_index = receiver.index();
for (int i = 0; i < arg_count; ++i) {
all[1 + i] = environment()->LookupRegister(
interpreter::Register(first_arg_index + i));
}
all[arity - 1] = new_target;
Node* value = MakeNode(call_new_op, static_cast<int>(arity), all, false);
Node* value = MakeNode(call_new_op, arity, all, false);
return value;
}
void BytecodeGraphBuilder::VisitConstruct() {
PrepareEagerCheckpoint();
interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t reg_count = bytecode_iterator().GetRegisterCountOperand(2);
// Slot index of 0 is used indicate no feedback slot is available. Assert
// the assumption that slot index 0 is never a valid feedback slot.
STATIC_ASSERT(FeedbackVector::kReservedIndexCount > 0);
@ -1629,9 +1682,9 @@ void BytecodeGraphBuilder::VisitConstruct() {
float const frequency = ComputeCallFrequency(slot_id);
const Operator* call = javascript()->Construct(
static_cast<int>(arg_count) + 2, frequency, feedback);
Node* value = ProcessConstructArguments(call, callee, new_target, first_arg,
arg_count + 2);
static_cast<uint32_t>(reg_count + 2), frequency, feedback);
Node* value =
ProcessConstructArguments(call, callee, new_target, receiver, reg_count);
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}

View File

@ -112,24 +112,24 @@ class BytecodeGraphBuilder {
Node** EnsureInputBufferSize(int size);
Node* const* GetCallArgumentsFromRegister(Node* callee,
Node* const* GetCallArgumentsFromRegister(Node* callee, Node* receiver,
interpreter::Register first_arg,
size_t arity);
int arg_count);
Node* ProcessCallArguments(const Operator* call_op, Node* const* args,
size_t arg_count);
int arg_count);
Node* ProcessCallArguments(const Operator* call_op, Node* callee,
interpreter::Register receiver, size_t arity);
interpreter::Register receiver, size_t reg_count);
Node* ProcessConstructArguments(const Operator* call_new_op, Node* callee,
Node* new_target,
interpreter::Register first_arg,
size_t arity);
interpreter::Register receiver,
size_t reg_count);
Node* ProcessConstructWithSpreadArguments(const Operator* op, Node* callee,
Node* new_target,
interpreter::Register first_arg,
size_t arity);
interpreter::Register receiver,
size_t reg_count);
Node* ProcessCallRuntimeArguments(const Operator* call_runtime_op,
interpreter::Register first_arg,
size_t arity);
interpreter::Register receiver,
size_t reg_count);
// Prepare information for eager deoptimization. This information is carried
// by dedicated {Checkpoint} nodes that are wired into the effect chain.
@ -159,12 +159,12 @@ class BytecodeGraphBuilder {
void BuildLdaLookupGlobalSlot(TypeofMode typeof_mode);
void BuildStaLookupSlot(LanguageMode language_mode);
void BuildCallVarArgs(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_hint);
void BuildCall(TailCallMode tail_call_mode, ConvertReceiverMode receiver_hint,
ConvertReceiverMode receiver_mode);
void BuildCall(TailCallMode tail_call_mode, ConvertReceiverMode receiver_mode,
Node* const* args, size_t arg_count, int slot_id);
void BuildCall(TailCallMode tail_call_mode, ConvertReceiverMode receiver_hint,
void BuildCall(TailCallMode tail_call_mode, ConvertReceiverMode receiver_mode,
std::initializer_list<Node*> args, int slot_id) {
BuildCall(tail_call_mode, receiver_hint, args.begin(), args.size(),
BuildCall(tail_call_mode, receiver_mode, args.begin(), args.size(),
slot_id);
}
void BuildBinaryOp(const Operator* op);

View File

@ -318,7 +318,7 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
eax, // argument count (not including receiver)
@ -328,7 +328,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
eax, // argument count (not including receiver)
@ -340,8 +340,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
Register registers[] = {
eax, // argument count (not including receiver)
edx, // target to the call. It is checked to be Array function.

View File

@ -607,7 +607,7 @@ void InterpreterDispatchDescriptor::InitializePlatformIndependent(
machine_types);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformIndependent(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kNumberOfArguments, kFirstArgument, kFunction
MachineType machine_types[] = {MachineType::Int32(), MachineType::Pointer(),
@ -616,7 +616,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformIndependent(
machine_types);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformIndependent(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kNumberOfArguments, kNewTarget, kConstructor, kFeedbackElement,
// kFirstArgument
@ -627,7 +627,7 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformIndependent(
machine_types);
}
void InterpreterPushArgsAndConstructArrayDescriptor::
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformIndependent(CallInterfaceDescriptorData* data) {
// kNumberOfArguments, kFunction, kFeedbackElement, kFirstArgument
MachineType machine_types[] = {MachineType::Int32(), MachineType::AnyTagged(),

View File

@ -79,9 +79,9 @@ class PlatformInterfaceDescriptor;
V(GrowArrayElements) \
V(NewArgumentsElements) \
V(InterpreterDispatch) \
V(InterpreterPushArgsAndCall) \
V(InterpreterPushArgsAndConstruct) \
V(InterpreterPushArgsAndConstructArray) \
V(InterpreterPushArgsThenCall) \
V(InterpreterPushArgsThenConstruct) \
V(InterpreterPushArgsThenConstructArray) \
V(InterpreterCEntry) \
V(ResumeGenerator) \
V(FrameDropperTrampoline) \
@ -839,30 +839,29 @@ class V8_EXPORT_PRIVATE InterpreterDispatchDescriptor
CallInterfaceDescriptor)
};
class InterpreterPushArgsAndCallDescriptor : public CallInterfaceDescriptor {
class InterpreterPushArgsThenCallDescriptor : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kNumberOfArguments, kFirstArgument, kFunction)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(
InterpreterPushArgsAndCallDescriptor, CallInterfaceDescriptor)
InterpreterPushArgsThenCallDescriptor, CallInterfaceDescriptor)
};
class InterpreterPushArgsAndConstructDescriptor
class InterpreterPushArgsThenConstructDescriptor
: public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kNumberOfArguments, kNewTarget, kConstructor,
kFeedbackElement, kFirstArgument)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(
InterpreterPushArgsAndConstructDescriptor, CallInterfaceDescriptor)
InterpreterPushArgsThenConstructDescriptor, CallInterfaceDescriptor)
};
class InterpreterPushArgsAndConstructArrayDescriptor
class InterpreterPushArgsThenConstructArrayDescriptor
: public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kNumberOfArguments, kFunction, kFeedbackElement,
kFirstArgument)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(
InterpreterPushArgsAndConstructArrayDescriptor, CallInterfaceDescriptor)
InterpreterPushArgsThenConstructArrayDescriptor, CallInterfaceDescriptor)
};
class InterpreterCEntryDescriptor : public CallInterfaceDescriptor {

View File

@ -1242,42 +1242,50 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::MarkTryEnd(int handler_id) {
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
RegisterList args,
int feedback_slot,
Call::CallType call_type,
TailCallMode tail_call_mode) {
if (tail_call_mode == TailCallMode::kDisallow) {
if (call_type == Call::NAMED_PROPERTY_CALL ||
call_type == Call::KEYED_PROPERTY_CALL) {
if (args.register_count() == 1) {
OutputCallProperty0(callable, args[0], feedback_slot);
} else if (args.register_count() == 2) {
OutputCallProperty1(callable, args[0], args[1], feedback_slot);
} else if (args.register_count() == 3) {
OutputCallProperty2(callable, args[0], args[1], args[2], feedback_slot);
} else {
OutputCallProperty(callable, args, args.register_count(),
feedback_slot);
}
} else {
if (args.register_count() == 1) {
OutputCall0(callable, args[0], feedback_slot);
} else if (args.register_count() == 2) {
OutputCall1(callable, args[0], args[1], feedback_slot);
} else if (args.register_count() == 3) {
OutputCall2(callable, args[0], args[1], args[2], feedback_slot);
} else {
OutputCall(callable, args, args.register_count(), feedback_slot);
}
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CallProperty(Register callable,
RegisterList args,
int feedback_slot) {
if (args.register_count() == 1) {
OutputCallProperty0(callable, args[0], feedback_slot);
} else if (args.register_count() == 2) {
OutputCallProperty1(callable, args[0], args[1], feedback_slot);
} else if (args.register_count() == 3) {
OutputCallProperty2(callable, args[0], args[1], args[2], feedback_slot);
} else {
DCHECK(tail_call_mode == TailCallMode::kAllow);
OutputTailCall(callable, args, args.register_count(), feedback_slot);
OutputCallProperty(callable, args, args.register_count(), feedback_slot);
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CallUndefinedReceiver(
Register callable, RegisterList args, int feedback_slot) {
if (args.register_count() == 0) {
OutputCallUndefinedReceiver0(callable, feedback_slot);
} else if (args.register_count() == 1) {
OutputCallUndefinedReceiver1(callable, args[0], feedback_slot);
} else if (args.register_count() == 2) {
OutputCallUndefinedReceiver2(callable, args[0], args[1], feedback_slot);
} else {
OutputCallUndefinedReceiver(callable, args, args.register_count(),
feedback_slot);
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CallAnyReceiver(Register callable,
RegisterList args,
int feedback_slot) {
OutputCallAnyReceiver(callable, args, args.register_count(), feedback_slot);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::TailCall(Register callable,
RegisterList args,
int feedback_slot) {
OutputTailCall(callable, args, args.register_count(), feedback_slot);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(Register callable,
RegisterList args) {
OutputCallWithSpread(callable, args, args.register_count());

View File

@ -238,14 +238,35 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
// Pop the current context and replace with |context|.
BytecodeArrayBuilder& PopContext(Register context);
// Call a JS function. The JSFunction or Callable to be called should be in
// |callable|. The arguments should be in |args|, with the receiver in
// |args[0]|. The call type of the expression is in |call_type|. Type feedback
// is recorded in the |feedback_slot| in the type feedback vector.
BytecodeArrayBuilder& Call(
Register callable, RegisterList args, int feedback_slot,
Call::CallType call_type,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
// Call a JS function which is known to be a property of a JS object. The
// JSFunction or Callable to be called should be in |callable|. The arguments
// should be in |args|, with the receiver in |args[0]|. The call type of the
// expression is in |call_type|. Type feedback is recorded in the
// |feedback_slot| in the type feedback vector.
BytecodeArrayBuilder& CallProperty(Register callable, RegisterList args,
int feedback_slot);
// Call a JS function with an known undefined receiver. The JSFunction or
// Callable to be called should be in |callable|. The arguments should be in
// |args|, with no receiver as it is implicitly set to undefined. Type
// feedback is recorded in the |feedback_slot| in the type feedback vector.
BytecodeArrayBuilder& CallUndefinedReceiver(Register callable,
RegisterList args,
int feedback_slot);
// Call a JS function with an any receiver, possibly (but not necessarily)
// undefined. The JSFunction or Callable to be called should be in |callable|.
// The arguments should be in |args|, with the receiver in |args[0]|. Type
// feedback is recorded in the |feedback_slot| in the type feedback vector.
BytecodeArrayBuilder& CallAnyReceiver(Register callable, RegisterList args,
int feedback_slot);
// Tail call into a JS function. The JSFunction or Callable to be called
// should be in |callable|. The arguments should be in |args|, with the
// receiver in |args[0]|. Type feedback is recorded in the |feedback_slot| in
// the type feedback vector.
BytecodeArrayBuilder& TailCall(Register callable, RegisterList args,
int feedback_slot);
// Call a JS function. The JSFunction or Callable to be called should be in
// |callable|, the receiver in |args[0]| and the arguments in |args[1]|

View File

@ -2597,6 +2597,12 @@ void BytecodeGenerator::VisitCall(Call* expr) {
Register callee = register_allocator()->NewRegister();
RegisterList args = register_allocator()->NewGrowableRegisterList();
bool implicit_undefined_receiver = false;
bool is_tail_call = (expr->tail_call_mode() == TailCallMode::kAllow);
// When a call contains a spread, a Call AST node is only created if there is
// exactly one spread, and it is the last argument.
bool is_spread_call = expr->only_last_arg_is_spread();
// TODO(petermarshall): We have a lot of call bytecodes that are very similar,
// see if we can reduce the number by adding a separate argument which
// specifies the call type (e.g., property, spread, tailcall, etc.).
@ -2613,7 +2619,13 @@ void BytecodeGenerator::VisitCall(Call* expr) {
}
case Call::GLOBAL_CALL: {
// Receiver is undefined for global calls.
BuildPushUndefinedIntoRegisterList(&args);
if (!is_tail_call && !is_spread_call) {
implicit_undefined_receiver = true;
} else {
// TODO(leszeks): There's no special bytecode for tail calls or spread
// calls with an undefined receiver, so just push undefined ourselves.
BuildPushUndefinedIntoRegisterList(&args);
}
// Load callee as a global variable.
VariableProxy* proxy = callee_expr->AsVariableProxy();
BuildVariableLoadForAccumulatorValue(proxy->var(),
@ -2633,6 +2645,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
DCHECK(Register::AreContiguous(callee, receiver));
RegisterList result_pair(callee.index(), 2);
USE(receiver);
Variable* variable = callee_expr->AsVariableProxy()->var();
builder()
->LoadLiteral(variable->raw_name())
@ -2643,7 +2656,14 @@ void BytecodeGenerator::VisitCall(Call* expr) {
break;
}
case Call::OTHER_CALL: {
BuildPushUndefinedIntoRegisterList(&args);
// Receiver is undefined for other calls.
if (!is_tail_call && !is_spread_call) {
implicit_undefined_receiver = true;
} else {
// TODO(leszeks): There's no special bytecode for tail calls or spread
// calls with an undefined receiver, so just push undefined ourselves.
BuildPushUndefinedIntoRegisterList(&args);
}
VisitForRegisterValue(callee_expr, callee);
break;
}
@ -2669,7 +2689,9 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// Evaluate all arguments to the function call and store in sequential args
// registers.
VisitArguments(expr->arguments(), &args);
CHECK_EQ(expr->arguments()->length() + 1, args.register_count());
int reciever_arg_count = implicit_undefined_receiver ? 0 : 1;
CHECK_EQ(reciever_arg_count + expr->arguments()->length(),
args.register_count());
// Resolve callee for a potential direct eval call. This block will mutate the
// callee value.
@ -2678,10 +2700,11 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// Set up arguments for ResolvePossiblyDirectEval by copying callee, source
// strings and function closure, and loading language and
// position.
Register first_arg = args[reciever_arg_count];
RegisterList runtime_call_args = register_allocator()->NewRegisterList(6);
builder()
->MoveRegister(callee, runtime_call_args[0])
.MoveRegister(args[1], runtime_call_args[1])
.MoveRegister(first_arg, runtime_call_args[1])
.MoveRegister(Register::function_closure(), runtime_call_args[2])
.LoadLiteral(Smi::FromInt(language_mode()))
.StoreAccumulatorInRegister(runtime_call_args[3])
@ -2698,15 +2721,23 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->SetExpressionPosition(expr);
// When a call contains a spread, a Call AST node is only created if there is
// exactly one spread, and it is the last argument.
if (expr->only_last_arg_is_spread()) {
DCHECK_EQ(TailCallMode::kDisallow, expr->tail_call_mode());
int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
if (is_spread_call) {
DCHECK(!is_tail_call);
DCHECK(!implicit_undefined_receiver);
builder()->CallWithSpread(callee, args);
} else if (is_tail_call) {
DCHECK(!implicit_undefined_receiver);
builder()->TailCall(callee, args, feedback_slot_index);
} else if (call_type == Call::NAMED_PROPERTY_CALL ||
call_type == Call::KEYED_PROPERTY_CALL) {
DCHECK(!implicit_undefined_receiver);
builder()->CallProperty(callee, args, feedback_slot_index);
} else if (implicit_undefined_receiver) {
builder()->CallUndefinedReceiver(callee, args, feedback_slot_index);
} else {
int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
builder()->Call(callee, args, feedback_slot_index, call_type,
expr->tail_call_mode());
builder()->CallAnyReceiver(callee, args, feedback_slot_index);
}
}
@ -2768,6 +2799,8 @@ void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
if (expr->is_jsruntime()) {
RegisterList args = register_allocator()->NewGrowableRegisterList();
// Allocate a register for the receiver and load it with undefined.
// TODO(leszeks): If CallJSRuntime always has an undefined receiver, use the
// same mechanism as CallUndefinedReceiver.
BuildPushUndefinedIntoRegisterList(&args);
VisitArguments(expr->arguments(), &args);
builder()->CallJSRuntime(expr->context_index(), args);
@ -3161,9 +3194,8 @@ void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
builder()->JumpIfNull(&async_iterator_null);
// Let iterator be Call(method, obj)
builder()->StoreAccumulatorInRegister(method).Call(
method, args, feedback_index(async_call_slot),
Call::NAMED_PROPERTY_CALL);
builder()->StoreAccumulatorInRegister(method).CallProperty(
method, args, feedback_index(async_call_slot));
// If Type(iterator) is not Object, throw a TypeError exception.
builder()->JumpIfJSReceiver(&done);
@ -3178,8 +3210,7 @@ void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
.StoreAccumulatorInRegister(method);
// Let syncIterator be Call(syncMethod, obj)
builder()->Call(method, args, feedback_index(call_slot),
Call::NAMED_PROPERTY_CALL);
builder()->CallProperty(method, args, feedback_index(call_slot));
// Return CreateAsyncFromSyncIterator(syncIterator)
// alias `method` register as it's no longer used
@ -3196,8 +3227,7 @@ void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
.StoreAccumulatorInRegister(method);
// Let iterator be Call(method, obj).
builder()->Call(method, args, feedback_index(call_slot),
Call::NAMED_PROPERTY_CALL);
builder()->CallProperty(method, args, feedback_index(call_slot));
// If Type(iterator) is not Object, throw a TypeError exception.
BytecodeLabel no_type_error;

View File

@ -238,8 +238,15 @@ bool Bytecodes::IsStarLookahead(Bytecode bytecode, OperandScale operand_scale) {
case Bytecode::kInc:
case Bytecode::kDec:
case Bytecode::kTypeOf:
case Bytecode::kCall:
case Bytecode::kCallAnyReceiver:
case Bytecode::kCallProperty:
case Bytecode::kCallProperty0:
case Bytecode::kCallProperty1:
case Bytecode::kCallProperty2:
case Bytecode::kCallUndefinedReceiver:
case Bytecode::kCallUndefinedReceiver0:
case Bytecode::kCallUndefinedReceiver1:
case Bytecode::kCallUndefinedReceiver2:
case Bytecode::kConstruct:
case Bytecode::kConstructWithSpread:
return true;

View File

@ -158,14 +158,8 @@ namespace interpreter {
V(GetSuperConstructor, AccumulatorUse::kRead, OperandType::kRegOut) \
\
/* Call operations */ \
V(Call, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kRegList, \
OperandType::kRegCount, OperandType::kIdx) \
V(Call0, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \
OperandType::kIdx) \
V(Call1, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \
OperandType::kReg, OperandType::kIdx) \
V(Call2, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \
OperandType::kReg, OperandType::kReg, OperandType::kIdx) \
V(CallAnyReceiver, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallProperty, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallProperty0, AccumulatorUse::kWrite, OperandType::kReg, \
@ -175,6 +169,14 @@ namespace interpreter {
V(CallProperty2, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kReg, OperandType::kReg, OperandType::kReg, \
OperandType::kIdx) \
V(CallUndefinedReceiver, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallUndefinedReceiver0, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kIdx) \
V(CallUndefinedReceiver1, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kReg, OperandType::kIdx) \
V(CallUndefinedReceiver2, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kReg, OperandType::kReg, OperandType::kIdx) \
V(CallWithSpread, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount) \
V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, \
@ -432,7 +434,7 @@ enum class Bytecode : uint8_t {
class V8_EXPORT_PRIVATE Bytecodes final {
public:
// The maximum number of operands a bytecode may have.
// The maximum number of operands a bytecode may have.
static const int kMaxOperands = 5;
// Returns string representation of |bytecode|.
@ -625,13 +627,15 @@ class V8_EXPORT_PRIVATE Bytecodes final {
// Returns true if the bytecode is a call or a constructor call.
static constexpr bool IsCallOrConstruct(Bytecode bytecode) {
return bytecode == Bytecode::kCall || bytecode == Bytecode::kCallProperty ||
bytecode == Bytecode::kCall0 ||
return bytecode == Bytecode::kCallAnyReceiver ||
bytecode == Bytecode::kCallProperty ||
bytecode == Bytecode::kCallProperty0 ||
bytecode == Bytecode::kCall1 ||
bytecode == Bytecode::kCallProperty1 ||
bytecode == Bytecode::kCall2 ||
bytecode == Bytecode::kCallProperty2 ||
bytecode == Bytecode::kCallUndefinedReceiver ||
bytecode == Bytecode::kCallUndefinedReceiver0 ||
bytecode == Bytecode::kCallUndefinedReceiver1 ||
bytecode == Bytecode::kCallUndefinedReceiver2 ||
bytecode == Bytecode::kTailCall ||
bytecode == Bytecode::kConstruct ||
bytecode == Bytecode::kCallWithSpread ||
@ -746,6 +750,34 @@ class V8_EXPORT_PRIVATE Bytecodes final {
// through the bytecode's handler.
static bool MakesCallAlongCriticalPath(Bytecode bytecode);
// Returns the receiver mode of the given call bytecode.
static ConvertReceiverMode GetReceiverMode(Bytecode bytecode) {
DCHECK(IsCallOrConstruct(bytecode));
switch (bytecode) {
case Bytecode::kCallProperty:
case Bytecode::kCallProperty0:
case Bytecode::kCallProperty1:
case Bytecode::kCallProperty2:
return ConvertReceiverMode::kNotNullOrUndefined;
case Bytecode::kCallUndefinedReceiver:
case Bytecode::kCallUndefinedReceiver0:
case Bytecode::kCallUndefinedReceiver1:
case Bytecode::kCallUndefinedReceiver2:
return ConvertReceiverMode::kNullOrUndefined;
case Bytecode::kCallAnyReceiver:
case Bytecode::kTailCall:
case Bytecode::kConstruct:
case Bytecode::kCallWithSpread:
case Bytecode::kConstructWithSpread:
case Bytecode::kInvokeIntrinsic:
case Bytecode::kCallJSRuntime:
return ConvertReceiverMode::kAny;
default:
UNREACHABLE();
return ConvertReceiverMode::kAny;
}
}
// Returns true if the bytecode is a debug break.
static bool IsDebugBreak(Bytecode bytecode);

View File

@ -555,11 +555,11 @@ Node* InterpreterAssembler::IncrementCallCount(Node* feedback_vector,
SKIP_WRITE_BARRIER);
}
Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Node* first_arg, Node* arg_count,
Node* slot_id,
Node* feedback_vector,
TailCallMode tail_call_mode) {
Node* InterpreterAssembler::CallJSWithFeedback(
compiler::Node* function, compiler::Node* context,
compiler::Node* first_arg, compiler::Node* arg_count,
compiler::Node* slot_id, compiler::Node* feedback_vector,
ConvertReceiverMode receiver_mode, TailCallMode tail_call_mode) {
// Static checks to assert it is safe to examine the type feedback element.
// We don't know that we have a weak cell. We might have a private symbol
// or an AllocationSite, but the memory is safe to examine.
@ -572,6 +572,8 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
// to be a pointer.
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
DCHECK(Bytecodes::IsCallOrConstruct(bytecode_));
DCHECK_EQ(Bytecodes::GetReceiverMode(bytecode_), receiver_mode);
STATIC_ASSERT(WeakCell::kSize >= kPointerSize);
STATIC_ASSERT(AllocationSite::kTransitionInfoOffset ==
WeakCell::kValueOffset &&
@ -598,8 +600,9 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
IncrementCallCount(feedback_vector, slot_id);
// Call using call function builtin.
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, InterpreterPushArgsMode::kJSFunction);
Callable callable = CodeFactory::InterpreterPushArgsThenCall(
isolate(), receiver_mode, tail_call_mode,
InterpreterPushArgsMode::kJSFunction);
Node* code_target = HeapConstant(callable.code());
Node* ret_value = CallStub(callable.descriptor(), code_target, context,
arg_count, first_arg, function);
@ -623,24 +626,33 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
GotoIfNot(IsAllocationSiteMap(LoadMap(feedback_element)),
&check_initialized);
// If it is not the Array() function, mark megamorphic.
Node* context_slot = LoadContextElement(LoadNativeContext(context),
Context::ARRAY_FUNCTION_INDEX);
Node* is_array_function = WordEqual(context_slot, function);
GotoIfNot(is_array_function, &mark_megamorphic);
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
// For undefined receivers (mostly global calls), do an additional check
// for the monomorphic Array function, which would otherwise appear
// megamorphic.
// It is a monomorphic Array function. Increment the call count.
IncrementCallCount(feedback_vector, slot_id);
// If it is not the Array() function, mark megamorphic.
Node* context_slot = LoadContextElement(LoadNativeContext(context),
Context::ARRAY_FUNCTION_INDEX);
Node* is_array_function = WordEqual(context_slot, function);
GotoIfNot(is_array_function, &mark_megamorphic);
// Call ArrayConstructorStub.
Callable callable_call =
CodeFactory::InterpreterPushArgsAndConstructArray(isolate());
Node* code_target_call = HeapConstant(callable_call.code());
Node* ret_value =
CallStub(callable_call.descriptor(), code_target_call, context,
arg_count, function, feedback_element, first_arg);
return_value.Bind(ret_value);
Goto(&end);
// It is a monomorphic Array function. Increment the call count.
IncrementCallCount(feedback_vector, slot_id);
// Call ArrayConstructorStub.
Callable callable_call =
CodeFactory::InterpreterPushArgsThenConstructArray(isolate());
Node* code_target_call = HeapConstant(callable_call.code());
Node* ret_value =
CallStub(callable_call.descriptor(), code_target_call, context,
arg_count, function, feedback_element, first_arg);
return_value.Bind(ret_value);
Goto(&end);
} else {
Goto(&mark_megamorphic);
}
Bind(&check_initialized);
{
@ -651,7 +663,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
HeapConstant(FeedbackVector::UninitializedSentinel(isolate())));
GotoIfNot(is_uninitialized, &mark_megamorphic);
Comment("handle_unitinitialized");
Comment("handle_uninitialized");
// If it is not a JSFunction mark it as megamorphic.
Node* is_smi = TaggedIsSmi(function);
GotoIf(is_smi, &mark_megamorphic);
@ -713,8 +725,9 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
IncrementCallCount(feedback_vector, slot_id);
// Call using call builtin.
Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, InterpreterPushArgsMode::kOther);
Callable callable_call = CodeFactory::InterpreterPushArgsThenCall(
isolate(), receiver_mode, tail_call_mode,
InterpreterPushArgsMode::kOther);
Node* code_target_call = HeapConstant(callable_call.code());
Node* ret_value = CallStub(callable_call.descriptor(), code_target_call,
context, arg_count, first_arg, function);
@ -728,11 +741,14 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Node* InterpreterAssembler::CallJS(Node* function, Node* context,
Node* first_arg, Node* arg_count,
ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode) {
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
DCHECK(Bytecodes::IsCallOrConstruct(bytecode_));
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, InterpreterPushArgsMode::kOther);
DCHECK_EQ(Bytecodes::GetReceiverMode(bytecode_), receiver_mode);
Callable callable = CodeFactory::InterpreterPushArgsThenCall(
isolate(), receiver_mode, tail_call_mode,
InterpreterPushArgsMode::kOther);
Node* code_target = HeapConstant(callable.code());
return CallStub(callable.descriptor(), code_target, context, arg_count,
@ -742,8 +758,9 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context,
Node* InterpreterAssembler::CallJSWithSpread(Node* function, Node* context,
Node* first_arg, Node* arg_count) {
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), TailCallMode::kDisallow,
DCHECK_EQ(Bytecodes::GetReceiverMode(bytecode_), ConvertReceiverMode::kAny);
Callable callable = CodeFactory::InterpreterPushArgsThenCall(
isolate(), ConvertReceiverMode::kAny, TailCallMode::kDisallow,
InterpreterPushArgsMode::kWithFinalSpread);
Node* code_target = HeapConstant(callable.code());
@ -787,7 +804,7 @@ Node* InterpreterAssembler::Construct(Node* constructor, Node* context,
{
Comment("call using ConstructFunction");
IncrementCallCount(feedback_vector, slot_id);
Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct(
Callable callable_function = CodeFactory::InterpreterPushArgsThenConstruct(
isolate(), InterpreterPushArgsMode::kJSFunction);
return_value.Bind(CallStub(callable_function.descriptor(),
HeapConstant(callable_function.code()), context,
@ -890,7 +907,7 @@ Node* InterpreterAssembler::Construct(Node* constructor, Node* context,
Bind(&call_construct);
{
Comment("call using Construct builtin");
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(
Callable callable = CodeFactory::InterpreterPushArgsThenConstruct(
isolate(), InterpreterPushArgsMode::kOther);
Node* code_target = HeapConstant(callable.code());
return_value.Bind(CallStub(callable.descriptor(), code_target, context,
@ -910,7 +927,7 @@ Node* InterpreterAssembler::ConstructWithSpread(Node* constructor,
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
Variable return_value(this, MachineRepresentation::kTagged);
Comment("call using ConstructWithSpread");
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(
Callable callable = CodeFactory::InterpreterPushArgsThenConstruct(
isolate(), InterpreterPushArgsMode::kWithFinalSpread);
Node* code_target = HeapConstant(callable.code());
return_value.Bind(CallStub(callable.descriptor(), code_target, context,

View File

@ -118,23 +118,25 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
compiler::Node* IncrementCallCount(compiler::Node* feedback_vector,
compiler::Node* slot_id);
// Call JSFunction or Callable |function| with |arg_count|
// arguments (not including receiver) and the first argument
// located at |first_arg|. Type feedback is collected in the
// slot at index |slot_id|.
compiler::Node* CallJSWithFeedback(compiler::Node* function,
compiler::Node* context,
compiler::Node* first_arg,
compiler::Node* arg_count,
compiler::Node* slot_id,
compiler::Node* feedback_vector,
TailCallMode tail_call_mode);
// Call JSFunction or Callable |function| with |arg_count| arguments (not
// including receiver) and the first argument located at |first_arg|. Type
// feedback is collected in the slot at index |slot_id|.
//
// If the |receiver_mode| is kNullOrUndefined, then the receiver is implicitly
// undefined and |first_arg| is the first parameter. Otherwise, |first_arg| is
// the receiver and it is converted according to |receiver_mode|.
compiler::Node* CallJSWithFeedback(
compiler::Node* function, compiler::Node* context,
compiler::Node* first_arg, compiler::Node* arg_count,
compiler::Node* slot_id, compiler::Node* feedback_vector,
ConvertReceiverMode receiver_mode, TailCallMode tail_call_mode);
// Call JSFunction or Callable |function| with |arg_count|
// arguments (not including receiver) and the first argument
// located at |first_arg|.
// Call JSFunction or Callable |function| with |arg_count| arguments (not
// including receiver) and the first argument located at |first_arg|, possibly
// including the receiver depending on |receiver_mode|.
compiler::Node* CallJS(compiler::Node* function, compiler::Node* context,
compiler::Node* first_arg, compiler::Node* arg_count,
ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode);
// Call JSFunction or Callable |function| with |arg_count|

View File

@ -73,11 +73,13 @@ class InterpreterGenerator {
void DoKeyedStoreIC(Callable ic, InterpreterAssembler* assembler);
// Generates code to perform a JS call that collects type feedback.
void DoJSCall(InterpreterAssembler* assembler, TailCallMode tail_call_mode);
void DoJSCall(InterpreterAssembler* assembler,
ConvertReceiverMode receiver_mode, TailCallMode tail_call_mode);
// Generates code to perform a JS call with a known number of arguments that
// collects type feedback.
void DoJSCallN(InterpreterAssembler* assembler, int n);
void DoJSCallN(InterpreterAssembler* assembler, int n,
ConvertReceiverMode receiver_mode);
// Generates code to perform delete via function_id.
void DoDelete(Runtime::FunctionId function_id,
@ -2322,50 +2324,78 @@ void InterpreterGenerator::DoGetSuperConstructor(
}
void InterpreterGenerator::DoJSCall(InterpreterAssembler* assembler,
ConvertReceiverMode receiver_mode,
TailCallMode tail_call_mode) {
Node* function_reg = __ BytecodeOperandReg(0);
Node* function = __ LoadRegister(function_reg);
Node* receiver_reg = __ BytecodeOperandReg(1);
Node* receiver_arg = __ RegisterLocation(receiver_reg);
Node* receiver_args_count = __ BytecodeOperandCount(2);
Node* receiver_count = __ Int32Constant(1);
Node* args_count = __ Int32Sub(receiver_args_count, receiver_count);
Node* first_arg_reg = __ BytecodeOperandReg(1);
Node* first_arg = __ RegisterLocation(first_arg_reg);
Node* arg_list_count = __ BytecodeOperandCount(2);
Node* args_count;
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
// The receiver is implied, so it is not in the argument list.
args_count = arg_list_count;
} else {
// Subtract the receiver from the argument count.
Node* receiver_count = __ Int32Constant(1);
args_count = __ Int32Sub(arg_list_count, receiver_count);
}
Node* slot_id = __ BytecodeOperandIdx(3);
Node* feedback_vector = __ LoadFeedbackVector();
Node* context = __ GetContext();
Node* result =
__ CallJSWithFeedback(function, context, receiver_arg, args_count,
slot_id, feedback_vector, tail_call_mode);
__ CallJSWithFeedback(function, context, first_arg, args_count, slot_id,
feedback_vector, receiver_mode, tail_call_mode);
__ SetAccumulator(result);
__ Dispatch();
}
void InterpreterGenerator::DoJSCallN(InterpreterAssembler* assembler,
int arg_count) {
const int kReceiverOperandIndex = 1;
const int kReceiverOperandCount = 1;
int arg_count,
ConvertReceiverMode receiver_mode) {
// Indices and counts of operands on the bytecode.
const int kFirstArgumentOperandIndex = 1;
const int kReceiverOperandCount =
(receiver_mode == ConvertReceiverMode::kNullOrUndefined) ? 0 : 1;
const int kSlotOperandIndex =
kReceiverOperandIndex + kReceiverOperandCount + arg_count;
const int kBoilerplatParameterCount = 7;
kFirstArgumentOperandIndex + kReceiverOperandCount + arg_count;
// Indices and counts of parameters to the call stub.
const int kBoilerplateParameterCount = 7;
const int kReceiverParameterIndex = 5;
const int kReceiverParameterCount = 1;
// Only used in a DCHECK.
USE(kReceiverParameterCount);
Node* function_reg = __ BytecodeOperandReg(0);
Node* function = __ LoadRegister(function_reg);
std::array<Node*, Bytecodes::kMaxOperands + kBoilerplatParameterCount> temp;
std::array<Node*, Bytecodes::kMaxOperands + kBoilerplateParameterCount> temp;
Callable call_ic = CodeFactory::CallIC(isolate_);
temp[0] = __ HeapConstant(call_ic.code());
temp[1] = function;
temp[2] = __ Int32Constant(arg_count);
temp[3] = __ BytecodeOperandIdxInt32(kSlotOperandIndex);
temp[4] = __ LoadFeedbackVector();
for (int i = 0; i < (arg_count + kReceiverOperandCount); ++i) {
Node* reg = __ BytecodeOperandReg(i + kReceiverOperandIndex);
temp[kReceiverParameterIndex + i] = __ LoadRegister(reg);
int parameter_index = kReceiverParameterIndex;
if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
// The first argument parameter (the receiver) is implied to be undefined.
Node* undefined_value =
__ HeapConstant(isolate_->factory()->undefined_value());
temp[parameter_index++] = undefined_value;
}
temp[kReceiverParameterIndex + arg_count + kReceiverOperandCount] =
__ GetContext();
// The bytecode argument operands are copied into the remaining argument
// parameters.
for (int i = 0; i < (kReceiverOperandCount + arg_count); ++i) {
Node* reg = __ BytecodeOperandReg(kFirstArgumentOperandIndex + i);
temp[parameter_index++] = __ LoadRegister(reg);
}
DCHECK_EQ(parameter_index,
kReceiverParameterIndex + kReceiverParameterCount + arg_count);
temp[parameter_index] = __ GetContext();
Node* result = __ CallStubN(call_ic.descriptor(), 1,
arg_count + kBoilerplatParameterCount, &temp[0]);
arg_count + kBoilerplateParameterCount, &temp[0]);
__ SetAccumulator(result);
__ Dispatch();
}
@ -2375,40 +2405,46 @@ void InterpreterGenerator::DoJSCallN(InterpreterAssembler* assembler,
// Call a JSfunction or Callable in |callable| with the |receiver| and
// |arg_count| arguments in subsequent registers. Collect type feedback
// into |feedback_slot_id|
void InterpreterGenerator::DoCall(InterpreterAssembler* assembler) {
DoJSCall(assembler, TailCallMode::kDisallow);
}
void InterpreterGenerator::DoCall0(InterpreterAssembler* assembler) {
DoJSCallN(assembler, 0);
}
void InterpreterGenerator::DoCall1(InterpreterAssembler* assembler) {
DoJSCallN(assembler, 1);
}
void InterpreterGenerator::DoCall2(InterpreterAssembler* assembler) {
DoJSCallN(assembler, 2);
void InterpreterGenerator::DoCallAnyReceiver(InterpreterAssembler* assembler) {
DoJSCall(assembler, ConvertReceiverMode::kAny, TailCallMode::kDisallow);
}
void InterpreterGenerator::DoCallProperty(InterpreterAssembler* assembler) {
// Same as Call
UNREACHABLE();
DoJSCall(assembler, ConvertReceiverMode::kNotNullOrUndefined,
TailCallMode::kDisallow);
}
void InterpreterGenerator::DoCallProperty0(InterpreterAssembler* assembler) {
// Same as Call0
UNREACHABLE();
DoJSCallN(assembler, 0, ConvertReceiverMode::kNotNullOrUndefined);
}
void InterpreterGenerator::DoCallProperty1(InterpreterAssembler* assembler) {
// Same as Call1
UNREACHABLE();
DoJSCallN(assembler, 1, ConvertReceiverMode::kNotNullOrUndefined);
}
void InterpreterGenerator::DoCallProperty2(InterpreterAssembler* assembler) {
// Same as Call2
UNREACHABLE();
DoJSCallN(assembler, 2, ConvertReceiverMode::kNotNullOrUndefined);
}
void InterpreterGenerator::DoCallUndefinedReceiver(
InterpreterAssembler* assembler) {
DoJSCall(assembler, ConvertReceiverMode::kNullOrUndefined,
TailCallMode::kDisallow);
}
void InterpreterGenerator::DoCallUndefinedReceiver0(
InterpreterAssembler* assembler) {
DoJSCallN(assembler, 0, ConvertReceiverMode::kNullOrUndefined);
}
void InterpreterGenerator::DoCallUndefinedReceiver1(
InterpreterAssembler* assembler) {
DoJSCallN(assembler, 1, ConvertReceiverMode::kNullOrUndefined);
}
void InterpreterGenerator::DoCallUndefinedReceiver2(
InterpreterAssembler* assembler) {
DoJSCallN(assembler, 2, ConvertReceiverMode::kNullOrUndefined);
}
// TailCall <callable> <receiver> <arg_count> <feedback_slot_id>
@ -2417,7 +2453,7 @@ void InterpreterGenerator::DoCallProperty2(InterpreterAssembler* assembler) {
// |arg_count| arguments in subsequent registers. Collect type feedback
// into |feedback_slot_id|
void InterpreterGenerator::DoTailCall(InterpreterAssembler* assembler) {
DoJSCall(assembler, TailCallMode::kAllow);
DoJSCall(assembler, ConvertReceiverMode::kAny, TailCallMode::kAllow);
}
// CallRuntime <function_id> <first_arg> <arg_count>
@ -2497,7 +2533,7 @@ void InterpreterGenerator::DoCallJSRuntime(InterpreterAssembler* assembler) {
// Call the function.
Node* result = __ CallJS(function, context, first_arg, args_count,
TailCallMode::kDisallow);
ConvertReceiverMode::kAny, TailCallMode::kDisallow);
__ SetAccumulator(result);
__ Dispatch();
}

View File

@ -309,7 +309,7 @@ Node* IntrinsicsGenerator::Call(Node* args_reg, Node* arg_count,
}
Node* result = __ CallJS(function, context, receiver_arg, target_args_count,
TailCallMode::kDisallow);
ConvertReceiverMode::kAny, TailCallMode::kDisallow);
return result;
}

View File

@ -52,28 +52,8 @@ void SetupInterpreter::InstallBytecodeHandlers(Interpreter* interpreter) {
bool SetupInterpreter::ReuseExistingHandler(Address* dispatch_table,
Bytecode bytecode,
OperandScale operand_scale) {
size_t index = Interpreter::GetDispatchTableIndex(bytecode, operand_scale);
switch (bytecode) {
case Bytecode::kCallProperty:
case Bytecode::kCallProperty0:
case Bytecode::kCallProperty1:
case Bytecode::kCallProperty2: {
const int offset = static_cast<int>(Bytecode::kCallProperty) -
static_cast<int>(Bytecode::kCall);
STATIC_ASSERT(offset == static_cast<int>(Bytecode::kCallProperty0) -
static_cast<int>(Bytecode::kCall0));
STATIC_ASSERT(offset == static_cast<int>(Bytecode::kCallProperty1) -
static_cast<int>(Bytecode::kCall1));
STATIC_ASSERT(offset == static_cast<int>(Bytecode::kCallProperty2) -
static_cast<int>(Bytecode::kCall2));
CHECK_LT(offset, index);
dispatch_table[index] = dispatch_table[index - offset];
return true;
break;
}
default:
return false;
}
// TODO(leszeks): reuse Lda[Immutable][Current]ContextSlot
return false;
}
// static

View File

@ -314,7 +314,7 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
@ -324,7 +324,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
@ -336,8 +336,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
a1, // the target to call verified to be Array function

View File

@ -313,7 +313,7 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
@ -323,7 +323,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
@ -335,8 +335,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
a1, // the target to call verified to be Array function

View File

@ -315,7 +315,7 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
r3, // argument count (not including receiver)
@ -325,7 +325,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
r3, // argument count (not including receiver)
@ -337,8 +337,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
Register registers[] = {
r3, // argument count (not including receiver)
r4, // target to call checked to be Array function

View File

@ -299,7 +299,7 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
r2, // argument count (not including receiver)
@ -309,7 +309,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
r2, // argument count (not including receiver)
@ -321,8 +321,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
Register registers[] = {
r2, // argument count (not including receiver)
r3, // target to call checked to be Array function

View File

@ -316,7 +316,7 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
rax, // argument count (not including receiver)
@ -326,7 +326,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
rax, // argument count (not including receiver)
@ -338,8 +338,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
Register registers[] = {
rax, // argument count (not including receiver)
rdx, // target to the call. It is checked to be Array function.

View File

@ -330,7 +330,7 @@ void InterpreterDispatchDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenCallDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
eax, // argument count (not including receiver)
@ -340,7 +340,7 @@ void InterpreterPushArgsAndCallDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
void InterpreterPushArgsThenConstructDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
eax, // argument count (not including receiver)
@ -352,8 +352,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
void InterpreterPushArgsThenConstructArrayDescriptor::
InitializePlatformSpecific(CallInterfaceDescriptorData* data) {
Register registers[] = {
eax, // argument count (not including receiver)
edx, // target to the call. It is checked to be Array function.

View File

@ -12,16 +12,14 @@ snippet: "
function f() { return t(); }
f();
"
frame size: 2
frame size: 1
parameter count: 1
bytecode array length: 14
bytecode array length: 10
bytecodes: [
/* 27 E> */ B(StackCheck),
/* 32 S> */ B(LdaUndefined),
B(Star), R(1),
B(LdaGlobal), U8(0), U8(4),
/* 32 S> */ B(LdaGlobal), U8(0), U8(4),
B(Star), R(0),
/* 39 E> */ B(Call0), R(0), R(1), U8(2),
/* 39 E> */ B(CallUndefinedReceiver0), R(0), U8(2),
/* 44 S> */ B(Return),
]
constant pool: [
@ -36,22 +34,20 @@ snippet: "
function f() { return t(1, 2, 3); }
f();
"
frame size: 5
frame size: 4
parameter count: 1
bytecode array length: 27
bytecode array length: 24
bytecodes: [
/* 34 E> */ B(StackCheck),
/* 39 S> */ B(LdaUndefined),
B(Star), R(1),
B(LdaGlobal), U8(0), U8(4),
/* 39 S> */ B(LdaGlobal), U8(0), U8(4),
B(Star), R(0),
B(LdaSmi), I8(1),
B(Star), R(2),
B(Star), R(1),
B(LdaSmi), I8(2),
B(Star), R(3),
B(Star), R(2),
B(LdaSmi), I8(3),
B(Star), R(4),
/* 46 E> */ B(Call), R(0), R(1), U8(4), U8(2),
B(Star), R(3),
/* 46 E> */ B(CallUndefinedReceiver), R(0), R(1), U8(3), U8(2),
/* 58 S> */ B(Return),
]
constant pool: [

View File

@ -9,9 +9,9 @@ wrap: yes
snippet: "
g = function(){}; eval(''); return g();
"
frame size: 10
frame size: 9
parameter count: 1
bytecode array length: 81
bytecode array length: 73
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
@ -24,29 +24,25 @@ bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(CreateClosure), U8(0), U8(2), U8(2),
/* 36 E> */ B(StaLookupSlotSloppy), U8(1),
/* 52 S> */ B(LdaUndefined),
B(Star), R(2),
/* 52 E> */ B(LdaLookupGlobalSlot), U8(2), U8(5), U8(1),
/* 52 S> */ B(LdaLookupGlobalSlot), U8(2), U8(5), U8(1),
B(Star), R(1),
B(LdaConstant), U8(3),
B(Star), R(3),
B(LdaZero),
B(Star), R(7),
B(LdaSmi), I8(30),
B(Star), R(8),
B(LdaSmi), I8(52),
B(Star), R(9),
B(Mov), R(1), R(4),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1),
/* 52 E> */ B(Call1), R(1), R(2), R(3), U8(3),
/* 62 S> */ B(LdaUndefined),
B(Star), R(2),
/* 69 E> */ B(LdaLookupGlobalSlot), U8(1), U8(9), U8(1),
B(LdaZero),
B(Star), R(6),
B(LdaSmi), I8(30),
B(Star), R(7),
B(LdaSmi), I8(52),
B(Star), R(8),
B(Mov), R(1), R(3),
B(Mov), R(2), R(4),
B(Mov), R(closure), R(5),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(3), U8(6),
B(Star), R(1),
/* 69 E> */ B(Call0), R(1), R(2), U8(7),
/* 52 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(3),
/* 62 S> */ B(LdaLookupGlobalSlot), U8(1), U8(9), U8(1),
B(Star), R(1),
/* 69 E> */ B(CallUndefinedReceiver0), R(1), U8(7),
/* 74 S> */ B(Return),
]
constant pool: [

View File

@ -22,7 +22,7 @@ snippet: "
"
frame size: 6
parameter count: 1
bytecode array length: 33
bytecode array length: 34
bytecodes: [
B(Mov), R(closure), R(0),
/* 99 E> */ B(StackCheck),
@ -34,7 +34,7 @@ bytecodes: [
B(Mov), R(this), R(3),
B(CallRuntime), U16(Runtime::kLoadFromSuper), R(3), U8(3),
B(Star), R(1),
/* 117 E> */ B(Call0), R(1), R(this), U8(2),
/* 117 E> */ B(CallAnyReceiver), R(1), R(this), U8(1), U8(2),
/* 126 E> */ B(AddSmi), I8(1), U8(8),
/* 131 S> */ B(Return),
]

View File

@ -75,18 +75,16 @@ handlers: [
snippet: "
var a; (function() { a = 2; })(); return a;
"
frame size: 3
frame size: 2
parameter count: 1
bytecode array length: 21
bytecode array length: 17
bytecodes: [
B(CreateFunctionContext), U8(1),
B(PushContext), R(0),
/* 30 E> */ B(StackCheck),
/* 41 S> */ B(LdaUndefined),
B(Star), R(2),
B(CreateClosure), U8(0), U8(4), U8(2),
/* 41 S> */ B(CreateClosure), U8(0), U8(4), U8(2),
B(Star), R(1),
/* 64 E> */ B(Call0), R(1), R(2), U8(2),
/* 64 E> */ B(CallUndefinedReceiver0), R(1), U8(2),
/* 68 S> */ B(LdaCurrentContextSlot), U8(4),
/* 78 S> */ B(Return),
]
@ -388,9 +386,9 @@ snippet: "
var b = 100;
return b
"
frame size: 3
frame size: 2
parameter count: 1
bytecode array length: 791
bytecode array length: 787
bytecodes: [
B(CreateFunctionContext), U8(254),
B(PushContext), R(0),
@ -901,11 +899,9 @@ bytecodes: [
/* 3421 E> */ B(StaCurrentContextSlot), U8(254),
/* 3435 S> */ B(LdaZero),
/* 3435 E> */ B(StaCurrentContextSlot), U8(255),
/* 3438 S> */ B(LdaUndefined),
B(Star), R(2),
B(LdaGlobal), U8(0), U8(4),
/* 3438 S> */ B(LdaGlobal), U8(0), U8(4),
B(Star), R(1),
/* 3438 E> */ B(Call0), R(1), R(2), U8(2),
/* 3438 E> */ B(CallUndefinedReceiver0), R(1), U8(2),
/* 3454 S> */ B(LdaSmi), I8(100),
/* 3454 E> */ B(Wide), B(StaCurrentContextSlot), U16(256),
/* 3459 S> */ B(Wide), B(LdaCurrentContextSlot), U16(256),

View File

@ -104,7 +104,7 @@ snippet: "
"
frame size: 4
parameter count: 1
bytecode array length: 31
bytecode array length: 27
bytecodes: [
B(LdaConstant), U8(0),
B(Star), R(1),
@ -113,11 +113,9 @@ bytecodes: [
B(Mov), R(closure), R(3),
B(CallRuntime), U16(Runtime::kDeclareGlobalsForInterpreter), R(1), U8(3),
/* 0 E> */ B(StackCheck),
/* 16 S> */ B(LdaUndefined),
B(Star), R(2),
B(LdaGlobal), U8(1), U8(2),
/* 16 S> */ B(LdaGlobal), U8(1), U8(2),
B(Star), R(1),
/* 16 E> */ B(Call0), R(1), R(2), U8(5),
/* 16 E> */ B(CallUndefinedReceiver0), R(1), U8(5),
B(Star), R(0),
/* 20 S> */ B(Return),
]

View File

@ -9,9 +9,9 @@ wrap: yes
snippet: "
return eval('1;');
"
frame size: 10
frame size: 9
parameter count: 1
bytecode array length: 62
bytecode array length: 58
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
@ -22,24 +22,22 @@ bytecodes: [
B(Ldar), R(new_target),
B(StaCurrentContextSlot), U8(5),
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaUndefined),
B(Star), R(2),
/* 41 E> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
/* 34 S> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
B(Star), R(1),
B(LdaConstant), U8(1),
B(Star), R(3),
B(Star), R(2),
B(LdaZero),
B(Star), R(7),
B(Star), R(6),
B(LdaSmi), I8(30),
B(Star), R(8),
B(Star), R(7),
B(LdaSmi), I8(41),
B(Star), R(9),
B(Mov), R(1), R(4),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(8),
B(Mov), R(1), R(3),
B(Mov), R(2), R(4),
B(Mov), R(closure), R(5),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(3), U8(6),
B(Star), R(1),
/* 41 E> */ B(Call1), R(1), R(2), R(3), U8(2),
/* 41 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(2),
/* 53 S> */ B(Return),
]
constant pool: [

View File

@ -27,16 +27,14 @@ handlers: [
snippet: "
return (function(){ })()
"
frame size: 2
frame size: 1
parameter count: 1
bytecode array length: 15
bytecode array length: 11
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaUndefined),
B(Star), R(1),
B(CreateClosure), U8(0), U8(4), U8(2),
/* 34 S> */ B(CreateClosure), U8(0), U8(4), U8(2),
B(Star), R(0),
/* 56 E> */ B(Call0), R(0), R(1), U8(2),
/* 56 E> */ B(CallUndefinedReceiver0), R(0), U8(2),
/* 59 S> */ B(Return),
]
constant pool: [
@ -49,18 +47,16 @@ handlers: [
snippet: "
return (function(x){ return x; })(1)
"
frame size: 3
frame size: 2
parameter count: 1
bytecode array length: 20
bytecode array length: 16
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaUndefined),
B(Star), R(1),
B(CreateClosure), U8(0), U8(4), U8(2),
/* 34 S> */ B(CreateClosure), U8(0), U8(4), U8(2),
B(Star), R(0),
B(LdaSmi), I8(1),
B(Star), R(2),
/* 67 E> */ B(Call1), R(0), R(1), R(2), U8(2),
B(Star), R(1),
/* 67 E> */ B(CallUndefinedReceiver1), R(0), R(1), U8(2),
/* 71 S> */ B(Return),
]
constant pool: [

View File

@ -10,9 +10,9 @@ test function name: f
snippet: "
eval('var x = 10;'); return x;
"
frame size: 10
frame size: 9
parameter count: 1
bytecode array length: 66
bytecode array length: 62
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
@ -23,24 +23,22 @@ bytecodes: [
B(Ldar), R(new_target),
B(StaCurrentContextSlot), U8(5),
/* 10 E> */ B(StackCheck),
/* 14 S> */ B(LdaUndefined),
B(Star), R(2),
/* 14 E> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
/* 14 S> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
B(Star), R(1),
B(LdaConstant), U8(1),
B(Star), R(3),
B(Star), R(2),
B(LdaZero),
B(Star), R(7),
B(Star), R(6),
B(LdaSmi), I8(10),
B(Star), R(8),
B(Star), R(7),
B(LdaSmi), I8(14),
B(Star), R(9),
B(Mov), R(1), R(4),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(8),
B(Mov), R(1), R(3),
B(Mov), R(2), R(4),
B(Mov), R(closure), R(5),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(3), U8(6),
B(Star), R(1),
/* 14 E> */ B(Call1), R(1), R(2), R(3), U8(2),
/* 14 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(2),
/* 35 S> */ B(LdaLookupGlobalSlot), U8(2), U8(6), U8(1),
/* 45 S> */ B(Return),
]
@ -56,9 +54,9 @@ handlers: [
snippet: "
eval('var x = 10;'); return typeof x;
"
frame size: 10
frame size: 9
parameter count: 1
bytecode array length: 67
bytecode array length: 63
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
@ -69,24 +67,22 @@ bytecodes: [
B(Ldar), R(new_target),
B(StaCurrentContextSlot), U8(5),
/* 10 E> */ B(StackCheck),
/* 14 S> */ B(LdaUndefined),
B(Star), R(2),
/* 14 E> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
/* 14 S> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
B(Star), R(1),
B(LdaConstant), U8(1),
B(Star), R(3),
B(Star), R(2),
B(LdaZero),
B(Star), R(7),
B(Star), R(6),
B(LdaSmi), I8(10),
B(Star), R(8),
B(Star), R(7),
B(LdaSmi), I8(14),
B(Star), R(9),
B(Mov), R(1), R(4),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(8),
B(Mov), R(1), R(3),
B(Mov), R(2), R(4),
B(Mov), R(closure), R(5),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(3), U8(6),
B(Star), R(1),
/* 14 E> */ B(Call1), R(1), R(2), R(3), U8(2),
/* 14 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(2),
/* 35 S> */ B(LdaLookupGlobalSlotInsideTypeof), U8(2), U8(6), U8(1),
B(TypeOf),
/* 52 S> */ B(Return),
@ -103,9 +99,9 @@ handlers: [
snippet: "
x = 20; return eval('');
"
frame size: 10
frame size: 9
parameter count: 1
bytecode array length: 66
bytecode array length: 62
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
@ -118,24 +114,22 @@ bytecodes: [
/* 10 E> */ B(StackCheck),
/* 14 S> */ B(LdaSmi), I8(20),
/* 16 E> */ B(StaLookupSlotSloppy), U8(0),
/* 22 S> */ B(LdaUndefined),
B(Star), R(2),
/* 29 E> */ B(LdaLookupGlobalSlot), U8(1), U8(4), U8(1),
/* 22 S> */ B(LdaLookupGlobalSlot), U8(1), U8(4), U8(1),
B(Star), R(1),
B(LdaConstant), U8(2),
B(Star), R(3),
B(Star), R(2),
B(LdaZero),
B(Star), R(7),
B(Star), R(6),
B(LdaSmi), I8(10),
B(Star), R(8),
B(Star), R(7),
B(LdaSmi), I8(29),
B(Star), R(9),
B(Mov), R(1), R(4),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(8),
B(Mov), R(1), R(3),
B(Mov), R(2), R(4),
B(Mov), R(closure), R(5),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(3), U8(6),
B(Star), R(1),
/* 29 E> */ B(Call1), R(1), R(2), R(3), U8(2),
/* 29 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(2),
/* 39 S> */ B(Return),
]
constant pool: [
@ -155,9 +149,9 @@ snippet: "
}
f();
"
frame size: 10
frame size: 9
parameter count: 1
bytecode array length: 66
bytecode array length: 62
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
@ -168,24 +162,22 @@ bytecodes: [
B(Ldar), R(new_target),
B(StaCurrentContextSlot), U8(5),
/* 38 E> */ B(StackCheck),
/* 44 S> */ B(LdaUndefined),
B(Star), R(2),
/* 44 E> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
/* 44 S> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
B(Star), R(1),
B(LdaConstant), U8(1),
B(Star), R(3),
B(Star), R(2),
B(LdaZero),
B(Star), R(7),
B(Star), R(6),
B(LdaSmi), I8(38),
B(Star), R(8),
B(Star), R(7),
B(LdaSmi), I8(44),
B(Star), R(9),
B(Mov), R(1), R(4),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(8),
B(Mov), R(1), R(3),
B(Mov), R(2), R(4),
B(Mov), R(closure), R(5),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(3), U8(6),
B(Star), R(1),
/* 44 E> */ B(Call1), R(1), R(2), R(3), U8(2),
/* 44 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(2),
/* 66 S> */ B(LdaLookupContextSlot), U8(2), U8(6), U8(1),
/* 76 S> */ B(Return),
]
@ -206,9 +198,9 @@ snippet: "
}
f();
"
frame size: 10
frame size: 9
parameter count: 1
bytecode array length: 66
bytecode array length: 62
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
@ -219,24 +211,22 @@ bytecodes: [
B(Ldar), R(new_target),
B(StaCurrentContextSlot), U8(5),
/* 34 E> */ B(StackCheck),
/* 40 S> */ B(LdaUndefined),
B(Star), R(2),
/* 40 E> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
/* 40 S> */ B(LdaLookupGlobalSlot), U8(0), U8(4), U8(1),
B(Star), R(1),
B(LdaConstant), U8(1),
B(Star), R(3),
B(Star), R(2),
B(LdaZero),
B(Star), R(7),
B(Star), R(6),
B(LdaSmi), I8(34),
B(Star), R(8),
B(Star), R(7),
B(LdaSmi), I8(40),
B(Star), R(9),
B(Mov), R(1), R(4),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(8),
B(Mov), R(1), R(3),
B(Mov), R(2), R(4),
B(Mov), R(closure), R(5),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(3), U8(6),
B(Star), R(1),
/* 40 E> */ B(Call1), R(1), R(2), R(3), U8(2),
/* 40 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(2),
/* 62 S> */ B(LdaLookupGlobalSlot), U8(2), U8(6), U8(1),
/* 72 S> */ B(Return),
]

View File

@ -171,7 +171,7 @@ snippet: "
"
frame size: 10
parameter count: 2
bytecode array length: 213
bytecode array length: 205
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(27),
@ -228,17 +228,15 @@ bytecodes: [
/* 64 S> */ B(Return),
B(Ldar), R(6),
/* 0 E> */ B(Throw),
/* 32 S> */ B(LdaUndefined),
B(Star), R(5),
/* 32 E> */ B(LdaModuleVariable), I8(-1), U8(0),
/* 32 S> */ B(LdaModuleVariable), I8(-1), U8(0),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(1),
B(Star), R(6),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(6), U8(1),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(5), U8(1),
B(Star), R(4),
B(LdaSmi), I8(42),
B(Star), R(6),
/* 32 E> */ B(Call1), R(4), R(5), R(6), U8(2),
B(Star), R(5),
/* 32 E> */ B(CallUndefinedReceiver1), R(4), R(5), U8(2),
B(Ldar), R(closure),
B(CreateBlockContext), U8(2),
B(PushContext), R(1),
@ -246,17 +244,15 @@ bytecodes: [
B(StaCurrentContextSlot), U8(4),
/* 47 S> */ B(LdaUndefined),
/* 47 E> */ B(StaCurrentContextSlot), U8(4),
/* 52 S> */ B(LdaUndefined),
B(Star), R(5),
/* 52 E> */ B(LdaModuleVariable), I8(-1), U8(1),
/* 52 S> */ B(LdaModuleVariable), I8(-1), U8(1),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(1),
B(Star), R(6),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(6), U8(1),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(5), U8(1),
B(Star), R(4),
B(LdaSmi), I8(42),
B(Star), R(6),
/* 52 E> */ B(Call1), R(4), R(5), R(6), U8(4),
B(Star), R(5),
/* 52 E> */ B(CallUndefinedReceiver1), R(4), R(5), U8(4),
B(StaContextSlot), R(1), U8(6), U8(0),
B(PopContext), R(1),
B(LdaCurrentContextSlot), U8(6),

View File

@ -1298,7 +1298,11 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.StoreAccumulatorInRegister(reg)
.MoveRegister(builder.Receiver(), args[0]);
builder.Call(reg, args, call_slot_index, Call::GLOBAL_CALL, tail_call_mode);
if (tail_call_mode == TailCallMode::kAllow) {
builder.TailCall(reg, args, call_slot_index);
} else {
builder.CallProperty(reg, args, call_slot_index);
}
builder.Return();
ast_factory.Internalize(isolate);
@ -1321,7 +1325,11 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
builder.LoadNamedProperty(builder.Receiver(), name, slot_index)
.StoreAccumulatorInRegister(reg)
.MoveRegister(builder.Receiver(), args[0]);
builder.Call(reg, args, call_slot_index, Call::GLOBAL_CALL, tail_call_mode);
if (tail_call_mode == TailCallMode::kAllow) {
builder.TailCall(reg, args, call_slot_index);
} else {
builder.CallProperty(reg, args, call_slot_index);
}
builder.Return();
ast_factory.Internalize(isolate);
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
@ -1353,7 +1361,11 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(Smi::FromInt(11))
.StoreAccumulatorInRegister(args[2]);
builder.Call(reg, args, call_slot_index, Call::GLOBAL_CALL, tail_call_mode);
if (tail_call_mode == TailCallMode::kAllow) {
builder.TailCall(reg, args, call_slot_index);
} else {
builder.CallProperty(reg, args, call_slot_index);
}
builder.Return();
@ -1402,7 +1414,11 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
.LoadLiteral(ast_factory.NewString(ast_factory.GetOneByteString("j")))
.StoreAccumulatorInRegister(args[10]);
builder.Call(reg, args, call_slot_index, Call::GLOBAL_CALL, tail_call_mode);
if (tail_call_mode == TailCallMode::kAllow) {
builder.TailCall(reg, args, call_slot_index);
} else {
builder.CallProperty(reg, args, call_slot_index);
}
builder.Return();

View File

@ -39,8 +39,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
Register reg(0);
Register other(reg.index() + 1);
Register wide(128);
RegisterList reg_list;
RegisterList single(0, 1), pair(0, 2), triple(0, 3);
RegisterList reg_list(0, 10);
RegisterList empty, single(0, 1), pair(0, 2), triple(0, 3);
// Emit argument creation operations.
builder.CreateArguments(CreateArgumentsType::kMappedArguments)
@ -145,16 +145,16 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.CreateObjectLiteral(0, 0, 0, reg);
// Call operations.
builder.Call(reg, reg_list, 1, Call::GLOBAL_CALL)
.Call(reg, single, 1, Call::GLOBAL_CALL)
.Call(reg, pair, 1, Call::GLOBAL_CALL)
.Call(reg, triple, 1, Call::GLOBAL_CALL)
.Call(reg, reg_list, 1, Call::NAMED_PROPERTY_CALL,
TailCallMode::kDisallow)
.Call(reg, single, 1, Call::NAMED_PROPERTY_CALL)
.Call(reg, pair, 1, Call::NAMED_PROPERTY_CALL)
.Call(reg, triple, 1, Call::NAMED_PROPERTY_CALL)
.Call(reg, reg_list, 1, Call::GLOBAL_CALL, TailCallMode::kAllow)
builder.CallAnyReceiver(reg, reg_list, 1)
.CallProperty(reg, reg_list, 1)
.CallProperty(reg, single, 1)
.CallProperty(reg, pair, 1)
.CallProperty(reg, triple, 1)
.CallUndefinedReceiver(reg, reg_list, 1)
.CallUndefinedReceiver(reg, empty, 1)
.CallUndefinedReceiver(reg, single, 1)
.CallUndefinedReceiver(reg, pair, 1)
.TailCall(reg, reg_list, 1)
.CallRuntime(Runtime::kIsArray, reg)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, pair)
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg_list)

View File

@ -38,10 +38,10 @@ TEST(BytecodeDecoder, DecodeBytecodeAndOperands) {
"LdaSmi.ExtraWide [-100000]"},
{{B(Star), R8(5)}, 2, 0, " Star r5"},
{{B(Wide), B(Star), R16(136)}, 4, 0, " Star.Wide r136"},
{{B(Wide), B(Call), R16(134), R16(135), U16(10), U16(177)},
{{B(Wide), B(CallAnyReceiver), R16(134), R16(135), U16(10), U16(177)},
10,
0,
"Call.Wide r134, r135-r144, [177]"},
"CallAnyReceiver.Wide r134, r135-r144, [177]"},
{{B(ForInPrepare), R8(10), R8(11)},
3,
0,

View File

@ -616,25 +616,27 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) {
}
TARGET_TEST_F(InterpreterAssemblerTest, CallJS) {
TailCallMode tail_call_modes[] = {TailCallMode::kDisallow,
TailCallMode::kAllow};
TRACED_FOREACH(TailCallMode, tail_call_mode, tail_call_modes) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
if (Bytecodes::IsCallOrConstruct(bytecode)) {
InterpreterAssemblerTestState state(this, bytecode);
InterpreterAssemblerForTest m(&state, bytecode);
Callable builtin = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, InterpreterPushArgsMode::kOther);
Node* function = m.IntPtrConstant(0);
Node* first_arg = m.IntPtrConstant(1);
Node* arg_count = m.Int32Constant(2);
Node* context = m.IntPtrConstant(3);
Node* call_js =
m.CallJS(function, context, first_arg, arg_count, tail_call_mode);
EXPECT_THAT(call_js,
IsCall(_, IsHeapConstant(builtin.code()), arg_count,
first_arg, function, context, _, _));
}
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
if (Bytecodes::IsCallOrConstruct(bytecode) &&
bytecode != Bytecode::kCallWithSpread) {
InterpreterAssemblerTestState state(this, bytecode);
InterpreterAssemblerForTest m(&state, bytecode);
ConvertReceiverMode receiver_mode = Bytecodes::GetReceiverMode(bytecode);
TailCallMode tail_call_mode = (bytecode == Bytecode::kTailCall)
? TailCallMode::kAllow
: TailCallMode::kDisallow;
Callable builtin = CodeFactory::InterpreterPushArgsThenCall(
isolate(), receiver_mode, tail_call_mode,
InterpreterPushArgsMode::kOther);
Node* function = m.IntPtrConstant(0);
Node* first_arg = m.IntPtrConstant(1);
Node* arg_count = m.Int32Constant(2);
Node* context = m.IntPtrConstant(3);
Node* call_js = m.CallJS(function, context, first_arg, arg_count,
receiver_mode, tail_call_mode);
EXPECT_THAT(call_js, IsCall(_, IsHeapConstant(builtin.code()), arg_count,
first_arg, function, context, _, _));
}
}
}