Commit 9a31162d authored by mythria's avatar mythria Committed by Commit bot

[Interpreter] Collect allocation site feedback in call bytecode handler.

Adds support to collect allocation site feedback for Array function calls
to the call bytecode handler.

BUG=v8:4280, v8:4780
LOG=N

Review-Url: https://codereview.chromium.org/2307903002
Cr-Commit-Position: refs/heads/master@{#39283}
parent 853892a5
......@@ -420,6 +420,17 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
r0, // argument count (not including receiver)
r1, // target to call checked to be Array function
r2, // allocation site feedback if available, undefined otherwise
r3 // address of the first argument
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterCEntryDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
......
......@@ -452,6 +452,17 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
x0, // argument count (not including receiver)
x1, // target to call checked to be Array function
x2, // allocation site feedback if available, undefined otherwise
x3 // address of the first argument
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterCEntryDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
......
......@@ -1162,8 +1162,15 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
__ Jump(lr);
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm, Register index,
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register limit, Register scratch) {
// Find the address of the last argument.
__ mov(limit, num_args);
__ mov(limit, Operand(limit, LSL, kPointerSizeLog2));
__ sub(limit, index, limit);
// TODO(mythria): Add a stack check before pushing arguments.
Label loop_header, loop_check;
__ b(al, &loop_check);
__ bind(&loop_header);
......@@ -1186,14 +1193,10 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// -- r1 : the target to call (can be any Object).
// -----------------------------------
// Find the address of the last argument.
__ add(r3, r0, Operand(1)); // Add one for receiver.
__ mov(r3, Operand(r3, LSL, kPointerSizeLog2));
__ sub(r3, r2, r3);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments.
Generate_InterpreterPushArgs(masm, r2, r3, r4);
// Push the arguments. r2, r4, r5 will be modified.
Generate_InterpreterPushArgs(masm, r3, r2, r4, r5);
// Call the target.
if (function_type == CallableType::kJSFunction) {
......@@ -1219,17 +1222,13 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// -- r4 : address of the first argument
// -----------------------------------
// Find the address of the last argument.
__ mov(r5, Operand(r0, LSL, kPointerSizeLog2));
__ sub(r5, r4, r5);
// Push a slot for the receiver to be constructed.
__ mov(ip, Operand::Zero());
__ push(ip);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments.
Generate_InterpreterPushArgs(masm, r4, r5, r6);
// Push the arguments. r5, r4, r6 will be modified.
Generate_InterpreterPushArgs(masm, r0, r4, r5, r6);
__ AssertUndefinedOrAllocationSite(r2, r5);
if (construct_type == CallableType::kJSFunction) {
......@@ -1249,6 +1248,29 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : argument count (not including receiver)
// -- r1 : target to call verified to be Array function
// -- r2 : allocation site feedback if available, undefined otherwise.
// -- r3 : address of the first argument
// -----------------------------------
__ add(r4, r0, Operand(1)); // Add one for receiver.
// 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);
// Array constructor expects constructor in r3. It is same as r1 here.
__ mov(r3, r1);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
// Set the return address to the correct point in the interpreter entry
// trampoline.
......
......@@ -1171,6 +1171,31 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
__ Ret();
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register last_arg, Register stack_addr,
Register scratch) {
__ Mov(scratch, num_args);
__ lsl(scratch, scratch, kPointerSizeLog2);
__ sub(last_arg, index, scratch);
// Set stack pointer and where to stop.
__ Mov(stack_addr, jssp);
__ Claim(scratch, 1);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments.
Label loop_header, loop_check;
__ B(&loop_check);
__ Bind(&loop_header);
// TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
__ Ldr(scratch, MemOperand(index, -kPointerSize, PostIndex));
__ Str(scratch, MemOperand(stack_addr, -kPointerSize, PreIndex));
__ Bind(&loop_check);
__ Cmp(index, last_arg);
__ B(gt, &loop_header);
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
......@@ -1183,24 +1208,11 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// -- x1 : the target to call (can be any Object).
// -----------------------------------
// Find the address of the last argument.
__ add(x3, x0, Operand(1)); // Add one for receiver.
__ lsl(x3, x3, kPointerSizeLog2);
__ sub(x4, x2, x3);
// Add one for the receiver.
__ add(x3, x0, Operand(1));
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments.
Label loop_header, loop_check;
__ Mov(x5, jssp);
__ Claim(x3, 1);
__ B(&loop_check);
__ Bind(&loop_header);
// TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
__ Ldr(x3, MemOperand(x2, -kPointerSize, PostIndex));
__ Str(x3, MemOperand(x5, -kPointerSize, PreIndex));
__ Bind(&loop_check);
__ Cmp(x2, x4);
__ B(gt, &loop_header);
// Push the arguments. x2, x4, x5, x6 will be modified.
Generate_InterpreterPushArgs(masm, x3, x2, x4, x5, x6);
// Call the target.
if (function_type == CallableType::kJSFunction) {
......@@ -1226,29 +1238,11 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// -- x4 : address of the first argument
// -----------------------------------
// Find the address of the last argument.
__ add(x5, x0, Operand(1)); // Add one for receiver (to be constructed).
__ lsl(x5, x5, kPointerSizeLog2);
// Set stack pointer and where to stop.
__ Mov(x6, jssp);
__ Claim(x5, 1);
__ sub(x7, x6, x5);
// Push a slot for the receiver.
__ Str(xzr, MemOperand(x6, -kPointerSize, PreIndex));
__ Push(xzr);
Label loop_header, loop_check;
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments.
__ B(&loop_check);
__ Bind(&loop_header);
// TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
__ Ldr(x5, MemOperand(x4, -kPointerSize, PostIndex));
__ Str(x5, MemOperand(x6, -kPointerSize, PreIndex));
__ Bind(&loop_check);
__ Cmp(x6, x7);
__ B(gt, &loop_header);
// Push the arguments. x5, x4, x6, x7 will be modified.
Generate_InterpreterPushArgs(masm, x0, x4, x5, x6, x7);
__ AssertUndefinedOrAllocationSite(x2, x6);
if (construct_type == CallableType::kJSFunction) {
......@@ -1267,6 +1261,28 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : argument count (not including receiver)
// -- x1 : target to call verified to be Array function
// -- x2 : allocation site feedback if available, undefined otherwise.
// -- x3 : address of the first argument
// -----------------------------------
__ add(x4, x0, Operand(1)); // Add one for the receiver.
// Push the arguments. x3, x5, x6, x7 will be modified.
Generate_InterpreterPushArgs(masm, x4, x3, x5, x6, x7);
// Array constructor expects constructor in x3. It is same as call target.
__ mov(x3, x1);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
// Set the return address to the correct point in the interpreter entry
// trampoline.
......
......@@ -129,6 +129,7 @@ namespace internal {
ASM(InterpreterPushArgsAndTailCallFunction) \
ASM(InterpreterPushArgsAndConstruct) \
ASM(InterpreterPushArgsAndConstructFunction) \
ASM(InterpreterPushArgsAndConstructArray) \
ASM(InterpreterEnterBytecodeDispatch) \
ASM(InterpreterOnStackReplacement) \
\
......
......@@ -761,42 +761,38 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
}
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edx : the new target
// -- edi : the constructor
// -- ebx : allocation site feedback (if available or undefined)
// -- ecx : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
namespace {
// Store edi, edx onto the stack. We need two extra registers
// so store edi, edx temporarily on stack.
__ Push(edi);
__ Push(edx);
// 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(
MacroAssembler* masm, Register num_args, Register start_addr,
Register scratch1, Register scratch2, bool receiver_in_args) {
// Store scratch2, scratch1 onto the stack. We need to restore the original
// values
// so store scratch2, scratch1 temporarily on stack.
__ Push(scratch2);
__ Push(scratch1);
// We have to pop return address and the two temporary registers before we
// can push arguments onto the stack. we do not have any free registers so
// update the stack and copy them into the correct places on the stack.
// current stack =====> required stack layout
// | | | edx | (2) <-- esp(1)
// | | | edi | (3)
// | | | scratch1 | (2) <-- esp(1)
// | | | scratch2 | (3)
// | | | return addr | (4)
// | | | arg N | (5)
// | edx | <-- esp | .... |
// | edi | | arg 0 |
// | scratch1 | <-- esp | .... |
// | scratch2 | | arg 0 |
// | return addr | | receiver slot |
// First increment the stack pointer to the correct location.
// we need additional slots for arguments and the receiver.
// Step 1 - compute the required increment to the stack.
__ mov(edx, eax);
__ shl(edx, kPointerSizeLog2);
__ add(edx, Immediate(kPointerSize));
__ mov(scratch1, num_args);
__ shl(scratch1, kPointerSizeLog2);
__ add(scratch1, Immediate(kPointerSize));
#ifdef _MSC_VER
// TODO(mythria): Move it to macro assembler.
......@@ -807,12 +803,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
const int page_size = 4 * 1024;
Label check_offset, update_stack_pointer;
__ bind(&check_offset);
__ cmp(edx, page_size);
__ cmp(scratch1, page_size);
__ j(less, &update_stack_pointer);
__ sub(esp, Immediate(page_size));
// Just to touch the page, before we increment further.
__ mov(Operand(esp, 0), Immediate(0));
__ sub(edx, Immediate(page_size));
__ sub(scratch1, Immediate(page_size));
__ jmp(&check_offset);
__ bind(&update_stack_pointer);
#endif
......@@ -820,44 +816,74 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// TODO(mythria): Add a stack check before updating the stack pointer.
// Step 1 - Update the stack pointer.
__ sub(esp, edx);
__ sub(esp, scratch1);
// Step 2 move edx to the correct location. Move edx first otherwise
// we may overwrite when eax = 0 or 1, basically when the source and
// Step 2 move scratch1 to the correct location. Move scratch1 first otherwise
// we may overwrite when num_args = 0 or 1, basically when the source and
// destination overlap. We at least need one extra slot for receiver,
// so no extra checks are required to avoid copy.
__ mov(edi, Operand(esp, eax, times_pointer_size, 1 * kPointerSize));
__ mov(Operand(esp, 0), edi);
__ mov(scratch1,
Operand(esp, num_args, times_pointer_size, 1 * kPointerSize));
__ mov(Operand(esp, 0), scratch1);
// Step 3 move edi to the correct location
__ mov(edi, Operand(esp, eax, times_pointer_size, 2 * kPointerSize));
__ mov(Operand(esp, 1 * kPointerSize), edi);
// Step 3 move scratch2 to the correct location
__ mov(scratch1,
Operand(esp, num_args, times_pointer_size, 2 * kPointerSize));
__ mov(Operand(esp, 1 * kPointerSize), scratch1);
// Step 4 move return address to the correct location
__ mov(edi, Operand(esp, eax, times_pointer_size, 3 * kPointerSize));
__ mov(Operand(esp, 2 * kPointerSize), edi);
// Slot meant for receiver contains return address. Reset it so that
// we will not incorrectly interpret return address as an object.
__ mov(Operand(esp, eax, times_pointer_size, 3 * kPointerSize), Immediate(0));
__ mov(scratch1,
Operand(esp, num_args, times_pointer_size, 3 * kPointerSize));
__ mov(Operand(esp, 2 * kPointerSize), scratch1);
// Step 5 copy arguments to correct locations.
__ mov(edx, eax);
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, 3 * kPointerSize),
Immediate(0));
__ mov(scratch1, num_args);
}
Label loop_header, loop_check;
__ jmp(&loop_check);
__ bind(&loop_header);
__ mov(edi, Operand(ecx, 0));
__ mov(Operand(esp, edx, times_pointer_size, 2 * kPointerSize), edi);
__ sub(ecx, Immediate(kPointerSize));
__ sub(edx, Immediate(1));
__ mov(scratch2, Operand(start_addr, 0));
__ mov(Operand(esp, scratch1, times_pointer_size, 2 * kPointerSize),
scratch2);
__ sub(start_addr, Immediate(kPointerSize));
__ sub(scratch1, Immediate(1));
__ bind(&loop_check);
__ cmp(edx, Immediate(0));
__ cmp(scratch1, Immediate(0));
__ j(greater, &loop_header, Label::kNear);
// Restore edi and edx.
__ Pop(edx);
__ Pop(edi);
// Restore scratch1 and scratch2.
__ Pop(scratch1);
__ Pop(scratch2);
}
} // end anonymous namespace
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edx : the new target
// -- edi : the constructor
// -- ebx : allocation site feedback (if available or undefined)
// -- ecx : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
// 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);
__ AssertUndefinedOrAllocationSite(ebx);
if (construct_type == CallableType::kJSFunction) {
......@@ -877,6 +903,30 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edx : the target to call checked to be Array function.
// -- ebx : the allocation site feedback
// -- ecx : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
// 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, ebx, true);
// Array constructor expects constructor in edi. It is same as edx here.
__ Move(edi, edx);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
// Set the return address to the correct point in the interpreter entry
// trampoline.
......
......@@ -1160,6 +1160,25 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
__ Jump(ra);
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register scratch, Register last_addr) {
// Find the address of the last argument.
__ mov(last_addr, num_args);
__ sll(last_addr, last_addr, kPointerSizeLog2);
__ Subu(last_addr, index, Operand(last_addr));
// Push the arguments.
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ lw(scratch, MemOperand(index));
__ Addu(index, index, Operand(-kPointerSize));
__ push(scratch);
__ bind(&loop_check);
__ Branch(&loop_header, gt, index, Operand(last_addr));
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
......@@ -1172,20 +1191,10 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// -- a1 : the target to call (can be any Object).
// -----------------------------------
// Find the address of the last argument.
__ Addu(a3, a0, Operand(1)); // Add one for receiver.
__ sll(a3, a3, kPointerSizeLog2);
__ Subu(a3, a2, Operand(a3));
__ Addu(t0, a0, Operand(1)); // Add one for receiver.
// Push the arguments.
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ lw(t0, MemOperand(a2));
__ Addu(a2, a2, Operand(-kPointerSize));
__ push(t0);
__ bind(&loop_check);
__ Branch(&loop_header, gt, a2, Operand(a3));
// This function modifies a2, t4 and t1.
Generate_InterpreterPushArgs(masm, t0, a2, t4, t1);
// Call the target.
if (function_type == CallableType::kJSFunction) {
......@@ -1211,22 +1220,11 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// -- t4 : address of the first argument
// -----------------------------------
// Find the address of the last argument.
__ sll(t0, a0, kPointerSizeLog2);
__ Subu(t0, t4, Operand(t0));
// Push a slot for the receiver.
__ push(zero_reg);
// Push the arguments.
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ lw(t1, MemOperand(t4));
__ Addu(t4, t4, Operand(-kPointerSize));
__ push(t1);
__ bind(&loop_check);
__ Branch(&loop_header, gt, t4, Operand(t0));
// This function modified t4, t1 and t0.
Generate_InterpreterPushArgs(masm, a0, t4, t1, t0);
__ AssertUndefinedOrAllocationSite(a2, t0);
if (construct_type == CallableType::kJSFunction) {
......@@ -1245,6 +1243,30 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the target to call checked to be Array function.
// -- a2 : allocation site feedback.
// -- a3 : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
__ Addu(t0, a0, Operand(1)); // Add one for receiver.
// This function modifies a3, t4, and t1.
Generate_InterpreterPushArgs(masm, t0, a3, t1, t4);
// ArrayConstructor stub expects constructor in a3. Set it here.
__ mov(a3, a1);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
// Set the return address to the correct point in the interpreter entry
// trampoline.
......
......@@ -1152,6 +1152,25 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
__ Jump(ra);
}
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args, Register index,
Register last_addr, Register scratch) {
// Find the address of the last argument.
__ mov(last_addr, num_args);
__ dsll(last_addr, last_addr, kPointerSizeLog2);
__ Dsubu(last_addr, index, Operand(last_addr));
// Push the arguments.
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ ld(scratch, MemOperand(index));
__ Daddu(index, index, Operand(-kPointerSize));
__ push(scratch);
__ bind(&loop_check);
__ Branch(&loop_header, gt, index, Operand(last_addr));
}
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
......@@ -1164,20 +1183,10 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// -- a1 : the target to call (can be any Object).
// -----------------------------------
// Find the address of the last argument.
__ Daddu(a3, a0, Operand(1)); // Add one for receiver.
__ dsll(a3, a3, kPointerSizeLog2);
__ Dsubu(a3, a2, Operand(a3));
// Push the arguments.
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ ld(t0, MemOperand(a2));
__ Daddu(a2, a2, Operand(-kPointerSize));
__ push(t0);
__ bind(&loop_check);
__ Branch(&loop_header, gt, a2, Operand(a3));
// This function modifies a2, t0 and a4.
Generate_InterpreterPushArgs(masm, a3, a2, a4, t0);
// Call the target.
if (function_type == CallableType::kJSFunction) {
......@@ -1203,22 +1212,11 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// -- a4 : address of the first argument
// -----------------------------------
// Find the address of the last argument.
__ dsll(t0, a0, kPointerSizeLog2);
__ Dsubu(t0, a4, Operand(t0));
// Push a slot for the receiver.
__ push(zero_reg);
// Push the arguments.
Label loop_header, loop_check;
__ Branch(&loop_check);
__ bind(&loop_header);
__ ld(t1, MemOperand(a4));
__ Daddu(a4, a4, Operand(-kPointerSize));
__ push(t1);
__ bind(&loop_check);
__ Branch(&loop_header, gt, a4, Operand(t0));
// This function modifies t0, a4 and a5.
Generate_InterpreterPushArgs(masm, a0, a4, a5, t0);
__ AssertUndefinedOrAllocationSite(a2, t0);
if (construct_type == CallableType::kJSFunction) {
......@@ -1237,6 +1235,30 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the target to call checked to be Array function.
// -- a2 : allocation site feedback.
// -- a3 : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
__ Daddu(a4, a0, Operand(1)); // Add one for receiver.
// This function modifies a3, a5 and a6.
Generate_InterpreterPushArgs(masm, a4, a3, a5, a6);
// ArrayConstructor stub expects constructor in a3. Set it here.
__ mov(a3, a1);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
// Set the return address to the correct point in the interpreter entry
// trampoline.
......
......@@ -785,24 +785,14 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register num_args,
Register start_address,
Register scratch, bool push_receiver) {
// ----------- 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
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
Register scratch) {
// Find the address of the last argument.
__ movp(scratch, num_args);
if (push_receiver) {
__ addp(scratch, Immediate(1)); // Add one for receiver.
}
__ Move(scratch, num_args);
__ shlp(scratch, Immediate(kPointerSizeLog2));
__ negp(scratch);
__ addp(scratch, start_address);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments.
Label loop_header, loop_check;
__ j(always, &loop_check);
......@@ -829,9 +819,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister);
// TODO(mythria): Add a stack check before pushing arguments.
// rax is readonly rcx and r8 will be modified.
Generate_InterpreterPushArgs(masm, rax, rbx, rcx, true);
// Number of values to be pushed.
__ Move(rcx, rax);
__ addp(rcx, Immediate(1)); // Add one for receiver.
// rbx and rdx will be modified.
Generate_InterpreterPushArgs(masm, rcx, rbx, rdx);
// Call the target.
__ PushReturnAddressFrom(kScratchRegister); // Re-push return address.
......@@ -868,9 +861,8 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Push slot for the receiver to be constructed.
__ Push(Immediate(0));
// TODO(mythria): Add a stack check before pushing arguments.
// rax is readonly rcx and r8 will be modified.
Generate_InterpreterPushArgs(masm, rax, rcx, r8, false);
// rcx and r8 will be modified.
Generate_InterpreterPushArgs(masm, rax, rcx, r8);
// Push return address in preparation for the tail-call.
__ PushReturnAddressFrom(kScratchRegister);
......@@ -893,6 +885,38 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
}
}
// static
void Builtins::Generate_InterpreterPushArgsAndConstructArray(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdx : the target to call checked to be Array function.
// -- rbx : the allocation site feedback
// -- rcx : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack.
// -----------------------------------
// Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister);
// Number of values to be pushed.
__ Move(r8, rax);
__ addp(r8, Immediate(1)); // Add one for receiver.
// rcx and rdi will be modified.
Generate_InterpreterPushArgs(masm, r8, rcx, rdi);
// Push return address in preparation for the tail-call.
__ PushReturnAddressFrom(kScratchRegister);
// Array constructor expects constructor in rdi. It is same as rdx here.
__ Move(rdi, rdx);
ArrayConstructorStub stub(masm->isolate());
__ TailCallStub(&stub);
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
// Set the return address to the correct point in the interpreter entry
// trampoline.
......
......@@ -605,6 +605,12 @@ Callable CodeFactory::InterpreterPushArgsAndConstruct(
InterpreterPushArgsAndConstructDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterPushArgsAndConstructArray(Isolate* isolate) {
return Callable(isolate->builtins()->InterpreterPushArgsAndConstructArray(),
InterpreterPushArgsAndConstructArrayDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterCEntry(Isolate* isolate, int result_size) {
// Note: If we ever use fpregs in the interpreter then we will need to
......
......@@ -162,6 +162,7 @@ class CodeFactory final {
CallableType function_type = CallableType::kAny);
static Callable InterpreterPushArgsAndConstruct(
Isolate* isolate, CallableType function_type = CallableType::kAny);
static Callable InterpreterPushArgsAndConstructArray(Isolate* isolate);
static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1);
static Callable InterpreterOnStackReplacement(Isolate* isolate);
};
......
......@@ -406,6 +406,17 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
eax, // argument count (not including receiver)
edx, // target to the call. It is checked to be Array function.
ebx, // allocation site feedback
ecx, // address of first argument
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterCEntryDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
......
......@@ -15,93 +15,94 @@ namespace internal {
class PlatformInterfaceDescriptor;
#define INTERFACE_DESCRIPTOR_LIST(V) \
V(Void) \
V(ContextOnly) \
V(OnStackWith1Args) \
V(OnStackWith2Args) \
V(OnStackWith3Args) \
V(OnStackWith4Args) \
V(OnStackWith5Args) \
V(OnStackWith6Args) \
V(OnStackWith7Args) \
V(Load) \
V(LoadWithVector) \
V(LoadGlobal) \
V(LoadGlobalWithVector) \
V(Store) \
V(StoreWithVector) \
V(StoreTransition) \
V(VectorStoreTransition) \
V(VarArgFunction) \
V(FastNewClosure) \
V(FastNewFunctionContext) \
V(FastNewObject) \
V(FastNewRestParameter) \
V(FastNewSloppyArguments) \
V(FastNewStrictArguments) \
V(TypeConversion) \
V(Typeof) \
V(FastCloneRegExp) \
V(FastCloneShallowArray) \
V(FastCloneShallowObject) \
V(CreateAllocationSite) \
V(CreateWeakCell) \
V(CallFunction) \
V(CallFunctionWithFeedback) \
V(CallFunctionWithFeedbackAndVector) \
V(CallConstruct) \
V(CallTrampoline) \
V(ConstructStub) \
V(ConstructTrampoline) \
V(RegExpConstructResult) \
V(CopyFastSmiOrObjectElements) \
V(TransitionElementsKind) \
V(AllocateHeapNumber) \
V(AllocateFloat32x4) \
V(AllocateInt32x4) \
V(AllocateUint32x4) \
V(AllocateBool32x4) \
V(AllocateInt16x8) \
V(AllocateUint16x8) \
V(AllocateBool16x8) \
V(AllocateInt8x16) \
V(AllocateUint8x16) \
V(AllocateBool8x16) \
V(ArrayNoArgumentConstructor) \
V(ArraySingleArgumentConstructor) \
V(ArrayNArgumentsConstructor) \
V(Compare) \
V(BinaryOp) \
V(BinaryOpWithAllocationSite) \
V(BinaryOpWithVector) \
V(CountOp) \
V(StringAdd) \
V(StringCompare) \
V(Keyed) \
V(Named) \
V(HasProperty) \
V(ForInFilter) \
V(GetProperty) \
V(CallHandler) \
V(ArgumentAdaptor) \
V(ApiCallbackWith0Args) \
V(ApiCallbackWith1Args) \
V(ApiCallbackWith2Args) \
V(ApiCallbackWith3Args) \
V(ApiCallbackWith4Args) \
V(ApiCallbackWith5Args) \
V(ApiCallbackWith6Args) \
V(ApiCallbackWith7Args) \
V(ApiGetter) \
V(StoreGlobalViaContext) \
V(MathPowTagged) \
V(MathPowInteger) \
V(GrowArrayElements) \
V(InterpreterDispatch) \
V(InterpreterPushArgsAndCall) \
V(InterpreterPushArgsAndConstruct) \
V(InterpreterCEntry) \
#define INTERFACE_DESCRIPTOR_LIST(V) \
V(Void) \
V(ContextOnly) \
V(OnStackWith1Args) \
V(OnStackWith2Args) \
V(OnStackWith3Args) \
V(OnStackWith4Args) \
V(OnStackWith5Args) \
V(OnStackWith6Args) \
V(OnStackWith7Args) \
V(Load) \
V(LoadWithVector) \
V(LoadGlobal) \
V(LoadGlobalWithVector) \
V(Store) \
V(StoreWithVector) \
V(StoreTransition) \
V(VectorStoreTransition) \
V(VarArgFunction) \
V(FastNewClosure) \
V(FastNewFunctionContext) \
V(FastNewObject) \
V(FastNewRestParameter) \
V(FastNewSloppyArguments) \
V(FastNewStrictArguments) \
V(TypeConversion) \
V(Typeof) \
V(FastCloneRegExp) \
V(FastCloneShallowArray) \
V(FastCloneShallowObject) \
V(CreateAllocationSite) \
V(CreateWeakCell) \
V(CallFunction) \
V(CallFunctionWithFeedback) \
V(CallFunctionWithFeedbackAndVector) \
V(CallConstruct) \
V(CallTrampoline) \
V(ConstructStub) \
V(ConstructTrampoline) \
V(RegExpConstructResult) \
V(CopyFastSmiOrObjectElements) \
V(TransitionElementsKind) \
V(AllocateHeapNumber) \
V(AllocateFloat32x4) \
V(AllocateInt32x4) \
V(AllocateUint32x4) \
V(AllocateBool32x4) \
V(AllocateInt16x8) \
V(AllocateUint16x8) \
V(AllocateBool16x8) \
V(AllocateInt8x16) \
V(AllocateUint8x16) \
V(AllocateBool8x16) \
V(ArrayNoArgumentConstructor) \
V(ArraySingleArgumentConstructor) \
V(ArrayNArgumentsConstructor) \
V(Compare) \
V(BinaryOp) \
V(BinaryOpWithAllocationSite) \
V(BinaryOpWithVector) \
V(CountOp) \
V(StringAdd) \
V(StringCompare) \
V(Keyed) \
V(Named) \
V(HasProperty) \
V(ForInFilter) \
V(GetProperty) \
V(CallHandler) \
V(ArgumentAdaptor) \
V(ApiCallbackWith0Args) \
V(ApiCallbackWith1Args) \
V(ApiCallbackWith2Args) \
V(ApiCallbackWith3Args) \
V(ApiCallbackWith4Args) \
V(ApiCallbackWith5Args) \
V(ApiCallbackWith6Args) \
V(ApiCallbackWith7Args) \
V(ApiGetter) \
V(StoreGlobalViaContext) \
V(MathPowTagged) \
V(MathPowInteger) \
V(GrowArrayElements) \
V(InterpreterDispatch) \
V(InterpreterPushArgsAndCall) \
V(InterpreterPushArgsAndConstruct) \
V(InterpreterPushArgsAndConstructArray) \
V(InterpreterCEntry) \
V(ResumeGenerator)
class CallInterfaceDescriptorData {
......@@ -913,6 +914,12 @@ class InterpreterPushArgsAndConstructDescriptor
CallInterfaceDescriptor)
};
class InterpreterPushArgsAndConstructArrayDescriptor
: public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(InterpreterPushArgsAndConstructArrayDescriptor,
CallInterfaceDescriptor)
};
class InterpreterCEntryDescriptor : public CallInterfaceDescriptor {
public:
......
......@@ -481,7 +481,8 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
WeakCell::kValueOffset == Symbol::kHashFieldSlot);
Variable return_value(this, MachineRepresentation::kTagged);
Label handle_monomorphic(this), extra_checks(this), end(this), call(this);
Label handle_monomorphic(this), extra_checks(this), end(this), call(this),
call_function(this);
// Slot id of 0 is used to indicate no typefeedback is available. Call using
// call builtin.
......@@ -523,12 +524,48 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Bind(&extra_checks);
{
Label check_initialized(this, Label::kDeferred), mark_megamorphic(this);
Label check_initialized(this, Label::kDeferred), mark_megamorphic(this),
check_allocation_site(this),
create_allocation_site(this, Label::kDeferred);
// Check if it is a megamorphic target
Node* is_megamorphic = WordEqual(
feedback_element,
HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())));
BranchIf(is_megamorphic, &call, &check_initialized);
BranchIf(is_megamorphic, &call, &check_allocation_site);
Bind(&check_allocation_site);
{
Node* is_allocation_site =
WordEqual(LoadMap(feedback_element),
LoadRoot(Heap::kAllocationSiteMapRootIndex));
GotoUnless(is_allocation_site, &check_initialized);
// If it is not the Array() function, mark megamorphic.
Node* context_slot =
LoadFixedArrayElement(LoadNativeContext(context),
Int32Constant(Context::ARRAY_FUNCTION_INDEX));
Node* is_array_function = WordEqual(context_slot, function);
GotoUnless(is_array_function, &mark_megamorphic);
// It is a monomorphic Array function. Increment the call count.
Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
Node* call_count =
LoadFixedArrayElement(type_feedback_vector, call_count_slot);
Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1)));
// Count is Smi, so we don't need a write barrier.
StoreFixedArrayElement(type_feedback_vector, call_count_slot, new_count,
SKIP_WRITE_BARRIER);
// 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);
}
Bind(&check_initialized);
{
......@@ -548,12 +585,12 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE));
GotoUnless(is_js_function, &mark_megamorphic);
// Check that it is not the Array() function.
// Check if it is the Array() function.
Node* context_slot =
LoadFixedArrayElement(LoadNativeContext(context),
Int32Constant(Context::ARRAY_FUNCTION_INDEX));
Node* is_array_function = WordEqual(context_slot, function);
GotoIf(is_array_function, &mark_megamorphic);
GotoIf(is_array_function, &create_allocation_site);
// Check if the function belongs to the same native context
Node* native_context = LoadNativeContext(
......@@ -572,13 +609,27 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
function);
// Call using call function builtin.
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kJSFunction);
Node* code_target = HeapConstant(callable.code());
Node* ret_value = CallStub(callable.descriptor(), code_target, context,
arg_count, first_arg, function);
return_value.Bind(ret_value);
Goto(&end);
Goto(&call_function);
}
Bind(&create_allocation_site);
{
// TODO(mythria): Inline the creation of the allocation site.
CreateAllocationSiteStub create_stub(isolate());
CallStub(create_stub.GetCallInterfaceDescriptor(),
HeapConstant(create_stub.GetCode()), context,
type_feedback_vector, SmiTag(slot_id));
// Initialize the count to 1.
Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
// Count is Smi, so we don't need a write barrier.
StoreFixedArrayElement(type_feedback_vector, call_count_slot,
SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER);
// Call using CallFunction builtin. CallICs have a PREMONOMORPHIC state.
// They start collecting feedback only when a call is executed the second
// time. So, do not pass any feedback here.
Goto(&call_function);
}
Bind(&mark_megamorphic);
......@@ -595,6 +646,17 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
}
}
Bind(&call_function);
{
Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kJSFunction);
Node* code_target_call = HeapConstant(callable_call.code());
Node* ret_value = CallStub(callable_call.descriptor(), code_target_call,
context, arg_count, first_arg, function);
return_value.Bind(ret_value);
Goto(&end);
}
Bind(&call);
{
// Call using call builtin.
......@@ -764,9 +826,8 @@ Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
Bind(&mark_megamorphic);
{
// MegamorphicSentinel is an immortal immovable object so no
// write-barrier
// is needed.
// MegamorphicSentinel is an immortal immovable object so
// write-barrier is not needed.
Comment("transition to megamorphic");
DCHECK(
Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
......
......@@ -398,6 +398,17 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
a1, // the target to call verified to be Array function
a2, // allocation site feedback
a3, // address of first argument
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterCEntryDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
......
......@@ -397,6 +397,17 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
a0, // argument count (not including receiver)
a1, // the target to call verified to be Array function
a2, // allocation site feedback
a3, // address of first argument
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterCEntryDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
......
......@@ -397,6 +397,17 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterPushArgsAndConstructArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
rax, // argument count (not including receiver)
rdx, // target to the call. It is checked to be Array function.
rbx, // allocation site feedback
rcx, // address of first argument
};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void InterpreterCEntryDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {
......
......@@ -356,9 +356,6 @@
'test-heap/TestCodeFlushingIncremental': [FAIL],
'test-heap/TestCodeFlushingIncrementalAbort': [PASS, ['mode == debug or dcheck_always_on == True', FAIL]],
# TODO(mythria,4780): Related to type feedback support for Array function.
'test-feedback-vector/VectorCallFeedbackForArray': [FAIL],
# TODO(mythria,4680): Lack of code-ageing in interpreter.
'test-heap/Regress169209': [FAIL],
......@@ -392,7 +389,6 @@
'test-cpu-profiler/CollectDeoptEvents': [FAIL],
'test-cpu-profiler/DeoptAtFirstLevelInlinedSource': [FAIL],
'test-cpu-profiler/DeoptAtSecondLevelInlinedSource': [FAIL],
'test-feedback-vector/VectorCallFeedbackForArray': [FAIL],
'test-heap/CompilationCacheCachingBehavior': [FAIL],
'test-heap/Regress169209': [FAIL],
'test-heap/TestCodeFlushing': [FAIL],
......@@ -465,9 +461,6 @@
'test-heap/TestCodeFlushingIncremental': [FAIL],
'test-heap/TestCodeFlushingIncrementalAbort': [PASS, ['mode == debug or dcheck_always_on == True', FAIL]],
# TODO(mythria,4780): Related to type feedback support for Array function.
'test-feedback-vector/VectorCallFeedbackForArray': [FAIL],
# TODO(mythria,4680): Lack of code-ageing in interpreter.
'test-heap/Regress169209': [FAIL],
......
......@@ -638,10 +638,6 @@
# Might trigger stack overflow.
'unicode-test': [SKIP],
# TODO(mythria, 4780): Related to lack of allocation site feedback for calls
# in interpreter.
'array-feedback': [FAIL],
# TODO(4680): Test doesn't know about three tier compiler pipeline.
'assert-opt-and-deopt': [SKIP],
......@@ -710,7 +706,6 @@
##############################################################################
['variant == ignition_staging', {
'array-feedback': [FAIL],
'assert-opt-and-deopt': [SKIP],
'compiler/deopt-inlined-from-call': [FAIL],
'compiler/increment-typefeedback': [FAIL],
......@@ -762,10 +757,6 @@
# Might trigger stack overflow.
'unicode-test': [SKIP],
# TODO(mythria, 4780): Related to lack of allocation site feedback for calls
# in interpreter.
'array-feedback': [FAIL],
'wasm/asm-wasm-f32': [PASS, ['arch in [arm64]', SKIP]],
'wasm/asm-wasm-f64': [PASS, ['arch in [arm64]', SKIP]],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment