Split parsing of functions and top-level code into two separate methods

Also move them to a separate interface header to avoid having to include
parser.h so much

BUG=v8:5589
R=verwaest@chromium.org,marja@chromium.org

Review-Url: https://codereview.chromium.org/2534393002
Cr-Commit-Position: refs/heads/master@{#41386}
This commit is contained in:
jochen 2016-11-30 05:21:11 -08:00 committed by Commit bot
parent 86af70afb0
commit a1473f5306
15 changed files with 155 additions and 91 deletions

View File

@ -1538,6 +1538,8 @@ v8_source_set("v8_base") {
"src/parsing/parser-base.h",
"src/parsing/parser.cc",
"src/parsing/parser.h",
"src/parsing/parsing.cc",
"src/parsing/parsing.h",
"src/parsing/pattern-rewriter.cc",
"src/parsing/preparse-data-format.h",
"src/parsing/preparse-data.cc",

View File

@ -28,7 +28,7 @@
#include "src/isolate-inl.h"
#include "src/log-inl.h"
#include "src/messages.h"
#include "src/parsing/parser.h"
#include "src/parsing/parsing.h"
#include "src/parsing/rewriter.h"
#include "src/parsing/scanner-character-streams.h"
#include "src/runtime-profiler.h"
@ -465,7 +465,7 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) {
PostponeInterruptsScope postpone(info->isolate());
// Parse and update CompilationInfo with the results.
if (!Parser::ParseStatic(info->parse_info())) return MaybeHandle<Code>();
if (!parsing::ParseAny(info->parse_info())) return MaybeHandle<Code>();
DCHECK_EQ(info->shared_info()->language_mode(),
info->literal()->language_mode());
@ -835,7 +835,7 @@ MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) {
}
// Parse and update CompilationInfo with the results.
if (!Parser::ParseStatic(info.parse_info())) return MaybeHandle<Code>();
if (!parsing::ParseFunction(info.parse_info())) return MaybeHandle<Code>();
Handle<SharedFunctionInfo> shared = info.shared_info();
DCHECK_EQ(shared->language_mode(), info.literal()->language_mode());
@ -965,7 +965,8 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
Handle<SharedFunctionInfo> result;
{ VMState<COMPILER> state(info->isolate());
if (parse_info->literal() == nullptr && !Parser::ParseStatic(parse_info)) {
if (parse_info->literal() == nullptr &&
!parsing::ParseProgram(parse_info)) {
return Handle<SharedFunctionInfo>::null();
}
@ -1030,7 +1031,7 @@ bool Compiler::Analyze(ParseInfo* info) {
}
bool Compiler::ParseAndAnalyze(ParseInfo* info) {
if (!Parser::ParseStatic(info)) return false;
if (!parsing::ParseAny(info)) return false;
if (!Compiler::Analyze(info)) return false;
DCHECK_NOT_NULL(info->literal());
DCHECK_NOT_NULL(info->scope());

View File

@ -6,13 +6,14 @@
#include <memory>
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/debug/debug.h"
#include "src/frames-inl.h"
#include "src/globals.h"
#include "src/isolate-inl.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
#include "src/parsing/parsing.h"
#include "src/parsing/rewriter.h"
namespace v8 {
@ -109,7 +110,7 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
// Inner function.
info.reset(new ParseInfo(&zone, shared_info));
}
if (Parser::ParseStatic(info.get()) && Rewriter::Rewrite(info.get())) {
if (parsing::ParseAny(info.get()) && Rewriter::Rewrite(info.get())) {
DeclarationScope* scope = info->literal()->scope();
if (!ignore_nested_scopes || collect_non_locals) {
CollectNonLocals(info.get(), scope);

View File

@ -3829,41 +3829,6 @@ void Parser::Internalize(Isolate* isolate, Handle<Script> script, bool error) {
}
}
// ----------------------------------------------------------------------------
// The Parser interface.
bool Parser::ParseStatic(ParseInfo* info) {
Parser parser(info);
if (parser.Parse(info)) {
info->set_language_mode(info->literal()->language_mode());
return true;
}
return false;
}
bool Parser::Parse(ParseInfo* info) {
DCHECK(info->literal() == NULL);
FunctionLiteral* result = NULL;
// Ok to use Isolate here; this function is only called in the main thread.
DCHECK(parsing_on_main_thread_);
Isolate* isolate = info->isolate();
if (info->is_toplevel()) {
SetCachedData(info);
result = ParseProgram(isolate, info);
} else {
result = ParseFunction(isolate, info);
}
info->set_literal(result);
Internalize(isolate, info->script(), result == NULL);
return (result != NULL);
}
void Parser::ParseOnBackground(ParseInfo* info) {
parsing_on_main_thread_ = false;

View File

@ -10,6 +10,7 @@
#include "src/base/compiler-specific.h"
#include "src/globals.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparse-data-format.h"
#include "src/parsing/preparse-data.h"
#include "src/parsing/preparser.h"
@ -207,11 +208,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
static bool const IsPreParser() { return false; }
// Parses the source code represented by the compilation info and sets its
// function literal. Returns false (and deallocates any allocated AST
// nodes) if parsing failed.
static bool ParseStatic(ParseInfo* info);
bool Parse(ParseInfo* info);
void ParseOnBackground(ParseInfo* info);
// Deserialize the scope chain prior to parsing in which the script is going
@ -233,6 +229,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
private:
friend class ParserBase<Parser>;
friend class v8::internal::ExpressionClassifier<ParserTypes<Parser>>;
friend bool v8::internal::parsing::ParseProgram(ParseInfo*);
friend bool v8::internal::parsing::ParseFunction(ParseInfo*);
bool AllowsLazyParsingWithoutUnresolvedVariables() const {
return scope()->AllowsLazyParsingWithoutUnresolvedVariables(

61
src/parsing/parsing.cc Normal file
View File

@ -0,0 +1,61 @@
// Copyright 2016 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/parsing/parsing.h"
#include <memory>
#include "src/ast/ast.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
namespace v8 {
namespace internal {
namespace parsing {
bool ParseProgram(ParseInfo* info) {
DCHECK(info->is_toplevel());
DCHECK_NULL(info->literal());
Parser parser(info);
FunctionLiteral* result = nullptr;
// Ok to use Isolate here; this function is only called in the main thread.
DCHECK(parser.parsing_on_main_thread_);
Isolate* isolate = info->isolate();
parser.SetCachedData(info);
result = parser.ParseProgram(isolate, info);
info->set_literal(result);
parser.Internalize(isolate, info->script(), result == nullptr);
if (result != nullptr) {
info->set_language_mode(info->literal()->language_mode());
}
return (result != nullptr);
}
bool ParseFunction(ParseInfo* info) {
DCHECK(!info->is_toplevel());
DCHECK_NULL(info->literal());
Parser parser(info);
FunctionLiteral* result = nullptr;
// Ok to use Isolate here; this function is only called in the main thread.
DCHECK(parser.parsing_on_main_thread_);
Isolate* isolate = info->isolate();
result = parser.ParseFunction(isolate, info);
info->set_literal(result);
parser.Internalize(isolate, info->script(), result == nullptr);
return (result != nullptr);
}
bool ParseAny(ParseInfo* info) {
return info->is_toplevel() ? ParseProgram(info) : ParseFunction(info);
}
} // namespace parsing
} // namespace internal
} // namespace v8

34
src/parsing/parsing.h Normal file
View File

@ -0,0 +1,34 @@
// Copyright 2016 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_PARSING_PARSING_H_
#define V8_PARSING_PARSING_H_
#include "src/globals.h"
namespace v8 {
namespace internal {
class ParseInfo;
namespace parsing {
// Parses the top-level source code represented by the parse info and sets its
// function literal. Returns false (and deallocates any allocated AST
// nodes) if parsing failed.
V8_EXPORT_PRIVATE bool ParseProgram(ParseInfo* info);
// Like ParseProgram but for an individual function.
V8_EXPORT_PRIVATE bool ParseFunction(ParseInfo* info);
// If you don't know whether info->is_toplevel() is true or not, use this method
// to dispatch to either of the above functions. Prefer to use the above methods
// whenever possible.
V8_EXPORT_PRIVATE bool ParseAny(ParseInfo* info);
} // namespace parsing
} // namespace internal
} // namespace v8
#endif // V8_PARSING_PARSING_H_

View File

@ -7,6 +7,7 @@
#include "src/ast/scopes.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/preparse-data.h"
namespace v8 {
namespace internal {

View File

@ -15,7 +15,7 @@
#include "src/isolate-inl.h"
#include "src/messages.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
#include "src/parsing/parsing.h"
#include "src/wasm/wasm-module.h"
namespace v8 {
@ -335,11 +335,13 @@ Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object) {
MessageLocation location;
if (ComputeLocation(isolate, &location)) {
Zone zone(isolate->allocator(), ZONE_NAME);
std::unique_ptr<ParseInfo> info(
location.function()->shared()->is_function()
? new ParseInfo(&zone, handle(location.function()->shared()))
: new ParseInfo(&zone, location.script()));
if (Parser::ParseStatic(info.get())) {
std::unique_ptr<ParseInfo> info;
if (location.function()->shared()->is_function()) {
info.reset(new ParseInfo(&zone, handle(location.function()->shared())));
} else {
info.reset(new ParseInfo(&zone, location.script()));
}
if (parsing::ParseAny(info.get())) {
CallPrinter printer(isolate,
location.function()->shared()->IsUserJavaScript());
Handle<String> str = printer.Print(info->literal(), location.start_pos());

View File

@ -1074,6 +1074,8 @@
'parsing/parser-base.h',
'parsing/parser.cc',
'parsing/parser.h',
'parsing/parsing.cc',
'parsing/parsing.h',
'parsing/pattern-rewriter.cc',
'parsing/preparse-data-format.h',
'parsing/preparse-data.cc',

View File

@ -14,7 +14,7 @@
#include "src/handles.h"
#include "src/objects-inl.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
#include "src/parsing/parsing.h"
#include "test/cctest/cctest.h"
namespace v8 {
@ -189,7 +189,7 @@ Handle<JSFunction> FunctionTester::CompileGraph(Graph* graph) {
ParseInfo parse_info(&zone, handle(function->shared()));
CompilationInfo info(&parse_info, function);
CHECK(Parser::ParseStatic(info.parse_info()));
CHECK(parsing::ParseFunction(info.parse_info()));
info.SetOptimizing();
Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph);

View File

@ -6,7 +6,7 @@
#include "src/compilation-info.h"
#include "src/compiler/ast-loop-assignment-analyzer.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
#include "src/parsing/parsing.h"
#include "src/parsing/rewriter.h"
#include "test/cctest/cctest.h"
@ -35,7 +35,7 @@ struct TestHelper : public HandleAndZoneScope {
ParseInfo parse_info(main_zone(), handle(function->shared()));
CompilationInfo info(&parse_info, function);
CHECK(Parser::ParseStatic(&parse_info));
CHECK(parsing::ParseFunction(&parse_info));
CHECK(Rewriter::Rewrite(&parse_info));
DeclarationScope::Analyze(&parse_info, AnalyzeMode::kRegular);

View File

@ -43,6 +43,7 @@
#include "src/objects.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparser.h"
#include "src/parsing/rewriter.h"
#include "src/parsing/scanner-character-streams.h"
@ -819,8 +820,7 @@ TEST(ScopeUsesArgumentsSuperThis) {
i::ParseInfo info(&zone, script);
// The information we're checking is only produced when eager parsing.
info.set_allow_lazy_parsing(false);
i::Parser parser(&info);
CHECK(parser.Parse(&info));
CHECK(i::parsing::ParseProgram(&info));
CHECK(i::Rewriter::Rewrite(&info));
i::DeclarationScope::Analyze(&info, i::AnalyzeMode::kRegular);
CHECK(info.literal() != NULL);
@ -1173,9 +1173,8 @@ TEST(ScopePositions) {
i::Handle<i::Script> script = factory->NewScript(source);
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo info(&zone, script);
i::Parser parser(&info);
info.set_language_mode(source_data[i].language_mode);
parser.Parse(&info);
i::parsing::ParseProgram(&info);
CHECK_NOT_NULL(info.literal());
// Check scope types and positions.
@ -1221,8 +1220,7 @@ TEST(DiscardFunctionBody) {
i::Handle<i::Script> script = factory->NewScript(source_code);
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo info(&zone, script);
i::Parser parser(&info);
parser.Parse(&info);
i::parsing::ParseProgram(&info);
function = info.literal();
CHECK_NOT_NULL(function);
CHECK_NOT_NULL(function->body());
@ -1287,9 +1285,17 @@ enum ParserSyncTestResult {
kError
};
template <typename Traits>
void SetParserFlags(i::ParserBase<Traits>* parser,
i::EnumSet<ParserFlag> flags) {
void SetGlobalFlags(i::EnumSet<ParserFlag> flags) {
i::FLAG_allow_natives_syntax = flags.Contains(kAllowNatives);
i::FLAG_harmony_function_sent = flags.Contains(kAllowHarmonyFunctionSent);
i::FLAG_harmony_async_await = flags.Contains(kAllowHarmonyAsyncAwait);
i::FLAG_harmony_restrictive_generators =
flags.Contains(kAllowHarmonyRestrictiveGenerators);
i::FLAG_harmony_trailing_commas = flags.Contains(kAllowHarmonyTrailingCommas);
i::FLAG_harmony_class_fields = flags.Contains(kAllowHarmonyClassFields);
}
void SetParserFlags(i::PreParser* parser, i::EnumSet<ParserFlag> flags) {
parser->set_allow_natives(flags.Contains(kAllowNatives));
parser->set_allow_harmony_function_sent(
flags.Contains(kAllowHarmonyFunctionSent));
@ -1303,7 +1309,6 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
flags.Contains(kAllowHarmonyClassFields));
}
void TestParserSyncWithFlags(i::Handle<i::String> source,
i::EnumSet<ParserFlag> flags,
ParserSyncTestResult result,
@ -1342,10 +1347,9 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo info(&zone, script);
info.set_allow_lazy_parsing(flags.Contains(kAllowLazy));
i::Parser parser(&info);
SetParserFlags(&parser, flags);
SetGlobalFlags(flags);
if (is_module) info.set_module();
parser.Parse(&info);
i::parsing::ParseProgram(&info);
function = info.literal();
if (function) {
parser_materialized_literals = function->materialized_literal_count();
@ -2477,7 +2481,7 @@ TEST(DontRegressPreParserDataSizes) {
i::ScriptData* sd = NULL;
info.set_cached_data(&sd);
info.set_compile_options(v8::ScriptCompiler::kProduceParserCache);
i::Parser::ParseStatic(&info);
i::parsing::ParseProgram(&info);
i::ParseData* pd = i::ParseData::FromCachedData(sd);
if (pd->FunctionCount() != test_cases[i].functions) {
@ -3363,6 +3367,7 @@ TEST(InnerAssignment) {
i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
i::Handle<i::SharedFunctionInfo> shared = i::handle(f->shared());
info = std::unique_ptr<i::ParseInfo>(new i::ParseInfo(&zone, shared));
CHECK(i::parsing::ParseFunction(info.get()));
} else {
i::Handle<i::String> source =
factory->InternalizeUtf8String(program.start());
@ -3371,9 +3376,8 @@ TEST(InnerAssignment) {
i::Handle<i::Script> script = factory->NewScript(source);
info = std::unique_ptr<i::ParseInfo>(new i::ParseInfo(&zone, script));
info->set_allow_lazy_parsing(false);
CHECK(i::parsing::ParseProgram(info.get()));
}
i::Parser parser(info.get());
CHECK(parser.Parse(info.get()));
CHECK(i::Compiler::Analyze(info.get()));
CHECK(info->literal() != NULL);
@ -5736,9 +5740,8 @@ TEST(BasicImportExportParsing) {
i::Handle<i::Script> script = factory->NewScript(source);
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo info(&zone, script);
i::Parser parser(&info);
info.set_module();
if (!parser.Parse(&info)) {
if (!i::parsing::ParseProgram(&info)) {
i::Handle<i::JSObject> exception_handle(
i::JSObject::cast(isolate->pending_exception()));
i::Handle<i::String> message_string = i::Handle<i::String>::cast(
@ -5762,8 +5765,7 @@ TEST(BasicImportExportParsing) {
i::Handle<i::Script> script = factory->NewScript(source);
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo info(&zone, script);
i::Parser parser(&info);
CHECK(!parser.Parse(&info));
CHECK(!i::parsing::ParseProgram(&info));
isolate->clear_pending_exception();
}
}
@ -5854,9 +5856,8 @@ TEST(ImportExportParsingErrors) {
i::Handle<i::Script> script = factory->NewScript(source);
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo info(&zone, script);
i::Parser parser(&info);
info.set_module();
CHECK(!parser.Parse(&info));
CHECK(!i::parsing::ParseProgram(&info));
isolate->clear_pending_exception();
}
}
@ -5892,9 +5893,8 @@ TEST(ModuleTopLevelFunctionDecl) {
i::Handle<i::Script> script = factory->NewScript(source);
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo info(&zone, script);
i::Parser parser(&info);
info.set_module();
CHECK(!parser.Parse(&info));
CHECK(!i::parsing::ParseProgram(&info));
isolate->clear_pending_exception();
}
}
@ -6091,9 +6091,8 @@ TEST(ModuleParsingInternals) {
i::Handle<i::Script> script = factory->NewScript(source);
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo info(&zone, script);
i::Parser parser(&info);
info.set_module();
CHECK(parser.Parse(&info));
CHECK(i::parsing::ParseProgram(&info));
CHECK(i::Compiler::Analyze(&info));
i::FunctionLiteral* func = info.literal();
i::ModuleScope* module_scope = func->scope()->AsModuleScope();
@ -6352,8 +6351,7 @@ void TestLanguageMode(const char* source,
factory->NewScript(factory->NewStringFromAsciiChecked(source));
i::Zone zone(CcTest::i_isolate()->allocator(), ZONE_NAME);
i::ParseInfo info(&zone, script);
i::Parser parser(&info);
parser.Parse(&info);
i::parsing::ParseProgram(&info);
CHECK(info.literal() != NULL);
CHECK_EQ(expected_language_mode, info.literal()->language_mode());
}

View File

@ -9,7 +9,7 @@
#include "include/v8.h"
#include "src/objects.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparser.h"
#include "test/fuzzer/fuzzer-support.h"
@ -36,8 +36,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
factory->NewScript(source.ToHandleChecked());
v8::internal::Zone zone(i_isolate->allocator(), ZONE_NAME);
v8::internal::ParseInfo info(&zone, script);
v8::internal::Parser parser(&info);
parser.Parse(&info);
v8::internal::parsing::ParseProgram(&info);
isolate->RequestGarbageCollectionForTesting(
v8::Isolate::kFullGarbageCollection);
return 0;

View File

@ -37,7 +37,7 @@
#include "src/api.h"
#include "src/compiler.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparse-data-format.h"
#include "src/parsing/preparse-data.h"
#include "src/parsing/preparser.h"
@ -99,7 +99,7 @@ std::pair<v8::base::TimeDelta, v8::base::TimeDelta> RunBaselineParser(
info.set_compile_options(v8::ScriptCompiler::kProduceParserCache);
v8::base::ElapsedTimer timer;
timer.Start();
bool success = Parser::ParseStatic(&info);
bool success = parsing::ParseProgram(&info);
parse_time1 = timer.Elapsed();
if (!success) {
fprintf(stderr, "Parsing failed\n");
@ -114,7 +114,7 @@ std::pair<v8::base::TimeDelta, v8::base::TimeDelta> RunBaselineParser(
info.set_compile_options(v8::ScriptCompiler::kConsumeParserCache);
v8::base::ElapsedTimer timer;
timer.Start();
bool success = Parser::ParseStatic(&info);
bool success = parsing::ParseProgram(&info);
parse_time2 = timer.Elapsed();
if (!success) {
fprintf(stderr, "Parsing failed\n");