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) { ...@@ -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) { Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kReg, DCHECK_EQ(interpreter::OperandType::kReg,
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index)); interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
...@@ -189,6 +196,16 @@ Node* InterpreterAssembler::SmiUntag(Node* value) { ...@@ -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) { Node* InterpreterAssembler::LoadObjectField(Node* object, int offset) {
return raw_assembler_->Load(kMachAnyTagged, object, return raw_assembler_->Load(kMachAnyTagged, object,
IntPtrConstant(offset - kHeapObjectTag)); IntPtrConstant(offset - kHeapObjectTag));
......
...@@ -37,6 +37,9 @@ class InterpreterAssembler { ...@@ -37,6 +37,9 @@ class InterpreterAssembler {
Handle<Code> GenerateCode(); 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 // Returns the Imm8 immediate for bytecode operand |operand_index| in the
// current bytecode. // current bytecode.
Node* BytecodeOperandImm8(int operand_index); Node* BytecodeOperandImm8(int operand_index);
...@@ -62,6 +65,9 @@ class InterpreterAssembler { ...@@ -62,6 +65,9 @@ class InterpreterAssembler {
Node* SmiTag(Node* value); Node* SmiTag(Node* value);
Node* SmiUntag(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. // Load a field from an object on the heap.
Node* LoadObjectField(Node* object, int offset); Node* LoadObjectField(Node* object, int offset);
......
...@@ -8,9 +8,12 @@ namespace v8 { ...@@ -8,9 +8,12 @@ namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate) BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone)
: isolate_(isolate), : isolate_(isolate),
bytecodes_(zone),
bytecode_generated_(false), bytecode_generated_(false),
constants_map_(isolate->heap(), zone),
constants_(zone),
parameter_count_(-1), parameter_count_(-1),
local_register_count_(-1), local_register_count_(-1),
temporary_register_count_(0), temporary_register_count_(0),
...@@ -48,10 +51,18 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { ...@@ -48,10 +51,18 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
int bytecode_size = static_cast<int>(bytecodes_.size()); int bytecode_size = static_cast<int>(bytecodes_.size());
int register_count = local_register_count_ + temporary_register_count_; int register_count = local_register_count_ + temporary_register_count_;
int frame_size = register_count * kPointerSize; int frame_size = register_count * kPointerSize;
Factory* factory = isolate_->factory(); 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 = Handle<BytecodeArray> output =
factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size, factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size,
parameter_count_, factory->empty_fixed_array()); parameter_count_, constant_pool);
bytecode_generated_ = true; bytecode_generated_ = true;
return output; return output;
} }
...@@ -72,7 +83,17 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( ...@@ -72,7 +83,17 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
} else if (raw_smi >= -128 && raw_smi <= 127) { } else if (raw_smi >= -128 && raw_smi <= 127) {
Output(Bytecode::kLdaSmi8, static_cast<uint8_t>(raw_smi)); Output(Bytecode::kLdaSmi8, static_cast<uint8_t>(raw_smi));
} else { } 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(); UNIMPLEMENTED();
} }
return *this; return *this;
...@@ -129,6 +150,26 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { ...@@ -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() { int BytecodeArrayBuilder::BorrowTemporaryRegister() {
DCHECK_GE(local_register_count_, 0); DCHECK_GE(local_register_count_, 0);
int temporary_reg_index = temporary_register_next_++; int temporary_reg_index = temporary_register_next_++;
...@@ -154,6 +195,8 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, ...@@ -154,6 +195,8 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
return false; return false;
case OperandType::kImm8: case OperandType::kImm8:
return true; return true;
case OperandType::kIdx:
return operand_value < constants_.size();
case OperandType::kReg: { case OperandType::kReg: {
int reg_index = Register::FromOperand(operand_value).index(); int reg_index = Register::FromOperand(operand_value).index();
return (reg_index >= 0 && reg_index < temporary_register_next_) || return (reg_index >= 0 && reg_index < temporary_register_next_) ||
......
...@@ -9,7 +9,10 @@ ...@@ -9,7 +9,10 @@
#include "src/ast.h" #include "src/ast.h"
#include "src/frames.h" #include "src/frames.h"
#include "src/identity-map.h"
#include "src/interpreter/bytecodes.h" #include "src/interpreter/bytecodes.h"
#include "src/zone.h"
#include "src/zone-containers.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -22,7 +25,7 @@ class Register; ...@@ -22,7 +25,7 @@ class Register;
class BytecodeArrayBuilder { class BytecodeArrayBuilder {
public: public:
explicit BytecodeArrayBuilder(Isolate* isolate); BytecodeArrayBuilder(Isolate* isolate, Zone* zone);
Handle<BytecodeArray> ToBytecodeArray(); Handle<BytecodeArray> ToBytecodeArray();
// Set number of parameters expected by function. // Set number of parameters expected by function.
...@@ -37,6 +40,7 @@ class BytecodeArrayBuilder { ...@@ -37,6 +40,7 @@ class BytecodeArrayBuilder {
// Constant loads to accumulator. // Constant loads to accumulator.
BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value); BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
BytecodeArrayBuilder& LoadUndefined(); BytecodeArrayBuilder& LoadUndefined();
BytecodeArrayBuilder& LoadNull(); BytecodeArrayBuilder& LoadNull();
BytecodeArrayBuilder& LoadTheHole(); BytecodeArrayBuilder& LoadTheHole();
...@@ -67,13 +71,18 @@ class BytecodeArrayBuilder { ...@@ -67,13 +71,18 @@ class BytecodeArrayBuilder {
bool OperandIsValid(Bytecode bytecode, int operand_index, bool OperandIsValid(Bytecode bytecode, int operand_index,
uint8_t operand_value) const; uint8_t operand_value) const;
size_t GetConstantPoolEntry(Handle<Object> object);
int BorrowTemporaryRegister(); int BorrowTemporaryRegister();
void ReturnTemporaryRegister(int reg_index); void ReturnTemporaryRegister(int reg_index);
Isolate* isolate_; Isolate* isolate_;
std::vector<uint8_t> bytecodes_; ZoneVector<uint8_t> bytecodes_;
bool bytecode_generated_; bool bytecode_generated_;
IdentityMap<size_t> constants_map_;
ZoneVector<Handle<Object>> constants_;
int parameter_count_; int parameter_count_;
int local_register_count_; int local_register_count_;
int temporary_register_count_; int temporary_register_count_;
......
...@@ -16,7 +16,7 @@ namespace internal { ...@@ -16,7 +16,7 @@ namespace internal {
namespace interpreter { namespace interpreter {
BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
: builder_(isolate) { : builder_(isolate, zone) {
InitializeAstVisitor(isolate, zone); InitializeAstVisitor(isolate, zone);
} }
...@@ -201,10 +201,6 @@ void BytecodeGenerator::VisitConditional(Conditional* node) { UNIMPLEMENTED(); } ...@@ -201,10 +201,6 @@ void BytecodeGenerator::VisitConditional(Conditional* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitLiteral(Literal* expr) { void BytecodeGenerator::VisitLiteral(Literal* expr) {
if (expr->IsPropertyName()) {
UNIMPLEMENTED();
}
Handle<Object> value = expr->value(); Handle<Object> value = expr->value();
if (value->IsSmi()) { if (value->IsSmi()) {
builder().LoadLiteral(Smi::cast(*value)); builder().LoadLiteral(Smi::cast(*value));
...@@ -219,7 +215,7 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) { ...@@ -219,7 +215,7 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
} else if (value->IsTheHole()) { } else if (value->IsTheHole()) {
builder().LoadTheHole(); builder().LoadTheHole();
} else { } else {
UNIMPLEMENTED(); builder().LoadLiteral(value);
} }
} }
......
...@@ -126,6 +126,9 @@ std::ostream& Bytecodes::Decode(std::ostream& os, ...@@ -126,6 +126,9 @@ std::ostream& Bytecodes::Decode(std::ostream& os,
OperandType op_type = GetOperandType(bytecode, i); OperandType op_type = GetOperandType(bytecode, i);
uint8_t operand = operands_start[i]; uint8_t operand = operands_start[i];
switch (op_type) { switch (op_type) {
case interpreter::OperandType::kIdx:
os << "[" << static_cast<unsigned int>(operand) << "]";
break;
case interpreter::OperandType::kImm8: case interpreter::OperandType::kImm8:
os << "#" << static_cast<int>(operand); os << "#" << static_cast<int>(operand);
break; break;
......
...@@ -19,6 +19,7 @@ namespace interpreter { ...@@ -19,6 +19,7 @@ namespace interpreter {
#define OPERAND_TYPE_LIST(V) \ #define OPERAND_TYPE_LIST(V) \
V(None) \ V(None) \
V(Imm8) \ V(Imm8) \
V(Idx) \
V(Reg) V(Reg)
// The list of bytecodes which are interpreted by the interpreter. // The list of bytecodes which are interpreted by the interpreter.
...@@ -27,6 +28,7 @@ namespace interpreter { ...@@ -27,6 +28,7 @@ namespace interpreter {
/* Loading the accumulator */ \ /* Loading the accumulator */ \
V(LdaZero, OperandType::kNone) \ V(LdaZero, OperandType::kNone) \
V(LdaSmi8, OperandType::kImm8) \ V(LdaSmi8, OperandType::kImm8) \
V(LdaConstant, OperandType::kIdx) \
V(LdaUndefined, OperandType::kNone) \ V(LdaUndefined, OperandType::kNone) \
V(LdaNull, OperandType::kNone) \ V(LdaNull, OperandType::kNone) \
V(LdaTheHole, OperandType::kNone) \ V(LdaTheHole, OperandType::kNone) \
......
...@@ -106,6 +106,17 @@ void Interpreter::DoLdaSmi8(compiler::InterpreterAssembler* assembler) { ...@@ -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 // LdaUndefined
// //
// Load Undefined into the accumulator. // Load Undefined into the accumulator.
......
...@@ -1209,17 +1209,6 @@ int WriteAsCFile(const char* filename, const char* varname, ...@@ -1209,17 +1209,6 @@ int WriteAsCFile(const char* filename, const char* varname,
const char* str, int size, bool verbose = true); 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 // Memory
......
...@@ -50,12 +50,15 @@ class BytecodeGeneratorHelper { ...@@ -50,12 +50,15 @@ class BytecodeGeneratorHelper {
// Structure for containing expected bytecode snippets. // Structure for containing expected bytecode snippets.
template<typename T>
struct ExpectedSnippet { struct ExpectedSnippet {
const char* body; const char* body;
int frame_size; int frame_size;
int parameter_count; int parameter_count;
int bytecode_length; int bytecode_length;
const uint8_t bytecode[16]; const uint8_t bytecode[16];
int constant_count;
T constants[16];
}; };
...@@ -69,16 +72,16 @@ TEST(PrimitiveReturnStatements) { ...@@ -69,16 +72,16 @@ TEST(PrimitiveReturnStatements) {
InitializedHandleScope handle_scope; InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper; BytecodeGeneratorHelper helper;
ExpectedSnippet snippets[] = { ExpectedSnippet<void*> snippets[] = {
{"return;", 0, 1, 2, {B(LdaUndefined), B(Return)}}, {"return;", 0, 1, 2, {B(LdaUndefined), B(Return)}, 0},
{"return null;", 0, 1, 2, {B(LdaNull), B(Return)}}, {"return null;", 0, 1, 2, {B(LdaNull), B(Return)}, 0},
{"return true;", 0, 1, 2, {B(LdaTrue), B(Return)}}, {"return true;", 0, 1, 2, {B(LdaTrue), B(Return)}, 0},
{"return false;", 0, 1, 2, {B(LdaFalse), B(Return)}}, {"return false;", 0, 1, 2, {B(LdaFalse), B(Return)}, 0},
{"return 0;", 0, 1, 2, {B(LdaZero), B(Return)}}, {"return 0;", 0, 1, 2, {B(LdaZero), B(Return)}, 0},
{"return +1;", 0, 1, 3, {B(LdaSmi8), U8(1), B(Return)}}, {"return +1;", 0, 1, 3, {B(LdaSmi8), U8(1), B(Return)}, 0},
{"return -1;", 0, 1, 3, {B(LdaSmi8), U8(-1), B(Return)}}, {"return -1;", 0, 1, 3, {B(LdaSmi8), U8(-1), B(Return)}, 0},
{"return +127;", 0, 1, 3, {B(LdaSmi8), U8(127), B(Return)}}, {"return +127;", 0, 1, 3, {B(LdaSmi8), U8(127), B(Return)}, 0},
{"return -128;", 0, 1, 3, {B(LdaSmi8), U8(-128), B(Return)}}, {"return -128;", 0, 1, 3, {B(LdaSmi8), U8(-128), B(Return)}, 0},
}; };
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
...@@ -90,6 +93,7 @@ TEST(PrimitiveReturnStatements) { ...@@ -90,6 +93,7 @@ TEST(PrimitiveReturnStatements) {
CHECK_EQ(ba->length(), snippets[i].bytecode_length); CHECK_EQ(ba->length(), snippets[i].bytecode_length);
CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
ba->length())); ba->length()));
CHECK_EQ(ba->constant_pool(), CcTest::heap()->empty_fixed_array());
} }
} }
...@@ -98,7 +102,7 @@ TEST(PrimitiveExpressions) { ...@@ -98,7 +102,7 @@ TEST(PrimitiveExpressions) {
InitializedHandleScope handle_scope; InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper; BytecodeGeneratorHelper helper;
ExpectedSnippet snippets[] = { ExpectedSnippet<void*> snippets[] = {
{"var x = 0; return x;", {"var x = 0; return x;",
kPointerSize, kPointerSize,
1, 1,
...@@ -108,7 +112,9 @@ TEST(PrimitiveExpressions) { ...@@ -108,7 +112,9 @@ TEST(PrimitiveExpressions) {
B(Star), R(0), // B(Star), R(0), //
B(Ldar), R(0), // B(Ldar), R(0), //
B(Return) // B(Return) //
}}, },
0
},
{"var x = 0; return x + 3;", {"var x = 0; return x + 3;",
2 * kPointerSize, 2 * kPointerSize,
1, 1,
...@@ -121,7 +127,9 @@ TEST(PrimitiveExpressions) { ...@@ -121,7 +127,9 @@ TEST(PrimitiveExpressions) {
B(LdaSmi8), U8(3), // B(LdaSmi8), U8(3), //
B(Add), R(1), // B(Add), R(1), //
B(Return) // B(Return) //
}}}; },
0
}};
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) { for (size_t i = 0; i < num_snippets; i++) {
...@@ -132,6 +140,7 @@ TEST(PrimitiveExpressions) { ...@@ -132,6 +140,7 @@ TEST(PrimitiveExpressions) {
CHECK_EQ(ba->length(), snippets[i].bytecode_length); CHECK_EQ(ba->length(), snippets[i].bytecode_length);
CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
ba->length())); ba->length()));
CHECK_EQ(ba->constant_pool(), CcTest::heap()->empty_fixed_array());
} }
} }
...@@ -142,17 +151,17 @@ TEST(Parameters) { ...@@ -142,17 +151,17 @@ TEST(Parameters) {
int last_param_index = int last_param_index =
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize; -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
ExpectedSnippet snippets[] = { ExpectedSnippet<void*> snippets[] = {
{"function f() { return this; }", {"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; }", {"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; }", {"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; }", {"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; }", {"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]); size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
...@@ -163,9 +172,160 @@ TEST(Parameters) { ...@@ -163,9 +172,160 @@ TEST(Parameters) {
CHECK_EQ(ba->length(), snippets[i].bytecode_length); CHECK_EQ(ba->length(), snippets[i].bytecode_length);
CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode, CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
ba->length())); 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 interpreter
} // namespace internal } // namespace internal
} // namespance v8 } // namespance v8
...@@ -101,11 +101,11 @@ using v8::internal::Token; ...@@ -101,11 +101,11 @@ using v8::internal::Token;
using namespace v8::internal::interpreter; using namespace v8::internal::interpreter;
TEST(InterpreterReturn) { TEST(InterpreterReturn) {
InitializedHandleScope handles; HandleAndZoneScope handles;
Handle<Object> undefined_value = Handle<Object> undefined_value =
handles.main_isolate()->factory()->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_locals_count(0);
builder.set_parameter_count(1); builder.set_parameter_count(1);
builder.Return(); builder.Return();
...@@ -119,11 +119,11 @@ TEST(InterpreterReturn) { ...@@ -119,11 +119,11 @@ TEST(InterpreterReturn) {
TEST(InterpreterLoadUndefined) { TEST(InterpreterLoadUndefined) {
InitializedHandleScope handles; HandleAndZoneScope handles;
Handle<Object> undefined_value = Handle<Object> undefined_value =
handles.main_isolate()->factory()->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_locals_count(0);
builder.set_parameter_count(1); builder.set_parameter_count(1);
builder.LoadUndefined().Return(); builder.LoadUndefined().Return();
...@@ -137,10 +137,10 @@ TEST(InterpreterLoadUndefined) { ...@@ -137,10 +137,10 @@ TEST(InterpreterLoadUndefined) {
TEST(InterpreterLoadNull) { TEST(InterpreterLoadNull) {
InitializedHandleScope handles; HandleAndZoneScope handles;
Handle<Object> null_value = handles.main_isolate()->factory()->null_value(); 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_locals_count(0);
builder.set_parameter_count(1); builder.set_parameter_count(1);
builder.LoadNull().Return(); builder.LoadNull().Return();
...@@ -154,11 +154,11 @@ TEST(InterpreterLoadNull) { ...@@ -154,11 +154,11 @@ TEST(InterpreterLoadNull) {
TEST(InterpreterLoadTheHole) { TEST(InterpreterLoadTheHole) {
InitializedHandleScope handles; HandleAndZoneScope handles;
Handle<Object> the_hole_value = Handle<Object> the_hole_value =
handles.main_isolate()->factory()->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_locals_count(0);
builder.set_parameter_count(1); builder.set_parameter_count(1);
builder.LoadTheHole().Return(); builder.LoadTheHole().Return();
...@@ -172,10 +172,10 @@ TEST(InterpreterLoadTheHole) { ...@@ -172,10 +172,10 @@ TEST(InterpreterLoadTheHole) {
TEST(InterpreterLoadTrue) { TEST(InterpreterLoadTrue) {
InitializedHandleScope handles; HandleAndZoneScope handles;
Handle<Object> true_value = handles.main_isolate()->factory()->true_value(); 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_locals_count(0);
builder.set_parameter_count(1); builder.set_parameter_count(1);
builder.LoadTrue().Return(); builder.LoadTrue().Return();
...@@ -189,10 +189,10 @@ TEST(InterpreterLoadTrue) { ...@@ -189,10 +189,10 @@ TEST(InterpreterLoadTrue) {
TEST(InterpreterLoadFalse) { TEST(InterpreterLoadFalse) {
InitializedHandleScope handles; HandleAndZoneScope handles;
Handle<Object> false_value = handles.main_isolate()->factory()->false_value(); 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_locals_count(0);
builder.set_parameter_count(1); builder.set_parameter_count(1);
builder.LoadFalse().Return(); builder.LoadFalse().Return();
...@@ -206,9 +206,12 @@ TEST(InterpreterLoadFalse) { ...@@ -206,9 +206,12 @@ TEST(InterpreterLoadFalse) {
TEST(InterpreterLoadLiteral) { TEST(InterpreterLoadLiteral) {
InitializedHandleScope handles; HandleAndZoneScope handles;
i::Factory* factory = handles.main_isolate()->factory();
// Small Smis.
for (int i = -128; i < 128; i++) { 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_locals_count(0);
builder.set_parameter_count(1); builder.set_parameter_count(1);
builder.LoadLiteral(Smi::FromInt(i)).Return(); builder.LoadLiteral(Smi::FromInt(i)).Return();
...@@ -219,14 +222,57 @@ TEST(InterpreterLoadLiteral) { ...@@ -219,14 +222,57 @@ TEST(InterpreterLoadLiteral) {
Handle<Object> return_val = callable().ToHandleChecked(); Handle<Object> return_val = callable().ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i)); 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) { TEST(InterpreterLoadStoreRegisters) {
InitializedHandleScope handles; HandleAndZoneScope handles;
Handle<Object> true_value = handles.main_isolate()->factory()->true_value(); Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
for (int i = 0; i <= Register::kMaxRegisterIndex; i++) { 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_locals_count(i + 1);
builder.set_parameter_count(1); builder.set_parameter_count(1);
Register reg(i); Register reg(i);
...@@ -246,10 +292,10 @@ TEST(InterpreterLoadStoreRegisters) { ...@@ -246,10 +292,10 @@ TEST(InterpreterLoadStoreRegisters) {
TEST(InterpreterAdd) { TEST(InterpreterAdd) {
InitializedHandleScope handles; HandleAndZoneScope handles;
// TODO(rmcilroy): Do add tests for heap numbers and strings once we support // TODO(rmcilroy): Do add tests for heap numbers and strings once we support
// them. // them.
BytecodeArrayBuilder builder(handles.main_isolate()); BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(1); builder.set_locals_count(1);
builder.set_parameter_count(1); builder.set_parameter_count(1);
Register reg(0); Register reg(0);
...@@ -268,9 +314,9 @@ TEST(InterpreterAdd) { ...@@ -268,9 +314,9 @@ TEST(InterpreterAdd) {
TEST(InterpreterSub) { TEST(InterpreterSub) {
InitializedHandleScope handles; HandleAndZoneScope handles;
// TODO(rmcilroy): Do add tests for heap numbers once we support them. // 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_locals_count(1);
builder.set_parameter_count(1); builder.set_parameter_count(1);
Register reg(0); Register reg(0);
...@@ -289,9 +335,9 @@ TEST(InterpreterSub) { ...@@ -289,9 +335,9 @@ TEST(InterpreterSub) {
TEST(InterpreterMul) { TEST(InterpreterMul) {
InitializedHandleScope handles; HandleAndZoneScope handles;
// TODO(rmcilroy): Do add tests for heap numbers once we support them. // 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_locals_count(1);
builder.set_parameter_count(1); builder.set_parameter_count(1);
Register reg(0); Register reg(0);
...@@ -310,9 +356,9 @@ TEST(InterpreterMul) { ...@@ -310,9 +356,9 @@ TEST(InterpreterMul) {
TEST(InterpreterDiv) { TEST(InterpreterDiv) {
InitializedHandleScope handles; HandleAndZoneScope handles;
// TODO(rmcilroy): Do add tests for heap numbers once we support them. // 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_locals_count(1);
builder.set_parameter_count(1); builder.set_parameter_count(1);
Register reg(0); Register reg(0);
...@@ -331,9 +377,9 @@ TEST(InterpreterDiv) { ...@@ -331,9 +377,9 @@ TEST(InterpreterDiv) {
TEST(InterpreterMod) { TEST(InterpreterMod) {
InitializedHandleScope handles; HandleAndZoneScope handles;
// TODO(rmcilroy): Do add tests for heap numbers once we support them. // 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_locals_count(1);
builder.set_parameter_count(1); builder.set_parameter_count(1);
Register reg(0); Register reg(0);
...@@ -352,8 +398,8 @@ TEST(InterpreterMod) { ...@@ -352,8 +398,8 @@ TEST(InterpreterMod) {
TEST(InterpreterParameter1) { TEST(InterpreterParameter1) {
InitializedHandleScope handles; HandleAndZoneScope handles;
BytecodeArrayBuilder builder(handles.main_isolate()); BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(1); builder.set_locals_count(1);
builder.set_parameter_count(1); builder.set_parameter_count(1);
builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return(); builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return();
...@@ -375,8 +421,8 @@ TEST(InterpreterParameter1) { ...@@ -375,8 +421,8 @@ TEST(InterpreterParameter1) {
TEST(InterpreterParameter8) { TEST(InterpreterParameter8) {
InitializedHandleScope handles; HandleAndZoneScope handles;
BytecodeArrayBuilder builder(handles.main_isolate()); BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(1); builder.set_locals_count(1);
builder.set_parameter_count(8); builder.set_parameter_count(8);
builder.LoadAccumulatorWithRegister(builder.Parameter(0)) builder.LoadAccumulatorWithRegister(builder.Parameter(0))
......
...@@ -177,6 +177,9 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { ...@@ -177,6 +177,9 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode); int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode);
for (int i = 0; i < number_of_operands; i++) { for (int i = 0; i < number_of_operands; i++) {
switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) { switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) {
case interpreter::OperandType::kIdx:
EXPECT_THAT(m.BytecodeOperandIdx(i), m.IsBytecodeOperand(i));
break;
case interpreter::OperandType::kImm8: case interpreter::OperandType::kImm8:
EXPECT_THAT(m.BytecodeOperandImm8(i), EXPECT_THAT(m.BytecodeOperandImm8(i),
m.IsBytecodeOperandSignExtended(i)); m.IsBytecodeOperandSignExtended(i));
...@@ -266,6 +269,25 @@ TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) { ...@@ -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) { TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode); InterpreterAssemblerForTest m(this, bytecode);
......
...@@ -11,7 +11,7 @@ namespace v8 { ...@@ -11,7 +11,7 @@ namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
class BytecodeArrayBuilderTest : public TestWithIsolate { class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
public: public:
BytecodeArrayBuilderTest() {} BytecodeArrayBuilderTest() {}
~BytecodeArrayBuilderTest() override {} ~BytecodeArrayBuilderTest() override {}
...@@ -19,7 +19,7 @@ class BytecodeArrayBuilderTest : public TestWithIsolate { ...@@ -19,7 +19,7 @@ class BytecodeArrayBuilderTest : public TestWithIsolate {
TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
BytecodeArrayBuilder builder(isolate()); BytecodeArrayBuilder builder(isolate(), zone());
builder.set_locals_count(1); builder.set_locals_count(1);
builder.set_parameter_count(0); builder.set_parameter_count(0);
...@@ -28,6 +28,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -28,6 +28,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Emit constant loads. // Emit constant loads.
builder.LoadLiteral(Smi::FromInt(0)) builder.LoadLiteral(Smi::FromInt(0))
.LoadLiteral(Smi::FromInt(8)) .LoadLiteral(Smi::FromInt(8))
.LoadLiteral(Smi::FromInt(10000000))
.LoadUndefined() .LoadUndefined()
.LoadNull() .LoadNull()
.LoadTheHole() .LoadTheHole()
...@@ -79,7 +80,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -79,7 +80,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
for (int locals = 0; locals < 5; locals++) { for (int locals = 0; locals < 5; locals++) {
for (int temps = 0; temps < 3; temps++) { for (int temps = 0; temps < 3; temps++) {
BytecodeArrayBuilder builder(isolate()); BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0); builder.set_parameter_count(0);
builder.set_locals_count(locals); builder.set_locals_count(locals);
builder.Return(); builder.Return();
...@@ -98,7 +99,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { ...@@ -98,7 +99,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) { TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) {
BytecodeArrayBuilder builder(isolate()); BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0); builder.set_parameter_count(0);
builder.set_locals_count(0); builder.set_locals_count(0);
builder.Return(); builder.Return();
...@@ -138,7 +139,7 @@ TEST_F(BytecodeArrayBuilderTest, RegisterValues) { ...@@ -138,7 +139,7 @@ TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
TEST_F(BytecodeArrayBuilderTest, Parameters) { TEST_F(BytecodeArrayBuilderTest, Parameters) {
BytecodeArrayBuilder builder(isolate()); BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(10); builder.set_parameter_count(10);
builder.set_locals_count(0); builder.set_locals_count(0);
...@@ -147,6 +148,29 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) { ...@@ -147,6 +148,29 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) {
CHECK_EQ(param9.index() - param0.index(), 9); 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 interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // 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