Commit 009e8b11 authored by marja's avatar marja Committed by Commit bot

[parser/test] Move cctest/PreParserScopeAnalysis into a new file.

BUG=v8:5516
R=vogelheim@chromium.org

Review-Url: https://codereview.chromium.org/2683573002
Cr-Commit-Position: refs/heads/master@{#42986}
parent 7d15175a
......@@ -92,12 +92,14 @@ v8_executable("cctest") {
"libplatform/test-tracing.cc",
"libsampler/test-sampler.cc",
"parsing/test-parse-decision.cc",
"parsing/test-preparser.cc",
"parsing/test-scanner-streams.cc",
"parsing/test-scanner.cc",
"print-extension.cc",
"print-extension.h",
"profiler-extension.cc",
"profiler-extension.h",
"scope-test-helper.h",
"test-access-checks.cc",
"test-accessor-assembler.cc",
"test-accessors.cc",
......@@ -184,6 +186,7 @@ v8_executable("cctest") {
"trace-extension.cc",
"trace-extension.h",
"types-fuzz.h",
"unicode-helpers.h",
"wasm/test-managed.cc",
"wasm/test-run-wasm-64.cc",
"wasm/test-run-wasm-asmjs.cc",
......
......@@ -113,12 +113,14 @@
'libplatform/test-tracing.cc',
'libsampler/test-sampler.cc',
'parsing/test-parse-decision.cc',
'parsing/test-preparser.cc',
'parsing/test-scanner-streams.cc',
'parsing/test-scanner.cc',
'print-extension.cc',
'print-extension.h',
'profiler-extension.cc',
'profiler-extension.h',
'scope-test-helper.h',
'test-access-checks.cc',
'test-accessor-assembler.cc',
'test-accessors.cc',
......@@ -205,6 +207,7 @@
'trace-extension.cc',
'trace-extension.h',
'types-fuzz.h',
'unicode-helpers.h',
'wasm/test-managed.cc',
'wasm/test-run-wasm.cc',
'wasm/test-run-wasm-64.cc',
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ast/ast.h"
#include "src/compiler.h"
#include "src/objects-inl.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parsing.h"
#include "test/cctest/cctest.h"
#include "test/cctest/scope-test-helper.h"
#include "test/cctest/unicode-helpers.h"
TEST(PreParserScopeAnalysis) {
i::FLAG_lazy_inner_functions = true;
i::FLAG_preparser_scope_analysis = true;
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
i::HandleScope scope(isolate);
LocalContext env;
const char* prefix = "(function outer() { ";
const char* suffix = " })();";
int prefix_len = Utf8LengthHelper(prefix);
int suffix_len = Utf8LengthHelper(suffix);
// The scope start positions must match; note the extra space in lazy_inner.
const char* lazy_inner = " function inner(%s) { %s }";
const char* eager_inner = "(function inner(%s) { %s })()";
struct {
const char* params;
const char* source;
} inners[] = {
// Simple cases
{"", "var1;"},
{"", "var1 = 5;"},
{"", "if (true) {}"},
{"", "function f1() {}"},
// Var declarations and assignments.
{"", "var var1;"},
{"", "var var1; var1 = 5;"},
{"", "if (true) { var var1; }"},
{"", "if (true) { var var1; var1 = 5; }"},
{"", "var var1; function f() { var1; }"},
{"", "var var1; var1 = 5; function f() { var1; }"},
{"", "var var1; function f() { var1 = 5; }"},
// Let declarations and assignments.
{"", "let var1;"},
{"", "let var1; var1 = 5;"},
{"", "if (true) { let var1; }"},
{"", "if (true) { let var1; var1 = 5; }"},
{"", "let var1; function f() { var1; }"},
{"", "let var1; var1 = 5; function f() { var1; }"},
{"", "let var1; function f() { var1 = 5; }"},
// Const declarations.
{"", "const var1 = 5;"},
{"", "if (true) { const var1 = 5; }"},
{"", "const var1 = 5; function f() { var1; }"},
// Redeclarations.
{"", "var var1; var var1;"},
{"", "var var1; var var1; var1 = 5;"},
{"", "var var1; if (true) { var var1; }"},
{"", "if (true) { var var1; var var1; }"},
{"", "var var1; if (true) { var var1; var1 = 5; }"},
{"", "if (true) { var var1; var var1; var1 = 5; }"},
{"", "var var1; var var1; function f() { var1; }"},
{"", "var var1; var var1; function f() { var1 = 5; }"},
// Shadowing declarations.
{"", "var var1; if (true) { var var1; }"},
{"", "var var1; if (true) { let var1; }"},
{"", "let var1; if (true) { let var1; }"},
{"", "var var1; if (true) { const var1 = 0; }"},
{"", "const var1 = 0; if (true) { const var1 = 0; }"},
// Arguments and this.
{"", "arguments;"},
{"", "arguments = 5;"},
{"", "if (true) { arguments; }"},
{"", "if (true) { arguments = 5; }"},
{"", "function f() { arguments; }"},
{"", "function f() { arguments = 5; }"},
{"", "this;"},
{"", "if (true) { this; }"},
{"", "function f() { this; }"},
// Variable called "arguments"
{"", "var arguments;"},
{"", "var arguments; arguments = 5;"},
{"", "if (true) { var arguments; }"},
{"", "if (true) { var arguments; arguments = 5; }"},
{"", "var arguments; function f() { arguments; }"},
{"", "var arguments; arguments = 5; function f() { arguments; }"},
{"", "var arguments; function f() { arguments = 5; }"},
{"", "let arguments;"},
{"", "let arguments; arguments = 5;"},
{"", "if (true) { let arguments; }"},
{"", "if (true) { let arguments; arguments = 5; }"},
{"", "let arguments; function f() { arguments; }"},
{"", "let arguments; arguments = 5; function f() { arguments; }"},
{"", "let arguments; function f() { arguments = 5; }"},
{"", "const arguments = 5;"},
{"", "if (true) { const arguments = 5; }"},
{"", "const arguments = 5; function f() { arguments; }"},
// Destructuring declarations.
{"", "var [var1, var2] = [1, 2];"},
{"", "var [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
{"", "var [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
{"", "var [var1, ...var2] = [1, 2, 3];"},
{"", "var {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
{"",
"var {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
{"", "var {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
{"", "let [var1, var2] = [1, 2];"},
{"", "let [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
{"", "let [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
{"", "let [var1, ...var2] = [1, 2, 3];"},
{"", "let {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
{"",
"let {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
{"", "let {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
{"", "const [var1, var2] = [1, 2];"},
{"", "const [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
{"", "const [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
{"", "const [var1, ...var2] = [1, 2, 3];"},
{"", "const {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
{"",
"const {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
{"", "const {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
// Referencing the function variable.
{"", "inner;"},
{"", "function f1() { f1; }"},
{"", "function f1() { inner; }"},
{"", "function f1() { function f2() { f1; } }"},
{"", "function arguments() {}"},
{"", "function f1() {} function f1() {}"},
{"", "var f1; function f1() {}"},
// Assigning to the function variable.
{"", "inner = 3;"},
{"", "function f1() { f1 = 3; }"},
{"", "function f1() { f1; } f1 = 3;"},
{"", "function arguments() {} arguments = 8"},
{"", "function f1() {} f1 = 3; function f1() {}"},
// Evals.
{"", "var var1; eval('');"},
{"", "var var1; function f1() { eval(''); }"},
{"", "let var1; eval('');"},
{"", "let var1; function f1() { eval(''); }"},
{"", "const var1 = 10; eval('');"},
{"", "const var1 = 10; function f1() { eval(''); }"},
// Standard for loops.
{"", "for (var var1 = 0; var1 < 10; ++var1) { }"},
{"", "for (let var1 = 0; var1 < 10; ++var1) { }"},
{"", "for (const var1 = 0; var1 < 10; ++var1) { }"},
{"",
"for (var var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"",
"for (let var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"",
"for (const var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"",
"'use strict'; for (var var1 = 0; var1 < 10; ++var1) { function foo() { "
"var1; } }"},
{"",
"'use strict'; for (let var1 = 0; var1 < 10; ++var1) { function foo() { "
"var1; } }"},
{"",
"'use strict'; for (const var1 = 0; var1 < 10; ++var1) { function foo() "
"{ var1; } }"},
// For of loops
{"", "for (var1 of [1, 2]) { }"},
{"", "for (var var1 of [1, 2]) { }"},
{"", "for (let var1 of [1, 2]) { }"},
{"", "for (const var1 of [1, 2]) { }"},
{"", "for (var1 of [1, 2]) { var1; }"},
{"", "for (var var1 of [1, 2]) { var1; }"},
{"", "for (let var1 of [1, 2]) { var1; }"},
{"", "for (const var1 of [1, 2]) { var1; }"},
{"", "for (var1 of [1, 2]) { var1 = 0; }"},
{"", "for (var var1 of [1, 2]) { var1 = 0; }"},
{"", "for (let var1 of [1, 2]) { var1 = 0; }"},
{"", "for (const var1 of [1, 2]) { var1 = 0; }"},
{"", "for (var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (var var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (let var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (const var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (var1 of [1, 2]) { function foo() { var1 = 0; } }"},
{"", "for (var var1 of [1, 2]) { function foo() { var1 = 0; } }"},
{"", "for (let var1 of [1, 2]) { function foo() { var1 = 0; } }"},
{"", "for (const var1 of [1, 2]) { function foo() { var1 = 0; } }"},
// For in loops
{"", "for (var1 in {a: 6}) { }"},
{"", "for (var var1 in {a: 6}) { }"},
{"", "for (let var1 in {a: 6}) { }"},
{"", "for (const var1 in {a: 6}) { }"},
{"", "for (var1 in {a: 6}) { var1; }"},
{"", "for (var var1 in {a: 6}) { var1; }"},
{"", "for (let var1 in {a: 6}) { var1; }"},
{"", "for (const var1 in {a: 6}) { var1; }"},
{"", "for (var1 in {a: 6}) { var1 = 0; }"},
{"", "for (var var1 in {a: 6}) { var1 = 0; }"},
{"", "for (let var1 in {a: 6}) { var1 = 0; }"},
{"", "for (const var1 in {a: 6}) { var1 = 0; }"},
{"", "for (var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (var var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (let var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (const var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"},
// Loops without declarations
{"", "var var1 = 0; for ( ; var1 < 2; ++var1) { }"},
{"",
"var var1 = 0; for ( ; var1 < 2; ++var1) { function foo() { var1; } }"},
{"", "var var1 = 0; for ( ; var1 > 2; ) { }"},
{"", "var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1; } }"},
{"",
"var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1 = 6; } }"},
{"", "var var1 = 0; for(var1; var1 < 2; ++var1) { }"},
{"",
"var var1 = 0; for (var1; var1 < 2; ++var1) { function foo() { var1; } "
"}"},
{"", "var var1 = 0; for (var1; var1 > 2; ) { }"},
{"", "var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1; } }"},
{"",
"var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1 = 6; } }"},
// Sloppy block functions.
{"", "if (true) { function f1() {} }"},
{"", "if (true) { function f1() {} function f1() {} }"},
{"", "if (true) { if (true) { function f1() {} } }"},
{"", "if (true) { if (true) { function f1() {} function f1() {} } }"},
{"", "if (true) { function f1() {} f1 = 3; }"},
{"", "if (true) { function f1() {} function foo() { f1; } }"},
{"", "if (true) { function f1() {} } function foo() { f1; }"},
{"",
"if (true) { function f1() {} function f1() {} function foo() { f1; } "
"}"},
{"",
"if (true) { function f1() {} function f1() {} } function foo() { f1; "
"}"},
{"",
"if (true) { if (true) { function f1() {} } function foo() { f1; } }"},
{"",
"if (true) { if (true) { function f1() {} function f1() {} } function "
"foo() { f1; } }"},
{"", "if (true) { function f1() {} f1 = 3; function foo() { f1; } }"},
{"", "if (true) { function f1() {} f1 = 3; } function foo() { f1; }"},
{"", "function inner2() { if (true) { function f1() {} } }"},
{"", "function inner2() { if (true) { function f1() {} f1 = 3; } }"},
{"", "var f1 = 1; if (true) { function f1() {} }"},
{"", "var f1 = 1; if (true) { function f1() {} } function foo() { f1; }"},
};
for (unsigned i = 0; i < arraysize(inners); ++i) {
// First compile with the lazy inner function and extract the scope data.
const char* inner_function = lazy_inner;
int inner_function_len = Utf8LengthHelper(inner_function) - 4;
int params_len = Utf8LengthHelper(inners[i].params);
int source_len = Utf8LengthHelper(inners[i].source);
int len =
prefix_len + inner_function_len + params_len + source_len + suffix_len;
i::ScopedVector<char> lazy_program(len + 1);
i::SNPrintF(lazy_program, "%s", prefix);
i::SNPrintF(lazy_program + prefix_len, inner_function, inners[i].params,
inners[i].source);
i::SNPrintF(lazy_program + prefix_len + inner_function_len + params_len +
source_len,
"%s", suffix);
i::Handle<i::String> source =
factory->InternalizeUtf8String(lazy_program.start());
source->PrintOn(stdout);
printf("\n");
i::Handle<i::Script> script = factory->NewScript(source);
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo lazy_info(&zone, script);
// No need to run scope analysis; preparser scope data is produced when
// parsing.
CHECK(i::parsing::ParseProgram(&lazy_info));
// Then parse eagerly and check against the scope data.
inner_function = eager_inner;
inner_function_len = Utf8LengthHelper(inner_function) - 4;
len =
prefix_len + inner_function_len + params_len + source_len + suffix_len;
i::ScopedVector<char> eager_program(len + 1);
i::SNPrintF(eager_program, "%s", prefix);
i::SNPrintF(eager_program + prefix_len, inner_function, inners[i].params,
inners[i].source);
i::SNPrintF(eager_program + prefix_len + inner_function_len + params_len +
source_len,
"%s", suffix);
source = factory->InternalizeUtf8String(eager_program.start());
source->PrintOn(stdout);
printf("\n");
script = factory->NewScript(source);
i::ParseInfo eager_info(&zone, script);
eager_info.set_allow_lazy_parsing(false);
CHECK(i::parsing::ParseProgram(&eager_info));
CHECK(i::Compiler::Analyze(&eager_info));
i::Scope* scope =
eager_info.literal()->scope()->inner_scope()->inner_scope();
DCHECK_NOT_NULL(scope);
DCHECK_NULL(scope->sibling());
DCHECK(scope->is_function_scope());
size_t index = 0;
i::ScopeTestHelper::CompareScopeToData(
scope, lazy_info.preparsed_scope_data(), index);
}
}
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_CCTEST_SCOPE_TEST_HELPER_H_
#define V8_CCTEST_SCOPE_TEST_HELPER_H_
#include "src/ast/scopes.h"
#include "src/ast/variables.h"
namespace v8 {
namespace internal {
class ScopeTestHelper {
public:
static bool MustAllocateInContext(Variable* var) {
return var->scope()->MustAllocateInContext(var);
}
// True if the scope is and its entire subscope tree are hidden.
static bool ScopeTreeIsHidden(Scope* scope) {
if (!scope->is_hidden()) {
return false;
}
for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) {
if (!ScopeTreeIsHidden(inner)) {
return false;
}
}
return true;
}
static void CompareScopeToData(Scope* scope, const PreParsedScopeData* data,
size_t& index) {
CHECK_EQ(data->backing_store_[index++], scope->scope_type());
CHECK_EQ(data->backing_store_[index++], scope->start_position());
CHECK_EQ(data->backing_store_[index++], scope->end_position());
int inner_scope_count = 0;
for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) {
// FIXME(marja): This is probably not the right condition for knowing what
// scopes are present in the preparse data.
if (!ScopeTreeIsHidden(inner)) {
++inner_scope_count;
}
}
CHECK_EQ(data->backing_store_[index++], inner_scope_count);
int variable_count = 0;
for (Variable* local : scope->locals_) {
if (local->mode() == VAR || local->mode() == LET ||
local->mode() == CONST) {
++variable_count;
}
}
CHECK_EQ(data->backing_store_[index++], variable_count);
for (Variable* local : scope->locals_) {
if (local->mode() == VAR || local->mode() == LET ||
local->mode() == CONST) {
#ifdef DEBUG
const AstRawString* local_name = local->raw_name();
int name_length = data->backing_store_[index++];
CHECK_EQ(name_length, local_name->length());
for (int i = 0; i < name_length; ++i) {
CHECK_EQ(data->backing_store_[index++], local_name->raw_data()[i]);
}
#endif
CHECK_EQ(data->backing_store_[index++], local->location());
CHECK_EQ(data->backing_store_[index++], local->maybe_assigned());
}
}
for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) {
if (!ScopeTreeIsHidden(inner)) {
CompareScopeToData(inner, data, index);
}
}
}
};
} // namespace internal
} // namespace v8
#endif // V8_CCTEST_SCOPE_TEST_HELPER_H_
......@@ -53,6 +53,8 @@
#include "src/utils.h"
#include "test/cctest/cctest.h"
#include "test/cctest/scope-test-helper.h"
#include "test/cctest/unicode-helpers.h"
TEST(ScanKeywords) {
struct KeywordToken {
......@@ -702,29 +704,6 @@ TEST(RegExpScanning) {
TestScanRegExp("/=?/", "=?");
}
static int Ucs2CharLength(unibrow::uchar c) {
if (c == unibrow::Utf8::kIncomplete || c == unibrow::Utf8::kBufferEmpty) {
return 0;
} else if (c < 0xffff) {
return 1;
} else {
return 2;
}
}
static int Utf8LengthHelper(const char* s) {
unibrow::Utf8::Utf8IncrementalBuffer buffer(unibrow::Utf8::kBufferEmpty);
int length = 0;
for (; *s != '\0'; s++) {
unibrow::uchar tmp = unibrow::Utf8::ValueOfIncremental(*s, &buffer);
length += Ucs2CharLength(tmp);
}
unibrow::uchar tmp = unibrow::Utf8::ValueOfIncrementalFinish(&buffer);
length += Ucs2CharLength(tmp);
return length;
}
TEST(ScopeUsesArgumentsSuperThis) {
static const struct {
const char* prefix;
......@@ -8826,82 +8805,6 @@ TEST(ArgumentsRedeclaration) {
}
}
namespace v8 {
namespace internal {
class ScopeTestHelper {
public:
static bool MustAllocateInContext(Variable* var) {
return var->scope()->MustAllocateInContext(var);
}
// True if the scope is and its entire subscope tree are hidden.
static bool ScopeTreeIsHidden(Scope* scope) {
if (!scope->is_hidden()) {
return false;
}
for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) {
if (!ScopeTreeIsHidden(inner)) {
return false;
}
}
return true;
}
static void CompareScopeToData(Scope* scope, const PreParsedScopeData* data,
size_t& index) {
CHECK_EQ(data->backing_store_[index++], scope->scope_type());
CHECK_EQ(data->backing_store_[index++], scope->start_position());
CHECK_EQ(data->backing_store_[index++], scope->end_position());
int inner_scope_count = 0;
for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) {
// FIXME(marja): This is probably not the right condition for knowing what
// scopes are present in the preparse data.
if (!ScopeTreeIsHidden(inner)) {
++inner_scope_count;
}
}
CHECK_EQ(data->backing_store_[index++], inner_scope_count);
int variable_count = 0;
for (Variable* local : scope->locals_) {
if (local->mode() == VAR || local->mode() == LET ||
local->mode() == CONST) {
++variable_count;
}
}
CHECK_EQ(data->backing_store_[index++], variable_count);
for (Variable* local : scope->locals_) {
if (local->mode() == VAR || local->mode() == LET ||
local->mode() == CONST) {
#ifdef DEBUG
const AstRawString* local_name = local->raw_name();
int name_length = data->backing_store_[index++];
CHECK_EQ(name_length, local_name->length());
for (int i = 0; i < name_length; ++i) {
CHECK_EQ(data->backing_store_[index++], local_name->raw_data()[i]);
}
#endif
CHECK_EQ(data->backing_store_[index++], local->location());
CHECK_EQ(data->backing_store_[index++], local->maybe_assigned());
}
}
for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) {
if (!ScopeTreeIsHidden(inner)) {
CompareScopeToData(inner, data, index);
}
}
}
};
} // namespace internal
} // namespace v8
// Test that lazily parsed inner functions don't result in overly pessimistic
// context allocations.
......@@ -9189,353 +9092,3 @@ TEST(NoPessimisticContextAllocation) {
}
}
}
TEST(PreParserScopeAnalysis) {
i::FLAG_lazy_inner_functions = true;
i::FLAG_preparser_scope_analysis = true;
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
i::HandleScope scope(isolate);
LocalContext env;
const char* prefix = "(function outer() { ";
const char* suffix = " })();";
int prefix_len = Utf8LengthHelper(prefix);
int suffix_len = Utf8LengthHelper(suffix);
// The scope start positions must match; note the extra space in lazy_inner.
const char* lazy_inner = " function inner(%s) { %s }";
const char* eager_inner = "(function inner(%s) { %s })()";
struct {
const char* params;
const char* source;
} inners[] = {
// Simple cases
{"", "var1;"},
{"", "var1 = 5;"},
{"", "if (true) {}"},
{"", "function f1() {}"},
// Var declarations and assignments.
{"", "var var1;"},
{"", "var var1; var1 = 5;"},
{"", "if (true) { var var1; }"},
{"", "if (true) { var var1; var1 = 5; }"},
{"", "var var1; function f() { var1; }"},
{"", "var var1; var1 = 5; function f() { var1; }"},
{"", "var var1; function f() { var1 = 5; }"},
// Let declarations and assignments.
{"", "let var1;"},
{"", "let var1; var1 = 5;"},
{"", "if (true) { let var1; }"},
{"", "if (true) { let var1; var1 = 5; }"},
{"", "let var1; function f() { var1; }"},
{"", "let var1; var1 = 5; function f() { var1; }"},
{"", "let var1; function f() { var1 = 5; }"},
// Const declarations.
{"", "const var1 = 5;"},
{"", "if (true) { const var1 = 5; }"},
{"", "const var1 = 5; function f() { var1; }"},
// Redeclarations.
{"", "var var1; var var1;"},
{"", "var var1; var var1; var1 = 5;"},
{"", "var var1; if (true) { var var1; }"},
{"", "if (true) { var var1; var var1; }"},
{"", "var var1; if (true) { var var1; var1 = 5; }"},
{"", "if (true) { var var1; var var1; var1 = 5; }"},
{"", "var var1; var var1; function f() { var1; }"},
{"", "var var1; var var1; function f() { var1 = 5; }"},
// Shadowing declarations.
{"", "var var1; if (true) { var var1; }"},
{"", "var var1; if (true) { let var1; }"},
{"", "let var1; if (true) { let var1; }"},
{"", "var var1; if (true) { const var1 = 0; }"},
{"", "const var1 = 0; if (true) { const var1 = 0; }"},
// Arguments and this.
{"", "arguments;"},
{"", "arguments = 5;"},
{"", "if (true) { arguments; }"},
{"", "if (true) { arguments = 5; }"},
{"", "function f() { arguments; }"},
{"", "function f() { arguments = 5; }"},
{"", "this;"},
{"", "if (true) { this; }"},
{"", "function f() { this; }"},
// Variable called "arguments"
{"", "var arguments;"},
{"", "var arguments; arguments = 5;"},
{"", "if (true) { var arguments; }"},
{"", "if (true) { var arguments; arguments = 5; }"},
{"", "var arguments; function f() { arguments; }"},
{"", "var arguments; arguments = 5; function f() { arguments; }"},
{"", "var arguments; function f() { arguments = 5; }"},
{"", "let arguments;"},
{"", "let arguments; arguments = 5;"},
{"", "if (true) { let arguments; }"},
{"", "if (true) { let arguments; arguments = 5; }"},
{"", "let arguments; function f() { arguments; }"},
{"", "let arguments; arguments = 5; function f() { arguments; }"},
{"", "let arguments; function f() { arguments = 5; }"},
{"", "const arguments = 5;"},
{"", "if (true) { const arguments = 5; }"},
{"", "const arguments = 5; function f() { arguments; }"},
// Destructuring declarations.
{"", "var [var1, var2] = [1, 2];"},
{"", "var [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
{"", "var [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
{"", "var [var1, ...var2] = [1, 2, 3];"},
{"", "var {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
{"",
"var {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
{"", "var {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
{"", "let [var1, var2] = [1, 2];"},
{"", "let [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
{"", "let [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
{"", "let [var1, ...var2] = [1, 2, 3];"},
{"", "let {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
{"",
"let {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
{"", "let {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
{"", "const [var1, var2] = [1, 2];"},
{"", "const [var1, var2, [var3, var4]] = [1, 2, [3, 4]];"},
{"", "const [{var1: var2}, {var3: var4}] = [{var1: 1}, {var3: 2}];"},
{"", "const [var1, ...var2] = [1, 2, 3];"},
{"", "const {var1: var2, var3: var4} = {var1: 1, var3: 2};"},
{"",
"const {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"},
{"", "const {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"},
// Referencing the function variable.
{"", "inner;"},
{"", "function f1() { f1; }"},
{"", "function f1() { inner; }"},
{"", "function f1() { function f2() { f1; } }"},
{"", "function arguments() {}"},
{"", "function f1() {} function f1() {}"},
{"", "var f1; function f1() {}"},
// Assigning to the function variable.
{"", "inner = 3;"},
{"", "function f1() { f1 = 3; }"},
{"", "function f1() { f1; } f1 = 3;"},
{"", "function arguments() {} arguments = 8"},
{"", "function f1() {} f1 = 3; function f1() {}"},
// Evals.
{"", "var var1; eval('');"},
{"", "var var1; function f1() { eval(''); }"},
{"", "let var1; eval('');"},
{"", "let var1; function f1() { eval(''); }"},
{"", "const var1 = 10; eval('');"},
{"", "const var1 = 10; function f1() { eval(''); }"},
// Standard for loops.
{"", "for (var var1 = 0; var1 < 10; ++var1) { }"},
{"", "for (let var1 = 0; var1 < 10; ++var1) { }"},
{"", "for (const var1 = 0; var1 < 10; ++var1) { }"},
{"",
"for (var var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"",
"for (let var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"",
"for (const var1 = 0; var1 < 10; ++var1) { function foo() { var1; } }"},
{"",
"'use strict'; for (var var1 = 0; var1 < 10; ++var1) { function foo() { "
"var1; } }"},
{"",
"'use strict'; for (let var1 = 0; var1 < 10; ++var1) { function foo() { "
"var1; } }"},
{"",
"'use strict'; for (const var1 = 0; var1 < 10; ++var1) { function foo() "
"{ var1; } }"},
// For of loops
{"", "for (var1 of [1, 2]) { }"},
{"", "for (var var1 of [1, 2]) { }"},
{"", "for (let var1 of [1, 2]) { }"},
{"", "for (const var1 of [1, 2]) { }"},
{"", "for (var1 of [1, 2]) { var1; }"},
{"", "for (var var1 of [1, 2]) { var1; }"},
{"", "for (let var1 of [1, 2]) { var1; }"},
{"", "for (const var1 of [1, 2]) { var1; }"},
{"", "for (var1 of [1, 2]) { var1 = 0; }"},
{"", "for (var var1 of [1, 2]) { var1 = 0; }"},
{"", "for (let var1 of [1, 2]) { var1 = 0; }"},
{"", "for (const var1 of [1, 2]) { var1 = 0; }"},
{"", "for (var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (var var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (let var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (const var1 of [1, 2]) { function foo() { var1; } }"},
{"", "for (var1 of [1, 2]) { function foo() { var1 = 0; } }"},
{"", "for (var var1 of [1, 2]) { function foo() { var1 = 0; } }"},
{"", "for (let var1 of [1, 2]) { function foo() { var1 = 0; } }"},
{"", "for (const var1 of [1, 2]) { function foo() { var1 = 0; } }"},
// For in loops
{"", "for (var1 in {a: 6}) { }"},
{"", "for (var var1 in {a: 6}) { }"},
{"", "for (let var1 in {a: 6}) { }"},
{"", "for (const var1 in {a: 6}) { }"},
{"", "for (var1 in {a: 6}) { var1; }"},
{"", "for (var var1 in {a: 6}) { var1; }"},
{"", "for (let var1 in {a: 6}) { var1; }"},
{"", "for (const var1 in {a: 6}) { var1; }"},
{"", "for (var1 in {a: 6}) { var1 = 0; }"},
{"", "for (var var1 in {a: 6}) { var1 = 0; }"},
{"", "for (let var1 in {a: 6}) { var1 = 0; }"},
{"", "for (const var1 in {a: 6}) { var1 = 0; }"},
{"", "for (var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (var var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (let var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (const var1 in {a: 6}) { function foo() { var1; } }"},
{"", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (var var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (let var1 in {a: 6}) { function foo() { var1 = 0; } }"},
{"", "for (const var1 in {a: 6}) { function foo() { var1 = 0; } }"},
// Loops without declarations
{"", "var var1 = 0; for ( ; var1 < 2; ++var1) { }"},
{"",
"var var1 = 0; for ( ; var1 < 2; ++var1) { function foo() { var1; } }"},
{"", "var var1 = 0; for ( ; var1 > 2; ) { }"},
{"", "var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1; } }"},
{"",
"var var1 = 0; for ( ; var1 > 2; ) { function foo() { var1 = 6; } }"},
{"", "var var1 = 0; for(var1; var1 < 2; ++var1) { }"},
{"",
"var var1 = 0; for (var1; var1 < 2; ++var1) { function foo() { var1; } "
"}"},
{"", "var var1 = 0; for (var1; var1 > 2; ) { }"},
{"", "var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1; } }"},
{"",
"var var1 = 0; for (var1; var1 > 2; ) { function foo() { var1 = 6; } }"},
// Sloppy block functions.
{"", "if (true) { function f1() {} }"},
{"", "if (true) { function f1() {} function f1() {} }"},
{"", "if (true) { if (true) { function f1() {} } }"},
{"", "if (true) { if (true) { function f1() {} function f1() {} } }"},
{"", "if (true) { function f1() {} f1 = 3; }"},
{"", "if (true) { function f1() {} function foo() { f1; } }"},
{"", "if (true) { function f1() {} } function foo() { f1; }"},
{"",
"if (true) { function f1() {} function f1() {} function foo() { f1; } "
"}"},
{"",
"if (true) { function f1() {} function f1() {} } function foo() { f1; "
"}"},
{"",
"if (true) { if (true) { function f1() {} } function foo() { f1; } }"},
{"",
"if (true) { if (true) { function f1() {} function f1() {} } function "
"foo() { f1; } }"},
{"", "if (true) { function f1() {} f1 = 3; function foo() { f1; } }"},
{"", "if (true) { function f1() {} f1 = 3; } function foo() { f1; }"},
{"", "function inner2() { if (true) { function f1() {} } }"},
{"", "function inner2() { if (true) { function f1() {} f1 = 3; } }"},
{"", "var f1 = 1; if (true) { function f1() {} }"},
{"", "var f1 = 1; if (true) { function f1() {} } function foo() { f1; }"},
};
for (unsigned i = 0; i < arraysize(inners); ++i) {
// First compile with the lazy inner function and extract the scope data.
const char* inner_function = lazy_inner;
int inner_function_len = Utf8LengthHelper(inner_function) - 4;
int params_len = Utf8LengthHelper(inners[i].params);
int source_len = Utf8LengthHelper(inners[i].source);
int len =
prefix_len + inner_function_len + params_len + source_len + suffix_len;
i::ScopedVector<char> lazy_program(len + 1);
i::SNPrintF(lazy_program, "%s", prefix);
i::SNPrintF(lazy_program + prefix_len, inner_function, inners[i].params,
inners[i].source);
i::SNPrintF(lazy_program + prefix_len + inner_function_len + params_len +
source_len,
"%s", suffix);
i::Handle<i::String> source =
factory->InternalizeUtf8String(lazy_program.start());
source->PrintOn(stdout);
printf("\n");
i::Handle<i::Script> script = factory->NewScript(source);
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo lazy_info(&zone, script);
// No need to run scope analysis; preparser scope data is produced when
// parsing.
CHECK(i::parsing::ParseProgram(&lazy_info));
// Then parse eagerly and check against the scope data.
inner_function = eager_inner;
inner_function_len = Utf8LengthHelper(inner_function) - 4;
len =
prefix_len + inner_function_len + params_len + source_len + suffix_len;
i::ScopedVector<char> eager_program(len + 1);
i::SNPrintF(eager_program, "%s", prefix);
i::SNPrintF(eager_program + prefix_len, inner_function, inners[i].params,
inners[i].source);
i::SNPrintF(eager_program + prefix_len + inner_function_len + params_len +
source_len,
"%s", suffix);
source = factory->InternalizeUtf8String(eager_program.start());
source->PrintOn(stdout);
printf("\n");
script = factory->NewScript(source);
i::ParseInfo eager_info(&zone, script);
eager_info.set_allow_lazy_parsing(false);
CHECK(i::parsing::ParseProgram(&eager_info));
CHECK(i::Compiler::Analyze(&eager_info));
i::Scope* scope =
eager_info.literal()->scope()->inner_scope()->inner_scope();
DCHECK_NOT_NULL(scope);
DCHECK_NULL(scope->sibling());
DCHECK(scope->is_function_scope());
size_t index = 0;
i::ScopeTestHelper::CompareScopeToData(
scope, lazy_info.preparsed_scope_data(), index);
}
}
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_CCTEST_UNICODE_HELPERS_H_
#define V8_CCTEST_UNICODE_HELPERS_H_
#include "src/unicode.h"
static int Ucs2CharLength(unibrow::uchar c) {
if (c == unibrow::Utf8::kIncomplete || c == unibrow::Utf8::kBufferEmpty) {
return 0;
} else if (c < 0xffff) {
return 1;
} else {
return 2;
}
}
static int Utf8LengthHelper(const char* s) {
unibrow::Utf8::Utf8IncrementalBuffer buffer(unibrow::Utf8::kBufferEmpty);
int length = 0;
for (; *s != '\0'; s++) {
unibrow::uchar tmp = unibrow::Utf8::ValueOfIncremental(*s, &buffer);
length += Ucs2CharLength(tmp);
}
unibrow::uchar tmp = unibrow::Utf8::ValueOfIncrementalFinish(&buffer);
length += Ucs2CharLength(tmp);
return length;
}
#endif // V8_CCTEST_UNICODE_HELPERS_H_
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