Commit 20fba512 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Adds Object literal support.

Adds Object literal support to the interpreter. Adds the following bytecodes:
 - ToName
 - CreateObjectLiteral.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31253}
parent 52225f39
......@@ -315,7 +315,7 @@ void BytecodeGraphBuilder::VisitKeyedStoreICStrict(
}
void BytecodeGraphBuilder::VisitCreateClosure(
void BytecodeGraphBuilder::VisitKeyedStoreICGeneric(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
......@@ -333,13 +333,19 @@ void BytecodeGraphBuilder::VisitPopContext(
}
void BytecodeGraphBuilder::VisitCreateClosure(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitCreateArrayLiteral(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitKeyedStoreICGeneric(
void BytecodeGraphBuilder::VisitCreateObjectLiteral(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
......@@ -513,7 +519,13 @@ void BytecodeGraphBuilder::VisitTestInstanceOf(
void BytecodeGraphBuilder::VisitToBoolean(
const interpreter::BytecodeArrayIterator& ToBoolean) {
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitToName(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
......
......@@ -371,6 +371,19 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral(
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
int literal_index, int flags) {
DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bytes.
if (FitsInIdx8Operand(literal_index)) {
Output(Bytecode::kCreateObjectLiteral, static_cast<uint8_t>(literal_index),
static_cast<uint8_t>(flags));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
Output(Bytecode::kPushContext, context.ToOperand());
return *this;
......@@ -414,6 +427,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() {
Output(Bytecode::kToName);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
if (label->is_forward_target()) {
// An earlier jump instruction refers to this label. Update it's location.
......
......@@ -86,6 +86,7 @@ class BytecodeArrayBuilder {
// Literals creation. Constant elements should be in the accumulator.
BytecodeArrayBuilder& CreateArrayLiteral(int literal_index, int flags);
BytecodeArrayBuilder& CreateObjectLiteral(int literal_index, int flags);
// Push the context in accumulator as the new context, and store in register
// |context|.
......@@ -121,6 +122,7 @@ class BytecodeArrayBuilder {
// Casts
BytecodeArrayBuilder& CastAccumulatorToBoolean();
BytecodeArrayBuilder& CastAccumulatorToName();
// Flow Control.
BytecodeArrayBuilder& Bind(BytecodeLabel* label);
......
This diff is collapsed.
......@@ -41,6 +41,11 @@ class BytecodeGenerator : public AstVisitor {
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);
void VisitNewLocalFunctionContext();
void VisitSetHomeObject(Register value, Register home_object,
ObjectLiteralProperty* property, int slot_number = 0);
void VisitObjectLiteralAccessor(Register home_object,
ObjectLiteralProperty* property,
Register value_out);
// Dispatched from VisitUnaryOperation.
void VisitVoid(UnaryOperation* expr);
......
......@@ -329,6 +329,24 @@ Register Register::FromOperand(uint8_t operand) {
return Register(-static_cast<int8_t>(operand));
}
bool Register::AreContiguous(Register reg1, Register reg2, Register reg3,
Register reg4, Register reg5) {
if (reg1.index() + 1 != reg2.index()) {
return false;
}
if (reg3.is_valid() && reg2.index() + 1 != reg3.index()) {
return false;
}
if (reg4.is_valid() && reg3.index() + 1 != reg4.index()) {
return false;
}
if (reg5.is_valid() && reg4.index() + 1 != reg5.index()) {
return false;
}
return true;
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -110,9 +110,11 @@ namespace interpreter {
\
/* Cast operators */ \
V(ToBoolean, OperandType::kNone) \
V(ToName, OperandType::kNone) \
\
/* Literals */ \
V(CreateArrayLiteral, OperandType::kIdx8, OperandType::kImm8) \
V(CreateObjectLiteral, OperandType::kIdx8, OperandType::kImm8) \
\
/* Closure allocation */ \
V(CreateClosure, OperandType::kImm8) \
......@@ -180,6 +182,7 @@ class Register {
return index_;
}
bool is_parameter() const { return index() < 0; }
bool is_valid() const { return index_ != kIllegalIndex; }
static Register FromParameterIndex(int index, int parameter_count);
int ToParameterIndex(int parameter_count) const;
......@@ -196,6 +199,11 @@ class Register {
static Register FromOperand(uint8_t operand);
uint8_t ToOperand() const;
static bool AreContiguous(Register reg1, Register reg2,
Register reg3 = Register(),
Register reg4 = Register(),
Register reg5 = Register());
private:
static const int kIllegalIndex = kMaxInt;
......
......@@ -349,8 +349,8 @@ void Interpreter::DoKeyedStoreICStrict(
// KeyedStoreICGeneric <object> <key>
//
// Calls the generic KeyStoreIC for <object> and the key <key> with the value in
// the accumulator.
// Calls the generic KeyedStoreIC for <object> and the key <key> with the value
// in the accumulator.
void Interpreter::DoKeyedStoreICGeneric(
compiler::InterpreterAssembler* assembler) {
Callable ic =
......@@ -656,6 +656,17 @@ void Interpreter::DoToBoolean(compiler::InterpreterAssembler* assembler) {
}
// ToName
//
// Cast the object referenced by the accumulator to a name.
void Interpreter::DoToName(compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* result = __ CallRuntime(Runtime::kToName, accumulator);
__ SetAccumulator(result);
__ Dispatch();
}
// Jump <imm8>
//
// Jump by number of bytes represented by the immediate operand |imm8|.
......@@ -730,12 +741,8 @@ void Interpreter::DoJumpIfFalseConstant(
}
// CreateArrayLiteral <idx> <flags>
//
// Creates an array literal for literal index <idx> with flags <flags> and
// constant elements in the accumulator.
void Interpreter::DoCreateArrayLiteral(
compiler::InterpreterAssembler* assembler) {
void Interpreter::DoCreateLiteral(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler) {
Node* constant_elements = __ GetAccumulator();
Node* literal_index_raw = __ BytecodeOperandIdx8(0);
Node* literal_index = __ SmiTag(literal_index_raw);
......@@ -744,13 +751,33 @@ void Interpreter::DoCreateArrayLiteral(
Node* closure = __ LoadRegister(Register::function_closure());
Node* literals_array =
__ LoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* result = __ CallRuntime(Runtime::kCreateArrayLiteral, literals_array,
literal_index, constant_elements, flags);
Node* result = __ CallRuntime(function_id, literals_array, literal_index,
constant_elements, flags);
__ SetAccumulator(result);
__ Dispatch();
}
// CreateArrayLiteral <idx> <flags>
//
// Creates an array literal for literal index <idx> with flags <flags> and
// constant elements in the accumulator.
void Interpreter::DoCreateArrayLiteral(
compiler::InterpreterAssembler* assembler) {
DoCreateLiteral(Runtime::kCreateArrayLiteral, assembler);
}
// CreateObjectLiteral <idx> <flags>
//
// Creates an object literal for literal index <idx> with flags <flags> and
// constant elements in the accumulator.
void Interpreter::DoCreateObjectLiteral(
compiler::InterpreterAssembler* assembler) {
DoCreateLiteral(Runtime::kCreateObjectLiteral, assembler);
}
// CreateClosure <tenured>
//
// Creates a new closure for SharedFunctionInfo in the accumulator with the
......
......@@ -66,6 +66,10 @@ class Interpreter {
void DoPropertyStoreIC(Callable ic,
compiler::InterpreterAssembler* assembler);
// Generates code ro create a literal via |function_id|.
void DoCreateLiteral(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler);
bool IsInterpreterTableInitialized(Handle<FixedArray> handler_table);
Isolate* isolate_;
......
......@@ -1672,3 +1672,56 @@ TEST(InterpreterArrayLiterals) {
CHECK(return_value->SameValue(*literals[i].second));
}
}
TEST(InterpreterObjectLiterals) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
std::pair<const char*, Handle<Object>> literals[14] = {
std::make_pair("return { }.name;",
factory->undefined_value()),
std::make_pair("return { name: 'string', val: 9.2 }.name;",
factory->NewStringFromStaticChars("string")),
std::make_pair("var a = 15; return { name: 'string', val: a }.val;",
Handle<Object>(Smi::FromInt(15), isolate)),
std::make_pair("var a = 5; return { val: a, val: a + 1 }.val;",
Handle<Object>(Smi::FromInt(6), isolate)),
std::make_pair("return { func: function() { return 'test' } }.func();",
factory->NewStringFromStaticChars("test")),
std::make_pair("return { func(a) { return a + 'st'; } }.func('te');",
factory->NewStringFromStaticChars("test")),
std::make_pair("return { get a() { return 22; } }.a;",
Handle<Object>(Smi::FromInt(22), isolate)),
std::make_pair("var a = { get b() { return this.x + 't'; },\n"
" set b(val) { this.x = val + 's' } };\n"
"a.b = 'te';\n"
"return a.b;",
factory->NewStringFromStaticChars("test")),
std::make_pair("var a = 123; return { 1: a }[1];",
Handle<Object>(Smi::FromInt(123), isolate)),
std::make_pair("return Object.getPrototypeOf({ __proto__: null });",
factory->null_value()),
std::make_pair("var a = 'test'; return { [a]: 1 }.test;",
Handle<Object>(Smi::FromInt(1), isolate)),
std::make_pair("var a = 'test'; return { b: a, [a]: a + 'ing' }['test']",
factory->NewStringFromStaticChars("testing")),
std::make_pair("var a = 'proto_str';\n"
"var b = { [a]: 1, __proto__: { var : a } };\n"
"return Object.getPrototypeOf(b).var",
factory->NewStringFromStaticChars("proto_str")),
std::make_pair("var n = 'name';\n"
"return { [n]: 'val', get a() { return 987 } }['a'];",
Handle<Object>(Smi::FromInt(987), isolate)),
};
for (size_t i = 0; i < arraysize(literals); i++) {
std::string source(InterpreterTester::SourceForBody(literals[i].first));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*literals[i].second));
}
}
......@@ -64,7 +64,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.CreateClosure(NOT_TENURED);
// Emit literal creation operations
builder.CreateArrayLiteral(0, 0);
builder.CreateArrayLiteral(0, 0)
.CreateObjectLiteral(0, 0);
// Call operations.
builder.Call(reg, reg, 0);
......@@ -103,7 +104,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CompareOperation(Token::Value::IN, reg, Strength::WEAK);
// Emit cast operator invocations.
builder.LoadNull().CastAccumulatorToBoolean();
builder.LoadNull()
.CastAccumulatorToBoolean()
.CastAccumulatorToName();
// Emit control flow. Return must be the last instruction.
BytecodeLabel start;
......
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