Index: src/x64/builtins-x64.cc |
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc |
index c13c732fbdf6868e39891f0fe34d13ddcf2d0500..8e782158cc68120da5ec8195991899564a596281 100644 |
--- a/src/x64/builtins-x64.cc |
+++ b/src/x64/builtins-x64.cc |
@@ -666,6 +666,133 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { |
} |
+// Generate code for entering a JS function with the interpreter. |
+// On entry to the function the receiver and arguments have been pushed on the |
+// stack left to right. The actual argument count matches the formal parameter |
+// count expected by the function. |
+// |
+// The live registers are: |
+// o rdi: the JS function object being called |
+// o rsi: our context |
+// o rbp: the caller's frame pointer |
+// o rsp: stack pointer (pointing to return address) |
+// |
+// The function builds a JS frame. Please see JavaScriptFrameConstants in |
+// frames-x64.h for its layout. |
+// TODO(rmcilroy): We will need to include the current bytecode pointer in the |
+// frame. |
+void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { |
+ // Open a frame scope to indicate that there is a frame on the stack. The |
+ // MANUAL indicates that the scope shouldn't actually generate code to set up |
+ // the frame (that is done below). |
+ FrameScope frame_scope(masm, StackFrame::MANUAL); |
+ __ pushq(rbp); // Caller's frame pointer. |
+ __ movp(rbp, rsp); |
+ __ Push(rsi); // Callee's context. |
+ __ Push(rdi); // Callee's JS function. |
+ |
+ // Get the bytecode array from the function object and load the pointer to the |
+ // first entry into edi (InterpreterBytecodeRegister). |
+ __ movp(r14, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
+ __ movp(r14, FieldOperand(r14, SharedFunctionInfo::kFunctionDataOffset)); |
+ |
+ if (FLAG_debug_code) { |
+ // Check function data field is actually a BytecodeArray object. |
+ __ AssertNotSmi(r14); |
+ __ CmpObjectType(r14, BYTECODE_ARRAY_TYPE, rax); |
+ __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry); |
+ } |
+ |
+ // Allocate the local and temporary register file on the stack. |
+ { |
+ // Load frame size from the BytecodeArray object. |
+ __ movl(rcx, FieldOperand(r14, BytecodeArray::kFrameSizeOffset)); |
+ |
+ // Do a stack check to ensure we don't go over the limit. |
+ Label ok; |
+ __ movp(rdx, rsp); |
+ __ subp(rdx, rcx); |
+ __ CompareRoot(rdx, Heap::kRealStackLimitRootIndex); |
+ __ j(above_equal, &ok, Label::kNear); |
+ __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); |
+ __ bind(&ok); |
+ |
+ // If ok, push undefined as the initial value for all register file entries. |
+ // Note: there should always be at least one stack slot for the return |
+ // register in the register file. |
+ Label loop_header; |
+ __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); |
+ __ bind(&loop_header); |
+ // TODO(rmcilroy): Consider doing more than one push per loop iteration. |
+ __ Push(rdx); |
+ // Continue loop if not done. |
+ __ subp(rcx, Immediate(kPointerSize)); |
+ __ j(not_equal, &loop_header, Label::kNear); |
+ } |
+ |
+ // TODO(rmcilroy): List of things not currently dealt with here but done in |
+ // fullcodegen's prologue: |
+ // - Support profiler (specifically profiling_counter). |
+ // - Call ProfileEntryHookStub when isolate has a function_entry_hook. |
+ // - Allow simulator stop operations if FLAG_stop_at is set. |
+ // - Deal with sloppy mode functions which need to replace the |
+ // receiver with the global proxy when called as functions (without an |
+ // explicit receiver object). |
+ // - Code aging of the BytecodeArray object. |
+ // - Supporting FLAG_trace. |
+ // |
+ // The following items are also not done here, and will probably be done using |
+ // explicit bytecodes instead: |
+ // - Allocating a new local context if applicable. |
+ // - Setting up a local binding to the this function, which is used in |
+ // derived constructors with super calls. |
+ // - Setting new.target if required. |
+ // - Dealing with REST parameters (only if |
+ // https://codereview.chromium.org/1235153006 doesn't land by then). |
+ // - Dealing with argument objects. |
+ |
+ // Perform stack guard check. |
+ { |
+ Label ok; |
+ __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
+ __ j(above_equal, &ok, Label::kNear); |
+ __ CallRuntime(Runtime::kStackGuard, 0); |
+ __ bind(&ok); |
+ } |
+ |
+ // Load bytecode offset and dispatch table into registers. |
+ __ movp(r12, Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag)); |
+ __ LoadRoot(r15, Heap::kInterpreterTableRootIndex); |
+ __ addp(r15, Immediate(FixedArray::kHeaderSize - kHeapObjectTag)); |
+ |
+ // Dispatch to the first bytecode handler for the function. |
+ __ movzxbp(rax, Operand(r14, r12, times_1, 0)); |
+ __ movp(rax, Operand(r15, rax, times_pointer_size, 0)); |
+ // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging |
+ // and header removal. |
+ __ addp(rax, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
+ __ jmp(rax); |
+} |
+ |
+ |
+void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { |
+ // TODO(rmcilroy): List of things not currently dealt with here but done in |
+ // fullcodegen's EmitReturnSequence. |
+ // - Supporting FLAG_trace for Runtime::TraceExit. |
+ // - Support profiler (specifically decrementing profiling_counter |
+ // appropriately and calling out to HandleInterrupts if necessary). |
+ |
+ // Load return value into r0. |
+ __ movp(rax, Operand(rbp, -kPointerSize - |
+ StandardFrameConstants::kFixedFrameSizeFromFp)); |
+ // Leave the frame (also dropping the register file). |
+ __ leave(); |
+ // Return droping receiver + arguments. |
+ // TODO(rmcilroy): Get number of arguments from BytecodeArray. |
+ __ Ret(1 * kPointerSize, rcx); |
+} |
+ |
+ |
void Builtins::Generate_CompileLazy(MacroAssembler* masm) { |
CallRuntimePassFunction(masm, Runtime::kCompileLazy); |
GenerateTailCallToReturnedCode(masm); |