[Interpreter] Add support for loading literals from the constant pool.
authorrmcilroy <rmcilroy@chromium.org>
Fri, 28 Aug 2015 15:40:52 +0000 (08:40 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 28 Aug 2015 15:41:07 +0000 (15:41 +0000)
Adds support to the interpreter for loading literals from the constant pool.
Adds the LoadConstant bytecode and makes use of it for loading large Smis and
HeapObject literals.

Also removes unused HandleVector from utils.h.

BUG=v8:4280
LOG=N

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

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

13 files changed:
src/compiler/interpreter-assembler.cc
src/compiler/interpreter-assembler.h
src/interpreter/bytecode-array-builder.cc
src/interpreter/bytecode-array-builder.h
src/interpreter/bytecode-generator.cc
src/interpreter/bytecodes.cc
src/interpreter/bytecodes.h
src/interpreter/interpreter.cc
src/utils.h
test/cctest/interpreter/test-bytecode-generator.cc
test/cctest/interpreter/test-interpreter.cc
test/unittests/compiler/interpreter-assembler-unittest.cc
test/unittests/interpreter/bytecode-array-builder-unittest.cc

index d6ca45fc54f5a0e9cc7538fdc6644c9da9308fc1..25d1b5eacffe1ef208e2553eef4246e1da0df9f6 100644 (file)
@@ -147,6 +147,13 @@ Node* InterpreterAssembler::BytecodeOperandImm8(int operand_index) {
 }
 
 
+Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) {
+  DCHECK_EQ(interpreter::OperandType::kIdx,
+            interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
+  return BytecodeOperand(operand_index);
+}
+
+
 Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
   DCHECK_EQ(interpreter::OperandType::kReg,
             interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
@@ -189,6 +196,16 @@ Node* InterpreterAssembler::SmiUntag(Node* value) {
 }
 
 
+Node* InterpreterAssembler::LoadConstantPoolEntry(Node* index) {
+  Node* constant_pool = LoadObjectField(BytecodeArrayTaggedPointer(),
+                                        BytecodeArray::kConstantPoolOffset);
+  Node* entry_offset = raw_assembler_->IntPtrAdd(
+      IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
+      raw_assembler_->WordShl(index, Int32Constant(kPointerSizeLog2)));
+  return raw_assembler_->Load(kMachAnyTagged, constant_pool, entry_offset);
+}
+
+
 Node* InterpreterAssembler::LoadObjectField(Node* object, int offset) {
   return raw_assembler_->Load(kMachAnyTagged, object,
                               IntPtrConstant(offset - kHeapObjectTag));
index 3dc0c96ee61eacd43921245558854a8d75dc589f..0f8996d7006c844d0fa38546d3f1f14d0f37e821 100644 (file)
@@ -37,6 +37,9 @@ class InterpreterAssembler {
 
   Handle<Code> GenerateCode();
 
+  // Returns the Idx immediate for bytecode operand |operand_index| in the
+  // current bytecode.
+  Node* BytecodeOperandIdx(int operand_index);
   // Returns the Imm8 immediate for bytecode operand |operand_index| in the
   // current bytecode.
   Node* BytecodeOperandImm8(int operand_index);
@@ -62,6 +65,9 @@ class InterpreterAssembler {
   Node* SmiTag(Node* value);
   Node* SmiUntag(Node* value);
 
+  // Load constant at |index| in the constant pool.
+  Node* LoadConstantPoolEntry(Node* index);
+
   // Load a field from an object on the heap.
   Node* LoadObjectField(Node* object, int offset);
 
index 7f5799e75345b246ab64dac32eaaf389866a633e..989fb2d17749c9c54fbabdd4e24696ee3a09db4d 100644 (file)
@@ -8,9 +8,12 @@ namespace v8 {
 namespace internal {
 namespace interpreter {
 
-BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate)
+BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone)
     : isolate_(isolate),
+      bytecodes_(zone),
       bytecode_generated_(false),
+      constants_map_(isolate->heap(), zone),
+      constants_(zone),
       parameter_count_(-1),
       local_register_count_(-1),
       temporary_register_count_(0),
@@ -48,10 +51,18 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
   int bytecode_size = static_cast<int>(bytecodes_.size());
   int register_count = local_register_count_ + temporary_register_count_;
   int frame_size = register_count * kPointerSize;
+
   Factory* factory = isolate_->factory();
+  int constants_count = static_cast<int>(constants_.size());
+  Handle<FixedArray> constant_pool =
+      factory->NewFixedArray(constants_count, TENURED);
+  for (int i = 0; i < constants_count; i++) {
+    constant_pool->set(i, *constants_[i]);
+  }
+
   Handle<BytecodeArray> output =
       factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size,
-                                parameter_count_, factory->empty_fixed_array());
+                                parameter_count_, constant_pool);
   bytecode_generated_ = true;
   return output;
 }
@@ -72,7 +83,17 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
   } else if (raw_smi >= -128 && raw_smi <= 127) {
     Output(Bytecode::kLdaSmi8, static_cast<uint8_t>(raw_smi));
   } else {
-    // TODO(oth): Put Smi in constant pool.
+    LoadLiteral(Handle<Object>(smi, isolate_));
+  }
+  return *this;
+}
+
+
+BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
+  size_t entry = GetConstantPoolEntry(object);
+  if (entry <= 255) {
+    Output(Bytecode::kLdaConstant, static_cast<uint8_t>(entry));
+  } else {
     UNIMPLEMENTED();
   }
   return *this;
@@ -129,6 +150,26 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
 }
 
 
+size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
+  // These constants shouldn't be added to the constant pool, the should use
+  // specialzed bytecodes instead.
+  DCHECK(!object.is_identical_to(isolate_->factory()->undefined_value()));
+  DCHECK(!object.is_identical_to(isolate_->factory()->null_value()));
+  DCHECK(!object.is_identical_to(isolate_->factory()->the_hole_value()));
+  DCHECK(!object.is_identical_to(isolate_->factory()->true_value()));
+  DCHECK(!object.is_identical_to(isolate_->factory()->false_value()));
+
+  size_t* entry = constants_map_.Find(object);
+  if (!entry) {
+    entry = constants_map_.Get(object);
+    *entry = constants_.size();
+    constants_.push_back(object);
+  }
+  DCHECK(constants_[*entry].is_identical_to(object));
+  return *entry;
+}
+
+
 int BytecodeArrayBuilder::BorrowTemporaryRegister() {
   DCHECK_GE(local_register_count_, 0);
   int temporary_reg_index = temporary_register_next_++;
@@ -154,6 +195,8 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
       return false;
     case OperandType::kImm8:
       return true;
+    case OperandType::kIdx:
+      return operand_value < constants_.size();
     case OperandType::kReg: {
       int reg_index = Register::FromOperand(operand_value).index();
       return (reg_index >= 0 && reg_index < temporary_register_next_) ||
index fda32e60baf11d43efd9118059f92109711da1c2..8a45c73bbbcbb4a7bd44ca05142c8ad63da08b4d 100644 (file)
@@ -9,7 +9,10 @@
 
 #include "src/ast.h"
 #include "src/frames.h"
+#include "src/identity-map.h"
 #include "src/interpreter/bytecodes.h"
+#include "src/zone.h"
+#include "src/zone-containers.h"
 
 namespace v8 {
 namespace internal {
@@ -22,7 +25,7 @@ class Register;
 
 class BytecodeArrayBuilder {
  public:
-  explicit BytecodeArrayBuilder(Isolate* isolate);
+  BytecodeArrayBuilder(Isolate* isolate, Zone* zone);
   Handle<BytecodeArray> ToBytecodeArray();
 
   // Set number of parameters expected by function.
@@ -37,6 +40,7 @@ class BytecodeArrayBuilder {
 
   // Constant loads to accumulator.
   BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
+  BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
   BytecodeArrayBuilder& LoadUndefined();
   BytecodeArrayBuilder& LoadNull();
   BytecodeArrayBuilder& LoadTheHole();
@@ -67,13 +71,18 @@ class BytecodeArrayBuilder {
   bool OperandIsValid(Bytecode bytecode, int operand_index,
                       uint8_t operand_value) const;
 
+  size_t GetConstantPoolEntry(Handle<Object> object);
+
   int BorrowTemporaryRegister();
   void ReturnTemporaryRegister(int reg_index);
 
   Isolate* isolate_;
-  std::vector<uint8_t> bytecodes_;
+  ZoneVector<uint8_t> bytecodes_;
   bool bytecode_generated_;
 
+  IdentityMap<size_t> constants_map_;
+  ZoneVector<Handle<Object>> constants_;
+
   int parameter_count_;
   int local_register_count_;
   int temporary_register_count_;
index 93d96ed3c2b3334ec2c976e2700a603cf0d2d459..8d35ea45f89c5f4fad03e0712ebfc657e49d26c7 100644 (file)
@@ -16,7 +16,7 @@ namespace internal {
 namespace interpreter {
 
 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
-    : builder_(isolate) {
+    : builder_(isolate, zone) {
   InitializeAstVisitor(isolate, zone);
 }
 
@@ -201,10 +201,6 @@ void BytecodeGenerator::VisitConditional(Conditional* node) { UNIMPLEMENTED(); }
 
 
 void BytecodeGenerator::VisitLiteral(Literal* expr) {
-  if (expr->IsPropertyName()) {
-    UNIMPLEMENTED();
-  }
-
   Handle<Object> value = expr->value();
   if (value->IsSmi()) {
     builder().LoadLiteral(Smi::cast(*value));
@@ -219,7 +215,7 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
   } else if (value->IsTheHole()) {
     builder().LoadTheHole();
   } else {
-    UNIMPLEMENTED();
+    builder().LoadLiteral(value);
   }
 }
 
index 8232b657e78e0d1de05c86db3754b287779a1ee9..5f334d1ff82ae844af75cfc528731fa89917e704 100644 (file)
@@ -126,6 +126,9 @@ std::ostream& Bytecodes::Decode(std::ostream& os,
     OperandType op_type = GetOperandType(bytecode, i);
     uint8_t operand = operands_start[i];
     switch (op_type) {
+      case interpreter::OperandType::kIdx:
+        os << "[" << static_cast<unsigned int>(operand) << "]";
+        break;
       case interpreter::OperandType::kImm8:
         os << "#" << static_cast<int>(operand);
         break;
index c4457499768b8440a1b47531b4f2e24409dfadd6..a5b34f791afcfa1ca7101a4333e9dcd34a3b8403 100644 (file)
@@ -19,6 +19,7 @@ namespace interpreter {
 #define OPERAND_TYPE_LIST(V) \
   V(None)                    \
   V(Imm8)                    \
+  V(Idx)                     \
   V(Reg)
 
 // The list of bytecodes which are interpreted by the interpreter.
@@ -27,6 +28,7 @@ namespace interpreter {
   /* Loading the accumulator */        \
   V(LdaZero, OperandType::kNone)       \
   V(LdaSmi8, OperandType::kImm8)       \
+  V(LdaConstant, OperandType::kIdx)    \
   V(LdaUndefined, OperandType::kNone)  \
   V(LdaNull, OperandType::kNone)       \
   V(LdaTheHole, OperandType::kNone)    \
index f3a6512bfbab5fc46a97556af9b9509b92982d1f..82b0b4772f6b4585ef4d2979d47334986c7b1ba2 100644 (file)
@@ -106,6 +106,17 @@ void Interpreter::DoLdaSmi8(compiler::InterpreterAssembler* assembler) {
 }
 
 
+// LdaConstant <idx>
+//
+// Load constant literal at |idx| in the constant pool into the accumulator.
+void Interpreter::DoLdaConstant(compiler::InterpreterAssembler* assembler) {
+  Node* index = __ BytecodeOperandIdx(0);
+  Node* constant = __ LoadConstantPoolEntry(index);
+  __ SetAccumulator(constant);
+  __ Dispatch();
+}
+
+
 // LdaUndefined
 //
 // Load Undefined into the accumulator.
index 582c5769936947698217cf5fd5ef219ab7e919eb..822b4b2e1edfea7c79a2d3566ab3f7b98de9e082 100644 (file)
@@ -1209,17 +1209,6 @@ int WriteAsCFile(const char* filename, const char* varname,
                  const char* str, int size, bool verbose = true);
 
 
-// ----------------------------------------------------------------------------
-// Data structures
-
-template <typename T>
-inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
-                                             int length) {
-  return Vector< Handle<Object> >(
-      reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
-}
-
-
 // ----------------------------------------------------------------------------
 // Memory
 
index 16dc3eea2b16bfd54434d083ec5bbff5c3bfbf5a..a9eb58aa3aa84c300a3c4d47ac57251bf7f4c7bf 100644 (file)
@@ -50,12 +50,15 @@ class BytecodeGeneratorHelper {
 
 
 // Structure for containing expected bytecode snippets.
+template<typename T>
 struct ExpectedSnippet {
   const char* body;
   int frame_size;
   int parameter_count;
   int bytecode_length;
   const uint8_t bytecode[16];
+  int constant_count;
+  T constants[16];
 };
 
 
@@ -69,16 +72,16 @@ TEST(PrimitiveReturnStatements) {
   InitializedHandleScope handle_scope;
   BytecodeGeneratorHelper helper;
 
-  ExpectedSnippet snippets[] = {
-      {"return;", 0, 1, 2, {B(LdaUndefined), B(Return)}},
-      {"return null;", 0, 1, 2, {B(LdaNull), B(Return)}},
-      {"return true;", 0, 1, 2, {B(LdaTrue), B(Return)}},
-      {"return false;", 0, 1, 2, {B(LdaFalse), B(Return)}},
-      {"return 0;", 0, 1, 2, {B(LdaZero), B(Return)}},
-      {"return +1;", 0, 1, 3, {B(LdaSmi8), U8(1), B(Return)}},
-      {"return -1;", 0, 1, 3, {B(LdaSmi8), U8(-1), B(Return)}},
-      {"return +127;", 0, 1, 3, {B(LdaSmi8), U8(127), B(Return)}},
-      {"return -128;", 0, 1, 3, {B(LdaSmi8), U8(-128), B(Return)}},
+  ExpectedSnippet<void*> snippets[] = {
+      {"return;", 0, 1, 2, {B(LdaUndefined), B(Return)}, 0},
+      {"return null;", 0, 1, 2, {B(LdaNull), B(Return)}, 0},
+      {"return true;", 0, 1, 2, {B(LdaTrue), B(Return)}, 0},
+      {"return false;", 0, 1, 2, {B(LdaFalse), B(Return)}, 0},
+      {"return 0;", 0, 1, 2, {B(LdaZero), B(Return)}, 0},
+      {"return +1;", 0, 1, 3, {B(LdaSmi8), U8(1), B(Return)}, 0},
+      {"return -1;", 0, 1, 3, {B(LdaSmi8), U8(-1), B(Return)}, 0},
+      {"return +127;", 0, 1, 3, {B(LdaSmi8), U8(127), B(Return)}, 0},
+      {"return -128;", 0, 1, 3, {B(LdaSmi8), U8(-128), B(Return)}, 0},
   };
 
   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
@@ -90,6 +93,7 @@ TEST(PrimitiveReturnStatements) {
     CHECK_EQ(ba->length(), snippets[i].bytecode_length);
     CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
                   ba->length()));
+    CHECK_EQ(ba->constant_pool(), CcTest::heap()->empty_fixed_array());
   }
 }
 
@@ -98,7 +102,7 @@ TEST(PrimitiveExpressions) {
   InitializedHandleScope handle_scope;
   BytecodeGeneratorHelper helper;
 
-  ExpectedSnippet snippets[] = {
+  ExpectedSnippet<void*> snippets[] = {
       {"var x = 0; return x;",
        kPointerSize,
        1,
@@ -108,7 +112,9 @@ TEST(PrimitiveExpressions) {
            B(Star), R(0),  //
            B(Ldar), R(0),  //
            B(Return)       //
-       }},
+       },
+       0
+      },
       {"var x = 0; return x + 3;",
        2 * kPointerSize,
        1,
@@ -121,7 +127,9 @@ TEST(PrimitiveExpressions) {
            B(LdaSmi8), U8(3),  //
            B(Add), R(1),       //
            B(Return)           //
-       }}};
+       },
+       0
+     }};
 
   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
   for (size_t i = 0; i < num_snippets; i++) {
@@ -132,6 +140,7 @@ TEST(PrimitiveExpressions) {
     CHECK_EQ(ba->length(), snippets[i].bytecode_length);
     CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
                   ba->length()));
+    CHECK_EQ(ba->constant_pool(), CcTest::heap()->empty_fixed_array());
   }
 }
 
@@ -142,17 +151,17 @@ TEST(Parameters) {
 
   int last_param_index =
       -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
-  ExpectedSnippet snippets[] = {
+  ExpectedSnippet<void*> snippets[] = {
       {"function f() { return this; }",
-       0, 1, 3, {B(Ldar), R(last_param_index), B(Return)}},
+       0, 1, 3, {B(Ldar), R(last_param_index), B(Return)}, 0},
       {"function f(arg1) { return arg1; }",
-       0, 2, 3, {B(Ldar), R(last_param_index), B(Return)}},
+       0, 2, 3, {B(Ldar), R(last_param_index), B(Return)}, 0},
       {"function f(arg1) { return this; }",
-       0, 2, 3, {B(Ldar), R(last_param_index - 1), B(Return)}},
+       0, 2, 3, {B(Ldar), R(last_param_index - 1), B(Return)}, 0},
       {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return arg4; }",
-       0, 8, 3, {B(Ldar), R(last_param_index - 3), B(Return)}},
+       0, 8, 3, {B(Ldar), R(last_param_index - 3), B(Return)}, 0},
       {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return this; }",
-       0, 8, 3, {B(Ldar), R(last_param_index - 7), B(Return)}}
+       0, 8, 3, {B(Ldar), R(last_param_index - 7), B(Return)}, 0}
   };
 
   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
@@ -163,9 +172,160 @@ TEST(Parameters) {
     CHECK_EQ(ba->length(), snippets[i].bytecode_length);
     CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
                   ba->length()));
+    CHECK_EQ(ba->constant_pool(), CcTest::heap()->empty_fixed_array());
   }
 }
 
+
+TEST(Constants) {
+  InitializedHandleScope handle_scope;
+  BytecodeGeneratorHelper helper;
+
+  // Check large SMIs.
+  {
+    ExpectedSnippet<int> snippets[] = {
+        {"return 12345678;", 0, 1, 3,
+         {
+            B(LdaConstant), U8(0),
+            B(Return)
+         }, 1, { 12345678 }
+        },
+        {"var a = 1234; return 5678;", 1 * kPointerSize, 1, 7,
+         {
+            B(LdaConstant), U8(0),
+            B(Star), R(0),
+            B(LdaConstant), U8(1),
+            B(Return)
+         }, 2, { 1234, 5678 }
+        },
+        {"var a = 1234; return 1234;",
+         1 * kPointerSize, 1, 7,
+         {
+            B(LdaConstant), U8(0),
+            B(Star), R(0),
+            B(LdaConstant), U8(0),
+            B(Return)
+         }, 1, { 1234 }
+        }
+    };
+
+    size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
+    for (size_t i = 0; i < num_snippets; i++) {
+      Handle<BytecodeArray> ba =
+          helper.MakeBytecodeForFunctionBody(snippets[i].body);
+      CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
+      CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
+      CHECK_EQ(ba->length(), snippets[i].bytecode_length);
+      CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
+                    ba->length()));
+      CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count);
+      for (int j = 0; j < snippets[i].constant_count; j++) {
+        CHECK_EQ(Smi::cast(ba->constant_pool()->get(j))->value(),
+                 snippets[i].constants[j]);
+      }
+    }
+  }
+
+  // Check heap number double constants
+  {
+    ExpectedSnippet<double> snippets[] = {
+        {"return 1.2;",
+         0, 1, 3,
+         {
+            B(LdaConstant), U8(0),
+            B(Return)
+         }, 1, { 1.2 }
+        },
+        {"var a = 1.2; return 2.6;", 1 * kPointerSize, 1, 7,
+         {
+            B(LdaConstant), U8(0),
+            B(Star), R(0),
+            B(LdaConstant), U8(1),
+            B(Return)
+         }, 2, { 1.2, 2.6 }
+        },
+        {"var a = 3.14; return 3.14;", 1 * kPointerSize, 1, 7,
+         {
+            B(LdaConstant), U8(0),
+            B(Star), R(0),
+            B(LdaConstant), U8(1),
+            B(Return)
+         }, 2,
+         // TODO(rmcilroy): Currently multiple identical double literals end up
+         // being allocated as new HeapNumbers and so require multiple constant
+         // pool entries. De-dup identical values.
+         { 3.14, 3.14 }
+        }
+    };
+
+    size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
+    for (size_t i = 0; i < num_snippets; i++) {
+      Handle<BytecodeArray> ba =
+          helper.MakeBytecodeForFunctionBody(snippets[i].body);
+      CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
+      CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
+      CHECK_EQ(ba->length(), snippets[i].bytecode_length);
+      CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
+                    ba->length()));
+      CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count);
+      for (int j = 0; j < snippets[i].constant_count; j++) {
+        CHECK_EQ(HeapNumber::cast(ba->constant_pool()->get(j))->value(),
+                 snippets[i].constants[j]);
+      }
+    }
+  }
+
+  // Check string literals
+  {
+    ExpectedSnippet<const char*> snippets[] = {
+        {"return \"This is a string\";", 0, 1, 3,
+         {
+            B(LdaConstant), U8(0),
+            B(Return)
+         }, 1,
+         { "This is a string" }
+        },
+        {"var a = \"First string\"; return \"Second string\";",
+         1 * kPointerSize, 1, 7,
+         {
+            B(LdaConstant), U8(0),
+            B(Star), R(0),
+            B(LdaConstant), U8(1),
+            B(Return)
+         }, 2, { "First string", "Second string"}
+        },
+        {"var a = \"Same string\"; return \"Same string\";",
+         1 * kPointerSize, 1, 7,
+         {
+            B(LdaConstant), U8(0),
+            B(Star), R(0),
+            B(LdaConstant), U8(0),
+            B(Return)
+         }, 1, { "Same string" }
+        }
+    };
+
+    size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
+    for (size_t i = 0; i < num_snippets; i++) {
+      Handle<BytecodeArray> ba =
+          helper.MakeBytecodeForFunctionBody(snippets[i].body);
+      CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
+      CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
+      CHECK_EQ(ba->length(), snippets[i].bytecode_length);
+      CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
+                    ba->length()));
+      CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count);
+      for (int j = 0; j < snippets[i].constant_count; j++) {
+        Handle<String> expected =
+            CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(
+                snippets[i].constants[j]);
+        CHECK(String::cast(ba->constant_pool()->get(j))->Equals(*expected));
+      }
+    }
+  }
+}
+
+
 }  // namespace interpreter
 }  // namespace internal
 }  // namespance v8
index 26deea642f68fa75188daab094b9b0063d76d671..397d7007724ffda32c2955c23536d9e39b98096f 100644 (file)
@@ -101,11 +101,11 @@ using v8::internal::Token;
 using namespace v8::internal::interpreter;
 
 TEST(InterpreterReturn) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   Handle<Object> undefined_value =
       handles.main_isolate()->factory()->undefined_value();
 
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(0);
   builder.set_parameter_count(1);
   builder.Return();
@@ -119,11 +119,11 @@ TEST(InterpreterReturn) {
 
 
 TEST(InterpreterLoadUndefined) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   Handle<Object> undefined_value =
       handles.main_isolate()->factory()->undefined_value();
 
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(0);
   builder.set_parameter_count(1);
   builder.LoadUndefined().Return();
@@ -137,10 +137,10 @@ TEST(InterpreterLoadUndefined) {
 
 
 TEST(InterpreterLoadNull) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   Handle<Object> null_value = handles.main_isolate()->factory()->null_value();
 
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(0);
   builder.set_parameter_count(1);
   builder.LoadNull().Return();
@@ -154,11 +154,11 @@ TEST(InterpreterLoadNull) {
 
 
 TEST(InterpreterLoadTheHole) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   Handle<Object> the_hole_value =
       handles.main_isolate()->factory()->the_hole_value();
 
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(0);
   builder.set_parameter_count(1);
   builder.LoadTheHole().Return();
@@ -172,10 +172,10 @@ TEST(InterpreterLoadTheHole) {
 
 
 TEST(InterpreterLoadTrue) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
 
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(0);
   builder.set_parameter_count(1);
   builder.LoadTrue().Return();
@@ -189,10 +189,10 @@ TEST(InterpreterLoadTrue) {
 
 
 TEST(InterpreterLoadFalse) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   Handle<Object> false_value = handles.main_isolate()->factory()->false_value();
 
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(0);
   builder.set_parameter_count(1);
   builder.LoadFalse().Return();
@@ -206,9 +206,12 @@ TEST(InterpreterLoadFalse) {
 
 
 TEST(InterpreterLoadLiteral) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
+  i::Factory* factory = handles.main_isolate()->factory();
+
+  // Small Smis.
   for (int i = -128; i < 128; i++) {
-    BytecodeArrayBuilder builder(handles.main_isolate());
+    BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
     builder.set_locals_count(0);
     builder.set_parameter_count(1);
     builder.LoadLiteral(Smi::FromInt(i)).Return();
@@ -219,14 +222,57 @@ TEST(InterpreterLoadLiteral) {
     Handle<Object> return_val = callable().ToHandleChecked();
     CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i));
   }
+
+  // Large Smis.
+  {
+    BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
+    builder.set_locals_count(0);
+    builder.set_parameter_count(1);
+    builder.LoadLiteral(Smi::FromInt(0x12345678)).Return();
+    Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
+
+    InterpreterTester tester(handles.main_isolate(), bytecode_array);
+    auto callable = tester.GetCallable<>();
+    Handle<Object> return_val = callable().ToHandleChecked();
+    CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x12345678));
+  }
+
+  // Heap numbers.
+  {
+    BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
+    builder.set_locals_count(0);
+    builder.set_parameter_count(1);
+    builder.LoadLiteral(factory->NewHeapNumber(-2.1e19)).Return();
+    Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
+
+    InterpreterTester tester(handles.main_isolate(), bytecode_array);
+    auto callable = tester.GetCallable<>();
+    Handle<Object> return_val = callable().ToHandleChecked();
+    CHECK_EQ(i::HeapNumber::cast(*return_val)->value(), -2.1e19);
+  }
+
+  // Strings.
+  {
+    BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
+    builder.set_locals_count(0);
+    builder.set_parameter_count(1);
+    Handle<i::String> string = factory->NewStringFromAsciiChecked("String");
+    builder.LoadLiteral(string).Return();
+    Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
+
+    InterpreterTester tester(handles.main_isolate(), bytecode_array);
+    auto callable = tester.GetCallable<>();
+    Handle<Object> return_val = callable().ToHandleChecked();
+    CHECK(i::String::cast(*return_val)->Equals(*string));
+  }
 }
 
 
 TEST(InterpreterLoadStoreRegisters) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
   for (int i = 0; i <= Register::kMaxRegisterIndex; i++) {
-    BytecodeArrayBuilder builder(handles.main_isolate());
+    BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
     builder.set_locals_count(i + 1);
     builder.set_parameter_count(1);
     Register reg(i);
@@ -246,10 +292,10 @@ TEST(InterpreterLoadStoreRegisters) {
 
 
 TEST(InterpreterAdd) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   // TODO(rmcilroy): Do add tests for heap numbers and strings once we support
   // them.
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(1);
   builder.set_parameter_count(1);
   Register reg(0);
@@ -268,9 +314,9 @@ TEST(InterpreterAdd) {
 
 
 TEST(InterpreterSub) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   // TODO(rmcilroy): Do add tests for heap numbers once we support them.
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(1);
   builder.set_parameter_count(1);
   Register reg(0);
@@ -289,9 +335,9 @@ TEST(InterpreterSub) {
 
 
 TEST(InterpreterMul) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   // TODO(rmcilroy): Do add tests for heap numbers once we support them.
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(1);
   builder.set_parameter_count(1);
   Register reg(0);
@@ -310,9 +356,9 @@ TEST(InterpreterMul) {
 
 
 TEST(InterpreterDiv) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   // TODO(rmcilroy): Do add tests for heap numbers once we support them.
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(1);
   builder.set_parameter_count(1);
   Register reg(0);
@@ -331,9 +377,9 @@ TEST(InterpreterDiv) {
 
 
 TEST(InterpreterMod) {
-  InitializedHandleScope handles;
+  HandleAndZoneScope handles;
   // TODO(rmcilroy): Do add tests for heap numbers once we support them.
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(1);
   builder.set_parameter_count(1);
   Register reg(0);
@@ -352,8 +398,8 @@ TEST(InterpreterMod) {
 
 
 TEST(InterpreterParameter1) {
-  InitializedHandleScope handles;
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  HandleAndZoneScope handles;
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(1);
   builder.set_parameter_count(1);
   builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return();
@@ -375,8 +421,8 @@ TEST(InterpreterParameter1) {
 
 
 TEST(InterpreterParameter8) {
-  InitializedHandleScope handles;
-  BytecodeArrayBuilder builder(handles.main_isolate());
+  HandleAndZoneScope handles;
+  BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
   builder.set_locals_count(1);
   builder.set_parameter_count(8);
   builder.LoadAccumulatorWithRegister(builder.Parameter(0))
index 9fdb7f51e617441698c30e02b0572e86c8e6eb42..b7e15a98ca02498eefe234eff55914e78b2712cd 100644 (file)
@@ -177,6 +177,9 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
     int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode);
     for (int i = 0; i < number_of_operands; i++) {
       switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) {
+        case interpreter::OperandType::kIdx:
+          EXPECT_THAT(m.BytecodeOperandIdx(i), m.IsBytecodeOperand(i));
+          break;
         case interpreter::OperandType::kImm8:
           EXPECT_THAT(m.BytecodeOperandImm8(i),
                       m.IsBytecodeOperandSignExtended(i));
@@ -266,6 +269,25 @@ TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) {
 }
 
 
+TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) {
+  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
+    InterpreterAssemblerForTest m(this, bytecode);
+    Node* index = m.Int32Constant(2);
+    Node* load_constant = m.LoadConstantPoolEntry(index);
+    Matcher<Node*> constant_pool_matcher = m.IsLoad(
+        kMachAnyTagged,
+        IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
+        IsIntPtrConstant(BytecodeArray::kConstantPoolOffset - kHeapObjectTag));
+    EXPECT_THAT(
+        load_constant,
+        m.IsLoad(kMachAnyTagged, constant_pool_matcher,
+                 IsIntPtrAdd(
+                     IsIntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
+                     IsWordShl(index, IsInt32Constant(kPointerSizeLog2)))));
+  }
+}
+
+
 TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) {
   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
     InterpreterAssemblerForTest m(this, bytecode);
index 9b4d3abbf28d4d2c149c935455cdc77c8a19962b..96c88466666ee0fe23ef877c89da1439bded629e 100644 (file)
@@ -11,7 +11,7 @@ namespace v8 {
 namespace internal {
 namespace interpreter {
 
-class BytecodeArrayBuilderTest : public TestWithIsolate {
+class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
  public:
   BytecodeArrayBuilderTest() {}
   ~BytecodeArrayBuilderTest() override {}
@@ -19,7 +19,7 @@ class BytecodeArrayBuilderTest : public TestWithIsolate {
 
 
 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
-  BytecodeArrayBuilder builder(isolate());
+  BytecodeArrayBuilder builder(isolate(), zone());
 
   builder.set_locals_count(1);
   builder.set_parameter_count(0);
@@ -28,6 +28,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
   // Emit constant loads.
   builder.LoadLiteral(Smi::FromInt(0))
       .LoadLiteral(Smi::FromInt(8))
+      .LoadLiteral(Smi::FromInt(10000000))
       .LoadUndefined()
       .LoadNull()
       .LoadTheHole()
@@ -79,7 +80,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
 TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
   for (int locals = 0; locals < 5; locals++) {
     for (int temps = 0; temps < 3; temps++) {
-      BytecodeArrayBuilder builder(isolate());
+      BytecodeArrayBuilder builder(isolate(), zone());
       builder.set_parameter_count(0);
       builder.set_locals_count(locals);
       builder.Return();
@@ -98,7 +99,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
 
 
 TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) {
-  BytecodeArrayBuilder builder(isolate());
+  BytecodeArrayBuilder builder(isolate(), zone());
   builder.set_parameter_count(0);
   builder.set_locals_count(0);
   builder.Return();
@@ -138,7 +139,7 @@ TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
 
 
 TEST_F(BytecodeArrayBuilderTest, Parameters) {
-  BytecodeArrayBuilder builder(isolate());
+  BytecodeArrayBuilder builder(isolate(), zone());
   builder.set_parameter_count(10);
   builder.set_locals_count(0);
 
@@ -147,6 +148,29 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) {
   CHECK_EQ(param9.index() - param0.index(), 9);
 }
 
+
+TEST_F(BytecodeArrayBuilderTest, Constants) {
+  BytecodeArrayBuilder builder(isolate(), zone());
+  builder.set_parameter_count(0);
+  builder.set_locals_count(0);
+
+  Factory* factory = isolate()->factory();
+  Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
+  Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2);
+  Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate());
+  Handle<HeapObject> heap_num_2_copy(*heap_num_2);
+  builder.LoadLiteral(heap_num_1)
+      .LoadLiteral(heap_num_2)
+      .LoadLiteral(large_smi)
+      .LoadLiteral(heap_num_1)
+      .LoadLiteral(heap_num_1)
+      .LoadLiteral(heap_num_2_copy);
+
+  Handle<BytecodeArray> array = builder.ToBytecodeArray();
+  // Should only have one entry for each identical constant.
+  CHECK_EQ(array->constant_pool()->length(), 3);
+}
+
 }  // namespace interpreter
 }  // namespace internal
 }  // namespace v8