[interpreter]: Changes to interpreter builtins for accumulator and register file...
authorrmcilroy <rmcilroy@chromium.org>
Tue, 18 Aug 2015 12:41:41 +0000 (05:41 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 18 Aug 2015 12:41:58 +0000 (12:41 +0000)
Makes the following modifications to the interpreter builtins and
InterpreterAssembler:
 - Adds an accumulator register and initializes it to undefined()
 - Adds a register file pointer register and use it instead of FramePointer to
   access registers
 - Modifies builtin to support functions with 0 regiters in the register file
 - Modifies builtin to Call rather than TailCall to first bytecode handler.

BUG=v8:4280
LOG=N

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

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

24 files changed:
src/arm/builtins-arm.cc
src/arm/macro-assembler-arm.h
src/arm64/builtins-arm64.cc
src/arm64/macro-assembler-arm64.h
src/compiler/interpreter-assembler.cc
src/compiler/interpreter-assembler.h
src/compiler/linkage.cc
src/compiler/linkage.h
src/compiler/raw-machine-assembler.cc
src/compiler/raw-machine-assembler.h
src/ia32/builtins-ia32.cc
src/ia32/macro-assembler-ia32.h
src/mips/builtins-mips.cc
src/mips/macro-assembler-mips.h
src/mips64/assembler-mips64.h
src/mips64/builtins-mips64.cc
src/mips64/macro-assembler-mips64.h
src/x64/builtins-x64.cc
src/x64/macro-assembler-x64.h
test/cctest/interpreter/test-interpreter.cc
test/unittests/compiler/interpreter-assembler-unittest.cc
test/unittests/compiler/interpreter-assembler-unittest.h
test/unittests/compiler/node-test-utils.cc
test/unittests/compiler/node-test-utils.h

index 75de918e8bb8651ebd5dc52474ed43b828d5f133..8d95694038ed57605741674b15b5eff43f7ed737 100644 (file)
@@ -8,7 +8,6 @@
 #include "src/debug/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 {
@@ -925,16 +924,17 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
     __ 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;
+    Label loop_check;
     __ LoadRoot(r9, Heap::kUndefinedValueRootIndex);
+    __ b(&loop_check, al);
     __ bind(&loop_header);
     // TODO(rmcilroy): Consider doing more than one push per loop iteration.
     __ push(r9);
     // Continue loop if not done.
+    __ bind(&loop_check);
     __ sub(r4, r4, Operand(kPointerSize), SetCC);
-    __ b(&loop_header, ne);
+    __ b(&loop_header, ge);
   }
 
   // TODO(rmcilroy): List of things not currently dealt with here but done in
@@ -968,7 +968,11 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
     __ bind(&ok);
   }
 
-  // Load bytecode offset and dispatch table into registers.
+  // Load accumulator, register file, bytecode offset, dispatch table into
+  // registers.
+  __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
+  __ sub(kInterpreterRegisterFileRegister, fp,
+         Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
   __ mov(kInterpreterBytecodeOffsetRegister,
          Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
   __ LoadRoot(kInterpreterDispatchTableRegister,
@@ -977,14 +981,14 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
          Operand(FixedArray::kHeaderSize - kHeapObjectTag));
 
   // Dispatch to the first bytecode handler for the function.
-  __ ldrb(r0, MemOperand(kInterpreterBytecodeArrayRegister,
+  __ ldrb(r1, MemOperand(kInterpreterBytecodeArrayRegister,
                          kInterpreterBytecodeOffsetRegister));
-  __ ldr(ip, MemOperand(kInterpreterDispatchTableRegister, r0, LSL,
+  __ ldr(ip, MemOperand(kInterpreterDispatchTableRegister, r1, 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);
+  __ Call(ip);
 }
 
 
@@ -995,9 +999,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
   //  - 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));
+  // The return value is in accumulator, which is already in r0.
+
   // Leave the frame (also dropping the register file).
   __ LeaveFrame(StackFrame::JAVA_SCRIPT);
   // Drop receiver + arguments.
index ea66d748b8e3c09169a005a85b9a860983e6d406..5ec2bd3f8b1d4106e7204d1f80a9b1888d870c1e 100644 (file)
@@ -18,6 +18,8 @@ const Register kReturnRegister0 = {kRegister_r0_Code};
 const Register kReturnRegister1 = {kRegister_r1_Code};
 const Register kJSFunctionRegister = {kRegister_r1_Code};
 const Register kContextRegister = {kRegister_r7_Code};
+const Register kInterpreterAccumulatorRegister = {kRegister_r0_Code};
+const Register kInterpreterRegisterFileRegister = {kRegister_r4_Code};
 const Register kInterpreterBytecodeOffsetRegister = {kRegister_r5_Code};
 const Register kInterpreterBytecodeArrayRegister = {kRegister_r6_Code};
 const Register kInterpreterDispatchTableRegister = {kRegister_r8_Code};
index b2f572b0d072f2a6e66cb7dfd09d147f97408ef6..2539b4369e8390ec92b2bff14e2128b3db9a9518 100644 (file)
@@ -990,7 +990,11 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
     __ Bind(&ok);
   }
 
-  // Load bytecode offset and dispatch table into registers.
+  // Load accumulator, register file, bytecode offset, dispatch table into
+  // registers.
+  __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
+  __ Sub(kInterpreterRegisterFileRegister, fp,
+         Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
   __ Mov(kInterpreterBytecodeOffsetRegister,
          Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
   __ LoadRoot(kInterpreterDispatchTableRegister,
@@ -999,14 +1003,14 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
          Operand(FixedArray::kHeaderSize - kHeapObjectTag));
 
   // Dispatch to the first bytecode handler for the function.
-  __ Ldrb(x0, MemOperand(kInterpreterBytecodeArrayRegister,
+  __ Ldrb(x1, MemOperand(kInterpreterBytecodeArrayRegister,
                          kInterpreterBytecodeOffsetRegister));
-  __ Mov(x0, Operand(x0, LSL, kPointerSizeLog2));
-  __ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x0));
+  __ Mov(x1, Operand(x1, LSL, kPointerSizeLog2));
+  __ Ldr(ip0, MemOperand(kInterpreterDispatchTableRegister, x1));
   // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
   // and header removal.
   __ Add(ip0, ip0, Operand(Code::kHeaderSize - kHeapObjectTag));
-  __ Jump(ip0);
+  __ Call(ip0);
 }
 
 
@@ -1017,9 +1021,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
   //  - 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));
+  // The return value is in accumulator, which is already in x0.
+
   // Leave the frame (also dropping the register file).
   __ LeaveFrame(StackFrame::JAVA_SCRIPT);
   // Drop receiver + arguments.
index 5e3c014163b9d827735e2cb90d9684a547d21291..76e2fdb3fb67d5db43aec3f0dd3f05ae950823c5 100644 (file)
@@ -39,6 +39,8 @@ namespace internal {
 #define kReturnRegister1 x1
 #define kJSFunctionRegister x1
 #define kContextRegister cp
+#define kInterpreterAccumulatorRegister x0
+#define kInterpreterRegisterFileRegister x18
 #define kInterpreterBytecodeOffsetRegister x19
 #define kInterpreterBytecodeArrayRegister x20
 #define kInterpreterDispatchTableRegister x21
index fbc170559dbea0389401a11499dc554f2c30b741..135a54815a4ff4057bc2d2446a16a2fc574fddf9 100644 (file)
@@ -31,6 +31,8 @@ InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone,
           Linkage::GetInterpreterDispatchDescriptor(zone), kMachPtr,
           InstructionSelector::SupportedMachineOperatorFlags())),
       end_node_(nullptr),
+      accumulator_(
+          raw_assembler_->Parameter(Linkage::kInterpreterAccumulatorParameter)),
       code_generated_(false) {}
 
 
@@ -60,70 +62,72 @@ Handle<Code> InterpreterAssembler::GenerateCode() {
 }
 
 
-Node* InterpreterAssembler::BytecodeArrayPointer() {
-  return raw_assembler_->Parameter(Linkage::kInterpreterBytecodeArrayParameter);
+Node* InterpreterAssembler::GetAccumulator() {
+  return accumulator_;
 }
 
 
-Node* InterpreterAssembler::BytecodeOffset() {
-  return raw_assembler_->Parameter(
-      Linkage::kInterpreterBytecodeOffsetParameter);
+void InterpreterAssembler::SetAccumulator(Node* value) {
+  accumulator_ = value;
 }
 
 
-Node* InterpreterAssembler::DispatchTablePointer() {
-  return raw_assembler_->Parameter(Linkage::kInterpreterDispatchTableParameter);
+Node* InterpreterAssembler::RegisterFileRawPointer() {
+  return raw_assembler_->Parameter(Linkage::kInterpreterRegisterFileParameter);
 }
 
 
-Node* InterpreterAssembler::FramePointer() {
-  return raw_assembler_->LoadFramePointer();
+Node* InterpreterAssembler::BytecodeArrayTaggedPointer() {
+  return raw_assembler_->Parameter(Linkage::kInterpreterBytecodeArrayParameter);
 }
 
 
-Node* InterpreterAssembler::RegisterFrameOffset(int index) {
-  DCHECK_LE(index, kMaxRegisterIndex);
-  return Int32Constant(kFirstRegisterOffsetFromFp -
-                       (index << kPointerSizeLog2));
+Node* InterpreterAssembler::BytecodeOffset() {
+  return raw_assembler_->Parameter(
+      Linkage::kInterpreterBytecodeOffsetParameter);
 }
 
 
-Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
-  return raw_assembler_->IntPtrSub(
-      Int32Constant(kFirstRegisterOffsetFromFp),
-      raw_assembler_->WordShl(index, Int32Constant(kPointerSizeLog2)));
+Node* InterpreterAssembler::DispatchTableRawPointer() {
+  return raw_assembler_->Parameter(Linkage::kInterpreterDispatchTableParameter);
 }
 
 
-Node* InterpreterAssembler::BytecodeOperand(int delta) {
-  DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
-  return raw_assembler_->Load(
-      kMachUint8, BytecodeArrayPointer(),
-      raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
+Node* InterpreterAssembler::RegisterFrameOffset(Node* index) {
+  return raw_assembler_->WordShl(index, Int32Constant(kPointerSizeLog2));
 }
 
 
-Node* InterpreterAssembler::LoadRegister(int index) {
-  return raw_assembler_->Load(kMachPtr, FramePointer(),
-                              RegisterFrameOffset(index));
+Node* InterpreterAssembler::LoadRegister(Node* reg_index) {
+  return raw_assembler_->Load(kMachPtr, RegisterFileRawPointer(),
+                              RegisterFrameOffset(reg_index));
 }
 
 
-Node* InterpreterAssembler::LoadRegister(Node* index) {
-  return raw_assembler_->Load(kMachPtr, FramePointer(),
-                              RegisterFrameOffset(index));
+Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
+  return raw_assembler_->Store(kMachPtr, RegisterFileRawPointer(),
+                               RegisterFrameOffset(reg_index), value);
 }
 
 
-Node* InterpreterAssembler::StoreRegister(Node* value, int index) {
-  return raw_assembler_->Store(kMachPtr, FramePointer(),
-                               RegisterFrameOffset(index), value);
+Node* InterpreterAssembler::BytecodeOperand(int delta) {
+  DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
+  return raw_assembler_->Load(
+      kMachUint8, BytecodeArrayTaggedPointer(),
+      raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
 }
 
 
-Node* InterpreterAssembler::StoreRegister(Node* value, Node* index) {
-  return raw_assembler_->Store(kMachPtr, FramePointer(),
-                               RegisterFrameOffset(index), value);
+Node* InterpreterAssembler::BytecodeOperandSignExtended(int delta) {
+  DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
+  Node* load = raw_assembler_->Load(
+      kMachInt8, BytecodeArrayTaggedPointer(),
+      raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
+  // Ensure that we sign extend to full pointer size
+  if (kPointerSize == 8) {
+    load = raw_assembler_->ChangeInt32ToInt64(load);
+  }
+  return load;
 }
 
 
@@ -132,14 +136,15 @@ void InterpreterAssembler::Return() {
       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);
+  STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
+  STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
+  STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
+  STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
+  STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
+  Node* tail_call = raw_assembler_->TailCallInterpreterDispatch(
+      call_descriptor(), exit_trampoline_code_object, GetAccumulator(),
+      RegisterFileRawPointer(), BytecodeOffset(), BytecodeArrayTaggedPointer(),
+      DispatchTableRawPointer());
   // This should always be the end node.
   SetEndInput(tail_call);
 }
@@ -153,24 +158,25 @@ Node* InterpreterAssembler::Advance(int delta) {
 void InterpreterAssembler::Dispatch() {
   Node* new_bytecode_offset = Advance(interpreter::Bytecodes::Size(bytecode_));
   Node* target_bytecode = raw_assembler_->Load(
-      kMachUint8, BytecodeArrayPointer(), new_bytecode_offset);
+      kMachUint8, BytecodeArrayTaggedPointer(), new_bytecode_offset);
 
   // TODO(rmcilroy): Create a code target dispatch table to avoid conversion
   // from code object on every dispatch.
   Node* target_code_object = raw_assembler_->Load(
-      kMachPtr, DispatchTablePointer(),
+      kMachPtr, DispatchTableRawPointer(),
       raw_assembler_->Word32Shl(target_bytecode,
                                 Int32Constant(kPointerSizeLog2)));
 
   // 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()), target_code_object,
-      new_bytecode_offset, BytecodeArrayPointer(), DispatchTablePointer(),
-      graph()->start(), graph()->start());
-  schedule()->AddTailCall(raw_assembler_->CurrentBlock(), tail_call);
+  STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
+  STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
+  STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
+  STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
+  STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
+  Node* tail_call = raw_assembler_->TailCallInterpreterDispatch(
+      call_descriptor(), target_code_object, GetAccumulator(),
+      RegisterFileRawPointer(), new_bytecode_offset,
+      BytecodeArrayTaggedPointer(), DispatchTableRawPointer());
   // This should always be the end node.
   SetEndInput(tail_call);
 }
@@ -185,7 +191,7 @@ void InterpreterAssembler::SetEndInput(Node* input) {
 void InterpreterAssembler::End() {
   DCHECK(end_node_);
   // TODO(rmcilroy): Support more than 1 end input.
-  Node* end = graph()->NewNode(common()->End(1), end_node_);
+  Node* end = graph()->NewNode(raw_assembler_->common()->End(1), end_node_);
   graph()->SetEnd(end);
 }
 
@@ -207,16 +213,6 @@ Schedule* InterpreterAssembler::schedule() {
 }
 
 
-MachineOperatorBuilder* InterpreterAssembler::machine() {
-  return raw_assembler_->machine();
-}
-
-
-CommonOperatorBuilder* InterpreterAssembler::common() {
-  return raw_assembler_->common();
-}
-
-
 Node* InterpreterAssembler::Int32Constant(int value) {
   return raw_assembler_->Int32Constant(value);
 }
@@ -231,7 +227,6 @@ Node* InterpreterAssembler::HeapConstant(Unique<HeapObject> object) {
   return raw_assembler_->HeapConstant(object);
 }
 
-
 }  // namespace interpreter
 }  // namespace internal
 }  // namespace v8
index ead7b92d7aa8b6792398e0308ece8cdf844c4f7b..7d095c9be49d8de0d2f7cad45c827a506d491ead 100644 (file)
@@ -22,9 +22,7 @@ class Zone;
 namespace compiler {
 
 class CallDescriptor;
-class CommonOperatorBuilder;
 class Graph;
-class MachineOperatorBuilder;
 class Node;
 class Operator;
 class RawMachineAssembler;
@@ -38,33 +36,29 @@ class InterpreterAssembler {
 
   Handle<Code> GenerateCode();
 
+  // Accumulator.
+  Node* GetAccumulator();
+  void SetAccumulator(Node* value);
+
+  // Loads from and stores to the interpreter register file.
+  Node* LoadRegister(Node* reg_index);
+  Node* StoreRegister(Node* value, Node* reg_index);
+
   // Constants.
   Node* Int32Constant(int value);
   Node* NumberConstant(double value);
   Node* HeapConstant(Unique<HeapObject> object);
 
-  // Returns the bytecode operand |index| for the current bytecode.
-  Node* BytecodeOperand(int index);
-
-  // Loads from and stores to the interpreter register file.
-  Node* LoadRegister(int index);
-  Node* LoadRegister(Node* index);
-  Node* StoreRegister(Node* value, int index);
-  Node* StoreRegister(Node* value, Node* index);
-
   // Returns from the function.
   void Return();
 
   // Dispatch to the bytecode.
   void Dispatch();
 
- protected:
-  static const int kFirstRegisterOffsetFromFp =
-      -kPointerSize - StandardFrameConstants::kFixedFrameSizeFromFp;
-
-  // TODO(rmcilroy): Increase this when required.
-  static const int kMaxRegisterIndex = 255;
+  Node* BytecodeOperand(int index);
+  Node* BytecodeOperandSignExtended(int index);
 
+ protected:
   // Close the graph.
   void End();
 
@@ -73,17 +67,16 @@ class InterpreterAssembler {
   Graph* graph();
 
  private:
+  // Returns a raw pointer to start of the register file on the stack.
+  Node* RegisterFileRawPointer();
   // Returns a tagged pointer to the current function's BytecodeArray object.
-  Node* BytecodeArrayPointer();
+  Node* BytecodeArrayTaggedPointer();
   // Returns the offset from the BytecodeArrayPointer of the current bytecode.
   Node* BytecodeOffset();
   // Returns a pointer to first entry in the interpreter dispatch table.
-  Node* DispatchTablePointer();
-  // Returns the frame pointer for the current function.
-  Node* FramePointer();
+  Node* DispatchTableRawPointer();
 
-  // Returns the offset of register |index|.
-  Node* RegisterFrameOffset(int index);
+  // Returns the offset of register |index| relative to RegisterFilePointer().
   Node* RegisterFrameOffset(Node* index);
 
   // Returns BytecodeOffset() advanced by delta bytecodes. Note: this does not
@@ -96,12 +89,11 @@ class InterpreterAssembler {
   // Private helpers which delegate to RawMachineAssembler.
   Isolate* isolate();
   Schedule* schedule();
-  MachineOperatorBuilder* machine();
-  CommonOperatorBuilder* common();
 
   interpreter::Bytecode bytecode_;
   base::SmartPointer<RawMachineAssembler> raw_assembler_;
   Node* end_node_;
+  Node* accumulator_;
   bool code_generated_;
 
   DISALLOW_COPY_AND_ASSIGN(InterpreterAssembler);
index 2c6d2a8ae41430da5d01ed82aea4cb35ffcadcfe..e6ef59898f9360eec3e3a491fc2bed695580c292 100644 (file)
@@ -392,19 +392,27 @@ CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr,
 
 
 CallDescriptor* Linkage::GetInterpreterDispatchDescriptor(Zone* zone) {
-  MachineSignature::Builder types(zone, 0, 3);
-  LocationSignature::Builder locations(zone, 0, 3);
+  MachineSignature::Builder types(zone, 0, 5);
+  LocationSignature::Builder locations(zone, 0, 5);
 
   // Add registers for fixed parameters passed via interpreter dispatch.
-  STATIC_ASSERT(0 == Linkage::kInterpreterBytecodeOffsetParameter);
+  STATIC_ASSERT(0 == Linkage::kInterpreterAccumulatorParameter);
+  types.AddParam(kMachAnyTagged);
+  locations.AddParam(regloc(kInterpreterAccumulatorRegister));
+
+  STATIC_ASSERT(1 == Linkage::kInterpreterRegisterFileParameter);
+  types.AddParam(kMachPtr);
+  locations.AddParam(regloc(kInterpreterRegisterFileRegister));
+
+  STATIC_ASSERT(2 == Linkage::kInterpreterBytecodeOffsetParameter);
   types.AddParam(kMachIntPtr);
   locations.AddParam(regloc(kInterpreterBytecodeOffsetRegister));
 
-  STATIC_ASSERT(1 == Linkage::kInterpreterBytecodeArrayParameter);
+  STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
   types.AddParam(kMachAnyTagged);
   locations.AddParam(regloc(kInterpreterBytecodeArrayRegister));
 
-  STATIC_ASSERT(2 == Linkage::kInterpreterDispatchTableParameter);
+  STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
   types.AddParam(kMachPtr);
   locations.AddParam(regloc(kInterpreterDispatchTableRegister));
 
index 623c9109d96b93b271c61daf5d811b2d694933cf..f5507a0594ea56fdfe2c3dd37300f4857e234cbb 100644 (file)
@@ -330,9 +330,11 @@ class Linkage : public ZoneObject {
 
   // Special parameter indices used to pass fixed register data through
   // interpreter dispatches.
-  static const int kInterpreterBytecodeOffsetParameter = 0;
-  static const int kInterpreterBytecodeArrayParameter = 1;
-  static const int kInterpreterDispatchTableParameter = 2;
+  static const int kInterpreterAccumulatorParameter = 0;
+  static const int kInterpreterRegisterFileParameter = 1;
+  static const int kInterpreterBytecodeOffsetParameter = 2;
+  static const int kInterpreterBytecodeArrayParameter = 3;
+  static const int kInterpreterDispatchTableParameter = 4;
 
  private:
   CallDescriptor* const incoming_;
index 2ce9ef20ccdc3122c9319c28d58f6390fad6fa17..8013f422f6b9ba42bd825b068367f3bc96730e44 100644 (file)
@@ -232,6 +232,17 @@ Node* RawMachineAssembler::CallCFunction8(
 }
 
 
+Node* RawMachineAssembler::TailCallInterpreterDispatch(
+    const CallDescriptor* call_descriptor, Node* target, Node* arg1, Node* arg2,
+    Node* arg3, Node* arg4, Node* arg5) {
+  Node* tail_call =
+      graph()->NewNode(common()->TailCall(call_descriptor), target, arg1, arg2,
+                       arg3, arg4, arg5, graph()->start(), graph()->start());
+  schedule()->AddTailCall(CurrentBlock(), tail_call);
+  return tail_call;
+}
+
+
 void RawMachineAssembler::Bind(Label* label) {
   DCHECK(current_block_ == nullptr);
   DCHECK(!label->bound_);
index 19ea2b0ad15f767b77aebe566a0b7da8ec04a62a..05f4ebab026de5f815a273519e8c4681185ca67a 100644 (file)
@@ -508,6 +508,9 @@ class RawMachineAssembler {
                        MachineType arg7_type, Node* function, Node* arg0,
                        Node* arg1, Node* arg2, Node* arg3, Node* arg4,
                        Node* arg5, Node* arg6, Node* arg7);
+  Node* TailCallInterpreterDispatch(const CallDescriptor* call_descriptor,
+                                    Node* target, Node* arg1, Node* arg2,
+                                    Node* arg3, Node* arg4, Node* arg5);
 
   // ===========================================================================
   // The following utility methods deal with control flow, hence might switch
index bb0a194df668f564bbe804eb6bdb533dae2a1033..15f3ace14ec28edffe5ab5a09f0ddb26bff301dc 100644 (file)
@@ -634,20 +634,23 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
 
   // 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));
+  __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+  __ mov(kInterpreterBytecodeArrayRegister,
+         FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
 
   if (FLAG_debug_code) {
     // Check function data field is actually a BytecodeArray object.
-    __ AssertNotSmi(edi);
-    __ CmpObjectType(edi, BYTECODE_ARRAY_TYPE, eax);
+    __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
+    __ CmpObjectType(kInterpreterBytecodeArrayRegister, 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));
+    __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
+                             BytecodeArray::kFrameSizeOffset));
 
     // Do a stack check to ensure we don't go over the limit.
     Label ok;
@@ -656,21 +659,22 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
     ExternalReference stack_limit =
         ExternalReference::address_of_real_stack_limit(masm->isolate());
     __ cmp(ecx, Operand::StaticVariable(stack_limit));
-    __ j(above_equal, &ok, Label::kNear);
+    __ j(above_equal, &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;
+    Label loop_check;
     __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
+    __ jmp(&loop_check);
     __ bind(&loop_header);
     // TODO(rmcilroy): Consider doing more than one push per loop iteration.
     __ push(eax);
     // Continue loop if not done.
+    __ bind(&loop_check);
     __ sub(ebx, Immediate(kPointerSize));
-    __ j(not_equal, &loop_header, Label::kNear);
+    __ j(greater_equal, &loop_header);
   }
 
   // TODO(rmcilroy): List of things not currently dealt with here but done in
@@ -700,25 +704,39 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
     ExternalReference stack_limit =
         ExternalReference::address_of_stack_limit(masm->isolate());
     __ cmp(esp, Operand::StaticVariable(stack_limit));
-    __ j(above_equal, &ok, Label::kNear);
+    __ j(above_equal, &ok);
     __ CallRuntime(Runtime::kStackGuard, 0);
     __ bind(&ok);
   }
 
-  // Load bytecode offset and dispatch table into registers.
-  __ mov(ecx, Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
+  // Load accumulator, register file, bytecode offset, dispatch table into
+  // registers.
+  __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
+  __ mov(kInterpreterRegisterFileRegister, ebp);
+  __ sub(
+      kInterpreterRegisterFileRegister,
+      Immediate(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
+  __ mov(kInterpreterBytecodeOffsetRegister,
+         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));
+  __ LoadRoot(kInterpreterDispatchTableRegister,
+              Heap::kInterpreterTableRootIndex);
+  __ add(kInterpreterDispatchTableRegister,
+         Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
+
+  // TODO(rmcilroy) Push our context as a stack located parameter of the
+  // bytecode handler.
 
   // 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));
+  __ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
+                          kInterpreterBytecodeOffsetRegister, times_1, 0));
+  __ mov(esi, Operand(kInterpreterDispatchTableRegister, esi,
+                      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);
+  __ add(esi, Immediate(Code::kHeaderSize - kHeapObjectTag));
+  __ call(esi);
 }
 
 
@@ -729,9 +747,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
   //  - 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));
+  // The return value is in accumulator, which is already in rax.
+
   // Leave the frame (also dropping the register file).
   __ leave();
   // Return droping receiver + arguments.
index 92aade9e2659e5beeb29ff6f753757af65486252..b228ef9a2850e272487fbe4355941dbf4c769d57 100644 (file)
@@ -18,6 +18,8 @@ const Register kReturnRegister0 = {kRegister_eax_Code};
 const Register kReturnRegister1 = {kRegister_edx_Code};
 const Register kJSFunctionRegister = {kRegister_edi_Code};
 const Register kContextRegister = {kRegister_esi_Code};
+const Register kInterpreterAccumulatorRegister = {kRegister_eax_Code};
+const Register kInterpreterRegisterFileRegister = {kRegister_edx_Code};
 const Register kInterpreterBytecodeOffsetRegister = {kRegister_ecx_Code};
 const Register kInterpreterBytecodeArrayRegister = {kRegister_edi_Code};
 const Register kInterpreterDispatchTableRegister = {kRegister_ebx_Code};
index 5eb0b3233d51daad0bc3407ccefc4501700a8e6f..44acfb99a1ca9a8b95ea48f2719fed59979b08bd 100644 (file)
@@ -916,14 +916,15 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
     __ 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;
+    Label loop_check;
     __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
+    __ Branch(&loop_check);
     __ bind(&loop_header);
     // TODO(rmcilroy): Consider doing more than one push per loop iteration.
     __ push(t1);
     // Continue loop if not done.
+    __ bind(&loop_check);
     __ Subu(t0, t0, Operand(kPointerSize));
     __ Branch(&loop_header, ge, t0, Operand(zero_reg));
   }
@@ -959,6 +960,10 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
   }
 
   // Load bytecode offset and dispatch table into registers.
+  __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
+  __ Subu(
+      kInterpreterRegisterFileRegister, fp,
+      Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
   __ li(kInterpreterBytecodeOffsetRegister,
         Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
   __ LoadRoot(kInterpreterDispatchTableRegister,
@@ -976,7 +981,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
   // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
   // and header removal.
   __ Addu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
-  __ Jump(at);
+  __ Call(at);
 }
 
 
@@ -987,9 +992,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
   //  - 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));
+  // The return value is in accumulator, which is already in v0.
+
   // Leave the frame (also dropping the register file).
   __ LeaveFrame(StackFrame::JAVA_SCRIPT);
   // Drop receiver + arguments.
index ee9ffe796238dd47137f5d2c406d02938dfd5fcb..995c082119e849c9300501622a34a615452ef288 100644 (file)
@@ -17,6 +17,8 @@ const Register kReturnRegister0 = {kRegister_v0_Code};
 const Register kReturnRegister1 = {kRegister_v1_Code};
 const Register kJSFunctionRegister = {kRegister_a1_Code};
 const Register kContextRegister = {Register::kCpRegister};
+const Register kInterpreterAccumulatorRegister = {kRegister_v0_Code};
+const Register kInterpreterRegisterFileRegister = {kRegister_t3_Code};
 const Register kInterpreterBytecodeOffsetRegister = {kRegister_t4_Code};
 const Register kInterpreterBytecodeArrayRegister = {kRegister_t5_Code};
 const Register kInterpreterDispatchTableRegister = {kRegister_t6_Code};
index 3ca72a72201ba4bb5bedc9587890409d82c04df4..01640723333947555e4c040a9459175272e4cb3c 100644 (file)
@@ -75,7 +75,7 @@ namespace internal {
 // Core register.
 struct Register {
   static const int kNumRegisters = v8::internal::kNumRegisters;
-  static const int kMaxNumAllocatableRegisters = 14;  // v0 through t6 and cp.
+  static const int kMaxNumAllocatableRegisters = 14;  // v0 through t2 and cp.
   static const int kSizeInBytes = 8;
   static const int kCpRegister = 23;  // cp (s7) is the 23rd register.
 
index f27a7b6b1f9718295ea2b6c34e3ca8bf09a0abb9..843daa1ee5cfb495a0c0bb9c280e022e714ff6af 100644 (file)
@@ -913,14 +913,15 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
     __ 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;
+    Label loop_check;
     __ LoadRoot(a5, Heap::kUndefinedValueRootIndex);
+    __ Branch(&loop_check);
     __ bind(&loop_header);
     // TODO(rmcilroy): Consider doing more than one push per loop iteration.
     __ push(a5);
     // Continue loop if not done.
+    __ bind(&loop_check);
     __ Dsubu(a4, a4, Operand(kPointerSize));
     __ Branch(&loop_header, ge, a4, Operand(zero_reg));
   }
@@ -956,6 +957,10 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
   }
 
   // Load bytecode offset and dispatch table into registers.
+  __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
+  __ Dsubu(
+      kInterpreterRegisterFileRegister, fp,
+      Operand(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
   __ li(kInterpreterBytecodeOffsetRegister,
         Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
   __ LoadRoot(kInterpreterDispatchTableRegister,
@@ -973,7 +978,7 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
   // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
   // and header removal.
   __ Daddu(at, at, Operand(Code::kHeaderSize - kHeapObjectTag));
-  __ Jump(at);
+  __ Call(at);
 }
 
 
@@ -984,9 +989,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
   //  - 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));
+  // The return value is in accumulator, which is already in v0.
+
   // Leave the frame (also dropping the register file).
   __ LeaveFrame(StackFrame::JAVA_SCRIPT);
   // Drop receiver + arguments.
index f45b1b0169cb1b080e0db71bdf9b82dfbf390e68..f2d36e22e2fd1c4a2cd2265f9c629748eda99f9a 100644 (file)
@@ -17,6 +17,8 @@ const Register kReturnRegister0 = {kRegister_v0_Code};
 const Register kReturnRegister1 = {kRegister_v1_Code};
 const Register kJSFunctionRegister = {kRegister_a1_Code};
 const Register kContextRegister = {kRegister_s7_Code};
+const Register kInterpreterAccumulatorRegister = {kRegister_v0_Code};
+const Register kInterpreterRegisterFileRegister = {kRegister_a7_Code};
 const Register kInterpreterBytecodeOffsetRegister = {kRegister_t0_Code};
 const Register kInterpreterBytecodeArrayRegister = {kRegister_t1_Code};
 const Register kInterpreterDispatchTableRegister = {kRegister_t2_Code};
index b9d456ebde403074b04b4d5cadb2cec9b8087ade..3a0d3dc95d317cf6226c86a67da0d41c1deb5ca8 100644 (file)
@@ -694,20 +694,23 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
 
   // 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));
+  __ movp(rax, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+  __ movp(kInterpreterBytecodeArrayRegister,
+          FieldOperand(rax, SharedFunctionInfo::kFunctionDataOffset));
 
   if (FLAG_debug_code) {
     // Check function data field is actually a BytecodeArray object.
-    __ AssertNotSmi(r14);
-    __ CmpObjectType(r14, BYTECODE_ARRAY_TYPE, rax);
+    __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
+    __ CmpObjectType(kInterpreterBytecodeArrayRegister, 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));
+    __ movl(rcx, FieldOperand(kInterpreterBytecodeArrayRegister,
+                              BytecodeArray::kFrameSizeOffset));
 
     // Do a stack check to ensure we don't go over the limit.
     Label ok;
@@ -719,16 +722,17 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
     __ 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;
+    Label loop_check;
     __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
+    __ j(always, &loop_check);
     __ bind(&loop_header);
     // TODO(rmcilroy): Consider doing more than one push per loop iteration.
     __ Push(rdx);
     // Continue loop if not done.
+    __ bind(&loop_check);
     __ subp(rcx, Immediate(kPointerSize));
-    __ j(not_equal, &loop_header, Label::kNear);
+    __ j(greater_equal, &loop_header, Label::kNear);
   }
 
   // TODO(rmcilroy): List of things not currently dealt with here but done in
@@ -761,18 +765,29 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
     __ 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));
+  // Load accumulator, register file, bytecode offset, dispatch table into
+  // registers.
+  __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
+  __ movp(kInterpreterRegisterFileRegister, rbp);
+  __ subp(
+      kInterpreterRegisterFileRegister,
+      Immediate(kPointerSize + StandardFrameConstants::kFixedFrameSizeFromFp));
+  __ movp(kInterpreterBytecodeOffsetRegister,
+          Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
+  __ LoadRoot(kInterpreterDispatchTableRegister,
+              Heap::kInterpreterTableRootIndex);
+  __ addp(kInterpreterDispatchTableRegister,
+          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));
+  __ movzxbp(rbx, Operand(kInterpreterBytecodeArrayRegister,
+                          kInterpreterBytecodeOffsetRegister, times_1, 0));
+  __ movp(rbx, Operand(kInterpreterDispatchTableRegister, rbx,
+                       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);
+  __ addp(rbx, Immediate(Code::kHeaderSize - kHeapObjectTag));
+  __ call(rbx);
 }
 
 
@@ -783,9 +798,8 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
   //  - 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));
+  // The return value is in accumulator, which is already in rax.
+
   // Leave the frame (also dropping the register file).
   __ leave();
   // Return droping receiver + arguments.
index 3fff11572c58f0c2c6b5ebc5f42a5342be0367c3..7852d39c03265e88c4afb86bd52220a7782f2b86 100644 (file)
@@ -20,6 +20,8 @@ const Register kReturnRegister0 = {kRegister_rax_Code};
 const Register kReturnRegister1 = {kRegister_rdx_Code};
 const Register kJSFunctionRegister = {kRegister_rdi_Code};
 const Register kContextRegister = {kRegister_rsi_Code};
+const Register kInterpreterAccumulatorRegister = {kRegister_rax_Code};
+const Register kInterpreterRegisterFileRegister = {kRegister_r11_Code};
 const Register kInterpreterBytecodeOffsetRegister = {kRegister_r12_Code};
 const Register kInterpreterBytecodeArrayRegister = {kRegister_r14_Code};
 const Register kInterpreterDispatchTableRegister = {kRegister_r15_Code};
index c3ecc5811122d9b472c2dca4b99b46753f6ecd57..d46672aca52073321c28c08539f17a73eda50858 100644 (file)
@@ -72,9 +72,7 @@ TEST(TestInterpreterReturn) {
       handles.main_isolate()->factory()->undefined_value();
 
   BytecodeArrayBuilder builder(handles.main_isolate());
-  // TODO(rmcilroy) set to 0 once BytecodeArray update to allow zero size
-  // register file.
-  builder.set_locals_count(1);
+  builder.set_locals_count(0);
   builder.Return();
   Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
 
index ebc2e65f59e59c3e9ecc90cf2794f0898a617b0f..a68527adf2d4eef5cbe3d080b32f6c976114a455 100644 (file)
@@ -10,6 +10,8 @@
 #include "test/unittests/compiler/compiler-test-utils.h"
 #include "test/unittests/compiler/node-test-utils.h"
 
+using ::testing::_;
+
 namespace v8 {
 namespace internal {
 namespace compiler {
@@ -93,6 +95,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) {
     EXPECT_THAT(
         tail_call_node,
         IsTailCall(m.call_descriptor(), code_target_matcher,
+                   IsParameter(Linkage::kInterpreterAccumulatorParameter),
+                   IsParameter(Linkage::kInterpreterRegisterFileParameter),
                    next_bytecode_offset_matcher,
                    IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
                    IsParameter(Linkage::kInterpreterDispatchTableParameter),
@@ -119,6 +123,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, Return) {
     EXPECT_THAT(
         tail_call_node,
         IsTailCall(m.call_descriptor(), IsHeapConstant(exit_trampoline),
+                   IsParameter(Linkage::kInterpreterAccumulatorParameter),
+                   IsParameter(Linkage::kInterpreterRegisterFileParameter),
                    IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
                    IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
                    IsParameter(Linkage::kInterpreterDispatchTableParameter),
@@ -146,48 +152,65 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
 }
 
 
-TARGET_TEST_F(InterpreterAssemblerTest, LoadRegisterFixed) {
+TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperandSignExtended) {
   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
     InterpreterAssemblerForTest m(this, bytecode);
-    for (int i = 0; i < m.kMaxRegisterIndex; i++) {
-      Node* load_reg_node = m.LoadRegister(i);
-      EXPECT_THAT(load_reg_node,
-                  m.IsLoad(kMachPtr, IsLoadFramePointer(),
-                           IsInt32Constant(m.kFirstRegisterOffsetFromFp -
-                                           (i << kPointerSizeLog2))));
+    int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode);
+    for (int i = 0; i < number_of_operands; i++) {
+      Node* load_arg_node = m.BytecodeOperandSignExtended(i);
+      Matcher<Node*> load_matcher = m.IsLoad(
+          kMachInt8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
+          IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
+                      IsInt32Constant(1 + i)));
+      if (kPointerSize == 8) {
+        load_matcher = IsChangeInt32ToInt64(load_matcher);
+      }
+      EXPECT_THAT(load_arg_node, load_matcher);
     }
   }
 }
 
 
-TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) {
+TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) {
   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
     InterpreterAssemblerForTest m(this, bytecode);
-    Node* reg_index_node = m.Int32Constant(44);
-    Node* load_reg_node = m.LoadRegister(reg_index_node);
-    EXPECT_THAT(
-        load_reg_node,
-        m.IsLoad(kMachPtr, IsLoadFramePointer(),
-                 IsIntPtrSub(IsInt32Constant(m.kFirstRegisterOffsetFromFp),
-                             IsWordShl(reg_index_node,
-                                       IsInt32Constant(kPointerSizeLog2)))));
+    // Should be incoming accumulator if not set.
+    EXPECT_THAT(m.GetAccumulator(),
+                IsParameter(Linkage::kInterpreterAccumulatorParameter));
+
+    // Should be set by SedtAccumulator.
+    Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef);
+    m.SetAccumulator(accumulator_value_1);
+    EXPECT_THAT(m.GetAccumulator(), accumulator_value_1);
+    Node* accumulator_value_2 = m.Int32Constant(42);
+    m.SetAccumulator(accumulator_value_2);
+    EXPECT_THAT(m.GetAccumulator(), accumulator_value_2);
+
+    // Should be passed to next bytecode handler on dispatch.
+    m.Dispatch();
+    Graph* graph = m.GetCompletedGraph();
+
+    Node* end = graph->end();
+    EXPECT_EQ(1, end->InputCount());
+    Node* tail_call_node = end->InputAt(0);
+
+    EXPECT_THAT(tail_call_node,
+                IsTailCall(m.call_descriptor(), _, accumulator_value_2, _, _, _,
+                           _, graph->start(), graph->start()));
   }
 }
 
 
-TARGET_TEST_F(InterpreterAssemblerTest, StoreRegisterFixed) {
+TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) {
   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
     InterpreterAssemblerForTest m(this, bytecode);
-    Node* store_value = m.Int32Constant(0xdeadbeef);
-    for (int i = 0; i < m.kMaxRegisterIndex; i++) {
-      Node* store_reg_node = m.StoreRegister(store_value, i);
-      EXPECT_THAT(store_reg_node,
-                  m.IsStore(StoreRepresentation(kMachPtr, kNoWriteBarrier),
-                            IsLoadFramePointer(),
-                            IsInt32Constant(m.kFirstRegisterOffsetFromFp -
-                                            (i << kPointerSizeLog2)),
-                            store_value));
-    }
+    Node* reg_index_node = m.Int32Constant(44);
+    Node* load_reg_node = m.LoadRegister(reg_index_node);
+    EXPECT_THAT(
+        load_reg_node,
+        m.IsLoad(kMachPtr,
+                 IsParameter(Linkage::kInterpreterRegisterFileParameter),
+                 IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2))));
   }
 }
 
@@ -201,10 +224,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) {
     EXPECT_THAT(
         store_reg_node,
         m.IsStore(StoreRepresentation(kMachPtr, kNoWriteBarrier),
-                  IsLoadFramePointer(),
-                  IsIntPtrSub(IsInt32Constant(m.kFirstRegisterOffsetFromFp),
-                              IsWordShl(reg_index_node,
-                                        IsInt32Constant(kPointerSizeLog2))),
+                  IsParameter(Linkage::kInterpreterRegisterFileParameter),
+                  IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)),
                   store_value));
   }
 }
index 30064415cd18fffc2241f8fa8f2b85729b1340a9..d3e645b27c44616e876a7febcf98be48363fe466 100644 (file)
@@ -41,8 +41,6 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone {
 
     using InterpreterAssembler::call_descriptor;
     using InterpreterAssembler::graph;
-    using InterpreterAssembler::kMaxRegisterIndex;
-    using InterpreterAssembler::kFirstRegisterOffsetFromFp;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(InterpreterAssemblerForTest);
index 4bdc295f5c9718e3bb41b9da6f191ddb59c35fa8..d097ee4b66ac170f47e759f0ad7a3410a4df67a2 100644 (file)
@@ -1730,6 +1730,42 @@ Matcher<Node*> IsTailCall(
 }
 
 
+Matcher<Node*> IsTailCall(
+    const Matcher<CallDescriptor const*>& descriptor_matcher,
+    const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+    const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+    const Matcher<Node*>& value4_matcher, const Matcher<Node*>& effect_matcher,
+    const Matcher<Node*>& control_matcher) {
+  std::vector<Matcher<Node*>> value_matchers;
+  value_matchers.push_back(value0_matcher);
+  value_matchers.push_back(value1_matcher);
+  value_matchers.push_back(value2_matcher);
+  value_matchers.push_back(value3_matcher);
+  value_matchers.push_back(value4_matcher);
+  return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
+                                           effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsTailCall(
+    const Matcher<CallDescriptor const*>& descriptor_matcher,
+    const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+    const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+    const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
+    const Matcher<Node*>& effect_matcher,
+    const Matcher<Node*>& control_matcher) {
+  std::vector<Matcher<Node*>> value_matchers;
+  value_matchers.push_back(value0_matcher);
+  value_matchers.push_back(value1_matcher);
+  value_matchers.push_back(value2_matcher);
+  value_matchers.push_back(value3_matcher);
+  value_matchers.push_back(value4_matcher);
+  value_matchers.push_back(value5_matcher);
+  return MakeMatcher(new IsTailCallMatcher(descriptor_matcher, value_matchers,
+                                           effect_matcher, control_matcher));
+}
+
+
 Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,
                                 const Matcher<Node*>& lhs_matcher,
                                 const Matcher<Node*>& rhs_matcher) {
index 056aa78776052b85eb1319447234754417c8d82f..149dcfc43924e0511b99db475ffac7771128646e 100644 (file)
@@ -145,6 +145,20 @@ Matcher<Node*> IsTailCall(
     const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
     const Matcher<Node*>& effect_matcher,
     const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsTailCall(
+    const Matcher<CallDescriptor const*>& descriptor_matcher,
+    const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+    const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+    const Matcher<Node*>& value4_matcher, const Matcher<Node*>& effect_matcher,
+    const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsTailCall(
+    const Matcher<CallDescriptor const*>& descriptor_matcher,
+    const Matcher<Node*>& value0_matcher, const Matcher<Node*>& value1_matcher,
+    const Matcher<Node*>& value2_matcher, const Matcher<Node*>& value3_matcher,
+    const Matcher<Node*>& value4_matcher, const Matcher<Node*>& value5_matcher,
+    const Matcher<Node*>& effect_matcher,
+    const Matcher<Node*>& control_matcher);
+
 
 Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
 Matcher<Node*> IsReferenceEqual(const Matcher<Type*>& type_matcher,