Commit 6eb00e4a authored by mythria's avatar mythria Committed by Commit bot

[Interpreter] Adds support for DeleteLookupSlot to Interpreter.

Adds support for deleting a variable in a lookup slot. Adds a new bytecode,
its implementation and tests. Also adds support for this bytecode to the
bytecode graph builder.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#33019}
parent eb5ecd83
......@@ -1320,6 +1320,16 @@ void BytecodeGraphBuilder::VisitDeletePropertySloppy(
}
void BytecodeGraphBuilder::VisitDeleteLookupSlot(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* name = environment()->LookupAccumulator();
const Operator* op = javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2);
Node* result = NewNode(op, environment()->Context(), name);
environment()->BindAccumulator(result, &states);
}
void BytecodeGraphBuilder::BuildCompareOp(
const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
......
......@@ -1001,6 +1001,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
}
BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() {
Output(Bytecode::kDeleteLookupSlot);
return *this;
}
size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
// These constants shouldn't be added to the constant pool, the should use
// specialzed bytecodes instead.
......
......@@ -188,6 +188,7 @@ class BytecodeArrayBuilder final {
// Deletes property from an object. This expects that accumulator contains
// the key to be deleted and the register contains a reference to the object.
BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
BytecodeArrayBuilder& DeleteLookupSlot();
// Tests.
BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg,
......
......@@ -1797,7 +1797,7 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
break;
}
case VariableLocation::LOOKUP: {
UNIMPLEMENTED();
builder()->LoadLiteral(variable->name()).DeleteLookupSlot();
break;
}
default:
......
......@@ -129,6 +129,7 @@ namespace interpreter {
V(TypeOf, OperandType::kNone) \
V(DeletePropertyStrict, OperandType::kReg8) \
V(DeletePropertySloppy, OperandType::kReg8) \
V(DeleteLookupSlot, OperandType::kNone) \
\
/* Call operations */ \
V(Call, OperandType::kReg8, OperandType::kReg8, OperandType::kCount8, \
......
......@@ -963,6 +963,20 @@ void Interpreter::DoDeletePropertySloppy(
}
// DeleteLookupSlot
//
// Delete the variable with the name specified in the accumulator by dynamically
// looking it up.
void Interpreter::DoDeleteLookupSlot(
compiler::InterpreterAssembler* assembler) {
Node* name = __ GetAccumulator();
Node* context = __ GetContext();
Node* result = __ CallRuntime(Runtime::kDeleteLookupSlot, context, name);
__ SetAccumulator(result);
__ Dispatch();
}
void Interpreter::DoJSCall(compiler::InterpreterAssembler* assembler) {
Node* function_reg = __ BytecodeOperandReg(0);
Node* function = __ LoadRegister(function_reg);
......
......@@ -978,6 +978,44 @@ TEST(BytecodeGraphBuilderDeleteGlobal) {
}
TEST(BytecodeGraphBuilderDeleteLookupSlot) {
HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate();
Zone* zone = scope.main_zone();
Factory* factory = isolate->factory();
// TODO(mythria): Add more tests when we have support for LdaLookupSlot.
const char* function_prologue = "var f;"
"var x = 1;"
"y = 10;"
"var obj = {val:10};"
"var z = 30;"
"function f1() {"
" var z = 20;"
" eval(\"function t() {";
const char* function_epilogue = " }; f = t; t();\");"
"}"
"f1();";
ExpectedSnippet<0> snippets[] = {
{"return delete y;", {factory->true_value()}},
{"return delete z;", {factory->false_value()}},
};
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) {
ScopedVector<char> script(1024);
SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet,
function_epilogue);
BytecodeGraphTester tester(isolate, zone, script.start(), "t");
auto callable = tester.GetCallable<>();
Handle<Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*snippets[i].return_value()));
}
}
bool get_compare_result(Token::Value opcode, Handle<Object> lhs_value,
Handle<Object> rhs_value) {
switch (opcode) {
......
......@@ -5794,6 +5794,66 @@ TEST(LookupSlotInEval) {
}
}
TEST(DeleteLookupSlot) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
const char* function_prologue = "var f;"
"var x = 1;"
"z = 10;"
"function f1() {"
" var y;"
" eval(\"function t() {";
const char* function_epilogue = " }; f = t; f();\");"
"}"
"f1();";
ExpectedSnippet<const char*> snippets[] = {
{"delete x;",
0 * kPointerSize,
1,
5,
{
B(LdaConstant), U8(0), //
B(DeleteLookupSlot), //
B(LdaUndefined), //
B(Return) //
},
1,
{"x"}},
{"return delete y;",
0 * kPointerSize,
1,
2,
{
B(LdaFalse), //
B(Return) //
},
0},
{"return delete z;",
0 * kPointerSize,
1,
4,
{
B(LdaConstant), U8(0), //
B(DeleteLookupSlot), //
B(Return) //
},
1,
{"z"}},
};
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);
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(script.c_str(), "t", "f");
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -3163,6 +3163,47 @@ TEST(TemporaryRegisterAllocation) {
}
}
TEST(InterpreterDeleteLookupSlot) {
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;"
"y = 10;"
"var obj = {val:10};"
"var z = 30;"
"function f1() {"
" var z = 20;"
" eval(\"function t() {";
const char* function_epilogue = " }; f = t;\");"
"}"
"f1();";
std::pair<const char*, Handle<Object>> delete_lookup_slot[] = {
{"return delete x;", factory->false_value()},
{"return delete y;", factory->true_value()},
{"return delete z;", factory->false_value()},
{"return delete obj.val;", factory->true_value()},
{"'use strict'; return delete obj.val;", factory->true_value()},
};
for (size_t i = 0; i < arraysize(delete_lookup_slot); i++) {
std::string script = std::string(function_prologue) +
std::string(delete_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(*delete_lookup_slot[i].second));
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -147,7 +147,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.LogicalNot().TypeOf();
// Emit delete
builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT);
builder.Delete(reg, LanguageMode::SLOPPY)
.Delete(reg, LanguageMode::STRICT)
.DeleteLookupSlot();
// Emit new.
builder.New(reg, reg, 0);
......
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