[interpreter] Add Interpreter{Entry,Exit}Trampoline builtins.
authorrmcilroy <rmcilroy@chromium.org>
Thu, 30 Jul 2015 11:36:26 +0000 (04:36 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 30 Jul 2015 11:36:43 +0000 (11:36 +0000)
Adds interpreter entry and exit trampoline builtins. Also implements the
Return bytecode handler and fixes a few bugs in InterpreterAssembler
highlighted by running on other architectures.

MIPS and MIPS64 port contributed by Paul Lind (paul.lind@imgtec.com)

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1245133002

Cr-Commit-Position: refs/heads/master@{#29929}

26 files changed:
src/arm/builtins-arm.cc
src/arm/macro-assembler-arm.h
src/arm64/assembler-arm64.h
src/arm64/builtins-arm64.cc
src/bailout-reason.h
src/builtins.h
src/compiler/arm/linkage-arm.cc
src/compiler/arm64/linkage-arm64.cc
src/compiler/interpreter-assembler.cc
src/compiler/interpreter-assembler.h
src/compiler/mips/linkage-mips.cc
src/compiler/mips64/linkage-mips64.cc
src/compiler/raw-machine-assembler.h
src/compiler/x64/linkage-x64.cc
src/full-codegen/arm/full-codegen-arm.cc
src/heap/heap.cc
src/ia32/builtins-ia32.cc
src/interpreter/interpreter.cc
src/mips/assembler-mips.h
src/mips/builtins-mips.cc
src/mips64/assembler-mips64.h
src/mips64/builtins-mips64.cc
src/x64/builtins-x64.cc
test/unittests/compiler/interpreter-assembler-unittest.cc
test/unittests/compiler/node-test-utils.cc
test/unittests/compiler/node-test-utils.h

index e3774cb27d50f3b97a9d9f4cdc80ec775d30b789..50066137e404759f01b1f57456002a8144660f92 100644 (file)
@@ -10,6 +10,7 @@
 #include "src/debug.h"
 #include "src/deoptimizer.h"
 #include "src/full-codegen/full-codegen.h"
+#include "src/interpreter/bytecodes.h"
 #include "src/runtime/runtime.h"
 
 namespace v8 {
@@ -869,6 +870,143 @@ 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 r1: the JS function object being called.
+//   o cp: our context
+//   o pp: the caller's constant pool pointer (if enabled)
+//   o fp: the caller's frame pointer
+//   o sp: stack pointer
+//   o lr: return address
+//
+// The function builds a JS frame.  Please see JavaScriptFrameConstants in
+// frames-arm.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);
+  __ PushFixedFrame(r1);
+  __ add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+
+  // Get the bytecode array from the function object and load the pointer to the
+  // first entry into kInterpreterBytecodeRegister.
+  __ ldr(r0, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+  __ ldr(kInterpreterBytecodeArrayRegister,
+         FieldMemOperand(r0, SharedFunctionInfo::kFunctionDataOffset));
+
+  if (FLAG_debug_code) {
+    // Check function data field is actually a BytecodeArray object.
+    __ SmiTst(kInterpreterBytecodeArrayRegister);
+    __ Assert(ne, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
+    __ CompareObjectType(kInterpreterBytecodeArrayRegister, r0, no_reg,
+                         BYTECODE_ARRAY_TYPE);
+    __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
+  }
+
+  // Allocate the local and temporary register file on the stack.
+  {
+    // Load frame size from the BytecodeArray object.
+    __ ldr(r4, FieldMemOperand(kInterpreterBytecodeArrayRegister,
+                               BytecodeArray::kFrameSizeOffset));
+
+    // Do a stack check to ensure we don't go over the limit.
+    Label ok;
+    __ sub(r9, sp, Operand(r4));
+    __ LoadRoot(r2, Heap::kRealStackLimitRootIndex);
+    __ cmp(r9, Operand(r2));
+    __ b(hs, &ok);
+    __ 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(r9, Heap::kUndefinedValueRootIndex);
+    __ bind(&loop_header);
+    // TODO(rmcilroy): Consider doing more than one push per loop iteration.
+    __ push(r9);
+    // Continue loop if not done.
+    __ sub(r4, r4, Operand(kPointerSize), SetCC);
+    __ b(&loop_header, ne);
+  }
+
+  // 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;
+    __ LoadRoot(ip, Heap::kStackLimitRootIndex);
+    __ cmp(sp, Operand(ip));
+    __ b(hs, &ok);
+    __ CallRuntime(Runtime::kStackGuard, 0);
+    __ bind(&ok);
+  }
+
+  // Load bytecode offset and dispatch table into registers.
+  __ mov(kInterpreterBytecodeOffsetRegister,
+         Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
+  __ LoadRoot(kInterpreterDispatchTableRegister,
+              Heap::kInterpreterTableRootIndex);
+  __ add(kInterpreterDispatchTableRegister, kInterpreterDispatchTableRegister,
+         Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+
+  // Dispatch to the first bytecode handler for the function.
+  __ ldrb(r0, MemOperand(kInterpreterBytecodeArrayRegister,
+                         kInterpreterBytecodeOffsetRegister));
+  __ ldr(ip, MemOperand(kInterpreterDispatchTableRegister, r0, LSL,
+                        kPointerSizeLog2));
+  // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
+  // and header removal.
+  __ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(ip);
+}
+
+
+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.
+  __ ldr(r0, MemOperand(fp, -kPointerSize -
+                                StandardFrameConstants::kFixedFrameSizeFromFp));
+  // Leave the frame (also dropping the register file).
+  __ LeaveFrame(StackFrame::JAVA_SCRIPT);
+  // Drop receiver + arguments.
+  __ Drop(1);  // TODO(rmcilroy): Get number of arguments from BytecodeArray.
+  __ Jump(lr);
+}
+
+
 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
   CallRuntimePassFunction(masm, Runtime::kCompileLazy);
   GenerateTailCallToReturnedCode(masm);
index b9e8238e200d57d2dc2c53a3ab5ef1615afb4b35..754c6ce9077858bcea14229279d58a9f4d340b96 100644 (file)
@@ -26,6 +26,15 @@ inline MemOperand FieldMemOperand(Register object, int offset) {
 const Register cp = { kRegister_r7_Code };  // JavaScript context pointer.
 const Register pp = { kRegister_r8_Code };  // Constant pool pointer.
 const Register kRootRegister = { kRegister_r10_Code };  // Roots array pointer.
+const Register kInterpreterBytecodeOffsetRegister = {
+    kRegister_r5_Code  // Interpreter bytecode offset.
+};
+const Register kInterpreterBytecodeArrayRegister = {
+    kRegister_r6_Code  // Interpreter bytecode array pointer.
+};
+const Register kInterpreterDispatchTableRegister = {
+    kRegister_r8_Code  // Interpreter dispatch table.
+};
 
 // Flags used for AllocateHeapNumber
 enum TaggingMode {
index 9c09dfe0420087778e4be89ec598609b52dd0c1b..b385938815fe16804310eb4cebab31c556482dfc 100644 (file)
@@ -400,6 +400,9 @@ ALIAS_REGISTER(Register, fp, x29);
 ALIAS_REGISTER(Register, lr, x30);
 ALIAS_REGISTER(Register, xzr, x31);
 ALIAS_REGISTER(Register, wzr, w31);
+ALIAS_REGISTER(Register, kInterpreterBytecodeOffsetRegister, x19);
+ALIAS_REGISTER(Register, kInterpreterBytecodeArrayRegister, x20);
+ALIAS_REGISTER(Register, kInterpreterDispatchTableRegister, x21);
 
 // Keeps the 0 double value.
 ALIAS_REGISTER(FPRegister, fp_zero, d15);
index 39bc8d052d277c47196c1ca3af3d5ac7f2104e99..b99431e0de6fad6930566c113f0c9287fdec2485 100644 (file)
@@ -893,6 +893,141 @@ 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:
+//   - x1: the JS function object being called.
+//   - cp: our context.
+//   - fp: our caller's frame pointer.
+//   - jssp: stack pointer.
+//   - lr: return address.
+//
+// The function builds a JS frame.  Please see JavaScriptFrameConstants in
+// frames-arm64.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);
+  __ Push(lr, fp, cp, x1);
+  __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
+
+  // Get the bytecode array from the function object and load the pointer to the
+  // first entry into kInterpreterBytecodeRegister.
+  __ Ldr(x0, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
+  __ Ldr(kInterpreterBytecodeArrayRegister,
+         FieldMemOperand(x0, SharedFunctionInfo::kFunctionDataOffset));
+
+  if (FLAG_debug_code) {
+    // Check function data field is actually a BytecodeArray object.
+    __ AssertNotSmi(kInterpreterBytecodeArrayRegister,
+                    kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
+    __ CompareObjectType(kInterpreterBytecodeArrayRegister, x0, x0,
+                         BYTECODE_ARRAY_TYPE);
+    __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
+  }
+
+  // Allocate the local and temporary register file on the stack.
+  {
+    // Load frame size from the BytecodeArray object.
+    __ Ldr(w11, FieldMemOperand(kInterpreterBytecodeArrayRegister,
+                                BytecodeArray::kFrameSizeOffset));
+
+    // Do a stack check to ensure we don't go over the limit.
+    Label ok;
+    DCHECK(jssp.Is(__ StackPointer()));
+    __ Sub(x10, jssp, Operand(x11));
+    __ CompareRoot(x10, Heap::kRealStackLimitRootIndex);
+    __ B(hs, &ok);
+    __ 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(x10, Heap::kUndefinedValueRootIndex);
+    // TODO(rmcilroy): Ensure we always have an even number of registers to
+    // allow stack to be 16 bit aligned (and remove need for jssp).
+    __ Lsr(x11, x11, kPointerSizeLog2);
+    __ PushMultipleTimes(x10, x11);
+    __ Bind(&loop_header);
+  }
+
+  // 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(jssp, Heap::kStackLimitRootIndex);
+    __ B(hs, &ok);
+    __ CallRuntime(Runtime::kStackGuard, 0);
+    __ Bind(&ok);
+  }
+
+  // Load bytecode offset and dispatch table into registers.
+  __ Mov(kInterpreterBytecodeOffsetRegister,
+         Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
+  __ LoadRoot(kInterpreterDispatchTableRegister,
+              Heap::kInterpreterTableRootIndex);
+  __ Add(kInterpreterDispatchTableRegister, kInterpreterDispatchTableRegister,
+         Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+
+  // Dispatch to the first bytecode handler for the function.
+  __ Ldrb(x0, MemOperand(kInterpreterBytecodeArrayRegister,
+                         kInterpreterBytecodeOffsetRegister));
+  __ Mov(x0, Operand(x0, LSL, kPointerSizeLog2));
+  __ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x0));
+  // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
+  // and header removal.
+  __ Add(ip0, ip0, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(ip0);
+}
+
+
+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 x0.
+  __ ldr(x0, MemOperand(fp, -kPointerSize -
+                                StandardFrameConstants::kFixedFrameSizeFromFp));
+  // Leave the frame (also dropping the register file).
+  __ LeaveFrame(StackFrame::JAVA_SCRIPT);
+  // Drop receiver + arguments.
+  // TODO(rmcilroy): Get number of arguments from BytecodeArray.
+  __ Drop(1, kXRegSize);
+  __ Ret();
+}
+
+
 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
   CallRuntimePassFunction(masm, Runtime::kCompileLazy);
   GenerateTailCallToReturnedCode(masm);
index 9b547258c7628da106015d34dd7397dec49b3ba6..8e7a07dc7a52e8e51ee2571c56d74dc7e89f6b9f 100644 (file)
@@ -87,6 +87,8 @@ namespace internal {
   V(kFunctionBeingDebugged, "Function is being debugged")                      \
   V(kFunctionCallsEval, "Function calls eval")                                 \
   V(kFunctionWithIllegalRedeclaration, "Function with illegal redeclaration")  \
+  V(kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry,                      \
+    "The function_data field should be a BytecodeArray on interpreter entry")  \
   V(kGeneratedCodeIsTooLarge, "Generated code is too large")                   \
   V(kGeneratorFailedToResume, "Generator failed to resume")                    \
   V(kGenerator, "Generator")                                                   \
index b526e785812ca13c6f8b5f90f9e57b6346f81f13..d7cd720fe14d005836e27d95545324fb57d2d34b 100644 (file)
@@ -72,6 +72,8 @@ enum BuiltinExtraArguments {
   V(JSConstructStubApi, BUILTIN, UNINITIALIZED, kNoExtraICState)             \
   V(JSEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState)              \
   V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState)     \
+  V(InterpreterEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState)     \
+  V(InterpreterExitTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState)      \
   V(CompileLazy, BUILTIN, UNINITIALIZED, kNoExtraICState)                    \
   V(CompileOptimized, BUILTIN, UNINITIALIZED, kNoExtraICState)               \
   V(CompileOptimizedConcurrent, BUILTIN, UNINITIALIZED, kNoExtraICState)     \
@@ -306,6 +308,8 @@ class Builtins {
   static void Generate_JSConstructStubApi(MacroAssembler* masm);
   static void Generate_JSEntryTrampoline(MacroAssembler* masm);
   static void Generate_JSConstructEntryTrampoline(MacroAssembler* masm);
+  static void Generate_InterpreterEntryTrampoline(MacroAssembler* masm);
+  static void Generate_InterpreterExitTrampoline(MacroAssembler* masm);
   static void Generate_NotifyDeoptimized(MacroAssembler* masm);
   static void Generate_NotifySoftDeoptimized(MacroAssembler* masm);
   static void Generate_NotifyLazyDeoptimized(MacroAssembler* masm);
index 142a72cb0d79e48e63d25b8c294ea499a39aedba..861743674cc17c467430f42f1533a52426b6092f 100644 (file)
@@ -17,9 +17,15 @@ struct ArmLinkageHelperTraits {
   static Register ReturnValue2Reg() { return r1; }
   static Register JSCallFunctionReg() { return r1; }
   static Register ContextReg() { return cp; }
-  static Register InterpreterBytecodeOffsetReg() { return r5; }
-  static Register InterpreterBytecodeArrayReg() { return r6; }
-  static Register InterpreterDispatchTableReg() { return r8; }
+  static Register InterpreterBytecodeOffsetReg() {
+    return kInterpreterBytecodeOffsetRegister;
+  }
+  static Register InterpreterBytecodeArrayReg() {
+    return kInterpreterBytecodeArrayRegister;
+  }
+  static Register InterpreterDispatchTableReg() {
+    return kInterpreterDispatchTableRegister;
+  }
   static Register RuntimeCallFunctionReg() { return r1; }
   static Register RuntimeCallArgCountReg() { return r0; }
   static RegList CCalleeSaveRegisters() {
index 4a601efb22fddaaf84fb74a1519b4a0ba47e036f..99d2d56848d5586b9a20ff335dc28b390968f720 100644 (file)
@@ -17,9 +17,15 @@ struct Arm64LinkageHelperTraits {
   static Register ReturnValue2Reg() { return x1; }
   static Register JSCallFunctionReg() { return x1; }
   static Register ContextReg() { return cp; }
-  static Register InterpreterBytecodeOffsetReg() { return x19; }
-  static Register InterpreterBytecodeArrayReg() { return x20; }
-  static Register InterpreterDispatchTableReg() { return x21; }
+  static Register InterpreterBytecodeOffsetReg() {
+    return kInterpreterBytecodeOffsetRegister;
+  }
+  static Register InterpreterBytecodeArrayReg() {
+    return kInterpreterBytecodeArrayRegister;
+  }
+  static Register InterpreterDispatchTableReg() {
+    return kInterpreterDispatchTableRegister;
+  }
   static Register RuntimeCallFunctionReg() { return x1; }
   static Register RuntimeCallArgCountReg() { return x0; }
   static RegList CCalleeSaveRegisters() {
index 93d857c0e404560adb34ae364bcf1fb7a38d8cf0..380d653c84a3b6086d4acde2eccf8678805863c2 100644 (file)
@@ -89,9 +89,9 @@ Node* InterpreterAssembler::RegisterFrameOffset(int index) {
 
 
 Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
-  return raw_assembler_->Int32Sub(
+  return raw_assembler_->IntPtrSub(
       Int32Constant(kFirstRegisterOffsetFromFp),
-      raw_assembler_->Word32Shl(index, Int32Constant(kPointerSizeLog2)));
+      raw_assembler_->WordShl(index, Int32Constant(kPointerSizeLog2)));
 }
 
 
@@ -127,6 +127,24 @@ Node* InterpreterAssembler::StoreRegister(Node* value, Node* index) {
 }
 
 
+void InterpreterAssembler::Return() {
+  Node* exit_trampoline_code_object =
+      HeapConstant(Unique<HeapObject>::CreateImmovable(
+          isolate()->builtins()->InterpreterExitTrampoline()));
+  // If the order of the parameters you need to change the call signature below.
+  STATIC_ASSERT(0 == Linkage::kInterpreterBytecodeOffsetParameter);
+  STATIC_ASSERT(1 == Linkage::kInterpreterBytecodeArrayParameter);
+  STATIC_ASSERT(2 == Linkage::kInterpreterDispatchTableParameter);
+  Node* tail_call = graph()->NewNode(
+      common()->TailCall(call_descriptor()), exit_trampoline_code_object,
+      BytecodeOffset(), BytecodeArrayPointer(), DispatchTablePointer(),
+      graph()->start(), graph()->start());
+  schedule()->AddTailCall(raw_assembler_->CurrentBlock(), tail_call);
+  // This should always be the end node.
+  SetEndInput(tail_call);
+}
+
+
 Node* InterpreterAssembler::Advance(int delta) {
   return raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(delta));
 }
@@ -153,7 +171,6 @@ void InterpreterAssembler::Dispatch() {
       new_bytecode_offset, BytecodeArrayPointer(), DispatchTablePointer(),
       graph()->start(), graph()->start());
   schedule()->AddTailCall(raw_assembler_->CurrentBlock(), tail_call);
-
   // This should always be the end node.
   SetEndInput(tail_call);
 }
@@ -210,6 +227,11 @@ Node* InterpreterAssembler::NumberConstant(double value) {
 }
 
 
+Node* InterpreterAssembler::HeapConstant(Unique<HeapObject> object) {
+  return raw_assembler_->HeapConstant(object);
+}
+
+
 }  // namespace interpreter
 }  // namespace internal
 }  // namespace v8
index b03e57a5f9681fa42ed9326bfedeac9294e9838a..b7ea4385f87d281e4d786e1d47ff848900a11eab 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/base/smart-pointers.h"
 #include "src/frames.h"
 #include "src/interpreter/bytecodes.h"
+#include "src/unique.h"
 
 namespace v8 {
 namespace internal {
@@ -40,6 +41,7 @@ class InterpreterAssembler {
   // Constants.
   Node* Int32Constant(int value);
   Node* NumberConstant(double value);
+  Node* HeapConstant(Unique<HeapObject> object);
 
   // Returns the bytecode argument |index| for the current bytecode.
   Node* BytecodeArg(int index);
@@ -50,6 +52,9 @@ class InterpreterAssembler {
   Node* StoreRegister(Node* value, int index);
   Node* StoreRegister(Node* value, Node* index);
 
+  // Returns from the function.
+  void Return();
+
   // Dispatch to the bytecode.
   void Dispatch();
 
index e2d8b6c3186067384ed3add5e2d46a28c686fd44..610ebbbb90cb2492a5dd93e3011c88ce77b31b40 100644 (file)
@@ -17,9 +17,15 @@ struct MipsLinkageHelperTraits {
   static Register ReturnValue2Reg() { return v1; }
   static Register JSCallFunctionReg() { return a1; }
   static Register ContextReg() { return cp; }
-  static Register InterpreterBytecodeOffsetReg() { return t4; }
-  static Register InterpreterBytecodeArrayReg() { return t5; }
-  static Register InterpreterDispatchTableReg() { return t6; }
+  static Register InterpreterBytecodeOffsetReg() {
+    return kInterpreterBytecodeOffsetRegister;
+  }
+  static Register InterpreterBytecodeArrayReg() {
+    return kInterpreterBytecodeArrayRegister;
+  }
+  static Register InterpreterDispatchTableReg() {
+    return kInterpreterDispatchTableRegister;
+  }
   static Register RuntimeCallFunctionReg() { return a1; }
   static Register RuntimeCallArgCountReg() { return a0; }
   static RegList CCalleeSaveRegisters() {
index f3d63e50ab77ca312ff9fbcb5d6492136970ea29..29cda7fcc37e12a95e8e0201354213fd10b7b526 100644 (file)
@@ -17,9 +17,15 @@ struct MipsLinkageHelperTraits {
   static Register ReturnValue2Reg() { return v1; }
   static Register JSCallFunctionReg() { return a1; }
   static Register ContextReg() { return cp; }
-  static Register InterpreterBytecodeOffsetReg() { return t1; }
-  static Register InterpreterBytecodeArrayReg() { return t2; }
-  static Register InterpreterDispatchTableReg() { return t3; }
+  static Register InterpreterBytecodeOffsetReg() {
+    return kInterpreterBytecodeOffsetRegister;
+  }
+  static Register InterpreterBytecodeArrayReg() {
+    return kInterpreterBytecodeArrayRegister;
+  }
+  static Register InterpreterDispatchTableReg() {
+    return kInterpreterDispatchTableRegister;
+  }
   static Register RuntimeCallFunctionReg() { return a1; }
   static Register RuntimeCallArgCountReg() { return a0; }
   static RegList CCalleeSaveRegisters() {
index 1e9a9502355ffe76f6a80d5e8119dc67ce7a9ad2..5fc710772e9d4645d3f1e2bdbe59ed9d8583cc78 100644 (file)
@@ -105,6 +105,9 @@ class RawMachineAssembler {
     Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object);
     return NewNode(common()->HeapConstant(val));
   }
+  Node* HeapConstant(Unique<HeapObject> object) {
+    return NewNode(common()->HeapConstant(object));
+  }
   Node* ExternalConstant(ExternalReference address) {
     return NewNode(common()->ExternalConstant(address));
   }
index d320b941dff4f27e99e6a2e1c6cbe68610b34d1e..5201c3cf432c7f98dd6aea73889171e601d55685 100644 (file)
@@ -24,8 +24,8 @@ struct X64LinkageHelperTraits {
   static Register JSCallFunctionReg() { return rdi; }
   static Register ContextReg() { return rsi; }
   static Register InterpreterBytecodeOffsetReg() { return r12; }
-  static Register InterpreterBytecodeArrayReg() { return rbx; }
-  static Register InterpreterDispatchTableReg() { return rdi; }
+  static Register InterpreterBytecodeArrayReg() { return r14; }
+  static Register InterpreterDispatchTableReg() { return r15; }
   static Register RuntimeCallFunctionReg() { return rbx; }
   static Register RuntimeCallArgCountReg() { return rax; }
   static RegList CCalleeSaveRegisters() {
index ab74ff02a75749c5c6e06d8ff4974212c48b7778..7616fb907f9c73d222302019583b3efc5fa0f10c 100644 (file)
@@ -315,7 +315,7 @@ void FullCodeGenerator::Generate() {
 
     // Arguments to ArgumentsAccessStub:
     //   function, receiver address, parameter count.
-    // The stub will rewrite receiever and parameter count if the previous
+    // The stub will rewrite receiver and parameter count if the previous
     // stack frame was an arguments adapter frame.
     ArgumentsAccessStub::Type type;
     if (is_strict(language_mode()) || !is_simple_parameter_list()) {
index b75c6f7bc6083d0990089dd6f3aec50e6b057b99..f28d17a9b68fab830756085901e3308d53db4896 100644 (file)
@@ -3511,6 +3511,7 @@ bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
     case kWeakObjectToCodeTableRootIndex:
     case kRetainedMapsRootIndex:
     case kWeakStackTraceListRootIndex:
+    case kInterpreterTableRootIndex:
 // Smi values
 #define SMI_ENTRY(type, name, Name) case k##Name##RootIndex:
       SMI_ROOT_LIST(SMI_ENTRY)
index 0a22d66f9284e53ce129b77462899f2d14b118d2..5e42f84696f4be7da130600d4e45ee1abc9091e6 100644 (file)
@@ -605,6 +605,139 @@ 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 edi: the JS function object being called
+//   o esi: our context
+//   o ebp: the caller's frame pointer
+//   o esp: stack pointer (pointing to return address)
+//
+// The function builds a JS frame.  Please see JavaScriptFrameConstants in
+// frames-ia32.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);
+  __ push(ebp);  // Caller's frame pointer.
+  __ mov(ebp, esp);
+  __ push(esi);  // Callee's context.
+  __ push(edi);  // Callee's JS function.
+
+  // Get the bytecode array from the function object and load the pointer to the
+  // first entry into edi (InterpreterBytecodeRegister).
+  __ mov(edi, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+  __ mov(edi, FieldOperand(edi, SharedFunctionInfo::kFunctionDataOffset));
+
+  if (FLAG_debug_code) {
+    // Check function data field is actually a BytecodeArray object.
+    __ AssertNotSmi(edi);
+    __ CmpObjectType(edi, BYTECODE_ARRAY_TYPE, eax);
+    __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
+  }
+
+  // Allocate the local and temporary register file on the stack.
+  {
+    // Load frame size from the BytecodeArray object.
+    __ mov(ebx, FieldOperand(edi, BytecodeArray::kFrameSizeOffset));
+
+    // Do a stack check to ensure we don't go over the limit.
+    Label ok;
+    __ mov(ecx, esp);
+    __ sub(ecx, ebx);
+    ExternalReference stack_limit =
+        ExternalReference::address_of_real_stack_limit(masm->isolate());
+    __ cmp(ecx, Operand::StaticVariable(stack_limit));
+    __ 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;
+    __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
+    __ bind(&loop_header);
+    // TODO(rmcilroy): Consider doing more than one push per loop iteration.
+    __ push(eax);
+    // Continue loop if not done.
+    __ sub(ebx, 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;
+    ExternalReference stack_limit =
+        ExternalReference::address_of_stack_limit(masm->isolate());
+    __ cmp(esp, Operand::StaticVariable(stack_limit));
+    __ j(above_equal, &ok, Label::kNear);
+    __ CallRuntime(Runtime::kStackGuard, 0);
+    __ bind(&ok);
+  }
+
+  // Load bytecode offset and dispatch table into registers.
+  __ mov(ecx, Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
+  // Since the dispatch table root might be set after builtins are generated,
+  // load directly from the roots table.
+  __ LoadRoot(ebx, Heap::kInterpreterTableRootIndex);
+  __ add(ebx, Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
+
+  // Dispatch to the first bytecode handler for the function.
+  __ movzx_b(eax, Operand(edi, ecx, times_1, 0));
+  __ mov(eax, Operand(ebx, eax, times_pointer_size, 0));
+  // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
+  // and header removal.
+  __ add(eax, Immediate(Code::kHeaderSize - kHeapObjectTag));
+  __ jmp(eax);
+}
+
+
+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.
+  __ mov(eax, Operand(ebp, -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, ecx);
+}
+
+
 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
   CallRuntimePassFunction(masm, Runtime::kCompileLazy);
   GenerateTailCallToReturnedCode(masm);
index 155f2c650de377bac3dac2eb1022714e191ca360..0542086d2cf95b977a9e4279c5a5abffe1e66381 100644 (file)
@@ -59,7 +59,7 @@ void Interpreter::DoLoadLiteral0(compiler::InterpreterAssembler* assembler) {
 
 // Return the value in register 0.
 void Interpreter::DoReturn(compiler::InterpreterAssembler* assembler) {
-  // TODO(rmcilroy) Jump to exit trampoline.
+  __ Return();
 }
 
 
index 4db04b065fd25a5a8712c05fe38fcc680962e636..0a6a85cf6f733f3960644539e86ed8dc2b101011 100644 (file)
@@ -332,6 +332,9 @@ const FPURegister f31 = { 31 };
 #define cp s7
 #define kLithiumScratchReg s3
 #define kLithiumScratchReg2 s4
+#define kInterpreterBytecodeOffsetRegister t4
+#define kInterpreterBytecodeArrayRegister t5
+#define kInterpreterDispatchTableRegister t6
 #define kLithiumScratchDouble f30
 #define kDoubleRegZero f28
 // Used on mips32r6 for compare operations.
index aa7cd9070c81707bdfb62ac4d83698e9e10d1426..93a10ce098394cfb4c62ff8978746926ec3d106b 100644 (file)
@@ -12,6 +12,7 @@
 #include "src/debug.h"
 #include "src/deoptimizer.h"
 #include "src/full-codegen/full-codegen.h"
+#include "src/interpreter/bytecodes.h"
 #include "src/runtime/runtime.h"
 
 
@@ -860,6 +861,144 @@ 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 a1: the JS function object being called.
+//   o cp: our context
+//   o fp: the caller's frame pointer
+//   o sp: stack pointer
+//   o ra: return address
+//
+// The function builds a JS frame. Please see JavaScriptFrameConstants in
+// frames-mips.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);
+
+  __ Push(ra, fp, cp, a1);
+  __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+
+  // Get the bytecode array from the function object and load the pointer to the
+  // first entry into kInterpreterBytecodeRegister.
+  __ lw(a0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+  __ lw(kInterpreterBytecodeArrayRegister,
+        FieldMemOperand(a0, SharedFunctionInfo::kFunctionDataOffset));
+
+  if (FLAG_debug_code) {
+    // Check function data field is actually a BytecodeArray object.
+    __ SmiTst(kInterpreterBytecodeArrayRegister, t0);
+    __ Assert(ne, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, t0,
+              Operand(zero_reg));
+    __ GetObjectType(kInterpreterBytecodeArrayRegister, t0, t0);
+    __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, t0,
+              Operand(BYTECODE_ARRAY_TYPE));
+  }
+
+  // Allocate the local and temporary register file on the stack.
+  {
+    // Load frame size from the BytecodeArray object.
+    __ lw(t0, FieldMemOperand(kInterpreterBytecodeArrayRegister,
+                              BytecodeArray::kFrameSizeOffset));
+
+    // Do a stack check to ensure we don't go over the limit.
+    Label ok;
+    __ Subu(t1, sp, Operand(t0));
+    __ LoadRoot(a2, Heap::kRealStackLimitRootIndex);
+    __ Branch(&ok, hs, t1, Operand(a2));
+    __ 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(t1, Heap::kUndefinedValueRootIndex);
+    __ bind(&loop_header);
+    // TODO(rmcilroy): Consider doing more than one push per loop iteration.
+    __ push(t1);
+    // Continue loop if not done.
+    __ Subu(t0, t0, Operand(kPointerSize));
+    __ Branch(&loop_header, ge, t0, Operand(zero_reg));
+  }
+
+  // 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;
+    __ LoadRoot(at, Heap::kStackLimitRootIndex);
+    __ Branch(&ok, hs, sp, Operand(at));
+    __ CallRuntime(Runtime::kStackGuard, 0);
+    __ bind(&ok);
+  }
+
+  // Load bytecode offset and dispatch table into registers.
+  __ li(kInterpreterBytecodeOffsetRegister,
+        Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
+  __ LoadRoot(kInterpreterDispatchTableRegister,
+              Heap::kInterpreterTableRootIndex);
+  __ Addu(kInterpreterDispatchTableRegister, kInterpreterDispatchTableRegister,
+          Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+
+  // Dispatch to the first bytecode handler for the function.
+  __ Addu(a0, kInterpreterBytecodeArrayRegister,
+          kInterpreterBytecodeOffsetRegister);
+  __ lbu(a0, MemOperand(a0));
+  __ sll(at, a0, kPointerSizeLog2);
+  __ Addu(at, kInterpreterDispatchTableRegister, at);
+  __ lw(at, MemOperand(at));
+  // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
+  // and header removal.
+  __ Addu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(at);
+}
+
+
+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 v0.
+  __ lw(v0, MemOperand(fp, -kPointerSize -
+                               StandardFrameConstants::kFixedFrameSizeFromFp));
+  // Leave the frame (also dropping the register file).
+  __ LeaveFrame(StackFrame::JAVA_SCRIPT);
+  // Drop receiver + arguments.
+  __ Drop(1);  // TODO(rmcilroy): Get number of arguments from BytecodeArray.
+  __ Jump(ra);
+}
+
+
 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
   CallRuntimePassFunction(masm, Runtime::kCompileLazy);
   GenerateTailCallToReturnedCode(masm);
index 529997ea016561198340085a8e6978042c7d3e34..923b20397f11029d9fa87f3eed16fbee98daf504 100644 (file)
@@ -324,6 +324,9 @@ const FPURegister f31 = { 31 };
 #define cp s7
 #define kLithiumScratchReg s3
 #define kLithiumScratchReg2 s4
+#define kInterpreterBytecodeOffsetRegister t0
+#define kInterpreterBytecodeArrayRegister t1
+#define kInterpreterDispatchTableRegister t2
 #define kLithiumScratchDouble f30
 #define kDoubleRegZero f28
 // Used on mips64r6 for compare operations.
index 04b854ee9e966086da9c3d92e95d55826f6ebd92..1426f15858b896dcac70c392f612b97ffeb431ca 100644 (file)
@@ -858,6 +858,144 @@ 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 a1: the JS function object being called.
+//   o cp: our context
+//   o fp: the caller's frame pointer
+//   o sp: stack pointer
+//   o ra: return address
+//
+// The function builds a JS frame. Please see JavaScriptFrameConstants in
+// frames-mips.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);
+
+  __ Push(ra, fp, cp, a1);
+  __ Daddu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
+
+  // Get the bytecode array from the function object and load the pointer to the
+  // first entry into kInterpreterBytecodeRegister.
+  __ ld(a0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+  __ ld(kInterpreterBytecodeArrayRegister,
+        FieldMemOperand(a0, SharedFunctionInfo::kFunctionDataOffset));
+
+  if (FLAG_debug_code) {
+    // Check function data field is actually a BytecodeArray object.
+    __ SmiTst(kInterpreterBytecodeArrayRegister, a4);
+    __ Assert(ne, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, a4,
+              Operand(zero_reg));
+    __ GetObjectType(kInterpreterBytecodeArrayRegister, a4, a4);
+    __ Assert(eq, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, a4,
+              Operand(BYTECODE_ARRAY_TYPE));
+  }
+
+  // Allocate the local and temporary register file on the stack.
+  {
+    // Load frame size from the BytecodeArray object.
+    __ ld(a4, FieldMemOperand(kInterpreterBytecodeArrayRegister,
+                              BytecodeArray::kFrameSizeOffset));
+
+    // Do a stack check to ensure we don't go over the limit.
+    Label ok;
+    __ Dsubu(a5, sp, Operand(a4));
+    __ LoadRoot(a2, Heap::kRealStackLimitRootIndex);
+    __ Branch(&ok, hs, a5, Operand(a2));
+    __ 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(a5, Heap::kUndefinedValueRootIndex);
+    __ bind(&loop_header);
+    // TODO(rmcilroy): Consider doing more than one push per loop iteration.
+    __ push(a5);
+    // Continue loop if not done.
+    __ Dsubu(a4, a4, Operand(kPointerSize));
+    __ Branch(&loop_header, ge, a4, Operand(zero_reg));
+  }
+
+  // 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;
+    __ LoadRoot(at, Heap::kStackLimitRootIndex);
+    __ Branch(&ok, hs, sp, Operand(at));
+    __ CallRuntime(Runtime::kStackGuard, 0);
+    __ bind(&ok);
+  }
+
+  // Load bytecode offset and dispatch table into registers.
+  __ li(kInterpreterBytecodeOffsetRegister,
+        Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
+  __ LoadRoot(kInterpreterDispatchTableRegister,
+              Heap::kInterpreterTableRootIndex);
+  __ Daddu(kInterpreterDispatchTableRegister, kInterpreterDispatchTableRegister,
+           Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+
+  // Dispatch to the first bytecode handler for the function.
+  __ Daddu(a0, kInterpreterBytecodeArrayRegister,
+           kInterpreterBytecodeOffsetRegister);
+  __ lbu(a0, MemOperand(a0));
+  __ dsll(at, a0, kPointerSizeLog2);
+  __ Daddu(at, kInterpreterDispatchTableRegister, at);
+  __ ld(at, MemOperand(at));
+  // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
+  // and header removal.
+  __ Daddu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(at);
+}
+
+
+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 v0.
+  __ ld(v0, MemOperand(fp, -kPointerSize -
+                               StandardFrameConstants::kFixedFrameSizeFromFp));
+  // Leave the frame (also dropping the register file).
+  __ LeaveFrame(StackFrame::JAVA_SCRIPT);
+  // Drop receiver + arguments.
+  __ Drop(1);  // TODO(rmcilroy): Get number of arguments from BytecodeArray.
+  __ Jump(ra);
+}
+
+
 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
   CallRuntimePassFunction(masm, Runtime::kCompileLazy);
   GenerateTailCallToReturnedCode(masm);
index c13c732fbdf6868e39891f0fe34d13ddcf2d0500..8e782158cc68120da5ec8195991899564a596281 100644 (file)
@@ -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);
index 7bc91ce994e2698ae7fe854ff6f73dc50eef9ca9..70b940f87863c2855b3d0cc08ee8c4e33e2d3887 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "src/compiler/graph.h"
 #include "src/compiler/node.h"
+#include "src/unique.h"
 #include "test/unittests/compiler/compiler-test-utils.h"
 #include "test/unittests/compiler/node-test-utils.h"
 
@@ -52,6 +53,20 @@ Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher,
 }
 
 
+Matcher<Node*> IsIntPtrSub(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher) {
+  return kPointerSize == 8 ? IsInt64Sub(lhs_matcher, rhs_matcher)
+                           : IsInt32Sub(lhs_matcher, rhs_matcher);
+}
+
+
+Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher,
+                         const Matcher<Node*>& rhs_matcher) {
+  return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher)
+                           : IsWord32Shl(lhs_matcher, rhs_matcher);
+}
+
+
 TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) {
   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
     InterpreterAssemblerForTest m(this, bytecode);
@@ -86,6 +101,32 @@ TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) {
 }
 
 
+TARGET_TEST_F(InterpreterAssemblerTest, Return) {
+  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+    InterpreterAssemblerForTest m(this, bytecode);
+    m.Return();
+    Graph* graph = m.GetCompletedGraph();
+
+    Node* end = graph->end();
+    EXPECT_EQ(1, end->InputCount());
+    Node* tail_call_node = end->InputAt(0);
+
+    EXPECT_EQ(CallDescriptor::kInterpreterDispatch,
+              m.call_descriptor()->kind());
+    Matcher<Unique<HeapObject>> exit_trampoline(
+        Unique<HeapObject>::CreateImmovable(
+            isolate()->builtins()->InterpreterExitTrampoline()));
+    EXPECT_THAT(
+        tail_call_node,
+        IsTailCall(m.call_descriptor(), IsHeapConstant(exit_trampoline),
+                   IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
+                   IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
+                   IsParameter(Linkage::kInterpreterDispatchTableParameter),
+                   graph->start(), graph->start()));
+  }
+}
+
+
 TARGET_TEST_F(InterpreterAssemblerTest, BytecodeArg) {
   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
     InterpreterAssemblerForTest m(this, bytecode);
@@ -127,9 +168,9 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) {
     EXPECT_THAT(
         load_reg_node,
         m.IsLoad(kMachPtr, IsLoadFramePointer(),
-                 IsInt32Sub(IsInt32Constant(m.kFirstRegisterOffsetFromFp),
-                            IsWord32Shl(reg_index_node,
-                                        IsInt32Constant(kPointerSizeLog2)))));
+                 IsIntPtrSub(IsInt32Constant(m.kFirstRegisterOffsetFromFp),
+                             IsWordShl(reg_index_node,
+                                       IsInt32Constant(kPointerSizeLog2)))));
   }
 }
 
@@ -161,9 +202,9 @@ TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) {
         store_reg_node,
         m.IsStore(StoreRepresentation(kMachPtr, kNoWriteBarrier),
                   IsLoadFramePointer(),
-                  IsInt32Sub(IsInt32Constant(m.kFirstRegisterOffsetFromFp),
-                             IsWord32Shl(reg_index_node,
-                                         IsInt32Constant(kPointerSizeLog2))),
+                  IsIntPtrSub(IsInt32Constant(m.kFirstRegisterOffsetFromFp),
+                              IsWordShl(reg_index_node,
+                                        IsInt32Constant(kPointerSizeLog2))),
                   store_value));
   }
 }
index 273a46a48a46553011ca36eedde774c3bd82491e..4bdc295f5c9718e3bb41b9da6f191ddb59c35fa8 100644 (file)
@@ -1893,6 +1893,7 @@ IS_BINOP_MATCHER(Int32LessThan)
 IS_BINOP_MATCHER(Uint32LessThan)
 IS_BINOP_MATCHER(Uint32LessThanOrEqual)
 IS_BINOP_MATCHER(Int64Add)
+IS_BINOP_MATCHER(Int64Sub)
 IS_BINOP_MATCHER(Float32Max)
 IS_BINOP_MATCHER(Float32Min)
 IS_BINOP_MATCHER(Float32Equal)
index 330e46d302f06cfd6c8a189990c32490529b4efc..056aa78776052b85eb1319447234754417c8d82f 100644 (file)
@@ -253,6 +253,8 @@ Matcher<Node*> IsUint32LessThanOrEqual(const Matcher<Node*>& lhs_matcher,
                                        const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsInt64Add(const Matcher<Node*>& lhs_matcher,
                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt64Sub(const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsChangeFloat64ToInt32(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsChangeFloat64ToUint32(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);