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

[Interpreter] Adds support for variable/function declarations in lookup slots.

Adds support for variable and function declarations in lookup slots to the
interpreter.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#33355}
parent 085487dd
......@@ -480,10 +480,32 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
variable->index());
}
break;
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
case VariableLocation::LOOKUP: {
DCHECK(IsDeclaredVariableMode(mode));
register_allocator()->PrepareForConsecutiveAllocations(3);
Register name = register_allocator()->NextConsecutiveRegister();
Register init_value = register_allocator()->NextConsecutiveRegister();
Register attributes = register_allocator()->NextConsecutiveRegister();
builder()->LoadLiteral(variable->name()).StoreAccumulatorInRegister(name);
if (hole_init) {
builder()->LoadTheHole().StoreAccumulatorInRegister(init_value);
} else {
// For variables, we must not use an initial value (such as 'undefined')
// because we may have a (legal) redeclaration and we must not destroy
// the current value.
builder()
->LoadLiteral(Smi::FromInt(0))
.StoreAccumulatorInRegister(init_value);
}
builder()
->LoadLiteral(Smi::FromInt(variable->DeclarationPropertyAttributes()))
.StoreAccumulatorInRegister(attributes)
.CallRuntime(Runtime::kDeclareLookupSlot, name, 3);
break;
}
}
}
......@@ -513,8 +535,20 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
variable->index());
break;
}
case VariableLocation::LOOKUP:
UNIMPLEMENTED();
case VariableLocation::LOOKUP: {
register_allocator()->PrepareForConsecutiveAllocations(3);
Register name = register_allocator()->NextConsecutiveRegister();
Register literal = register_allocator()->NextConsecutiveRegister();
Register attributes = register_allocator()->NextConsecutiveRegister();
builder()->LoadLiteral(variable->name()).StoreAccumulatorInRegister(name);
VisitForAccumulatorValue(decl->fun());
builder()
->StoreAccumulatorInRegister(literal)
.LoadLiteral(Smi::FromInt(variable->DeclarationPropertyAttributes()))
.StoreAccumulatorInRegister(attributes)
.CallRuntime(Runtime::kDeclareLookupSlot, name, 3);
}
}
}
......@@ -533,7 +567,10 @@ void BytecodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
RegisterAllocationScope register_scope(this);
DCHECK(globals()->empty());
AstVisitor::VisitDeclarations(declarations);
for (int i = 0; i < declarations->length(); i++) {
RegisterAllocationScope register_scope(this);
Visit(declarations->at(i));
}
if (globals()->empty()) return;
int array_index = 0;
Handle<FixedArray> data = isolate()->factory()->NewFixedArray(
......@@ -1319,6 +1356,8 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
break;
}
case VariableLocation::LOOKUP: {
// TODO(mythria): Use Runtime::kInitializeLegacyConstLookupSlot for
// initializations of const declarations.
builder()->StoreLookupSlot(variable->name(), language_mode());
break;
}
......@@ -1559,7 +1598,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
DCHECK(Register::AreContiguous(callee, receiver));
Variable* variable = callee_expr->AsVariableProxy()->var();
builder()
->MoveRegister(Register::function_context(), context)
->MoveRegister(execution_context()->reg(), context)
.LoadLiteral(variable->name())
.StoreAccumulatorInRegister(name)
.CallRuntimeForPair(Runtime::kLoadLookupSlot, context, 2, callee);
......
......@@ -6233,7 +6233,6 @@ TEST(Eval) {
Zone zone;
int closure = Register::function_closure().index();
int context = Register::function_context().index();
int new_target = Register::new_target().index();
int first_context_slot = Context::MIN_CONTEXT_SLOTS;
......@@ -6253,7 +6252,7 @@ TEST(Eval) {
B(StaContextSlot), R(0), U8(first_context_slot + 1), //
B(Ldar), R(new_target), //
B(StaContextSlot), R(0), U8(first_context_slot + 2), //
B(Mov), R(context), R(3), //
B(Mov), R(0), R(3), //
B(LdaConstant), U8(0), //
B(Star), R(4), //
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), //
......@@ -6291,7 +6290,6 @@ TEST(LookupSlot) {
int closure = Register::function_closure().index();
int first_context_slot = Context::MIN_CONTEXT_SLOTS;
int context = Register::function_context().index();
int new_target = Register::new_target().index();
ExpectedSnippet<const char*> snippets[] = {
......@@ -6309,7 +6307,7 @@ TEST(LookupSlot) {
B(StaContextSlot), R(0), U8(first_context_slot + 1), //
B(Ldar), R(new_target), //
B(StaContextSlot), R(0), U8(first_context_slot + 2), //
B(Mov), R(context), R(3), //
B(Mov), R(0), R(3), //
B(LdaConstant), U8(0), //
B(Star), R(4), //
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), //
......@@ -6346,7 +6344,7 @@ TEST(LookupSlot) {
B(StaContextSlot), R(0), U8(first_context_slot + 1), //
B(Ldar), R(new_target), //
B(StaContextSlot), R(0), U8(first_context_slot + 2), //
B(Mov), R(context), R(3), //
B(Mov), R(0), R(3), //
B(LdaConstant), U8(0), //
B(Star), R(4), //
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), //
......@@ -6386,7 +6384,7 @@ TEST(LookupSlot) {
B(StaContextSlot), R(0), U8(first_context_slot + 2), //
B(LdaSmi8), U8(20), //
B(StaLookupSlotSloppy), U8(0), //
B(Mov), R(context), R(3), //
B(Mov), R(0), R(3), //
B(LdaConstant), U8(1), //
B(Star), R(4), //
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), //
......@@ -6432,7 +6430,6 @@ TEST(CallLookupSlot) {
i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec);
int closure = Register::function_closure().index();
int context = Register::function_context().index();
int new_target = Register::new_target().index();
ExpectedSnippet<InstanceType> snippets[] = {
......@@ -6452,7 +6449,7 @@ TEST(CallLookupSlot) {
B(StaContextSlot), R(0), U8(6), //
B(CreateClosure), U8(0), U8(0), //
B(StaLookupSlotSloppy), U8(1), //
B(Mov), R(context), R(3), //
B(Mov), R(0), R(3), //
B(LdaConstant), U8(2), //
B(Star), R(4), //
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), //
......@@ -6470,7 +6467,7 @@ TEST(CallLookupSlot) {
U8(5), //
B(Star), R(1), //
B(Call), R(1), R(2), U8(1), U8(0), //
B(Mov), R(context), R(3), //
B(Mov), R(0), R(3), //
B(LdaConstant), U8(1), //
B(Star), R(4), //
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), //
......@@ -6493,6 +6490,8 @@ TEST(CallLookupSlot) {
}
// TODO(mythria): tests for variable/function declaration in lookup slots.
TEST(LookupSlotInEval) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
......@@ -6557,10 +6556,8 @@ TEST(LookupSlotInEval) {
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");
helper.MakeBytecode(script.c_str(), "*", "f");
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
......@@ -6654,10 +6651,8 @@ TEST(LookupSlotWideInEval) {
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");
helper.MakeBytecode(script.c_str(), "*", "f");
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
......@@ -6717,7 +6712,7 @@ TEST(DeleteLookupSlotInEval) {
std::string(snippets[i].code_snippet) +
std::string(function_epilogue);
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(script.c_str(), "t", "f");
helper.MakeBytecode(script.c_str(), "*", "f");
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
......
......@@ -3562,6 +3562,81 @@ TEST(InterpreterEvalGlobal) {
}
}
TEST(InterpreterEvalVariableDecl) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
std::pair<const char*, Handle<Object>> eval_global[] = {
{"function f() { eval('var x = 10; x++;'); return x; }",
handle(Smi::FromInt(11), isolate)},
{"function f() { var x = 20; eval('var x = 10; x++;'); return x; }",
handle(Smi::FromInt(11), isolate)},
{"function f() {"
" var x = 20;"
" eval('\"use strict\"; var x = 10; x++;');"
" return x; }",
handle(Smi::FromInt(20), isolate)},
{"function f() {"
" var y = 30;"
" eval('var x = {1:20}; x[2]=y;');"
" return x[2]; }",
handle(Smi::FromInt(30), isolate)},
{"function f() {"
" eval('var x = {name:\"test\"};');"
" return x.name; }",
factory->NewStringFromStaticChars("test")},
{"function f() {"
" eval('var x = [{name:\"test\"}, {type:\"cc\"}];');"
" return x[1].type+x[0].name; }",
factory->NewStringFromStaticChars("cctest")},
{"function f() {\n"
" var x = 3;\n"
" var get_eval_x;\n"
" eval('\"use strict\"; "
" var x = 20; "
" get_eval_x = function func() {return x;};');\n"
" return get_eval_x() + x;\n"
"}",
handle(Smi::FromInt(23), isolate)},
// TODO(mythria): Add tests with const declarations.
};
for (size_t i = 0; i < arraysize(eval_global); i++) {
InterpreterTester tester(handles.main_isolate(), eval_global[i].first, "*");
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*eval_global[i].second));
}
}
TEST(InterpreterEvalFunctionDecl) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
std::pair<const char*, Handle<Object>> eval_func_decl[] = {
{"function f() {\n"
" var x = 3;\n"
" eval('var x = 20;"
" function get_x() {return x;};');\n"
" return get_x() + x;\n"
"}",
handle(Smi::FromInt(40), isolate)},
};
for (size_t i = 0; i < arraysize(eval_func_decl); i++) {
InterpreterTester tester(handles.main_isolate(), eval_func_decl[i].first,
"*");
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*eval_func_decl[i].second));
}
}
} // 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