Commit a4162898 authored by mythria's avatar mythria Committed by Commit bot

[Interpreter] Add support for Load / Store to Lookup slots.

Adds support for loading and storing lookup variables.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#32913}
parent d0304f91
......@@ -583,6 +583,30 @@ void BytecodeGraphBuilder::VisitStaContextSlot(
}
void BytecodeGraphBuilder::VisitLdaLookupSlot(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitLdaLookupSlotInsideTypeof(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitStaLookupSlotSloppy(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitStaLookupSlotStrict(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::BuildNamedLoad(
const interpreter::BytecodeArrayIterator& iterator) {
Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
......
......@@ -383,6 +383,11 @@ Node* InterpreterAssembler::LoadTypeFeedbackVector() {
}
Node* InterpreterAssembler::Projection(int index, Node* node) {
return raw_assembler_->Projection(index, node);
}
Node* InterpreterAssembler::CallConstruct(Node* new_target, Node* constructor,
Node* first_arg, Node* arg_count) {
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(isolate());
......
......@@ -105,6 +105,9 @@ class InterpreterAssembler {
// Load the TypeFeedbackVector for the current function.
Node* LoadTypeFeedbackVector();
// Project the output value at index |index|
Node* Projection(int index, Node* node);
// Call constructor |constructor| with |arg_count| arguments (not
// including receiver) and the first argument located at
// |first_arg|. The |new_target| is the same as the
......
......@@ -438,6 +438,34 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot(
const Handle<String> name, TypeofMode typeof_mode) {
Bytecode bytecode = (typeof_mode == INSIDE_TYPEOF)
? Bytecode::kLdaLookupSlotInsideTypeof
: Bytecode::kLdaLookupSlot;
size_t name_index = GetConstantPoolEntry(name);
if (FitsInIdx8Operand(name_index)) {
Output(bytecode, static_cast<uint8_t>(name_index));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
const Handle<String> name, LanguageMode language_mode) {
Bytecode bytecode = BytecodeForStoreLookupSlot(language_mode);
size_t name_index = GetConstantPoolEntry(name);
if (FitsInIdx8Operand(name_index)) {
Output(bytecode, static_cast<uint8_t>(name_index));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
Register object, size_t name_index, int feedback_slot,
LanguageMode language_mode) {
......@@ -1322,6 +1350,23 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal(
}
// static
Bytecode BytecodeArrayBuilder::BytecodeForStoreLookupSlot(
LanguageMode language_mode) {
switch (language_mode) {
case SLOPPY:
return Bytecode::kStaLookupSlotSloppy;
case STRICT:
return Bytecode::kStaLookupSlotStrict;
case STRONG:
UNIMPLEMENTED();
default:
UNREACHABLE();
}
return static_cast<Bytecode>(-1);
}
// static
Bytecode BytecodeArrayBuilder::BytecodeForCreateArguments(
CreateArgumentsType type) {
......
......@@ -117,6 +117,14 @@ class BytecodeArrayBuilder {
int feedback_slot,
LanguageMode language_mode);
// Lookup the variable with |name|.
BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name,
TypeofMode typeof_mode);
// Store value in the accumulator into the variable with |name|.
BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name,
LanguageMode language_mode);
// Create a new closure for the SharedFunctionInfo.
BytecodeArrayBuilder& CreateClosure(Handle<SharedFunctionInfo> shared_info,
PretenureFlag tenured);
......@@ -226,6 +234,7 @@ class BytecodeArrayBuilder {
static Bytecode BytecodeForLoadGlobal(LanguageMode language_mode,
TypeofMode typeof_mode);
static Bytecode BytecodeForStoreGlobal(LanguageMode language_mode);
static Bytecode BytecodeForStoreLookupSlot(LanguageMode language_mode);
static Bytecode BytecodeForCreateArguments(CreateArgumentsType type);
static Bytecode BytecodeForDelete(LanguageMode language_mode);
......
......@@ -1309,8 +1309,11 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
// let variables.
break;
}
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
case VariableLocation::LOOKUP: {
builder()->LoadLookupSlot(variable->name(), typeof_mode);
execution_result()->SetResultInAccumulator();
break;
}
}
}
......@@ -1386,8 +1389,10 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
builder()->StoreContextSlot(context_reg, variable->index());
break;
}
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
case VariableLocation::LOOKUP: {
builder()->StoreLookupSlot(variable->name(), language_mode());
break;
}
}
}
......
......@@ -66,6 +66,12 @@ namespace interpreter {
V(LdaContextSlot, OperandType::kReg8, OperandType::kIdx8) \
V(StaContextSlot, OperandType::kReg8, OperandType::kIdx8) \
\
/* Load-Store lookup slots */ \
V(LdaLookupSlot, OperandType::kIdx8) \
V(LdaLookupSlotInsideTypeof, OperandType::kIdx8) \
V(StaLookupSlotSloppy, OperandType::kIdx8) \
V(StaLookupSlotStrict, OperandType::kIdx8) \
\
/* Register-accumulator transfers */ \
V(Ldar, OperandType::kReg8) \
V(Star, OperandType::kReg8) \
......
......@@ -424,6 +424,71 @@ void Interpreter::DoStaContextSlot(compiler::InterpreterAssembler* assembler) {
}
void Interpreter::DoLoadLookupSlot(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler) {
Node* index = __ BytecodeOperandIdx(0);
Node* name = __ LoadConstantPoolEntry(index);
Node* context = __ GetContext();
Node* result_pair = __ CallRuntime(function_id, context, name);
Node* result = __ Projection(0, result_pair);
__ SetAccumulator(result);
__ Dispatch();
}
// LdaLookupSlot <name_index>
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically.
void Interpreter::DoLdaLookupSlot(compiler::InterpreterAssembler* assembler) {
DoLoadLookupSlot(Runtime::kLoadLookupSlot, assembler);
}
// LdaLookupSlotInsideTypeof <name_index>
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically without causing a NoReferenceError.
void Interpreter::DoLdaLookupSlotInsideTypeof(
compiler::InterpreterAssembler* assembler) {
DoLoadLookupSlot(Runtime::kLoadLookupSlotNoReferenceError, assembler);
}
void Interpreter::DoStoreLookupSlot(LanguageMode language_mode,
compiler::InterpreterAssembler* assembler) {
Node* value = __ GetAccumulator();
Node* index = __ BytecodeOperandIdx(0);
Node* name = __ LoadConstantPoolEntry(index);
Node* context = __ GetContext();
Node* language_mode_node = __ NumberConstant(language_mode);
Node* result = __ CallRuntime(Runtime::kStoreLookupSlot, value, context, name,
language_mode_node);
__ SetAccumulator(result);
__ Dispatch();
}
// StaLookupSlotSloppy <name_index>
//
// Store the object in accumulator to the object with the name in constant
// pool entry |name_index| in sloppy mode.
void Interpreter::DoStaLookupSlotSloppy(
compiler::InterpreterAssembler* assembler) {
DoStoreLookupSlot(LanguageMode::SLOPPY, assembler);
}
// StaLookupSlotStrict <name_index>
//
// Store the object in accumulator to the object with the name in constant
// pool entry |name_index| in strict mode.
void Interpreter::DoStaLookupSlotStrict(
compiler::InterpreterAssembler* assembler) {
DoStoreLookupSlot(LanguageMode::STRICT, assembler);
}
void Interpreter::DoLoadIC(Callable ic,
compiler::InterpreterAssembler* assembler) {
Node* code_target = __ HeapConstant(ic.code());
......
......@@ -95,6 +95,14 @@ class Interpreter {
void DoDelete(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler);
// Generates code to perform a lookup slot load via |function_id|.
void DoLoadLookupSlot(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler);
// Generates code to perform a lookup slot store depending on |language_mode|.
void DoStoreLookupSlot(LanguageMode language_mode,
compiler::InterpreterAssembler* assembler);
bool IsInterpreterTableInitialized(Handle<FixedArray> handler_table);
Isolate* isolate_;
......
......@@ -55,6 +55,15 @@ class BytecodeGeneratorHelper {
return handle(js_function->shared()->bytecode_array(), CcTest::i_isolate());
}
Handle<BytecodeArray> MakeBytecode(const char* script, const char* filter,
const char* function_name) {
const char* old_ignition_filter = i::FLAG_ignition_filter;
i::FLAG_ignition_filter = filter;
Handle<BytecodeArray> return_val = MakeBytecode(script, function_name);
i::FLAG_ignition_filter = old_ignition_filter;
return return_val;
}
Handle<BytecodeArray> MakeBytecodeForFunctionBody(const char* body) {
ScopedVector<char> program(3072);
SNPrintF(program, "function %s() { %s }\n%s();", kFunctionName, body,
......@@ -69,14 +78,9 @@ class BytecodeGeneratorHelper {
}
Handle<BytecodeArray> MakeBytecodeForFunctionNoFilter(const char* function) {
const char* old_ignition_filter = i::FLAG_ignition_filter;
i::FLAG_ignition_filter = "*";
ScopedVector<char> program(3072);
SNPrintF(program, "%s\n%s();", function, kFunctionName);
Handle<BytecodeArray> return_val =
MakeBytecode(program.start(), kFunctionName);
i::FLAG_ignition_filter = old_ignition_filter;
return return_val;
return MakeBytecode(program.start(), "*", kFunctionName);
}
};
......@@ -5719,6 +5723,79 @@ TEST(AssignmentsInBinaryExpression) {
}
}
TEST(LookupSlotInEval) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
const char* function_prologue = "var f;"
"var x = 1;"
"function f1() {"
" eval(\"function t() {";
const char* function_epilogue = " }; f = t; f();\");"
"}"
"f1();";
ExpectedSnippet<const char*> snippets[] = {
{"return x;",
0 * kPointerSize,
1,
3,
{
B(LdaLookupSlot), U8(0), //
B(Return) //
},
1,
{"x"}},
{"x = 10;",
0 * kPointerSize,
1,
6,
{
B(LdaSmi8), U8(10), //
B(StaLookupSlotSloppy), U8(0), //
B(LdaUndefined), //
B(Return), //
},
1,
{"x"}},
{"'use strict'; x = 10;",
0 * kPointerSize,
1,
6,
{
B(LdaSmi8), U8(10), //
B(StaLookupSlotStrict), U8(0), //
B(LdaUndefined), //
B(Return), //
},
1,
{"x"}},
{"return typeof x;",
0 * kPointerSize,
1,
4,
{
B(LdaLookupSlotInsideTypeof), U8(0), //
B(TypeOf), //
B(Return), //
},
1,
{"x"}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {
std::string script = std::string(function_prologue) +
std::string(snippets[i].code_snippet) +
std::string(function_epilogue);
// TODO(mythria): use * as filter when function declarations are supported
// inside eval.
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(script.c_str(), "t", "f");
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -3093,6 +3093,42 @@ TEST(InterpreterToName) {
}
}
TEST(InterpreterLookupSlot) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
// TODO(mythria): Add more tests when we have support for eval/with.
const char* function_prologue = "var f;"
"var x = 1;"
"function f1() {"
" eval(\"function t() {";
const char* function_epilogue = " }; f = t;\");"
"}"
"f1();";
std::pair<const char*, Handle<Object>> lookup_slot[] = {
{"return x;", handle(Smi::FromInt(1), isolate)},
{"return typeof x;", factory->NewStringFromStaticChars("number")},
{"x = 10; return x;", handle(Smi::FromInt(10), isolate)},
{"'use strict'; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
};
for (size_t i = 0; i < arraysize(lookup_slot); i++) {
std::string script = std::string(function_prologue) +
std::string(lookup_slot[i].first) +
std::string(function_epilogue);
InterpreterTester tester(handles.main_isolate(), script.c_str(), "t");
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*lookup_slot[i].second));
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -93,8 +93,15 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.StoreNamedProperty(reg, 0, 2056, LanguageMode::STRICT)
.StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT);
// Emit closure operations.
// Emit load / store lookup slots.
Factory* factory = isolate()->factory();
Handle<String> name = factory->NewStringFromStaticChars("var_name");
builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
.LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF)
.StoreLookupSlot(name, LanguageMode::SLOPPY)
.StoreLookupSlot(name, LanguageMode::STRICT);
// Emit closure operations.
Handle<SharedFunctionInfo> shared_info = factory->NewSharedFunctionInfo(
factory->NewStringFromStaticChars("function_a"), MaybeHandle<Code>(),
false);
......
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