Commit b4164754 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add support for loading literals from the constant pool.

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}
parent 50916155
......@@ -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));
......
......@@ -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);
......
......@@ -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_) ||
......
......@@ -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_;
......
......@@ -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);
}
}
......
......@@ -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;
......
......@@ -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) \
......
......@@ -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.
......
......@@ -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
......
......@@ -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
......@@ -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))
......
......@@ -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);
......
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment