| Index: test/cctest/interpreter/test-bytecode-generator.cc
|
| diff --git a/test/cctest/interpreter/test-bytecode-generator.cc b/test/cctest/interpreter/test-bytecode-generator.cc
|
| index 456dead3c047f2fcb9fad4ca7efb601b656d4133..cd91fde0ef0d837b4aaa4a8ad010fdd60408a433 100644
|
| --- a/test/cctest/interpreter/test-bytecode-generator.cc
|
| +++ b/test/cctest/interpreter/test-bytecode-generator.cc
|
| @@ -55,6 +55,21 @@ 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;
|
| + CompileRun(script);
|
| + i::FLAG_ignition_filter = old_ignition_filter;
|
| + v8::Local<v8::Context> context =
|
| + v8::Isolate::GetCurrent()->GetCurrentContext();
|
| + Local<Function> function = Local<Function>::Cast(
|
| + CcTest::global()->Get(context, v8_str(function_name)).ToLocalChecked());
|
| + i::Handle<i::JSFunction> js_function =
|
| + i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*function));
|
| + return handle(js_function->shared()->bytecode_array(), CcTest::i_isolate());
|
| + }
|
| +
|
| Handle<BytecodeArray> MakeBytecodeForFunctionBody(const char* body) {
|
| ScopedVector<char> program(3072);
|
| SNPrintF(program, "function %s() { %s }\n%s();", kFunctionName, body,
|
| @@ -5565,7 +5580,7 @@ TEST(Eval) {
|
| B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
|
| U8(5), //
|
| B(Star), R(1), //
|
| - B(Call), R(1), R(2), U8(1), U8(2), //
|
| + B(Call), R(1), R(2), U8(1), U8(0), //
|
| B(Return), //
|
| },
|
| 2,
|
| @@ -5579,6 +5594,266 @@ TEST(Eval) {
|
| }
|
| }
|
|
|
| +
|
| +TEST(StoreLookupSlotSloppy) {
|
| + InitializedHandleScope handle_scope;
|
| + BytecodeGeneratorHelper helper;
|
| +
|
| + 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[] = {
|
| + {"x = 20; return eval('');",
|
| + 9 * kPointerSize,
|
| + 1,
|
| + 80,
|
| + {
|
| + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
|
| + U8(1), //
|
| + B(PushContext), R(0), //
|
| + B(Ldar), THIS(1), //
|
| + B(StaContextSlot), R(0), U8(first_context_slot), //
|
| + B(CreateMappedArguments), //
|
| + B(StaContextSlot), R(0), U8(first_context_slot + 1), //
|
| + B(Ldar), R(new_target), //
|
| + B(StaContextSlot), R(0), U8(first_context_slot + 2), //
|
| + B(LdaSmi8), U8(20), //
|
| + B(StaLookupSlotSloppy), U8(0), R(0), //
|
| + B(Mov), R(context), R(3), //
|
| + B(LdaConstant), U8(1), //
|
| + B(Star), R(4), //
|
| + B(CallRuntime), U16(Runtime::kInterpreterLoadLookupSlotCallee), //
|
| + R(3), U8(2), //
|
| + B(Star), R(1), //
|
| + B(CallRuntime), U16(Runtime::kInterpreterLoadLookupSlotReceiver), //
|
| + R(3), U8(2), //
|
| + B(Star), R(2), //
|
| + B(LdaConstant), U8(2), //
|
| + B(Star), R(3), //
|
| + B(Mov), R(1), R(4), //
|
| + B(Mov), R(3), R(5), //
|
| + B(Mov), R(closure), R(6), //
|
| + B(LdaZero), //
|
| + B(Star), R(7), //
|
| + B(LdaSmi8), U8(10), //
|
| + B(Star), R(8), //
|
| + B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
|
| + U8(5), //
|
| + B(Star), R(1), //
|
| + B(Call), R(1), R(2), U8(1), U8(0), //
|
| + B(Return), //
|
| + },
|
| + 3,
|
| + {"x", "eval", ""}},
|
| + };
|
| +
|
| + for (size_t i = 0; i < arraysize(snippets); i++) {
|
| + Handle<BytecodeArray> bytecode_array =
|
| + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
|
| + CheckBytecodeArrayEqual(snippets[i], bytecode_array);
|
| + }
|
| +}
|
| +
|
| +
|
| +TEST(LdaLookupSlot) {
|
| + InitializedHandleScope handle_scope;
|
| + BytecodeGeneratorHelper helper;
|
| +
|
| + 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[] = {
|
| + {"eval('var x = 10;'); return x;",
|
| + 9 * kPointerSize,
|
| + 1,
|
| + 78,
|
| + {
|
| + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
|
| + U8(1), //
|
| + B(PushContext), R(0), //
|
| + B(Ldar), THIS(1), //
|
| + B(StaContextSlot), R(0), U8(first_context_slot), //
|
| + B(CreateMappedArguments), //
|
| + 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(LdaConstant), U8(0), //
|
| + B(Star), R(4), //
|
| + B(CallRuntime), U16(Runtime::kInterpreterLoadLookupSlotCallee), //
|
| + R(3), U8(2), //
|
| + B(Star), R(1), //
|
| + B(CallRuntime), U16(Runtime::kInterpreterLoadLookupSlotReceiver), //
|
| + R(3), U8(2), //
|
| + B(Star), R(2), //
|
| + B(LdaConstant), U8(1), //
|
| + B(Star), R(3), //
|
| + B(Mov), R(1), R(4), //
|
| + B(Mov), R(3), R(5), //
|
| + B(Mov), R(closure), R(6), //
|
| + B(LdaZero), //
|
| + B(Star), R(7), //
|
| + B(LdaSmi8), U8(10), //
|
| + B(Star), R(8), //
|
| + B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
|
| + U8(5), //
|
| + B(Star), R(1), //
|
| + B(Call), R(1), R(2), U8(1), U8(0), //
|
| + B(LdaLookupSlot), U8(2), R(0), //
|
| + B(Return), //
|
| + },
|
| + 3,
|
| + {"eval", "var x = 10;", "x"}},
|
| + };
|
| +
|
| + for (size_t i = 0; i < arraysize(snippets); i++) {
|
| + Handle<BytecodeArray> bytecode_array =
|
| + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
|
| + CheckBytecodeArrayEqual(snippets[i], bytecode_array);
|
| + }
|
| +}
|
| +
|
| +
|
| +TEST(LdaLookupSlotInsideTypeOf) {
|
| + InitializedHandleScope handle_scope;
|
| + BytecodeGeneratorHelper helper;
|
| +
|
| + 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[] = {
|
| + {"eval('var x = 10;'); return typeof x;",
|
| + 9 * kPointerSize,
|
| + 1,
|
| + 79,
|
| + {
|
| + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
|
| + U8(1), //
|
| + B(PushContext), R(0), //
|
| + B(Ldar), THIS(1), //
|
| + B(StaContextSlot), R(0), U8(first_context_slot), //
|
| + B(CreateMappedArguments), //
|
| + 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(LdaConstant), U8(0), //
|
| + B(Star), R(4), //
|
| + B(CallRuntime), U16(Runtime::kInterpreterLoadLookupSlotCallee), //
|
| + R(3), U8(2), //
|
| + B(Star), R(1), //
|
| + B(CallRuntime), U16(Runtime::kInterpreterLoadLookupSlotReceiver), //
|
| + R(3), U8(2), //
|
| + B(Star), R(2), //
|
| + B(LdaConstant), U8(1), //
|
| + B(Star), R(3), //
|
| + B(Mov), R(1), R(4), //
|
| + B(Mov), R(3), R(5), //
|
| + B(Mov), R(closure), R(6), //
|
| + B(LdaZero), //
|
| + B(Star), R(7), //
|
| + B(LdaSmi8), U8(10), //
|
| + B(Star), R(8), //
|
| + B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), //
|
| + U8(5), //
|
| + B(Star), R(1), //
|
| + B(Call), R(1), R(2), U8(1), U8(0), //
|
| + B(LdaLookupSlotInsideTypeof), U8(2), R(0), //
|
| + B(TypeOf), //
|
| + B(Return), //
|
| + },
|
| + 3,
|
| + {"eval", "var x = 10;", "x"}},
|
| + };
|
| +
|
| + for (size_t i = 0; i < arraysize(snippets); i++) {
|
| + Handle<BytecodeArray> bytecode_array =
|
| + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
|
| + CheckBytecodeArrayEqual(snippets[i], bytecode_array);
|
| + }
|
| +}
|
| +
|
| +
|
| +TEST(LookupSlotInEval) {
|
| + InitializedHandleScope handle_scope;
|
| + BytecodeGeneratorHelper helper;
|
| +
|
| + int context = Register::function_context().index();
|
| +
|
| + 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,
|
| + 4,
|
| + {
|
| + B(LdaLookupSlot), U8(0), R(context), //
|
| + B(Return) //
|
| + },
|
| + 1,
|
| + {"x"}},
|
| + {"x = 10;",
|
| + 0 * kPointerSize,
|
| + 1,
|
| + 7,
|
| + {
|
| + B(LdaSmi8), U8(10), //
|
| + B(StaLookupSlotSloppy), U8(0), R(context), //
|
| + B(LdaUndefined), //
|
| + B(Return), //
|
| + },
|
| + 1,
|
| + {"x"}},
|
| + {"'use strict'; x = 10;",
|
| + 0 * kPointerSize,
|
| + 1,
|
| + 7,
|
| + {
|
| + B(LdaSmi8), U8(10), //
|
| + B(StaLookupSlotStrict), U8(0), R(context), //
|
| + B(LdaUndefined), //
|
| + B(Return), //
|
| + },
|
| + 1,
|
| + {"x"}},
|
| + {"return typeof x;",
|
| + 0 * kPointerSize,
|
| + 1,
|
| + 5,
|
| + {
|
| + B(LdaLookupSlotInsideTypeof), U8(0), R(context), //
|
| + 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
|
|
|