}
+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));
}
+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));
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);
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);
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),
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;
}
} 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;
}
+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_++;
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_) ||
#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 {
class BytecodeArrayBuilder {
public:
- explicit BytecodeArrayBuilder(Isolate* isolate);
+ BytecodeArrayBuilder(Isolate* isolate, Zone* zone);
Handle<BytecodeArray> ToBytecodeArray();
// Set number of parameters expected by function.
// Constant loads to accumulator.
BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
+ BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
BytecodeArrayBuilder& LoadUndefined();
BytecodeArrayBuilder& LoadNull();
BytecodeArrayBuilder& LoadTheHole();
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_;
namespace interpreter {
BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
- : builder_(isolate) {
+ : builder_(isolate, zone) {
InitializeAstVisitor(isolate, zone);
}
void BytecodeGenerator::VisitLiteral(Literal* expr) {
- if (expr->IsPropertyName()) {
- UNIMPLEMENTED();
- }
-
Handle<Object> value = expr->value();
if (value->IsSmi()) {
builder().LoadLiteral(Smi::cast(*value));
} else if (value->IsTheHole()) {
builder().LoadTheHole();
} else {
- UNIMPLEMENTED();
+ builder().LoadLiteral(value);
}
}
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;
#define OPERAND_TYPE_LIST(V) \
V(None) \
V(Imm8) \
+ V(Idx) \
V(Reg)
// The list of bytecodes which are interpreted by the 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) \
}
+// 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.
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
// 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];
};
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]);
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());
}
}
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
- ExpectedSnippet snippets[] = {
+ ExpectedSnippet<void*> snippets[] = {
{"var x = 0; return x;",
kPointerSize,
1,
B(Star), R(0), //
B(Ldar), R(0), //
B(Return) //
- }},
+ },
+ 0
+ },
{"var x = 0; return x + 3;",
2 * kPointerSize,
1,
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++) {
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());
}
}
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]);
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
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();
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();
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();
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();
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();
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();
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();
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);
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);
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);
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);
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);
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);
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();
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))
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));
}
+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);
namespace internal {
namespace interpreter {
-class BytecodeArrayBuilderTest : public TestWithIsolate {
+class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
public:
BytecodeArrayBuilderTest() {}
~BytecodeArrayBuilderTest() override {}
TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
- BytecodeArrayBuilder builder(isolate());
+ BytecodeArrayBuilder builder(isolate(), zone());
builder.set_locals_count(1);
builder.set_parameter_count(0);
// Emit constant loads.
builder.LoadLiteral(Smi::FromInt(0))
.LoadLiteral(Smi::FromInt(8))
+ .LoadLiteral(Smi::FromInt(10000000))
.LoadUndefined()
.LoadNull()
.LoadTheHole()
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();
TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) {
- BytecodeArrayBuilder builder(isolate());
+ BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.Return();
TEST_F(BytecodeArrayBuilderTest, Parameters) {
- BytecodeArrayBuilder builder(isolate());
+ BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(10);
builder.set_locals_count(0);
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