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

[Interpreter] Collect type feedback for 'new' in the bytecode handler

Collect type feedback in the bytecode handler for 'new' bytecode. The
earlier cl (https://codereview.chromium.org/2153433002/) was reverted
because that implementation did not collect allocation site feedback.
This regressed delta blue by an order of magnitude. This implementation
includes collection of allocation site feedback.

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

Review-Url: https://codereview.chromium.org/2190293003
Cr-Commit-Position: refs/heads/master@{#38364}
parent 4b4c354b
...@@ -403,7 +403,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific( ...@@ -403,7 +403,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
r0, // argument count (not including receiver) r0, // argument count (not including receiver)
r3, // new target r3, // new target
r1, // constructor to call r1, // constructor to call
r2 // address of the first argument r2, // allocation site feedback if available, undefined otherwise
r4 // address of the first argument
}; };
data->InitializePlatformSpecific(arraysize(registers), registers); data->InitializePlatformSpecific(arraysize(registers), registers);
} }
......
...@@ -435,7 +435,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific( ...@@ -435,7 +435,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
x0, // argument count (not including receiver) x0, // argument count (not including receiver)
x3, // new target x3, // new target
x1, // constructor to call x1, // constructor to call
x2 // address of the first argument x2, // allocation site feedback if available, undefined otherwise
x4 // address of the first argument
}; };
data->InitializePlatformSpecific(arraysize(registers), registers); data->InitializePlatformSpecific(arraysize(registers), registers);
} }
......
...@@ -1189,6 +1189,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1189,6 +1189,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ mov(r3, Operand(r3, LSL, kPointerSizeLog2)); __ mov(r3, Operand(r3, LSL, kPointerSizeLog2));
__ sub(r3, r2, r3); __ sub(r3, r2, r3);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments. // Push the arguments.
Generate_InterpreterPushArgs(masm, r2, r3, r4); Generate_InterpreterPushArgs(masm, r2, r3, r4);
...@@ -1206,27 +1207,44 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1206,27 +1207,44 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r0 : argument count (not including receiver) // -- r0 : argument count (not including receiver)
// -- r3 : new target // -- r3 : new target
// -- r1 : constructor to call // -- r1 : constructor to call
// -- r2 : address of the first argument // -- r2 : allocation site feedback if available, undefined otherwise.
// -- r4 : address of the first argument
// ----------------------------------- // -----------------------------------
// Find the address of the last argument. // Find the address of the last argument.
__ mov(r4, Operand(r0, LSL, kPointerSizeLog2)); __ mov(r5, Operand(r0, LSL, kPointerSizeLog2));
__ sub(r4, r2, r4); __ sub(r5, r4, r5);
// Push a slot for the receiver to be constructed. // Push a slot for the receiver to be constructed.
__ mov(ip, Operand::Zero()); __ mov(ip, Operand::Zero());
__ push(ip); __ push(ip);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments. // Push the arguments.
Generate_InterpreterPushArgs(masm, r2, r4, r5); Generate_InterpreterPushArgs(masm, r4, r5, r6);
// Call the constructor with r0, r1, and r3 unmodified. __ AssertUndefinedOrAllocationSite(r2, r5);
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); if (construct_type == CallableType::kJSFunction) {
__ AssertFunction(r1);
// Tail call to the function-specific construct stub (still in the caller
// context at this point).
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r4, FieldMemOperand(r4, SharedFunctionInfo::kConstructStubOffset));
// Jump to the construct function.
__ add(pc, r4, Operand(Code::kHeaderSize - kHeapObjectTag));
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with r0, r1, and r3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -1186,6 +1186,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1186,6 +1186,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ lsl(x3, x3, kPointerSizeLog2); __ lsl(x3, x3, kPointerSizeLog2);
__ sub(x4, x2, x3); __ sub(x4, x2, x3);
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments. // Push the arguments.
Label loop_header, loop_check; Label loop_header, loop_check;
__ Mov(x5, jssp); __ Mov(x5, jssp);
...@@ -1213,12 +1214,14 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1213,12 +1214,14 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- x0 : argument count (not including receiver) // -- x0 : argument count (not including receiver)
// -- x3 : new target // -- x3 : new target
// -- x1 : constructor to call // -- x1 : constructor to call
// -- x2 : address of the first argument // -- x2 : allocation site feedback if available, undefined otherwise
// -- x4 : address of the first argument
// ----------------------------------- // -----------------------------------
// Find the address of the last argument. // Find the address of the last argument.
...@@ -1228,24 +1231,38 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -1228,24 +1231,38 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// Set stack pointer and where to stop. // Set stack pointer and where to stop.
__ Mov(x6, jssp); __ Mov(x6, jssp);
__ Claim(x5, 1); __ Claim(x5, 1);
__ sub(x4, x6, x5); __ sub(x7, x6, x5);
// Push a slot for the receiver. // Push a slot for the receiver.
__ Str(xzr, MemOperand(x6, -kPointerSize, PreIndex)); __ Str(xzr, MemOperand(x6, -kPointerSize, PreIndex));
Label loop_header, loop_check; Label loop_header, loop_check;
// TODO(mythria): Add a stack check before pushing arguments.
// Push the arguments. // Push the arguments.
__ B(&loop_check); __ B(&loop_check);
__ Bind(&loop_header); __ Bind(&loop_header);
// TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned. // TODO(rmcilroy): Push two at a time once we ensure we keep stack aligned.
__ Ldr(x5, MemOperand(x2, -kPointerSize, PostIndex)); __ Ldr(x5, MemOperand(x4, -kPointerSize, PostIndex));
__ Str(x5, MemOperand(x6, -kPointerSize, PreIndex)); __ Str(x5, MemOperand(x6, -kPointerSize, PreIndex));
__ Bind(&loop_check); __ Bind(&loop_check);
__ Cmp(x6, x4); __ Cmp(x6, x7);
__ B(gt, &loop_header); __ B(gt, &loop_header);
// Call the constructor with x0, x1, and x3 unmodified. __ AssertUndefinedOrAllocationSite(x2, x6);
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); if (construct_type == CallableType::kJSFunction) {
__ AssertFunction(x1);
// Tail call to the function-specific construct stub (still in the caller
// context at this point).
__ Ldr(x4, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(x4, FieldMemOperand(x4, SharedFunctionInfo::kConstructStubOffset));
__ Add(x4, x4, Code::kHeaderSize - kHeapObjectTag);
__ Br(x4);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with x0, x1, and x3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -50,5 +50,27 @@ void Builtins::Generate_InterpreterPushArgsAndTailCallFunction( ...@@ -50,5 +50,27 @@ void Builtins::Generate_InterpreterPushArgsAndTailCallFunction(
CallableType::kJSFunction); CallableType::kJSFunction);
} }
Handle<Code> Builtins::InterpreterPushArgsAndConstruct(
CallableType function_type) {
switch (function_type) {
case CallableType::kJSFunction:
return InterpreterPushArgsAndConstructFunction();
case CallableType::kAny:
return InterpreterPushArgsAndConstruct();
}
UNREACHABLE();
return Handle<Code>::null();
}
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(masm, CallableType::kAny);
}
void Builtins::Generate_InterpreterPushArgsAndConstructFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(
masm, CallableType::kJSFunction);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -126,9 +126,10 @@ namespace internal { ...@@ -126,9 +126,10 @@ namespace internal {
ASM(InterpreterMarkBaselineOnReturn) \ ASM(InterpreterMarkBaselineOnReturn) \
ASM(InterpreterPushArgsAndCall) \ ASM(InterpreterPushArgsAndCall) \
ASM(InterpreterPushArgsAndCallFunction) \ ASM(InterpreterPushArgsAndCallFunction) \
ASM(InterpreterPushArgsAndConstruct) \
ASM(InterpreterPushArgsAndTailCall) \ ASM(InterpreterPushArgsAndTailCall) \
ASM(InterpreterPushArgsAndTailCallFunction) \ ASM(InterpreterPushArgsAndTailCallFunction) \
ASM(InterpreterPushArgsAndConstruct) \
ASM(InterpreterPushArgsAndConstructFunction) \
ASM(InterpreterEnterBytecodeDispatch) \ ASM(InterpreterEnterBytecodeDispatch) \
ASM(InterpreterOnStackReplacement) \ ASM(InterpreterOnStackReplacement) \
\ \
...@@ -581,6 +582,7 @@ class Builtins { ...@@ -581,6 +582,7 @@ class Builtins {
Handle<Code> InterpreterPushArgsAndCall( Handle<Code> InterpreterPushArgsAndCall(
TailCallMode tail_call_mode, TailCallMode tail_call_mode,
CallableType function_type = CallableType::kAny); CallableType function_type = CallableType::kAny);
Handle<Code> InterpreterPushArgsAndConstruct(CallableType function_type);
Code* builtin(Name name) { Code* builtin(Name name) {
// Code::cast cannot be used here since we access builtins // Code::cast cannot be used here since we access builtins
...@@ -625,6 +627,9 @@ class Builtins { ...@@ -625,6 +627,9 @@ class Builtins {
MacroAssembler* masm, TailCallMode tail_call_mode, MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type); CallableType function_type);
static void Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType function_type);
static void Generate_DatePrototype_GetField(MacroAssembler* masm, static void Generate_DatePrototype_GetField(MacroAssembler* masm,
int field_index); int field_index);
......
...@@ -702,19 +702,20 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) { ...@@ -702,19 +702,20 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
} }
static void Generate_InterpreterPushArgs(MacroAssembler* masm, static void Generate_InterpreterPushArgs(MacroAssembler* masm,
Register array_limit) { Register array_limit,
Register start_address) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- ebx : Pointer to the last argument in the args array. // -- start_address : Pointer to the last argument in the args array.
// -- array_limit : Pointer to one before the first argument in the // -- array_limit : Pointer to one before the first argument in the
// args array. // args array.
// ----------------------------------- // -----------------------------------
Label loop_header, loop_check; Label loop_header, loop_check;
__ jmp(&loop_check); __ jmp(&loop_check);
__ bind(&loop_header); __ bind(&loop_header);
__ Push(Operand(ebx, 0)); __ Push(Operand(start_address, 0));
__ sub(ebx, Immediate(kPointerSize)); __ sub(start_address, Immediate(kPointerSize));
__ bind(&loop_check); __ bind(&loop_check);
__ cmp(ebx, array_limit); __ cmp(start_address, array_limit);
__ j(greater, &loop_header, Label::kNear); __ j(greater, &loop_header, Label::kNear);
} }
...@@ -740,7 +741,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -740,7 +741,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
__ neg(ecx); __ neg(ecx);
__ add(ecx, ebx); __ add(ecx, ebx);
Generate_InterpreterPushArgs(masm, ecx); // TODO(mythria): Add a stack check before pushing the arguments.
Generate_InterpreterPushArgs(masm, ecx, ebx);
// Call the target. // Call the target.
__ Push(edx); // Re-push return address. __ Push(edx); // Re-push return address.
...@@ -758,40 +760,115 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -758,40 +760,115 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver) // -- eax : the number of arguments (not including the receiver)
// -- edx : the new target // -- edx : the new target
// -- edi : the constructor // -- edi : the constructor
// -- ebx : the address of the first argument to be pushed. Subsequent // -- 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 // arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack. // they are to be pushed onto the stack.
// ----------------------------------- // -----------------------------------
// Pop return address to allow tail-call after pushing arguments. // Store edi, edx onto the stack. We need two extra registers
__ Pop(ecx); // so store edi, edx temporarily on stack.
// Push edi in the slot meant for receiver. We need an extra register
// so store edi temporarily on stack.
__ Push(edi); __ Push(edi);
__ Push(edx);
// Find the address of the last argument. // We have to pop return address and the two temporary registers before we
__ mov(edi, eax); // can push arguments onto the stack. we do not have any free registers so
__ neg(edi); // update the stack and copy them into the correct places on the stack.
__ shl(edi, kPointerSizeLog2); // current stack =====> required stack layout
__ add(edi, ebx); // | | | edx | (2) <-- esp(1)
// | | | edi | (3)
Generate_InterpreterPushArgs(masm, edi); // | | | return addr | (4)
// | | | arg N | (5)
// | edx | <-- esp | .... |
// | edi | | 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));
#ifdef _MSC_VER
// TODO(mythria): Move it to macro assembler.
// In windows, we cannot increment the stack size by more than one page
// (mimimum page size is 4KB) without accessing at least one byte on the
// page. Check this:
// https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx.
const int page_size = 4 * 1024;
Label check_offset, update_stack_pointer;
__ bind(&check_offset);
__ cmp(edx, 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));
__ jmp(&check_offset);
__ bind(&update_stack_pointer);
#endif
// TODO(mythria): Add a stack check before updating the stack pointer.
// Step 1 - Update the stack pointer.
__ sub(esp, edx);
// 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
// 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);
// 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 4 move return address to the correct location
__ mov(edi, Operand(esp, eax, times_pointer_size, 3 * kPointerSize));
__ mov(Operand(esp, 2 * kPointerSize), edi);
// Step 5 copy arguments to correct locations.
__ mov(edx, eax);
// Restore the constructor from slot on stack. It was pushed at the slot Label loop_header, loop_check;
// meant for receiver. __ jmp(&loop_check);
__ mov(edi, Operand(esp, eax, times_pointer_size, 0)); __ 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));
__ bind(&loop_check);
__ cmp(edx, Immediate(0));
__ j(greater, &loop_header, Label::kNear);
// Re-push return address. // Restore edi and edx.
__ Push(ecx); __ Pop(edx);
__ Pop(edi);
__ AssertUndefinedOrAllocationSite(ebx);
if (construct_type == CallableType::kJSFunction) {
// Tail call to the function-specific construct stub (still in the caller
// context at this point).
__ AssertFunction(edi);
__ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
__ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
__ jmp(ecx);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with unmodified eax, edi, ebi values. // Call the constructor with unmodified eax, edi, edx values.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -1198,17 +1198,19 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1198,17 +1198,19 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argument count (not including receiver) // -- a0 : argument count (not including receiver)
// -- a3 : new target // -- a3 : new target
// -- a1 : constructor to call // -- a1 : constructor to call
// -- a2 : address of the first argument // -- a2 : allocation site feedback if available, undefined otherwise.
// -- t4 : address of the first argument
// ----------------------------------- // -----------------------------------
// Find the address of the last argument. // Find the address of the last argument.
__ sll(t0, a0, kPointerSizeLog2); __ sll(t0, a0, kPointerSizeLog2);
__ Subu(t0, a2, Operand(t0)); __ Subu(t0, t4, Operand(t0));
// Push a slot for the receiver. // Push a slot for the receiver.
__ push(zero_reg); __ push(zero_reg);
...@@ -1217,14 +1219,27 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -1217,14 +1219,27 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
Label loop_header, loop_check; Label loop_header, loop_check;
__ Branch(&loop_check); __ Branch(&loop_check);
__ bind(&loop_header); __ bind(&loop_header);
__ lw(t1, MemOperand(a2)); __ lw(t1, MemOperand(t4));
__ Addu(a2, a2, Operand(-kPointerSize)); __ Addu(t4, t4, Operand(-kPointerSize));
__ push(t1); __ push(t1);
__ bind(&loop_check); __ bind(&loop_check);
__ Branch(&loop_header, gt, a2, Operand(t0)); __ Branch(&loop_header, gt, t4, Operand(t0));
// Call the constructor with a0, a1, and a3 unmodified. __ AssertUndefinedOrAllocationSite(a2, t0);
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); if (construct_type == CallableType::kJSFunction) {
__ AssertFunction(a1);
// Tail call to the function-specific construct stub (still in the caller
// context at this point).
__ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lw(t0, FieldMemOperand(t0, SharedFunctionInfo::kConstructStubOffset));
__ Addu(at, t0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(at);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with a0, a1, and a3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -1190,17 +1190,19 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1190,17 +1190,19 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- a0 : argument count (not including receiver) // -- a0 : argument count (not including receiver)
// -- a3 : new target // -- a3 : new target
// -- a1 : constructor to call // -- a1 : constructor to call
// -- a2 : address of the first argument // -- a2 : allocation site feedback if available, undefined otherwise.
// -- a4 : address of the first argument
// ----------------------------------- // -----------------------------------
// Find the address of the last argument. // Find the address of the last argument.
__ dsll(t0, a0, kPointerSizeLog2); __ dsll(t0, a0, kPointerSizeLog2);
__ Dsubu(t0, a2, Operand(t0)); __ Dsubu(t0, a4, Operand(t0));
// Push a slot for the receiver. // Push a slot for the receiver.
__ push(zero_reg); __ push(zero_reg);
...@@ -1209,14 +1211,27 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -1209,14 +1211,27 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
Label loop_header, loop_check; Label loop_header, loop_check;
__ Branch(&loop_check); __ Branch(&loop_check);
__ bind(&loop_header); __ bind(&loop_header);
__ ld(t1, MemOperand(a2)); __ ld(t1, MemOperand(a4));
__ Daddu(a2, a2, Operand(-kPointerSize)); __ Daddu(a4, a4, Operand(-kPointerSize));
__ push(t1); __ push(t1);
__ bind(&loop_check); __ bind(&loop_check);
__ Branch(&loop_header, gt, a2, Operand(t0)); __ Branch(&loop_header, gt, a4, Operand(t0));
// Call the constructor with a0, a1, and a3 unmodified. __ AssertUndefinedOrAllocationSite(a2, t0);
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); if (construct_type == CallableType::kJSFunction) {
__ AssertFunction(a1);
// Tail call to the function-specific construct stub (still in the caller
// context at this point).
__ ld(a4, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ ld(a4, FieldMemOperand(a4, SharedFunctionInfo::kConstructStubOffset));
__ Daddu(at, a4, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(at);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor with a0, a1, and a3 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -778,7 +778,9 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) { ...@@ -778,7 +778,9 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
} }
static void Generate_InterpreterPushArgs(MacroAssembler* masm, static void Generate_InterpreterPushArgs(MacroAssembler* masm,
bool push_receiver) { Register num_args,
Register start_address,
Register scratch, bool push_receiver) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver) // -- rax : the number of arguments (not including the receiver)
// -- rbx : the address of the first argument to be pushed. Subsequent // -- rbx : the address of the first argument to be pushed. Subsequent
...@@ -787,23 +789,23 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, ...@@ -787,23 +789,23 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// ----------------------------------- // -----------------------------------
// Find the address of the last argument. // Find the address of the last argument.
__ movp(rcx, rax); __ movp(scratch, num_args);
if (push_receiver) { if (push_receiver) {
__ addp(rcx, Immediate(1)); // Add one for receiver. __ addp(scratch, Immediate(1)); // Add one for receiver.
} }
__ shlp(rcx, Immediate(kPointerSizeLog2)); __ shlp(scratch, Immediate(kPointerSizeLog2));
__ negp(rcx); __ negp(scratch);
__ addp(rcx, rbx); __ addp(scratch, start_address);
// Push the arguments. // Push the arguments.
Label loop_header, loop_check; Label loop_header, loop_check;
__ j(always, &loop_check); __ j(always, &loop_check);
__ bind(&loop_header); __ bind(&loop_header);
__ Push(Operand(rbx, 0)); __ Push(Operand(start_address, 0));
__ subp(rbx, Immediate(kPointerSize)); __ subp(start_address, Immediate(kPointerSize));
__ bind(&loop_check); __ bind(&loop_check);
__ cmpp(rbx, rcx); __ cmpp(start_address, scratch);
__ j(greater, &loop_header, Label::kNear); __ j(greater, &loop_header, Label::kNear);
} }
...@@ -822,7 +824,9 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -822,7 +824,9 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Pop return address to allow tail-call after pushing arguments. // Pop return address to allow tail-call after pushing arguments.
__ PopReturnAddressTo(kScratchRegister); __ PopReturnAddressTo(kScratchRegister);
Generate_InterpreterPushArgs(masm, true); // 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);
// Call the target. // Call the target.
__ PushReturnAddressFrom(kScratchRegister); // Re-push return address. __ PushReturnAddressFrom(kScratchRegister); // Re-push return address.
...@@ -840,13 +844,15 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -840,13 +844,15 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
} }
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, CallableType construct_type) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver) // -- rax : the number of arguments (not including the receiver)
// -- rdx : the new target (either the same as the constructor or // -- rdx : the new target (either the same as the constructor or
// the JSFunction on which new was invoked initially) // the JSFunction on which new was invoked initially)
// -- rdi : the constructor to call (can be any Object) // -- rdi : the constructor to call (can be any Object)
// -- rbx : the address of the first argument to be pushed. Subsequent // -- rbx : the allocation site feedback if available, undefined otherwise
// -- rcx : the address of the first argument to be pushed. Subsequent
// arguments should be consecutive above this, in the same order as // arguments should be consecutive above this, in the same order as
// they are to be pushed onto the stack. // they are to be pushed onto the stack.
// ----------------------------------- // -----------------------------------
...@@ -857,13 +863,29 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { ...@@ -857,13 +863,29 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
// Push slot for the receiver to be constructed. // Push slot for the receiver to be constructed.
__ Push(Immediate(0)); __ Push(Immediate(0));
Generate_InterpreterPushArgs(masm, false); // 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);
// Push return address in preparation for the tail-call. // Push return address in preparation for the tail-call.
__ PushReturnAddressFrom(kScratchRegister); __ PushReturnAddressFrom(kScratchRegister);
// Call the constructor (rax, rdx, rdi passed on). __ AssertUndefinedOrAllocationSite(rbx);
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); if (construct_type == CallableType::kJSFunction) {
// Tail call to the function-specific construct stub (still in the caller
// context at this point).
__ AssertFunction(rdi);
__ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
__ movp(rcx, FieldOperand(rcx, SharedFunctionInfo::kConstructStubOffset));
__ leap(rcx, FieldOperand(rcx, Code::kHeaderSize));
// Jump to the constructor function (rax, rbx, rdx passed on).
__ jmp(rcx);
} else {
DCHECK_EQ(construct_type, CallableType::kAny);
// Call the constructor (rax, rdx, rdi passed on).
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
} }
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
...@@ -576,9 +576,11 @@ Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate, ...@@ -576,9 +576,11 @@ Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
} }
// static // static
Callable CodeFactory::InterpreterPushArgsAndConstruct(Isolate* isolate) { Callable CodeFactory::InterpreterPushArgsAndConstruct(
return Callable(isolate->builtins()->InterpreterPushArgsAndConstruct(), Isolate* isolate, CallableType function_type) {
InterpreterPushArgsAndConstructDescriptor(isolate)); return Callable(
isolate->builtins()->InterpreterPushArgsAndConstruct(function_type),
InterpreterPushArgsAndConstructDescriptor(isolate));
} }
// static // static
......
...@@ -156,7 +156,8 @@ class CodeFactory final { ...@@ -156,7 +156,8 @@ class CodeFactory final {
static Callable InterpreterPushArgsAndCall( static Callable InterpreterPushArgsAndCall(
Isolate* isolate, TailCallMode tail_call_mode, Isolate* isolate, TailCallMode tail_call_mode,
CallableType function_type = CallableType::kAny); CallableType function_type = CallableType::kAny);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate); static Callable InterpreterPushArgsAndConstruct(
Isolate* isolate, CallableType function_type = CallableType::kAny);
static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1); static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1);
static Callable InterpreterOnStackReplacement(Isolate* isolate); static Callable InterpreterOnStackReplacement(Isolate* isolate);
}; };
......
...@@ -1094,12 +1094,17 @@ void BytecodeGraphBuilder::VisitNew() { ...@@ -1094,12 +1094,17 @@ void BytecodeGraphBuilder::VisitNew() {
interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0); interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1); interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2); size_t arg_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(TypeFeedbackVector::kReservedIndexCount > 0);
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3));
Node* new_target = environment()->LookupAccumulator(); Node* new_target = environment()->LookupAccumulator();
Node* callee = environment()->LookupRegister(callee_reg); Node* callee = environment()->LookupRegister(callee_reg);
// TODO(turbofan): Pass the feedback here.
const Operator* call = javascript()->CallConstruct( const Operator* call =
static_cast<int>(arg_count) + 2, VectorSlotPair()); javascript()->CallConstruct(static_cast<int>(arg_count) + 2, feedback);
Node* value = ProcessCallNewArguments(call, callee, new_target, first_arg, Node* value = ProcessCallNewArguments(call, callee, new_target, first_arg,
arg_count + 2); arg_count + 2);
environment()->BindAccumulator(value, &states); environment()->BindAccumulator(value, &states);
......
...@@ -389,7 +389,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific( ...@@ -389,7 +389,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
eax, // argument count (not including receiver) eax, // argument count (not including receiver)
edx, // new target edx, // new target
edi, // constructor edi, // constructor
ebx, // address of first argument ebx, // allocation site feedback
ecx, // address of first argument
}; };
data->InitializePlatformSpecific(arraysize(registers), registers); data->InitializePlatformSpecific(arraysize(registers), registers);
} }
......
...@@ -588,13 +588,15 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, ...@@ -588,13 +588,15 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
Register first_arg, Register first_arg,
size_t arg_count) { size_t arg_count,
int feedback_slot_id) {
if (!first_arg.is_valid()) { if (!first_arg.is_valid()) {
DCHECK_EQ(0u, arg_count); DCHECK_EQ(0u, arg_count);
first_arg = Register(0); first_arg = Register(0);
} }
Output(Bytecode::kNew, RegisterOperand(constructor), Output(Bytecode::kNew, RegisterOperand(constructor),
RegisterOperand(first_arg), UnsignedOperand(arg_count)); RegisterOperand(first_arg), UnsignedOperand(arg_count),
UnsignedOperand(feedback_slot_id));
return *this; return *this;
} }
......
...@@ -176,7 +176,7 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -176,7 +176,7 @@ class BytecodeArrayBuilder final : public ZoneObject {
// consecutive arguments starting at |first_arg| for the constuctor // consecutive arguments starting at |first_arg| for the constuctor
// invocation. // invocation.
BytecodeArrayBuilder& New(Register constructor, Register first_arg, BytecodeArrayBuilder& New(Register constructor, Register first_arg,
size_t arg_count); size_t arg_count, int feedback_slot);
// Call the runtime function with |function_id|. The first argument should be // Call the runtime function with |function_id|. The first argument should be
// in |first_arg| and all subsequent arguments should be in registers // in |first_arg| and all subsequent arguments should be in registers
......
...@@ -2619,7 +2619,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { ...@@ -2619,7 +2619,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
if (expr->CallFeedbackICSlot().IsInvalid()) { if (expr->CallFeedbackICSlot().IsInvalid()) {
DCHECK(call_type == Call::POSSIBLY_EVAL_CALL); DCHECK(call_type == Call::POSSIBLY_EVAL_CALL);
// Valid type feedback slots can only be greater than kReservedIndexCount. // Valid type feedback slots can only be greater than kReservedIndexCount.
// We use 0 to indicate an invalid slot it. Statically assert that 0 cannot // We use 0 to indicate an invalid slot id. Statically assert that 0 cannot
// be a valid slot id. // be a valid slot id.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
feedback_slot_index = 0; feedback_slot_index = 0;
...@@ -2654,7 +2654,13 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { ...@@ -2654,7 +2654,13 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
// Call construct. // Call construct.
builder()->SetExpressionPosition(expr); builder()->SetExpressionPosition(expr);
builder()->New(constructor, first_arg, args->length()); // Valid type feedback slots can only be greater than kReservedIndexCount.
// Assert that 0 cannot be valid a valid slot id.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
// Type feedback is not necessary for super constructor calls. The type
// information can be inferred in most cases. Slot id 0 indicates type
// feedback is not required.
builder()->New(constructor, first_arg, args->length(), 0);
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
...@@ -2671,7 +2677,8 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) { ...@@ -2671,7 +2677,8 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) {
// constructor for CallNew. // constructor for CallNew.
builder() builder()
->LoadAccumulatorWithRegister(constructor) ->LoadAccumulatorWithRegister(constructor)
.New(constructor, first_arg, args->length()); .New(constructor, first_arg, args->length(),
feedback_index(expr->CallNewFeedbackSlot()));
execution_result()->SetResultInAccumulator(); execution_result()->SetResultInAccumulator();
} }
......
...@@ -197,7 +197,7 @@ namespace interpreter { ...@@ -197,7 +197,7 @@ namespace interpreter {
\ \
/* New operator */ \ /* New operator */ \
V(New, AccumulatorUse::kReadWrite, OperandType::kReg, \ V(New, AccumulatorUse::kReadWrite, OperandType::kReg, \
OperandType::kMaybeReg, OperandType::kRegCount) \ OperandType::kMaybeReg, OperandType::kRegCount, OperandType::kIdx) \
\ \
/* Test Operators */ \ /* Test Operators */ \
V(TestEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \ V(TestEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \
......
...@@ -489,7 +489,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context, ...@@ -489,7 +489,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0)); Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
GotoIf(is_feedback_unavailable, &call); GotoIf(is_feedback_unavailable, &call);
// The checks. First, does rdi match the recorded monomorphic target? // The checks. First, does function match the recorded monomorphic target?
Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id); Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
Node* feedback_value = LoadWeakCellValue(feedback_element); Node* feedback_value = LoadWeakCellValue(feedback_element);
Node* is_monomorphic = WordEqual(function, feedback_value); Node* is_monomorphic = WordEqual(function, feedback_value);
...@@ -623,11 +623,202 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context, ...@@ -623,11 +623,202 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context,
Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context, Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
Node* new_target, Node* first_arg, Node* new_target, Node* first_arg,
Node* arg_count) { Node* arg_count, Node* slot_id,
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(isolate()); Node* type_feedback_vector) {
Node* code_target = HeapConstant(callable.code()); Label call_construct(this), js_function(this), end(this);
return CallStub(callable.descriptor(), code_target, context, arg_count, Variable return_value(this, MachineRepresentation::kTagged);
new_target, constructor, first_arg); Variable allocation_feedback(this, MachineRepresentation::kTagged);
allocation_feedback.Bind(UndefinedConstant());
// Slot id of 0 is used to indicate no type feedback is available.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
GotoIf(is_feedback_unavailable, &call_construct);
// Check that the constructor is not a smi.
Node* is_smi = WordIsSmi(constructor);
GotoIf(is_smi, &call_construct);
// Check that constructor is a JSFunction.
Node* instance_type = LoadInstanceType(constructor);
Node* is_js_function =
WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE));
BranchIf(is_js_function, &js_function, &call_construct);
Bind(&js_function);
{
// Cache the called function in a feedback vector slot. Cache states
// are uninitialized, monomorphic (indicated by a JSFunction), and
// megamorphic.
// TODO(mythria/v8:5210): Check if it is better to mark extra_checks as a
// deferred block so that call_construct_function will be scheduled just
// after increment_count and in the fast path we can reduce one branch in
// the
// fast path.
Label increment_count(this), extra_checks(this),
call_construct_function(this);
Node* feedback_element =
LoadFixedArrayElement(type_feedback_vector, slot_id);
Node* feedback_value = LoadWeakCellValue(feedback_element);
Node* is_monomorphic = WordEqual(constructor, feedback_value);
BranchIf(is_monomorphic, &increment_count, &extra_checks);
Bind(&extra_checks);
{
Label mark_megamorphic(this), initialize(this),
check_allocation_site(this), check_initialized(this),
set_alloc_feedback_and_inc_count(this);
{
// Check if it is a megamorphic target
Comment("check if megamorphic");
Node* is_megamorphic = WordEqual(
feedback_element,
HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())));
GotoIf(is_megamorphic, &call_construct_function);
Comment("check if weak cell");
Node* is_weak_cell = WordEqual(LoadMap(feedback_element),
LoadRoot(Heap::kWeakCellMapRootIndex));
GotoUnless(is_weak_cell, &check_allocation_site);
// If the weak cell is cleared, we have a new chance to become
// monomorphic.
Comment("check if weak cell is cleared");
Node* is_smi = WordIsSmi(feedback_value);
BranchIf(is_smi, &initialize, &mark_megamorphic);
}
Bind(&check_allocation_site);
{
Comment("check if it is an allocation site");
Node* is_allocation_site =
WordEqual(LoadObjectField(feedback_element, 0),
LoadRoot(Heap::kAllocationSiteMapRootIndex));
GotoUnless(is_allocation_site, &check_initialized);
// Make sure the function is the Array() function
Node* context_slot =
LoadFixedArrayElement(LoadNativeContext(context),
Int32Constant(Context::ARRAY_FUNCTION_INDEX));
Node* is_array_function = WordEqual(context_slot, constructor);
BranchIf(is_array_function, &set_alloc_feedback_and_inc_count,
&mark_megamorphic);
}
Bind(&set_alloc_feedback_and_inc_count);
{
allocation_feedback.Bind(feedback_element);
Goto(&increment_count);
}
Bind(&check_initialized);
{
// Check if it is uninitialized.
Comment("check if uninitialized");
Node* is_uninitialized = WordEqual(
feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex));
BranchIf(is_uninitialized, &initialize, &mark_megamorphic);
}
Bind(&initialize);
{
Label initialize_count(this), create_weak_cell(this),
create_allocation_site(this);
Comment("initialize the feedback element");
// Check that it is the Array() function.
Node* context_slot =
LoadFixedArrayElement(LoadNativeContext(context),
Int32Constant(Context::ARRAY_FUNCTION_INDEX));
Node* is_array_function = WordEqual(context_slot, constructor);
BranchIf(is_array_function, &create_allocation_site, &create_weak_cell);
Bind(&create_allocation_site);
{
// TODO(mythria): Inline the creation of allocation site.
CreateAllocationSiteStub create_stub(isolate());
CallStub(create_stub.GetCallInterfaceDescriptor(),
HeapConstant(create_stub.GetCode()), context,
type_feedback_vector, SmiTag(slot_id));
Node* feedback_element =
LoadFixedArrayElement(type_feedback_vector, slot_id);
allocation_feedback.Bind(feedback_element);
Goto(&initialize_count);
}
Bind(&create_weak_cell);
{
CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id),
constructor);
Goto(&initialize_count);
}
Bind(&initialize_count);
{
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);
Goto(&call_construct_function);
}
}
Bind(&mark_megamorphic);
{
// MegamorphicSentinel is an immortal immovable object so no
// write-barrier
// is needed.
Comment("transition to megamorphic");
DCHECK(
Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex));
StoreFixedArrayElement(
type_feedback_vector, slot_id,
HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())),
SKIP_WRITE_BARRIER);
Goto(&call_construct_function);
}
}
Bind(&increment_count);
{
// Increment the call count.
Comment("increment 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);
Goto(&call_construct_function);
}
Bind(&call_construct_function);
{
Comment("call using callConstructFunction");
Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), CallableType::kJSFunction);
return_value.Bind(CallStub(callable_function.descriptor(),
HeapConstant(callable_function.code()),
context, arg_count, new_target, constructor,
allocation_feedback.value(), first_arg));
Goto(&end);
}
}
Bind(&call_construct);
{
Comment("call using callConstruct builtin");
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), CallableType::kAny);
Node* code_target = HeapConstant(callable.code());
return_value.Bind(CallStub(callable.descriptor(), code_target, context,
arg_count, new_target, constructor,
UndefinedConstant(), first_arg));
Goto(&end);
}
Bind(&end);
return return_value.value();
} }
Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context, Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context,
......
...@@ -120,7 +120,9 @@ class InterpreterAssembler : public CodeStubAssembler { ...@@ -120,7 +120,9 @@ class InterpreterAssembler : public CodeStubAssembler {
compiler::Node* context, compiler::Node* context,
compiler::Node* new_target, compiler::Node* new_target,
compiler::Node* first_arg, compiler::Node* first_arg,
compiler::Node* arg_count); compiler::Node* arg_count,
compiler::Node* slot_id,
compiler::Node* type_feedback_vector);
// Call runtime function with |arg_count| arguments and the first argument // Call runtime function with |arg_count| arguments and the first argument
// located at |first_arg|. // located at |first_arg|.
......
...@@ -1305,9 +1305,11 @@ void Interpreter::DoCallConstruct(InterpreterAssembler* assembler) { ...@@ -1305,9 +1305,11 @@ void Interpreter::DoCallConstruct(InterpreterAssembler* assembler) {
Node* first_arg_reg = __ BytecodeOperandReg(1); Node* first_arg_reg = __ BytecodeOperandReg(1);
Node* first_arg = __ RegisterLocation(first_arg_reg); Node* first_arg = __ RegisterLocation(first_arg_reg);
Node* args_count = __ BytecodeOperandCount(2); Node* args_count = __ BytecodeOperandCount(2);
Node* slot_id = __ BytecodeOperandIdx(3);
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* context = __ GetContext(); Node* context = __ GetContext();
Node* result = Node* result = __ CallConstruct(constructor, context, new_target, first_arg,
__ CallConstruct(constructor, context, new_target, first_arg, args_count); args_count, slot_id, type_feedback_vector);
__ SetAccumulator(result); __ SetAccumulator(result);
__ Dispatch(); __ Dispatch();
} }
......
...@@ -381,7 +381,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific( ...@@ -381,7 +381,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
a0, // argument count (not including receiver) a0, // argument count (not including receiver)
a3, // new target a3, // new target
a1, // constructor to call a1, // constructor to call
a2 // address of the first argument a2, // allocation site feedback if available, undefined otherwise.
t4 // address of the first argument
}; };
data->InitializePlatformSpecific(arraysize(registers), registers); data->InitializePlatformSpecific(arraysize(registers), registers);
} }
......
...@@ -380,7 +380,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific( ...@@ -380,7 +380,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
a0, // argument count (not including receiver) a0, // argument count (not including receiver)
a3, // new target a3, // new target
a1, // constructor to call a1, // constructor to call
a2 // address of the first argument a2, // allocation site feedback if available, undefined otherwise.
a4 // address of the first argument
}; };
data->InitializePlatformSpecific(arraysize(registers), registers); data->InitializePlatformSpecific(arraysize(registers), registers);
} }
......
...@@ -380,7 +380,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific( ...@@ -380,7 +380,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
rax, // argument count (not including receiver) rax, // argument count (not including receiver)
rdx, // new target rdx, // new target
rdi, // constructor rdi, // constructor
rbx, // address of first argument rbx, // allocation site feedback if available, undefined otherwise
rcx, // address of first argument
}; };
data->InitializePlatformSpecific(arraysize(registers), registers); data->InitializePlatformSpecific(arraysize(registers), registers);
} }
......
...@@ -130,12 +130,6 @@ ...@@ -130,12 +130,6 @@
# TODO(mythria,4780): Related to type feedback support for Array function. # TODO(mythria,4780): Related to type feedback support for Array function.
'test-feedback-vector/VectorCallFeedbackForArray': [PASS, NO_IGNITION], 'test-feedback-vector/VectorCallFeedbackForArray': [PASS, NO_IGNITION],
# TODO(mythria,4780): Related to type feedback support for constructor.
'test-feedback-vector/VectorConstructCounts': [PASS, NO_IGNITION],
'test-heap/WeakFunctionInConstructor': [PASS, NO_IGNITION],
'test-heap/IncrementalMarkingClearsMonomorphicConstructor': [PASS, NO_IGNITION],
'test-heap/IncrementalMarkingPreservesMonomorphicConstructor': [PASS, NO_IGNITION],
# TODO(mythria,4680): Lack of code-ageing in interpreter. # TODO(mythria,4680): Lack of code-ageing in interpreter.
'test-heap/Regress169209': [PASS, NO_IGNITION], 'test-heap/Regress169209': [PASS, NO_IGNITION],
...@@ -150,8 +144,8 @@ ...@@ -150,8 +144,8 @@
# BUG(4680): Missing type feedback makes optimistic optimizations fail. # BUG(4680): Missing type feedback makes optimistic optimizations fail.
'test-cpu-profiler/DeoptUntrackedFunction': [PASS, NO_IGNITION], 'test-cpu-profiler/DeoptUntrackedFunction': [PASS, NO_IGNITION],
# BUG(4680): Ignition doesn't support allocation sites currently. # TODO(mythria, 4780): In interpreter we disable mementos when creating array
'test-heap/EnsureAllocationSiteDependentCodesProcessed': [PASS, NO_IGNITION], # literals.
'test-heap/OptimizedPretenuringAllocationFolding': [PASS, NO_IGNITION], 'test-heap/OptimizedPretenuringAllocationFolding': [PASS, NO_IGNITION],
'test-heap/OptimizedPretenuringdoubleArrayLiterals': [PASS, NO_IGNITION], 'test-heap/OptimizedPretenuringdoubleArrayLiterals': [PASS, NO_IGNITION],
'test-heap/OptimizedPretenuringNestedDoubleLiterals': [PASS, NO_IGNITION], 'test-heap/OptimizedPretenuringNestedDoubleLiterals': [PASS, NO_IGNITION],
...@@ -429,12 +423,6 @@ ...@@ -429,12 +423,6 @@
# TODO(mythria,4780): Related to type feedback support for Array function. # TODO(mythria,4780): Related to type feedback support for Array function.
'test-feedback-vector/VectorCallFeedbackForArray': [FAIL], 'test-feedback-vector/VectorCallFeedbackForArray': [FAIL],
# TODO(mythria,4780): Related to type feedback support for constructor.
'test-feedback-vector/VectorConstructCounts': [FAIL],
'test-heap/WeakFunctionInConstructor': [FAIL],
'test-heap/IncrementalMarkingClearsMonomorphicConstructor': [FAIL],
'test-heap/IncrementalMarkingPreservesMonomorphicConstructor': [FAIL],
# TODO(mythria,4680): Lack of code-ageing in interpreter. # TODO(mythria,4680): Lack of code-ageing in interpreter.
'test-heap/Regress169209': [FAIL], 'test-heap/Regress169209': [FAIL],
...@@ -446,8 +434,8 @@ ...@@ -446,8 +434,8 @@
'test-cpu-profiler/CollectDeoptEvents': [FAIL], 'test-cpu-profiler/CollectDeoptEvents': [FAIL],
'test-cpu-profiler/DeoptUntrackedFunction': [FAIL], 'test-cpu-profiler/DeoptUntrackedFunction': [FAIL],
# BUG(4680): Ignition doesn't support allocation sites currently. # TODO(mythria, 4780): In interpreter we disable mementos when creating array
'test-heap/EnsureAllocationSiteDependentCodesProcessed': [FAIL], # literals.
'test-heap/OptimizedPretenuringAllocationFolding': [FAIL], 'test-heap/OptimizedPretenuringAllocationFolding': [FAIL],
'test-heap/OptimizedPretenuringdoubleArrayLiterals': [FAIL], 'test-heap/OptimizedPretenuringdoubleArrayLiterals': [FAIL],
'test-heap/OptimizedPretenuringNestedDoubleLiterals': [FAIL], 'test-heap/OptimizedPretenuringNestedDoubleLiterals': [FAIL],
......
...@@ -16,12 +16,12 @@ snippet: " ...@@ -16,12 +16,12 @@ snippet: "
" "
frame size: 1 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 11 bytecode array length: 12
bytecodes: [ bytecodes: [
/* 45 E> */ B(StackCheck), /* 45 E> */ B(StackCheck),
/* 50 S> */ B(LdrGlobal), U8(3), R(0), /* 50 S> */ B(LdrGlobal), U8(3), R(0),
B(Ldar), R(0), B(Ldar), R(0),
/* 57 E> */ B(New), R(0), R(0), U8(0), /* 57 E> */ B(New), R(0), R(0), U8(0), U8(1),
/* 68 S> */ B(Return), /* 68 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -37,14 +37,14 @@ snippet: " ...@@ -37,14 +37,14 @@ snippet: "
" "
frame size: 2 frame size: 2
parameter count: 1 parameter count: 1
bytecode array length: 15 bytecode array length: 16
bytecodes: [ bytecodes: [
/* 58 E> */ B(StackCheck), /* 58 E> */ B(StackCheck),
/* 63 S> */ B(LdrGlobal), U8(3), R(0), /* 63 S> */ B(LdrGlobal), U8(3), R(0),
B(LdaSmi), U8(3), B(LdaSmi), U8(3),
B(Star), R(1), B(Star), R(1),
B(Ldar), R(0), B(Ldar), R(0),
/* 70 E> */ B(New), R(0), R(1), U8(1), /* 70 E> */ B(New), R(0), R(1), U8(1), U8(1),
/* 82 S> */ B(Return), /* 82 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -65,7 +65,7 @@ snippet: " ...@@ -65,7 +65,7 @@ snippet: "
" "
frame size: 4 frame size: 4
parameter count: 1 parameter count: 1
bytecode array length: 23 bytecode array length: 24
bytecodes: [ bytecodes: [
/* 100 E> */ B(StackCheck), /* 100 E> */ B(StackCheck),
/* 105 S> */ B(LdrGlobal), U8(3), R(0), /* 105 S> */ B(LdrGlobal), U8(3), R(0),
...@@ -76,7 +76,7 @@ bytecodes: [ ...@@ -76,7 +76,7 @@ bytecodes: [
B(LdaSmi), U8(5), B(LdaSmi), U8(5),
B(Star), R(3), B(Star), R(3),
B(Ldar), R(0), B(Ldar), R(0),
/* 112 E> */ B(New), R(0), R(1), U8(3), /* 112 E> */ B(New), R(0), R(1), U8(3), U8(1),
/* 130 S> */ B(Return), /* 130 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -127,7 +127,7 @@ snippet: " ...@@ -127,7 +127,7 @@ snippet: "
" "
frame size: 5 frame size: 5
parameter count: 1 parameter count: 1
bytecode array length: 105 bytecode array length: 106
bytecodes: [ bytecodes: [
B(Mov), R(closure), R(1), B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
...@@ -147,7 +147,7 @@ bytecodes: [ ...@@ -147,7 +147,7 @@ bytecodes: [
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(4), B(Star), R(4),
/* 118 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), /* 118 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1),
/* 118 E> */ B(New), R(2), R(3), U8(1), /* 118 E> */ B(New), R(2), R(3), U8(1), U8(0),
B(Star), R(2), B(Star), R(2),
B(Ldar), R(this), B(Ldar), R(this),
B(JumpIfNotHole), U8(4), B(JumpIfNotHole), U8(4),
...@@ -195,7 +195,7 @@ snippet: " ...@@ -195,7 +195,7 @@ snippet: "
" "
frame size: 4 frame size: 4
parameter count: 1 parameter count: 1
bytecode array length: 101 bytecode array length: 102
bytecodes: [ bytecodes: [
B(Mov), R(closure), R(1), B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0), B(Mov), R(new_target), R(0),
...@@ -213,7 +213,7 @@ bytecodes: [ ...@@ -213,7 +213,7 @@ bytecodes: [
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(3), B(Star), R(3),
/* 117 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(3), U8(1), /* 117 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(3), U8(1),
/* 117 E> */ B(New), R(2), R(0), U8(0), /* 117 E> */ B(New), R(2), R(0), U8(0), U8(0),
B(Star), R(2), B(Star), R(2),
B(Ldar), R(this), B(Ldar), R(this),
B(JumpIfNotHole), U8(4), B(JumpIfNotHole), U8(4),
......
...@@ -196,7 +196,7 @@ snippet: " ...@@ -196,7 +196,7 @@ snippet: "
" "
frame size: 8 frame size: 8
parameter count: 1 parameter count: 1
bytecode array length: 72 bytecode array length: 73
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(1), B(CreateFunctionContext), U8(1),
B(PushContext), R(3), B(PushContext), R(3),
...@@ -227,7 +227,7 @@ bytecodes: [ ...@@ -227,7 +227,7 @@ bytecodes: [
B(Star), R(5), B(Star), R(5),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(5), U8(1), B(CallRuntime), U16(Runtime::kThrowReferenceError), R(5), U8(1),
B(Star), R(4), B(Star), R(4),
/* 94 E> */ B(New), R(4), R(0), U8(0), /* 94 E> */ B(New), R(4), R(0), U8(0), U8(3),
/* 103 S> */ B(Return), /* 103 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -223,10 +223,13 @@ ...@@ -223,10 +223,13 @@
############################################################################ ############################################################################
# Ignition # Ignition
# TODO(mythria, 4780): Related to type feedback for calls in interpreter. # TODO(mythria, 4780): Related to lack of allocation site feedback for calls.
'array-literal-feedback': [PASS, NO_IGNITION],
'regress/regress-4121': [PASS, NO_IGNITION], 'regress/regress-4121': [PASS, NO_IGNITION],
# TODO(mythria, 4780): In interpreter we disable mementos when creating array
# literals.
'array-literal-feedback': [PASS, NO_IGNITION],
# TODO(4680): Test doesn't know about three tier compiler pipeline. # TODO(4680): Test doesn't know about three tier compiler pipeline.
'assert-opt-and-deopt': [PASS, NO_IGNITION], 'assert-opt-and-deopt': [PASS, NO_IGNITION],
...@@ -261,7 +264,6 @@ ...@@ -261,7 +264,6 @@
'smi-mul-const': [PASS, NO_IGNITION], 'smi-mul-const': [PASS, NO_IGNITION],
'smi-mul': [PASS, NO_IGNITION], 'smi-mul': [PASS, NO_IGNITION],
'unary-minus-deopt': [PASS, NO_IGNITION], 'unary-minus-deopt': [PASS, NO_IGNITION],
'array-constructor-feedback': [PASS, NO_IGNITION],
'array-feedback': [PASS, NO_IGNITION], 'array-feedback': [PASS, NO_IGNITION],
'allocation-site-info': [PASS, NO_IGNITION], 'allocation-site-info': [PASS, NO_IGNITION],
...@@ -702,11 +704,14 @@ ...@@ -702,11 +704,14 @@
############################################################################## ##############################################################################
['variant == ignition_turbofan', { ['variant == ignition_turbofan', {
# TODO(mythria, 4780): Related to type feedback for calls in interpreter. # TODO(mythria, 4780): Related to lack of allocation site feedback for calls
'array-literal-feedback': [FAIL], # in interpreter.
'regress/regress-4121': [FAIL], 'regress/regress-4121': [FAIL],
'array-constructor-feedback': [FAIL],
'array-feedback': [FAIL], 'array-feedback': [FAIL],
# TODO(mythria, 4780): In interpreter we disable mementos when creating array
# literals.
'array-literal-feedback': [FAIL],
'allocation-site-info': [FAIL], 'allocation-site-info': [FAIL],
'wasm/asm-wasm-f32': [PASS, ['arch in [arm64]', SKIP]], 'wasm/asm-wasm-f32': [PASS, ['arch in [arm64]', SKIP]],
......
...@@ -165,8 +165,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -165,8 +165,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT); builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT);
// Emit new. // Emit new.
builder.New(reg, reg, 0); builder.New(reg, reg, 0, 1);
builder.New(wide, wide, 0); builder.New(wide, wide, 0, 1);
// Emit test operator invocations. // Emit test operator invocations.
builder.CompareOperation(Token::Value::EQ, reg) builder.CompareOperation(Token::Value::EQ, reg)
...@@ -456,7 +456,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { ...@@ -456,7 +456,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
// Ensure temporaries are used so not optimized away by the // Ensure temporaries are used so not optimized away by the
// register optimizer. // register optimizer.
builder.New(Register(locals + contexts), Register(locals + contexts), builder.New(Register(locals + contexts), Register(locals + contexts),
static_cast<size_t>(temps)); static_cast<size_t>(temps), 0);
} }
builder.Return(); builder.Return();
......
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