Commit 6d7ba101 authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

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

  port 7e5b8fee (r39120)

  original commit message:
  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=

Review-Url: https://codereview.chromium.org/2293253007
Cr-Commit-Position: refs/heads/master@{#39145}
parent e09e08eb
......@@ -705,19 +705,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);
}
......@@ -743,7 +744,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.
......@@ -761,40 +763,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);
Generate_InterpreterPushArgs(masm, edi);
// 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 |
// 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);
// 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);
// 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));
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);
// Re-push return address.
__ Push(ecx);
// 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, ebi values.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
// Call the constructor with unmodified eax, edi, edx values.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
}
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
......
......@@ -398,7 +398,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);
}
......
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