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( ...@@ -315,7 +315,7 @@ void BytecodeGraphBuilder::VisitKeyedStoreICStrict(
} }
void BytecodeGraphBuilder::VisitCreateClosure( void BytecodeGraphBuilder::VisitKeyedStoreICGeneric(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -333,13 +333,19 @@ void BytecodeGraphBuilder::VisitPopContext( ...@@ -333,13 +333,19 @@ void BytecodeGraphBuilder::VisitPopContext(
} }
void BytecodeGraphBuilder::VisitCreateClosure(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitCreateArrayLiteral( void BytecodeGraphBuilder::VisitCreateArrayLiteral(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGraphBuilder::VisitKeyedStoreICGeneric( void BytecodeGraphBuilder::VisitCreateObjectLiteral(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -513,7 +519,13 @@ void BytecodeGraphBuilder::VisitTestInstanceOf( ...@@ -513,7 +519,13 @@ void BytecodeGraphBuilder::VisitTestInstanceOf(
void BytecodeGraphBuilder::VisitToBoolean( void BytecodeGraphBuilder::VisitToBoolean(
const interpreter::BytecodeArrayIterator& ToBoolean) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitToName(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
......
...@@ -371,6 +371,19 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral( ...@@ -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) { BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
Output(Bytecode::kPushContext, context.ToOperand()); Output(Bytecode::kPushContext, context.ToOperand());
return *this; return *this;
...@@ -414,6 +427,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { ...@@ -414,6 +427,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() {
Output(Bytecode::kToName);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) { BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
if (label->is_forward_target()) { if (label->is_forward_target()) {
// An earlier jump instruction refers to this label. Update it's location. // An earlier jump instruction refers to this label. Update it's location.
......
...@@ -86,6 +86,7 @@ class BytecodeArrayBuilder { ...@@ -86,6 +86,7 @@ class BytecodeArrayBuilder {
// Literals creation. Constant elements should be in the accumulator. // Literals creation. Constant elements should be in the accumulator.
BytecodeArrayBuilder& CreateArrayLiteral(int literal_index, int flags); 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 // Push the context in accumulator as the new context, and store in register
// |context|. // |context|.
...@@ -121,6 +122,7 @@ class BytecodeArrayBuilder { ...@@ -121,6 +122,7 @@ class BytecodeArrayBuilder {
// Casts // Casts
BytecodeArrayBuilder& CastAccumulatorToBoolean(); BytecodeArrayBuilder& CastAccumulatorToBoolean();
BytecodeArrayBuilder& CastAccumulatorToName();
// Flow Control. // Flow Control.
BytecodeArrayBuilder& Bind(BytecodeLabel* label); BytecodeArrayBuilder& Bind(BytecodeLabel* label);
......
This diff is collapsed.
...@@ -41,6 +41,11 @@ class BytecodeGenerator : public AstVisitor { ...@@ -41,6 +41,11 @@ class BytecodeGenerator : public AstVisitor {
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot); void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot); void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);
void VisitNewLocalFunctionContext(); 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. // Dispatched from VisitUnaryOperation.
void VisitVoid(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr);
......
...@@ -329,6 +329,24 @@ Register Register::FromOperand(uint8_t operand) { ...@@ -329,6 +329,24 @@ Register Register::FromOperand(uint8_t operand) {
return Register(-static_cast<int8_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 interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -110,9 +110,11 @@ namespace interpreter { ...@@ -110,9 +110,11 @@ namespace interpreter {
\ \
/* Cast operators */ \ /* Cast operators */ \
V(ToBoolean, OperandType::kNone) \ V(ToBoolean, OperandType::kNone) \
V(ToName, OperandType::kNone) \
\ \
/* Literals */ \ /* Literals */ \
V(CreateArrayLiteral, OperandType::kIdx8, OperandType::kImm8) \ V(CreateArrayLiteral, OperandType::kIdx8, OperandType::kImm8) \
V(CreateObjectLiteral, OperandType::kIdx8, OperandType::kImm8) \
\ \
/* Closure allocation */ \ /* Closure allocation */ \
V(CreateClosure, OperandType::kImm8) \ V(CreateClosure, OperandType::kImm8) \
...@@ -180,6 +182,7 @@ class Register { ...@@ -180,6 +182,7 @@ class Register {
return index_; return index_;
} }
bool is_parameter() const { return index() < 0; } bool is_parameter() const { return index() < 0; }
bool is_valid() const { return index_ != kIllegalIndex; }
static Register FromParameterIndex(int index, int parameter_count); static Register FromParameterIndex(int index, int parameter_count);
int ToParameterIndex(int parameter_count) const; int ToParameterIndex(int parameter_count) const;
...@@ -196,6 +199,11 @@ class Register { ...@@ -196,6 +199,11 @@ class Register {
static Register FromOperand(uint8_t operand); static Register FromOperand(uint8_t operand);
uint8_t ToOperand() const; uint8_t ToOperand() const;
static bool AreContiguous(Register reg1, Register reg2,
Register reg3 = Register(),
Register reg4 = Register(),
Register reg5 = Register());
private: private:
static const int kIllegalIndex = kMaxInt; static const int kIllegalIndex = kMaxInt;
......
...@@ -349,8 +349,8 @@ void Interpreter::DoKeyedStoreICStrict( ...@@ -349,8 +349,8 @@ void Interpreter::DoKeyedStoreICStrict(
// KeyedStoreICGeneric <object> <key> // KeyedStoreICGeneric <object> <key>
// //
// Calls the generic KeyStoreIC for <object> and the key <key> with the value in // Calls the generic KeyedStoreIC for <object> and the key <key> with the value
// the accumulator. // in the accumulator.
void Interpreter::DoKeyedStoreICGeneric( void Interpreter::DoKeyedStoreICGeneric(
compiler::InterpreterAssembler* assembler) { compiler::InterpreterAssembler* assembler) {
Callable ic = Callable ic =
...@@ -656,6 +656,17 @@ void Interpreter::DoToBoolean(compiler::InterpreterAssembler* assembler) { ...@@ -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 <imm8>
// //
// Jump by number of bytes represented by the immediate operand |imm8|. // Jump by number of bytes represented by the immediate operand |imm8|.
...@@ -730,12 +741,8 @@ void Interpreter::DoJumpIfFalseConstant( ...@@ -730,12 +741,8 @@ void Interpreter::DoJumpIfFalseConstant(
} }
// CreateArrayLiteral <idx> <flags> void Interpreter::DoCreateLiteral(Runtime::FunctionId function_id,
// compiler::InterpreterAssembler* assembler) {
// Creates an array literal for literal index <idx> with flags <flags> and
// constant elements in the accumulator.
void Interpreter::DoCreateArrayLiteral(
compiler::InterpreterAssembler* assembler) {
Node* constant_elements = __ GetAccumulator(); Node* constant_elements = __ GetAccumulator();
Node* literal_index_raw = __ BytecodeOperandIdx8(0); Node* literal_index_raw = __ BytecodeOperandIdx8(0);
Node* literal_index = __ SmiTag(literal_index_raw); Node* literal_index = __ SmiTag(literal_index_raw);
...@@ -744,13 +751,33 @@ void Interpreter::DoCreateArrayLiteral( ...@@ -744,13 +751,33 @@ void Interpreter::DoCreateArrayLiteral(
Node* closure = __ LoadRegister(Register::function_closure()); Node* closure = __ LoadRegister(Register::function_closure());
Node* literals_array = Node* literals_array =
__ LoadObjectField(closure, JSFunction::kLiteralsOffset); __ LoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* result = __ CallRuntime(Runtime::kCreateArrayLiteral, literals_array, Node* result = __ CallRuntime(function_id, literals_array, literal_index,
literal_index, constant_elements, flags); constant_elements, flags);
__ SetAccumulator(result); __ SetAccumulator(result);
__ Dispatch(); __ 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> // CreateClosure <tenured>
// //
// Creates a new closure for SharedFunctionInfo in the accumulator with the // Creates a new closure for SharedFunctionInfo in the accumulator with the
......
...@@ -66,6 +66,10 @@ class Interpreter { ...@@ -66,6 +66,10 @@ class Interpreter {
void DoPropertyStoreIC(Callable ic, void DoPropertyStoreIC(Callable ic,
compiler::InterpreterAssembler* assembler); 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); bool IsInterpreterTableInitialized(Handle<FixedArray> handler_table);
Isolate* isolate_; Isolate* isolate_;
......
...@@ -1672,3 +1672,56 @@ TEST(InterpreterArrayLiterals) { ...@@ -1672,3 +1672,56 @@ TEST(InterpreterArrayLiterals) {
CHECK(return_value->SameValue(*literals[i].second)); 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) { ...@@ -64,7 +64,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.CreateClosure(NOT_TENURED); builder.CreateClosure(NOT_TENURED);
// Emit literal creation operations // Emit literal creation operations
builder.CreateArrayLiteral(0, 0); builder.CreateArrayLiteral(0, 0)
.CreateObjectLiteral(0, 0);
// Call operations. // Call operations.
builder.Call(reg, reg, 0); builder.Call(reg, reg, 0);
...@@ -103,7 +104,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -103,7 +104,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CompareOperation(Token::Value::IN, reg, Strength::WEAK); .CompareOperation(Token::Value::IN, reg, Strength::WEAK);
// Emit cast operator invocations. // Emit cast operator invocations.
builder.LoadNull().CastAccumulatorToBoolean(); builder.LoadNull()
.CastAccumulatorToBoolean()
.CastAccumulatorToName();
// Emit control flow. Return must be the last instruction. // Emit control flow. Return must be the last instruction.
BytecodeLabel start; 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