[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. Reland of https://codereview.chromium.org/2190293003/ with a bug fix. BUG=v8:4280, v8:4780 LOG=N Review-Url: https://codereview.chromium.org/2225923003 Cr-Commit-Position: refs/heads/master@{#39120}
This commit is contained in:
parent
836299aa9c
commit
7e5b8feed3
@ -414,7 +414,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
|
||||
r0, // argument count (not including receiver)
|
||||
r3, // new target
|
||||
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);
|
||||
}
|
||||
|
@ -446,7 +446,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
|
||||
x0, // argument count (not including receiver)
|
||||
x3, // new target
|
||||
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);
|
||||
}
|
||||
|
@ -1191,6 +1191,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
__ 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);
|
||||
|
||||
@ -1208,27 +1209,44 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
|
||||
MacroAssembler* masm, CallableType construct_type) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : argument count (not including receiver)
|
||||
// -- r3 : new target
|
||||
// -- 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.
|
||||
__ mov(r4, Operand(r0, LSL, kPointerSizeLog2));
|
||||
__ sub(r4, r2, r4);
|
||||
__ 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, r2, r4, r5);
|
||||
Generate_InterpreterPushArgs(masm, r4, r5, r6);
|
||||
|
||||
// Call the constructor with r0, r1, and r3 unmodified.
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
__ AssertUndefinedOrAllocationSite(r2, r5);
|
||||
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) {
|
||||
|
@ -1188,6 +1188,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
__ lsl(x3, x3, kPointerSizeLog2);
|
||||
__ sub(x4, x2, x3);
|
||||
|
||||
// TODO(mythria): Add a stack check before pushing arguments.
|
||||
// Push the arguments.
|
||||
Label loop_header, loop_check;
|
||||
__ Mov(x5, jssp);
|
||||
@ -1215,12 +1216,14 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
|
||||
MacroAssembler* masm, CallableType construct_type) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- x0 : argument count (not including receiver)
|
||||
// -- x3 : new target
|
||||
// -- 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.
|
||||
@ -1230,24 +1233,38 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
// Set stack pointer and where to stop.
|
||||
__ Mov(x6, jssp);
|
||||
__ Claim(x5, 1);
|
||||
__ sub(x4, x6, x5);
|
||||
__ sub(x7, x6, x5);
|
||||
|
||||
// Push a slot for the receiver.
|
||||
__ Str(xzr, MemOperand(x6, -kPointerSize, PreIndex));
|
||||
|
||||
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(x2, -kPointerSize, PostIndex));
|
||||
__ Ldr(x5, MemOperand(x4, -kPointerSize, PostIndex));
|
||||
__ Str(x5, MemOperand(x6, -kPointerSize, PreIndex));
|
||||
__ Bind(&loop_check);
|
||||
__ Cmp(x6, x4);
|
||||
__ Cmp(x6, x7);
|
||||
__ B(gt, &loop_header);
|
||||
|
||||
// Call the constructor with x0, x1, and x3 unmodified.
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
__ AssertUndefinedOrAllocationSite(x2, x6);
|
||||
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) {
|
||||
|
@ -50,5 +50,27 @@ void Builtins::Generate_InterpreterPushArgsAndTailCallFunction(
|
||||
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 v8
|
||||
|
@ -123,9 +123,10 @@ namespace internal {
|
||||
ASM(InterpreterMarkBaselineOnReturn) \
|
||||
ASM(InterpreterPushArgsAndCall) \
|
||||
ASM(InterpreterPushArgsAndCallFunction) \
|
||||
ASM(InterpreterPushArgsAndConstruct) \
|
||||
ASM(InterpreterPushArgsAndTailCall) \
|
||||
ASM(InterpreterPushArgsAndTailCallFunction) \
|
||||
ASM(InterpreterPushArgsAndConstruct) \
|
||||
ASM(InterpreterPushArgsAndConstructFunction) \
|
||||
ASM(InterpreterEnterBytecodeDispatch) \
|
||||
ASM(InterpreterOnStackReplacement) \
|
||||
\
|
||||
@ -618,6 +619,7 @@ class Builtins {
|
||||
Handle<Code> InterpreterPushArgsAndCall(
|
||||
TailCallMode tail_call_mode,
|
||||
CallableType function_type = CallableType::kAny);
|
||||
Handle<Code> InterpreterPushArgsAndConstruct(CallableType function_type);
|
||||
|
||||
Code* builtin(Name name) {
|
||||
// Code::cast cannot be used here since we access builtins
|
||||
@ -671,6 +673,9 @@ class Builtins {
|
||||
MacroAssembler* masm, TailCallMode tail_call_mode,
|
||||
CallableType function_type);
|
||||
|
||||
static void Generate_InterpreterPushArgsAndConstructImpl(
|
||||
MacroAssembler* masm, CallableType function_type);
|
||||
|
||||
static void Generate_DatePrototype_GetField(MacroAssembler* masm,
|
||||
int field_index);
|
||||
|
||||
|
@ -704,19 +704,20 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
static void Generate_InterpreterPushArgs(MacroAssembler* masm,
|
||||
Register array_limit) {
|
||||
Register array_limit,
|
||||
Register start_address) {
|
||||
// ----------- 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
|
||||
// args array.
|
||||
// -----------------------------------
|
||||
Label loop_header, loop_check;
|
||||
__ jmp(&loop_check);
|
||||
__ bind(&loop_header);
|
||||
__ Push(Operand(ebx, 0));
|
||||
__ sub(ebx, Immediate(kPointerSize));
|
||||
__ Push(Operand(start_address, 0));
|
||||
__ sub(start_address, Immediate(kPointerSize));
|
||||
__ bind(&loop_check);
|
||||
__ cmp(ebx, array_limit);
|
||||
__ cmp(start_address, array_limit);
|
||||
__ j(greater, &loop_header, Label::kNear);
|
||||
}
|
||||
|
||||
@ -742,7 +743,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
__ neg(ecx);
|
||||
__ 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.
|
||||
__ Push(edx); // Re-push return address.
|
||||
@ -760,40 +762,119 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
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 : 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
|
||||
// they are to be pushed onto the stack.
|
||||
// -----------------------------------
|
||||
|
||||
// Pop return address to allow tail-call after pushing arguments.
|
||||
__ Pop(ecx);
|
||||
|
||||
// Push edi in the slot meant for receiver. We need an extra register
|
||||
// so store edi temporarily on stack.
|
||||
// Store edi, edx onto the stack. We need two extra registers
|
||||
// so store edi, edx temporarily on stack.
|
||||
__ Push(edi);
|
||||
__ Push(edx);
|
||||
|
||||
// Find the address of the last argument.
|
||||
__ mov(edi, eax);
|
||||
__ neg(edi);
|
||||
__ shl(edi, kPointerSizeLog2);
|
||||
__ add(edi, ebx);
|
||||
// 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)
|
||||
// | | | return addr | (4)
|
||||
// | | | arg N | (5)
|
||||
// | edx | <-- esp | .... |
|
||||
// | edi | | arg 0 |
|
||||
// | return addr | | receiver slot |
|
||||
|
||||
Generate_InterpreterPushArgs(masm, edi);
|
||||
// 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));
|
||||
|
||||
// Restore the constructor from slot on stack. It was pushed at the slot
|
||||
// meant for receiver.
|
||||
__ mov(edi, Operand(esp, eax, times_pointer_size, 0));
|
||||
#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
|
||||
|
||||
// Re-push return address.
|
||||
__ Push(ecx);
|
||||
// TODO(mythria): Add a stack check before updating the stack pointer.
|
||||
|
||||
// Call the constructor with unmodified eax, edi, ebi values.
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
// 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);
|
||||
|
||||
// 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));
|
||||
|
||||
// Step 5 copy arguments to correct locations.
|
||||
__ mov(edx, eax);
|
||||
|
||||
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));
|
||||
__ bind(&loop_check);
|
||||
__ cmp(edx, Immediate(0));
|
||||
__ j(greater, &loop_header, Label::kNear);
|
||||
|
||||
// Restore edi and edx.
|
||||
__ 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, edx values.
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
}
|
||||
}
|
||||
|
||||
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
|
||||
|
@ -1201,17 +1201,19 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
|
||||
MacroAssembler* masm, CallableType construct_type) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argument count (not including receiver)
|
||||
// -- a3 : new target
|
||||
// -- 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.
|
||||
__ sll(t0, a0, kPointerSizeLog2);
|
||||
__ Subu(t0, a2, Operand(t0));
|
||||
__ Subu(t0, t4, Operand(t0));
|
||||
|
||||
// Push a slot for the receiver.
|
||||
__ push(zero_reg);
|
||||
@ -1220,14 +1222,27 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
Label loop_header, loop_check;
|
||||
__ Branch(&loop_check);
|
||||
__ bind(&loop_header);
|
||||
__ lw(t1, MemOperand(a2));
|
||||
__ Addu(a2, a2, Operand(-kPointerSize));
|
||||
__ lw(t1, MemOperand(t4));
|
||||
__ Addu(t4, t4, Operand(-kPointerSize));
|
||||
__ push(t1);
|
||||
__ 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.
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
__ AssertUndefinedOrAllocationSite(a2, t0);
|
||||
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) {
|
||||
|
@ -1193,17 +1193,19 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
|
||||
MacroAssembler* masm, CallableType construct_type) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : argument count (not including receiver)
|
||||
// -- a3 : new target
|
||||
// -- 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.
|
||||
__ dsll(t0, a0, kPointerSizeLog2);
|
||||
__ Dsubu(t0, a2, Operand(t0));
|
||||
__ Dsubu(t0, a4, Operand(t0));
|
||||
|
||||
// Push a slot for the receiver.
|
||||
__ push(zero_reg);
|
||||
@ -1212,14 +1214,27 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
Label loop_header, loop_check;
|
||||
__ Branch(&loop_check);
|
||||
__ bind(&loop_header);
|
||||
__ ld(t1, MemOperand(a2));
|
||||
__ Daddu(a2, a2, Operand(-kPointerSize));
|
||||
__ ld(t1, MemOperand(a4));
|
||||
__ Daddu(a4, a4, Operand(-kPointerSize));
|
||||
__ push(t1);
|
||||
__ 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.
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
__ AssertUndefinedOrAllocationSite(a2, t0);
|
||||
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) {
|
||||
|
@ -783,7 +783,9 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(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 -------------
|
||||
// -- rax : the number of arguments (not including the receiver)
|
||||
// -- rbx : the address of the first argument to be pushed. Subsequent
|
||||
@ -792,23 +794,23 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
|
||||
// -----------------------------------
|
||||
|
||||
// Find the address of the last argument.
|
||||
__ movp(rcx, rax);
|
||||
__ movp(scratch, num_args);
|
||||
if (push_receiver) {
|
||||
__ addp(rcx, Immediate(1)); // Add one for receiver.
|
||||
__ addp(scratch, Immediate(1)); // Add one for receiver.
|
||||
}
|
||||
|
||||
__ shlp(rcx, Immediate(kPointerSizeLog2));
|
||||
__ negp(rcx);
|
||||
__ addp(rcx, rbx);
|
||||
__ shlp(scratch, Immediate(kPointerSizeLog2));
|
||||
__ negp(scratch);
|
||||
__ addp(scratch, start_address);
|
||||
|
||||
// Push the arguments.
|
||||
Label loop_header, loop_check;
|
||||
__ j(always, &loop_check);
|
||||
__ bind(&loop_header);
|
||||
__ Push(Operand(rbx, 0));
|
||||
__ subp(rbx, Immediate(kPointerSize));
|
||||
__ Push(Operand(start_address, 0));
|
||||
__ subp(start_address, Immediate(kPointerSize));
|
||||
__ bind(&loop_check);
|
||||
__ cmpp(rbx, rcx);
|
||||
__ cmpp(start_address, scratch);
|
||||
__ j(greater, &loop_header, Label::kNear);
|
||||
}
|
||||
|
||||
@ -827,7 +829,9 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
// Pop return address to allow tail-call after pushing arguments.
|
||||
__ 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.
|
||||
__ PushReturnAddressFrom(kScratchRegister); // Re-push return address.
|
||||
@ -845,13 +849,15 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
||||
}
|
||||
|
||||
// static
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
|
||||
MacroAssembler* masm, CallableType construct_type) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : the number of arguments (not including the receiver)
|
||||
// -- rdx : the new target (either the same as the constructor or
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -- 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
|
||||
// they are to be pushed onto the stack.
|
||||
// -----------------------------------
|
||||
@ -862,13 +868,29 @@ void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
|
||||
// Push slot for the receiver to be constructed.
|
||||
__ 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.
|
||||
__ PushReturnAddressFrom(kScratchRegister);
|
||||
|
||||
// Call the constructor (rax, rdx, rdi passed on).
|
||||
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
|
||||
__ AssertUndefinedOrAllocationSite(rbx);
|
||||
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) {
|
||||
|
@ -594,9 +594,11 @@ Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::InterpreterPushArgsAndConstruct(Isolate* isolate) {
|
||||
return Callable(isolate->builtins()->InterpreterPushArgsAndConstruct(),
|
||||
InterpreterPushArgsAndConstructDescriptor(isolate));
|
||||
Callable CodeFactory::InterpreterPushArgsAndConstruct(
|
||||
Isolate* isolate, CallableType function_type) {
|
||||
return Callable(
|
||||
isolate->builtins()->InterpreterPushArgsAndConstruct(function_type),
|
||||
InterpreterPushArgsAndConstructDescriptor(isolate));
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -160,7 +160,8 @@ class CodeFactory final {
|
||||
static Callable InterpreterPushArgsAndCall(
|
||||
Isolate* isolate, TailCallMode tail_call_mode,
|
||||
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 InterpreterOnStackReplacement(Isolate* isolate);
|
||||
};
|
||||
|
@ -1160,12 +1160,17 @@ void BytecodeGraphBuilder::VisitNew() {
|
||||
interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
|
||||
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
|
||||
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* callee = environment()->LookupRegister(callee_reg);
|
||||
// TODO(turbofan): Pass the feedback here.
|
||||
const Operator* call = javascript()->CallConstruct(
|
||||
static_cast<int>(arg_count) + 2, VectorSlotPair());
|
||||
|
||||
const Operator* call =
|
||||
javascript()->CallConstruct(static_cast<int>(arg_count) + 2, feedback);
|
||||
Node* value = ProcessCallNewArguments(call, callee, new_target, first_arg,
|
||||
arg_count + 2);
|
||||
environment()->BindAccumulator(value, &states);
|
||||
|
@ -400,7 +400,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
|
||||
eax, // argument count (not including receiver)
|
||||
edx, // new target
|
||||
edi, // constructor
|
||||
ebx, // address of first argument
|
||||
ebx, // allocation site feedback
|
||||
ecx, // address of first argument
|
||||
};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
@ -616,13 +616,15 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
|
||||
Register first_arg,
|
||||
size_t arg_count) {
|
||||
size_t arg_count,
|
||||
int feedback_slot_id) {
|
||||
if (!first_arg.is_valid()) {
|
||||
DCHECK_EQ(0u, arg_count);
|
||||
first_arg = Register(0);
|
||||
}
|
||||
Output(Bytecode::kNew, RegisterOperand(constructor),
|
||||
RegisterOperand(first_arg), UnsignedOperand(arg_count));
|
||||
RegisterOperand(first_arg), UnsignedOperand(arg_count),
|
||||
UnsignedOperand(feedback_slot_id));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ class BytecodeArrayBuilder final : public ZoneObject {
|
||||
// consecutive arguments starting at |first_arg| for the constuctor
|
||||
// invocation.
|
||||
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
|
||||
// in |first_arg| and all subsequent arguments should be in registers
|
||||
|
@ -2674,7 +2674,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
||||
if (expr->CallFeedbackICSlot().IsInvalid()) {
|
||||
DCHECK(call_type == Call::POSSIBLY_EVAL_CALL);
|
||||
// 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.
|
||||
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
|
||||
feedback_slot_index = 0;
|
||||
@ -2709,7 +2709,13 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
|
||||
|
||||
// Call construct.
|
||||
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();
|
||||
}
|
||||
|
||||
@ -2726,7 +2732,8 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) {
|
||||
// constructor for CallNew.
|
||||
builder()
|
||||
->LoadAccumulatorWithRegister(constructor)
|
||||
.New(constructor, first_arg, args->length());
|
||||
.New(constructor, first_arg, args->length(),
|
||||
feedback_index(expr->CallNewFeedbackSlot()));
|
||||
execution_result()->SetResultInAccumulator();
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ namespace interpreter {
|
||||
\
|
||||
/* New operator */ \
|
||||
V(New, AccumulatorUse::kReadWrite, OperandType::kReg, \
|
||||
OperandType::kMaybeReg, OperandType::kRegCount) \
|
||||
OperandType::kMaybeReg, OperandType::kRegCount, OperandType::kIdx) \
|
||||
\
|
||||
/* Test Operators */ \
|
||||
V(TestEqual, AccumulatorUse::kReadWrite, OperandType::kReg, \
|
||||
|
@ -489,7 +489,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
|
||||
Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
|
||||
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_value = LoadWeakCellValue(feedback_element);
|
||||
Node* is_monomorphic = WordEqual(function, feedback_value);
|
||||
@ -623,11 +623,202 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context,
|
||||
|
||||
Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
|
||||
Node* new_target, Node* first_arg,
|
||||
Node* arg_count) {
|
||||
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(isolate());
|
||||
Node* code_target = HeapConstant(callable.code());
|
||||
return CallStub(callable.descriptor(), code_target, context, arg_count,
|
||||
new_target, constructor, first_arg);
|
||||
Node* arg_count, Node* slot_id,
|
||||
Node* type_feedback_vector) {
|
||||
Label call_construct(this), js_function(this), end(this);
|
||||
Variable return_value(this, MachineRepresentation::kTagged);
|
||||
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,
|
||||
|
@ -120,7 +120,9 @@ class InterpreterAssembler : public CodeStubAssembler {
|
||||
compiler::Node* context,
|
||||
compiler::Node* new_target,
|
||||
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
|
||||
// located at |first_arg|.
|
||||
|
@ -1575,9 +1575,11 @@ void Interpreter::DoCallConstruct(InterpreterAssembler* assembler) {
|
||||
Node* first_arg_reg = __ BytecodeOperandReg(1);
|
||||
Node* first_arg = __ RegisterLocation(first_arg_reg);
|
||||
Node* args_count = __ BytecodeOperandCount(2);
|
||||
Node* slot_id = __ BytecodeOperandIdx(3);
|
||||
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
|
||||
Node* context = __ GetContext();
|
||||
Node* result =
|
||||
__ CallConstruct(constructor, context, new_target, first_arg, args_count);
|
||||
Node* result = __ CallConstruct(constructor, context, new_target, first_arg,
|
||||
args_count, slot_id, type_feedback_vector);
|
||||
__ SetAccumulator(result);
|
||||
__ Dispatch();
|
||||
}
|
||||
|
@ -392,7 +392,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
|
||||
a0, // argument count (not including receiver)
|
||||
a3, // new target
|
||||
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);
|
||||
}
|
||||
|
@ -391,7 +391,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
|
||||
a0, // argument count (not including receiver)
|
||||
a3, // new target
|
||||
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);
|
||||
}
|
||||
|
@ -391,7 +391,8 @@ void InterpreterPushArgsAndConstructDescriptor::InitializePlatformSpecific(
|
||||
rax, // argument count (not including receiver)
|
||||
rdx, // new target
|
||||
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);
|
||||
}
|
||||
|
@ -352,11 +352,6 @@
|
||||
# TODO(mythria,4780): Related to type feedback support for Array function.
|
||||
'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/IncrementalMarkingPreservesMonomorphicConstructor': [FAIL],
|
||||
|
||||
# TODO(mythria,4680): Lack of code-ageing in interpreter.
|
||||
'test-heap/Regress169209': [FAIL],
|
||||
|
||||
@ -372,8 +367,7 @@
|
||||
'test-cpu-profiler/CollectDeoptEvents': [FAIL],
|
||||
'test-cpu-profiler/DeoptUntrackedFunction': [SKIP],
|
||||
|
||||
# BUG(4680): Ignition doesn't support allocation sites currently.
|
||||
'test-heap/EnsureAllocationSiteDependentCodesProcessed': [FAIL],
|
||||
# BUG(4680): Ignition doesn't support mementos when creating array literals.
|
||||
'test-heap/OptimizedPretenuringAllocationFolding': [FAIL],
|
||||
'test-heap/OptimizedPretenuringdoubleArrayLiterals': [FAIL],
|
||||
'test-heap/OptimizedPretenuringNestedDoubleLiterals': [FAIL],
|
||||
@ -404,10 +398,7 @@
|
||||
'test-cpu-profiler/DeoptAtFirstLevelInlinedSource': [FAIL],
|
||||
'test-cpu-profiler/DeoptAtSecondLevelInlinedSource': [FAIL],
|
||||
'test-feedback-vector/VectorCallFeedbackForArray': [FAIL],
|
||||
'test-feedback-vector/VectorConstructCounts': [FAIL],
|
||||
'test-heap/CompilationCacheCachingBehavior': [FAIL],
|
||||
'test-heap/EnsureAllocationSiteDependentCodesProcessed': [FAIL],
|
||||
'test-heap/IncrementalMarkingPreservesMonomorphicConstructor': [FAIL],
|
||||
'test-heap/OptimizedPretenuringAllocationFolding': [FAIL],
|
||||
'test-heap/OptimizedPretenuringdoubleArrayLiterals': [FAIL],
|
||||
'test-heap/OptimizedPretenuringNestedDoubleLiterals': [FAIL],
|
||||
@ -421,7 +412,6 @@
|
||||
'test-heap/TestCodeFlushingIncremental': [FAIL],
|
||||
'test-heap/TestCodeFlushingIncrementalScavenge': [FAIL],
|
||||
'test-heap/TestCodeFlushingPreAged': [FAIL],
|
||||
'test-heap/WeakFunctionInConstructor': [FAIL],
|
||||
'test-run-inlining/InlineBuiltin': [FAIL],
|
||||
'test-run-inlining/InlineLoopGuardedEmpty': [FAIL],
|
||||
'test-run-inlining/InlineLoopGuardedOnce': [FAIL],
|
||||
@ -491,11 +481,6 @@
|
||||
# TODO(mythria,4780): Related to type feedback support for Array function.
|
||||
'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/IncrementalMarkingPreservesMonomorphicConstructor': [FAIL],
|
||||
|
||||
# TODO(mythria,4680): Lack of code-ageing in interpreter.
|
||||
'test-heap/Regress169209': [FAIL],
|
||||
|
||||
@ -507,8 +492,8 @@
|
||||
'test-cpu-profiler/CollectDeoptEvents': [FAIL],
|
||||
'test-cpu-profiler/DeoptUntrackedFunction': [SKIP],
|
||||
|
||||
# BUG(4680): Ignition doesn't support allocation sites currently.
|
||||
'test-heap/EnsureAllocationSiteDependentCodesProcessed': [FAIL],
|
||||
# TODO(mythria, 4780): In interpreter we disable mementos when creating array
|
||||
# literals.
|
||||
'test-heap/OptimizedPretenuringAllocationFolding': [FAIL],
|
||||
'test-heap/OptimizedPretenuringdoubleArrayLiterals': [FAIL],
|
||||
'test-heap/OptimizedPretenuringNestedDoubleLiterals': [FAIL],
|
||||
|
@ -16,12 +16,12 @@ snippet: "
|
||||
"
|
||||
frame size: 1
|
||||
parameter count: 1
|
||||
bytecode array length: 11
|
||||
bytecode array length: 12
|
||||
bytecodes: [
|
||||
/* 45 E> */ B(StackCheck),
|
||||
/* 50 S> */ B(LdrGlobal), U8(3), 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),
|
||||
]
|
||||
constant pool: [
|
||||
@ -37,14 +37,14 @@ snippet: "
|
||||
"
|
||||
frame size: 2
|
||||
parameter count: 1
|
||||
bytecode array length: 15
|
||||
bytecode array length: 16
|
||||
bytecodes: [
|
||||
/* 58 E> */ B(StackCheck),
|
||||
/* 63 S> */ B(LdrGlobal), U8(3), R(0),
|
||||
B(LdaSmi), U8(3),
|
||||
B(Star), R(1),
|
||||
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),
|
||||
]
|
||||
constant pool: [
|
||||
@ -65,7 +65,7 @@ snippet: "
|
||||
"
|
||||
frame size: 4
|
||||
parameter count: 1
|
||||
bytecode array length: 23
|
||||
bytecode array length: 24
|
||||
bytecodes: [
|
||||
/* 100 E> */ B(StackCheck),
|
||||
/* 105 S> */ B(LdrGlobal), U8(3), R(0),
|
||||
@ -76,7 +76,7 @@ bytecodes: [
|
||||
B(LdaSmi), U8(5),
|
||||
B(Star), R(3),
|
||||
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),
|
||||
]
|
||||
constant pool: [
|
||||
|
@ -106,7 +106,7 @@ snippet: "
|
||||
"
|
||||
frame size: 4
|
||||
parameter count: 1
|
||||
bytecode array length: 79
|
||||
bytecode array length: 80
|
||||
bytecodes: [
|
||||
B(Mov), R(closure), R(1),
|
||||
B(Mov), R(new_target), R(0),
|
||||
@ -116,7 +116,7 @@ bytecodes: [
|
||||
B(LdaSmi), U8(1),
|
||||
B(Star), R(3),
|
||||
B(Ldar), R(new_target),
|
||||
/* 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(Ldar), R(this),
|
||||
B(JumpIfNotHole), U8(4),
|
||||
@ -162,7 +162,7 @@ snippet: "
|
||||
"
|
||||
frame size: 4
|
||||
parameter count: 1
|
||||
bytecode array length: 75
|
||||
bytecode array length: 76
|
||||
bytecodes: [
|
||||
B(Mov), R(closure), R(1),
|
||||
B(Mov), R(new_target), R(0),
|
||||
@ -170,7 +170,7 @@ bytecodes: [
|
||||
/* 117 S> */ B(CallRuntime), U16(Runtime::k_GetSuperConstructor), R(closure), U8(1),
|
||||
B(Star), R(2),
|
||||
B(Ldar), R(new_target),
|
||||
/* 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(Ldar), R(this),
|
||||
B(JumpIfNotHole), U8(4),
|
||||
|
@ -196,7 +196,7 @@ snippet: "
|
||||
"
|
||||
frame size: 8
|
||||
parameter count: 1
|
||||
bytecode array length: 72
|
||||
bytecode array length: 73
|
||||
bytecodes: [
|
||||
B(CreateFunctionContext), U8(1),
|
||||
B(PushContext), R(3),
|
||||
@ -227,7 +227,7 @@ bytecodes: [
|
||||
B(Star), R(5),
|
||||
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(5), U8(1),
|
||||
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),
|
||||
]
|
||||
constant pool: [
|
||||
|
@ -637,14 +637,20 @@
|
||||
# Might trigger stack overflow.
|
||||
'unicode-test': [SKIP],
|
||||
|
||||
# TODO(mythria, 4780): Related to type feedback for calls in interpreter.
|
||||
'array-literal-feedback': [FAIL],
|
||||
# TODO(mythria, 4780): Related to lack of allocation site feedback for calls
|
||||
# in interpreter.
|
||||
'array-feedback': [FAIL],
|
||||
'regress/regress-4121': [FAIL],
|
||||
|
||||
# TODO(mythria, 4780): In interpreter we disable mementos when creating array
|
||||
# literals.
|
||||
'array-literal-feedback': [FAIL],
|
||||
|
||||
# TODO(4680): Test doesn't know about three tier compiler pipeline.
|
||||
'assert-opt-and-deopt': [SKIP],
|
||||
|
||||
# BUG(rmcilroy,4989): Function is optimized without type feedback and so immediately deopts again, causing check failure in the test.
|
||||
# BUG(rmcilroy,4989): Function is optimized without type feedback and so
|
||||
# immediately deopts again, causing check failure in the test.
|
||||
'compiler/deopt-inlined-from-call': [FAIL],
|
||||
'compiler/increment-typefeedback': [FAIL],
|
||||
'compiler/manual-concurrent-recompile': [FAIL],
|
||||
@ -675,8 +681,6 @@
|
||||
'smi-mul-const': [FAIL],
|
||||
'smi-mul': [FAIL],
|
||||
'unary-minus-deopt': [FAIL],
|
||||
'array-constructor-feedback': [FAIL],
|
||||
'array-feedback': [FAIL],
|
||||
'allocation-site-info': [FAIL],
|
||||
}], # variant == ignition
|
||||
|
||||
@ -712,7 +716,6 @@
|
||||
##############################################################################
|
||||
['variant == ignition_staging', {
|
||||
'allocation-site-info': [FAIL],
|
||||
'array-constructor-feedback': [FAIL],
|
||||
'array-feedback': [FAIL],
|
||||
'array-literal-feedback': [FAIL],
|
||||
'assert-opt-and-deopt': [SKIP],
|
||||
@ -767,11 +770,14 @@
|
||||
# Might trigger stack overflow.
|
||||
'unicode-test': [SKIP],
|
||||
|
||||
# TODO(mythria, 4780): Related to type feedback for calls in interpreter.
|
||||
'array-literal-feedback': [FAIL],
|
||||
# TODO(mythria, 4780): Related to lack of allocation site feedback for calls
|
||||
# in interpreter.
|
||||
'regress/regress-4121': [FAIL],
|
||||
'array-constructor-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],
|
||||
|
||||
'wasm/asm-wasm-f32': [PASS, ['arch in [arm64]', SKIP]],
|
||||
|
@ -171,8 +171,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT);
|
||||
|
||||
// Emit new.
|
||||
builder.New(reg, reg, 0);
|
||||
builder.New(wide, wide, 0);
|
||||
builder.New(reg, reg, 0, 1);
|
||||
builder.New(wide, wide, 0, 1);
|
||||
|
||||
// Emit test operator invocations.
|
||||
builder.CompareOperation(Token::Value::EQ, reg, 1)
|
||||
@ -463,7 +463,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
|
||||
// Ensure temporaries are used so not optimized away by the
|
||||
// register optimizer.
|
||||
builder.New(Register(locals + contexts), Register(locals + contexts),
|
||||
static_cast<size_t>(temps));
|
||||
static_cast<size_t>(temps), 0);
|
||||
}
|
||||
builder.Return();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user