[parser] Inital parallel parse tasks implementation.
While parsing top-level code eager functions are skipped just like lazy ones, but also a parse task is created for each. The parse tasks are run by the compiler dispatcher and can be executed either on background thread or in idle time. After parsing of top-level code finishes it waits for all unfinished parser tasks - possibly picking up and executing them on current thread. Afterwards parse task results are stitched together with top-level AST, in case of failures eager functions are treated just like lazy - parsing/compilation is retriggered for them in the runtime and proper errors are generated (performance is not optimized for error case at all). BUG=v8:6093 Change-Id: I718dd2acc8a70ae1b09c2dea2616716605d7b05d Reviewed-on: https://chromium-review.googlesource.com/483439 Commit-Queue: Wiktor Garbacz <wiktorg@google.com> Reviewed-by: Marja Hölttä <marja@chromium.org> Reviewed-by: Jochen Eisinger <jochen@chromium.org> Reviewed-by: Daniel Vogelheim <vogelheim@chromium.org> Cr-Commit-Position: refs/heads/master@{#44849}
This commit is contained in:
parent
a17f244607
commit
56a6fda316
@ -350,6 +350,23 @@ bool FunctionLiteral::NeedsHomeObject(Expression* expr) {
|
||||
return expr->AsFunctionLiteral()->scope()->NeedsHomeObject();
|
||||
}
|
||||
|
||||
void FunctionLiteral::ReplaceBodyAndScope(FunctionLiteral* other) {
|
||||
DCHECK_NULL(body_);
|
||||
DCHECK_NOT_NULL(scope_);
|
||||
DCHECK_NOT_NULL(other->scope());
|
||||
|
||||
Scope* outer_scope = scope_->outer_scope();
|
||||
|
||||
body_ = other->body();
|
||||
scope_ = other->scope();
|
||||
scope_->ReplaceOuterScope(outer_scope);
|
||||
#ifdef DEBUG
|
||||
scope_->set_replaced_from_parse_task(true);
|
||||
#endif
|
||||
|
||||
function_length_ = other->function_length_;
|
||||
}
|
||||
|
||||
ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value,
|
||||
Kind kind, bool is_computed_name)
|
||||
: LiteralProperty(key, value, is_computed_name),
|
||||
|
@ -2742,6 +2742,8 @@ class FunctionLiteral final : public Expression {
|
||||
function_literal_id_ = function_literal_id;
|
||||
}
|
||||
|
||||
void ReplaceBodyAndScope(FunctionLiteral* other);
|
||||
|
||||
private:
|
||||
friend class AstNodeFactory;
|
||||
|
||||
|
@ -1799,7 +1799,9 @@ void Scope::CheckZones() {
|
||||
DCHECK_NULL(scope->inner_scope_);
|
||||
continue;
|
||||
}
|
||||
CHECK_EQ(scope->zone(), zone());
|
||||
if (!scope->replaced_from_parse_task()) {
|
||||
CHECK_EQ(scope->zone(), zone());
|
||||
}
|
||||
scope->CheckZones();
|
||||
}
|
||||
}
|
||||
|
@ -456,6 +456,11 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
|
||||
|
||||
// Check that all Scopes in the scope tree use the same Zone.
|
||||
void CheckZones();
|
||||
|
||||
bool replaced_from_parse_task() const { return replaced_from_parse_task_; }
|
||||
void set_replaced_from_parse_task(bool replaced_from_parse_task) {
|
||||
replaced_from_parse_task_ = replaced_from_parse_task;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Retrieve `IsSimpleParameterList` of current or outer function.
|
||||
@ -535,6 +540,10 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
|
||||
// True if this scope may contain objects from a temp zone that needs to be
|
||||
// fixed up.
|
||||
bool needs_migration_;
|
||||
|
||||
// True if scope comes from other zone - as a result of being created in a
|
||||
// parse tasks.
|
||||
bool replaced_from_parse_task_ = false;
|
||||
#endif
|
||||
|
||||
// Source positions.
|
||||
|
@ -43,7 +43,7 @@ enum class CompileJobStatus {
|
||||
kDone,
|
||||
};
|
||||
|
||||
class CompileJobFinishCallback {
|
||||
class V8_EXPORT_PRIVATE CompileJobFinishCallback {
|
||||
public:
|
||||
virtual ~CompileJobFinishCallback() {}
|
||||
virtual void ParseFinished(std::unique_ptr<ParseInfo> parse_info) = 0;
|
||||
|
@ -248,8 +248,6 @@ CompilerDispatcher::~CompilerDispatcher() {
|
||||
bool CompilerDispatcher::CanEnqueue() {
|
||||
if (!IsEnabled()) return false;
|
||||
|
||||
DCHECK(FLAG_ignition);
|
||||
|
||||
if (memory_pressure_level_.Value() != MemoryPressureLevel::kNone) {
|
||||
return false;
|
||||
}
|
||||
@ -263,6 +261,8 @@ bool CompilerDispatcher::CanEnqueue() {
|
||||
}
|
||||
|
||||
bool CompilerDispatcher::CanEnqueue(Handle<SharedFunctionInfo> function) {
|
||||
DCHECK_IMPLIES(IsEnabled(), FLAG_ignition);
|
||||
|
||||
if (!CanEnqueue()) return false;
|
||||
|
||||
// We only handle functions (no eval / top-level code / wasm) that are
|
||||
@ -598,7 +598,7 @@ CompilerDispatcher::JobMap::const_iterator CompilerDispatcher::GetJobFor(
|
||||
|
||||
void CompilerDispatcher::ScheduleIdleTaskFromAnyThread() {
|
||||
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
|
||||
DCHECK(platform_->IdleTasksEnabled(v8_isolate));
|
||||
if (!platform_->IdleTasksEnabled(v8_isolate)) return;
|
||||
{
|
||||
base::LockGuard<base::Mutex> lock(&mutex_);
|
||||
if (idle_task_scheduled_) return;
|
||||
|
@ -40,7 +40,10 @@ ParseInfo::ParseInfo(AccountingAllocator* zone_allocator)
|
||||
function_name_(nullptr),
|
||||
runtime_call_stats_(nullptr),
|
||||
literal_(nullptr),
|
||||
deferred_handles_(nullptr) {}
|
||||
deferred_handles_(nullptr),
|
||||
child_infos_(FLAG_use_parse_tasks
|
||||
? new std::map<int, std::unique_ptr<ParseInfo>>()
|
||||
: nullptr) {}
|
||||
|
||||
ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared)
|
||||
: ParseInfo(shared->GetIsolate()->allocator()) {
|
||||
@ -164,6 +167,13 @@ void ParseInfo::InitFromIsolate(Isolate* isolate) {
|
||||
set_ast_string_constants(isolate->ast_string_constants());
|
||||
}
|
||||
|
||||
void ParseInfo::ParseFinished(std::unique_ptr<ParseInfo> info) {
|
||||
if (info->literal()) {
|
||||
int start_position = info->literal()->start_position();
|
||||
child_infos_->insert(std::make_pair(start_position, std::move(info)));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool ParseInfo::script_is_native() const {
|
||||
return script_->type() == Script::TYPE_NATIVE;
|
||||
|
@ -5,9 +5,11 @@
|
||||
#ifndef V8_PARSING_PARSE_INFO_H_
|
||||
#define V8_PARSING_PARSE_INFO_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "src/compiler-dispatcher/compiler-dispatcher-job.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/parsing/preparsed-scope-data.h"
|
||||
@ -33,7 +35,7 @@ class Utf16CharacterStream;
|
||||
class Zone;
|
||||
|
||||
// A container for the inputs, configuration options, and outputs of parsing.
|
||||
class V8_EXPORT_PRIVATE ParseInfo {
|
||||
class V8_EXPORT_PRIVATE ParseInfo : public CompileJobFinishCallback {
|
||||
public:
|
||||
explicit ParseInfo(AccountingAllocator* zone_allocator);
|
||||
ParseInfo(Handle<Script> script);
|
||||
@ -243,6 +245,12 @@ class V8_EXPORT_PRIVATE ParseInfo {
|
||||
}
|
||||
}
|
||||
|
||||
const std::map<int, std::unique_ptr<ParseInfo>>* child_infos() const {
|
||||
return child_infos_.get();
|
||||
}
|
||||
|
||||
void ParseFinished(std::unique_ptr<ParseInfo> info) override;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool script_is_native() const;
|
||||
#endif // DEBUG
|
||||
@ -302,6 +310,8 @@ class V8_EXPORT_PRIVATE ParseInfo {
|
||||
//----------- Output of parsing and scope analysis ------------------------
|
||||
FunctionLiteral* literal_;
|
||||
std::shared_ptr<DeferredHandles> deferred_handles_;
|
||||
// The key of the map is the FunctionLiteral's start_position
|
||||
std::unique_ptr<std::map<int, std::unique_ptr<ParseInfo>>> child_infos_;
|
||||
|
||||
void SetFlag(Flag f) { flags_ |= f; }
|
||||
void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; }
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "src/parsing/parser.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "src/api.h"
|
||||
@ -14,6 +15,7 @@
|
||||
#include "src/bailout-reason.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "src/char-predicates-inl.h"
|
||||
#include "src/compiler-dispatcher/compiler-dispatcher.h"
|
||||
#include "src/messages.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/parsing/duplicate-finder.h"
|
||||
@ -621,24 +623,14 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
|
||||
source = String::Flatten(source);
|
||||
FunctionLiteral* result;
|
||||
|
||||
if (FLAG_use_parse_tasks) {
|
||||
source_ = source;
|
||||
compiler_dispatcher_ = isolate->compiler_dispatcher();
|
||||
main_parse_info_ = info;
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For(source));
|
||||
if (FLAG_use_parse_tasks) {
|
||||
// FIXME(wiktorg) make it useful for something
|
||||
// TODO(wiktorg) make preparser work also with modules
|
||||
if (!info->is_module()) {
|
||||
scanner_.Initialize(stream.get());
|
||||
// NOTE: Some features will be double counted - once here and one more
|
||||
// time while being fully parsed by a parse task.
|
||||
PreParser::PreParseResult result =
|
||||
reusable_preparser()->PreParseProgram(false, use_counts_);
|
||||
if (result == PreParser::kPreParseStackOverflow) {
|
||||
set_stack_overflow();
|
||||
return nullptr;
|
||||
}
|
||||
stream->Seek(0);
|
||||
}
|
||||
}
|
||||
scanner_.Initialize(stream.get());
|
||||
result = DoParseProgram(info);
|
||||
}
|
||||
@ -647,6 +639,14 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
|
||||
}
|
||||
HandleSourceURLComments(isolate, info->script());
|
||||
|
||||
if (FLAG_use_parse_tasks) {
|
||||
compiler_dispatcher_->FinishAllNow();
|
||||
StitchAst(info, isolate);
|
||||
source_ = Handle<String>();
|
||||
compiler_dispatcher_ = nullptr;
|
||||
main_parse_info_ = nullptr;
|
||||
}
|
||||
|
||||
if (FLAG_trace_parse && result != nullptr) {
|
||||
double ms = timer.Elapsed().InMillisecondsF();
|
||||
if (info->is_eval()) {
|
||||
@ -2621,12 +2621,16 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
DCHECK_IMPLIES(parse_lazily(), allow_lazy_);
|
||||
DCHECK_IMPLIES(parse_lazily(), extension_ == nullptr);
|
||||
|
||||
const bool source_is_external =
|
||||
!source_.is_null() && (source_->IsExternalTwoByteString() ||
|
||||
source_->IsExternalOneByteString());
|
||||
const bool is_lazy =
|
||||
eager_compile_hint == FunctionLiteral::kShouldLazyCompile;
|
||||
const bool is_top_level =
|
||||
impl()->AllowsLazyParsingWithoutUnresolvedVariables();
|
||||
const bool is_lazy_top_level_function = is_lazy && is_top_level;
|
||||
const bool is_lazy_inner_function = is_lazy && !is_top_level;
|
||||
const bool is_eager_top_level_function = !is_lazy && is_top_level;
|
||||
const bool is_declaration = function_type == FunctionLiteral::kDeclaration;
|
||||
|
||||
RuntimeCallTimerScope runtime_timer(
|
||||
@ -2656,9 +2660,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
parse_lazily() && FLAG_lazy_inner_functions && is_lazy_inner_function &&
|
||||
(is_declaration || FLAG_aggressive_lazy_inner_functions);
|
||||
|
||||
bool should_use_parse_task =
|
||||
FLAG_use_parse_tasks && parse_lazily() && compiler_dispatcher_ &&
|
||||
is_eager_top_level_function && source_is_external;
|
||||
|
||||
// This may be modified later to reflect preparsing decision taken
|
||||
bool should_preparse =
|
||||
(parse_lazily() && is_lazy_top_level_function) || should_preparse_inner;
|
||||
bool should_preparse = (parse_lazily() && (is_lazy_top_level_function ||
|
||||
should_use_parse_task)) ||
|
||||
should_preparse_inner;
|
||||
|
||||
ZoneList<Statement*>* body = nullptr;
|
||||
int expected_property_count = -1;
|
||||
@ -2704,15 +2713,16 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
// try to lazy parse in the first place, we'll have to parse eagerly.
|
||||
if (should_preparse) {
|
||||
DCHECK(parse_lazily());
|
||||
DCHECK(is_lazy_top_level_function || is_lazy_inner_function);
|
||||
DCHECK(is_lazy_top_level_function || is_lazy_inner_function ||
|
||||
should_use_parse_task);
|
||||
Scanner::BookmarkScope bookmark(scanner());
|
||||
bookmark.Set();
|
||||
LazyParsingResult result =
|
||||
SkipFunction(kind, scope, &num_parameters, is_lazy_inner_function,
|
||||
is_lazy_top_level_function, CHECK_OK);
|
||||
|
||||
// TODO(wiktorg) revisit preparsing aborted in case of parse tasks
|
||||
if (result == kLazyParsingAborted) {
|
||||
DCHECK(is_lazy_top_level_function);
|
||||
bookmark.Apply();
|
||||
// This is probably an initialization function. Inform the compiler it
|
||||
// should also eager-compile this function, and that we expect it to be
|
||||
@ -2723,6 +2733,39 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
zone_scope.Reset();
|
||||
// Trigger eager (re-)parsing, just below this block.
|
||||
should_preparse = false;
|
||||
should_use_parse_task = false;
|
||||
}
|
||||
if (should_use_parse_task) {
|
||||
int start_pos = scope->start_position();
|
||||
if (function_name_location.IsValid()) {
|
||||
start_pos = function_name_location.beg_pos;
|
||||
}
|
||||
// Warning!
|
||||
// Only sets fields in compiler_hints that are currently used.
|
||||
int compiler_hints = SharedFunctionInfo::FunctionKindBits::encode(kind);
|
||||
if (function_type == FunctionLiteral::kDeclaration) {
|
||||
compiler_hints |= 1 << SharedFunctionInfo::kIsDeclaration;
|
||||
}
|
||||
// TODO(wiktorg) enqueue parse tasks before preparsing
|
||||
should_use_parse_task = compiler_dispatcher_->Enqueue(
|
||||
source_, start_pos, scope->end_position(), language_mode,
|
||||
function_literal_id, allow_natives(), parsing_module_,
|
||||
function_type == FunctionLiteral::kNamedExpression, compiler_hints,
|
||||
main_parse_info_, nullptr);
|
||||
if (FLAG_trace_parse_tasks) {
|
||||
PrintF("Spining off task for function at %d: %s\n",
|
||||
scope->start_position(),
|
||||
should_use_parse_task ? "SUCCESS" : "FAILED");
|
||||
}
|
||||
if (should_use_parse_task) {
|
||||
scope->ResetAfterPreparsing(ast_value_factory(), false);
|
||||
} else {
|
||||
// Fallback to eager parsing below if we failed to enqueue parse tasks
|
||||
bookmark.Apply();
|
||||
scope->ResetAfterPreparsing(ast_value_factory(), true);
|
||||
zone_scope.Reset();
|
||||
should_preparse = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2784,6 +2827,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
function_name, scope, body, expected_property_count, num_parameters,
|
||||
function_length, duplicate_parameters, function_type, eager_compile_hint,
|
||||
pos, true, function_literal_id);
|
||||
if (should_use_parse_task) {
|
||||
literals_to_stitch_.emplace_back(function_literal);
|
||||
}
|
||||
function_literal->set_function_token_position(function_token_pos);
|
||||
if (should_be_used_once_hint)
|
||||
function_literal->set_should_be_used_once_hint();
|
||||
@ -2800,6 +2846,8 @@ Parser::LazyParsingResult Parser::SkipFunction(FunctionKind kind,
|
||||
int* num_parameters,
|
||||
bool is_inner_function,
|
||||
bool may_abort, bool* ok) {
|
||||
FunctionState function_state(&function_state_, &scope_, function_scope);
|
||||
|
||||
DCHECK_NE(kNoSourcePosition, function_scope->start_position());
|
||||
DCHECK_EQ(kNoSourcePosition, parameters_end_pos_);
|
||||
if (produce_cached_parse_data()) CHECK(log_);
|
||||
@ -2833,32 +2881,6 @@ Parser::LazyParsingResult Parser::SkipFunction(FunctionKind kind,
|
||||
cached_parse_data_->Reject();
|
||||
}
|
||||
|
||||
if (FLAG_use_parse_tasks && !is_inner_function &&
|
||||
reusable_preparser()->preparse_data()) {
|
||||
// All top-level functions are already preparsed and parser tasks for eager
|
||||
// functions are already created. Use data gathered during the preparse step
|
||||
// to skip the function.
|
||||
PreParseData::FunctionData data =
|
||||
reusable_preparser()->preparse_data()->GetFunctionData(
|
||||
function_scope->start_position());
|
||||
if (data.is_valid()) {
|
||||
if (FLAG_trace_parse_tasks) {
|
||||
PrintF("Skipping top level func @ %d : %d using preparse data\n",
|
||||
function_scope->start_position(), data.end);
|
||||
}
|
||||
function_scope->set_end_position(data.end);
|
||||
scanner()->SeekForward(data.end - 1);
|
||||
Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete));
|
||||
*num_parameters = data.num_parameters;
|
||||
SetLanguageMode(function_scope, data.language_mode);
|
||||
if (data.uses_super_property) {
|
||||
function_scope->RecordSuperPropertyUsage();
|
||||
}
|
||||
SkipFunctionLiterals(data.num_inner_functions);
|
||||
return kLazyParsingComplete;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(marja): There are 3 ways to skip functions now. Unify them.
|
||||
if (preparsed_scope_data_->Consuming()) {
|
||||
DCHECK(FLAG_experimental_preparser_scope_analysis);
|
||||
@ -5198,6 +5220,35 @@ Statement* Parser::FinalizeForOfStatement(ForOfStatement* loop,
|
||||
return final_loop;
|
||||
}
|
||||
|
||||
void Parser::StitchAst(ParseInfo* top_level_parse_info, Isolate* isolate) {
|
||||
if (literals_to_stitch_.empty()) return;
|
||||
auto* child_infos = top_level_parse_info->child_infos();
|
||||
DCHECK_NOT_NULL(child_infos);
|
||||
DCHECK(std::is_sorted(literals_to_stitch_.begin(), literals_to_stitch_.end(),
|
||||
[](FunctionLiteral* a, FunctionLiteral* b) {
|
||||
return a->start_position() < b->start_position();
|
||||
}));
|
||||
auto it = literals_to_stitch_.begin();
|
||||
for (auto& child_info : *child_infos) {
|
||||
ParseInfo* result = child_info.second.get();
|
||||
// If the parse task failed the function will be treated as lazy function
|
||||
// and reparsed before it gets called
|
||||
if (!result) continue;
|
||||
if (!result->literal()) continue;
|
||||
while ((*it)->start_position() != result->literal()->start_position()) {
|
||||
if (++it == literals_to_stitch_.end()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
FunctionLiteral* literal = *it;
|
||||
// TODO(wiktorg) in the future internalize somewhere else (stitching may be
|
||||
// done on streamer thread)
|
||||
result->ast_value_factory()->Internalize(isolate);
|
||||
literal->ReplaceBodyAndScope(result->literal());
|
||||
literal->SetShouldEagerCompile();
|
||||
}
|
||||
}
|
||||
|
||||
#undef CHECK_OK
|
||||
#undef CHECK_OK_VOID
|
||||
#undef CHECK_FAILED
|
||||
|
@ -273,6 +273,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
||||
|
||||
void SetCachedData(ParseInfo* info);
|
||||
|
||||
void StitchAst(ParseInfo* top_level_parse_info, Isolate* isolate);
|
||||
|
||||
ScriptCompiler::CompileOptions compile_options() const {
|
||||
return compile_options_;
|
||||
}
|
||||
@ -1152,6 +1154,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
||||
PreParser* reusable_preparser_;
|
||||
Mode mode_;
|
||||
|
||||
std::vector<FunctionLiteral*> literals_to_stitch_;
|
||||
Handle<String> source_;
|
||||
CompilerDispatcher* compiler_dispatcher_ = nullptr;
|
||||
ParseInfo* main_parse_info_ = nullptr;
|
||||
|
||||
friend class ParserTarget;
|
||||
friend class ParserTargetScope;
|
||||
ParserTarget* target_stack_; // for break, continue statements
|
||||
|
@ -101,10 +101,8 @@ PreParserIdentifier PreParser::GetSymbol() const {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
PreParser::PreParseResult PreParser::PreParseProgram(bool is_module,
|
||||
int* use_counts) {
|
||||
PreParser::PreParseResult PreParser::PreParseProgram(bool is_module) {
|
||||
DCHECK_NULL(scope_);
|
||||
use_counts_ = use_counts;
|
||||
DeclarationScope* scope = NewScriptScope();
|
||||
#ifdef DEBUG
|
||||
scope->set_is_being_lazily_parsed(true);
|
||||
@ -123,7 +121,6 @@ PreParser::PreParseResult PreParser::PreParseProgram(bool is_module,
|
||||
PreParserStatementList body;
|
||||
ParseStatementList(body, Token::EOS, &ok);
|
||||
original_scope_ = nullptr;
|
||||
use_counts_ = nullptr;
|
||||
if (stack_overflow()) return kPreParseStackOverflow;
|
||||
if (!ok) {
|
||||
ReportUnexpectedToken(scanner()->current_token());
|
||||
@ -289,9 +286,6 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
runtime_call_stats_,
|
||||
counters[track_unresolved_variables_][parsing_on_main_thread_]);
|
||||
|
||||
bool is_top_level =
|
||||
scope()->AllowsLazyParsingWithoutUnresolvedVariables(original_scope_);
|
||||
|
||||
DeclarationScope* function_scope = NewFunctionScope(kind);
|
||||
function_scope->SetLanguageMode(language_mode);
|
||||
FunctionState function_state(&function_state_, &scope_, function_scope);
|
||||
@ -339,22 +333,6 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
|
||||
}
|
||||
|
||||
if (FLAG_use_parse_tasks && is_top_level && preparse_data_) {
|
||||
preparse_data_->AddFunctionData(
|
||||
start_position, PreParseData::FunctionData(
|
||||
end_position, formals.num_parameters(),
|
||||
GetLastFunctionLiteralId() - func_id, language_mode,
|
||||
function_scope->uses_super_property()));
|
||||
// TODO(wiktorg) spin-off a parse task
|
||||
if (FLAG_trace_parse_tasks) {
|
||||
PrintF("Saved function at %d to %d with:\n", start_position,
|
||||
end_position);
|
||||
PrintF("\t- %d params\n", formals.num_parameters());
|
||||
PrintF("\t- %d function length\n", formals.function_length);
|
||||
PrintF("\t- %d inner-funcs\n", GetLastFunctionLiteralId() - func_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_experimental_preparser_scope_analysis &&
|
||||
track_unresolved_variables_ && preparsed_scope_data_ != nullptr) {
|
||||
preparsed_scope_data_->AddSkippableFunction(
|
||||
|
@ -901,7 +901,6 @@ class PreParser : public ParserBase<PreParser> {
|
||||
ast_value_factory, runtime_call_stats,
|
||||
preparsed_scope_data, parsing_on_main_thread),
|
||||
use_counts_(nullptr),
|
||||
preparse_data_(FLAG_use_parse_tasks ? new PreParseData() : nullptr),
|
||||
track_unresolved_variables_(false),
|
||||
pending_error_handler_(pending_error_handler) {}
|
||||
|
||||
@ -913,8 +912,7 @@ class PreParser : public ParserBase<PreParser> {
|
||||
// success (even if parsing failed, the pre-parse data successfully
|
||||
// captured the syntax error), and false if a stack-overflow happened
|
||||
// during parsing.
|
||||
PreParseResult PreParseProgram(bool is_module = false,
|
||||
int* use_counts = nullptr);
|
||||
PreParseResult PreParseProgram(bool is_module = false);
|
||||
|
||||
// Parses a single function literal, from the opening parentheses before
|
||||
// parameters to the closing brace after the body.
|
||||
@ -930,8 +928,6 @@ class PreParser : public ParserBase<PreParser> {
|
||||
bool track_unresolved_variables,
|
||||
bool may_abort, int* use_counts);
|
||||
|
||||
const PreParseData* preparse_data() const { return preparse_data_.get(); }
|
||||
|
||||
private:
|
||||
// These types form an algebra over syntactic categories that is just
|
||||
// rich enough to let us recognize and propagate the constructs that
|
||||
@ -1669,7 +1665,6 @@ class PreParser : public ParserBase<PreParser> {
|
||||
// Preparser's private field members.
|
||||
|
||||
int* use_counts_;
|
||||
std::unique_ptr<PreParseData> preparse_data_;
|
||||
bool track_unresolved_variables_;
|
||||
PreParserLogger log_;
|
||||
PendingCompilationErrorHandler* pending_error_handler_;
|
||||
|
47
test/mjsunit/parse-tasks.js
Normal file
47
test/mjsunit/parse-tasks.js
Normal file
@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
|
||||
// Flags: --compiler-dispatcher --use-parse-tasks --use-external-strings
|
||||
|
||||
(function(a) {
|
||||
assertEquals(a, "IIFE");
|
||||
})("IIFE");
|
||||
|
||||
(function(a, ...rest) {
|
||||
assertEquals(a, 1);
|
||||
assertEquals(rest.length, 2);
|
||||
assertEquals(rest[0], 2);
|
||||
assertEquals(rest[1], 3);
|
||||
})(1,2,3);
|
||||
|
||||
var outer_var = 42;
|
||||
|
||||
function lazy_outer() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
var eager_outer = (function() { return 42; });
|
||||
|
||||
(function() {
|
||||
assertEquals(outer_var, 42);
|
||||
assertEquals(lazy_outer(), 42);
|
||||
assertEquals(eager_outer(), 42);
|
||||
})();
|
||||
|
||||
var gen = (function*() {
|
||||
yield 1;
|
||||
yield 2;
|
||||
})();
|
||||
|
||||
assertEquals(gen.next().value, 1);
|
||||
assertEquals(gen.next().value, 2);
|
||||
|
||||
var result = (function recursive(a=0) {
|
||||
if (a == 1) {
|
||||
return 42;
|
||||
}
|
||||
return recursive(1);
|
||||
})();
|
||||
|
||||
assertEquals(result, 42);
|
Loading…
Reference in New Issue
Block a user