Reland^5 "[parser] Introduce UnoptimizedCompileFlags"

This is a reland of e1b93a4ff5
which was a reland of 313d4844d9
which was a reland of 0a59e0cb08
which was a reland of 146f5375da
which was a reland of d91679bf3a

Give up on using C++ bitfields, go back to having base::BitField and
getters/setters.

Original change's description:
> [parser] Introduce UnoptimizedCompileFlags
>
> UnoptimizedCompileFlags defines the input flags shared between parse and
> compile (currently parse-only). It is set initially with some values, and
> is immutable after being passed to ParseInfo (ParseInfo still has getters
> for the fields, but no setters).
>
> Since a few of the existing flags were output flags, ParseInfo now has a
> new output_flags field, which will eventually migrate to a ParseOutputs
> structure.
>
> Bug: v8:10314
> Change-Id: If3890a5fad883bca80a97bf9dfe44d91797dc286
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2096580
> Commit-Queue: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Simon Zünd <szuend@chromium.org>
> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#66782}

TBR=ulan@chromium.org,szuend@chromium.org

Bug: v8:10314
Change-Id: I54bcd107a0e85cf1a2ddeef0759100547eb65652
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2157378
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67309}
This commit is contained in:
Leszek Swirski 2020-04-22 12:45:31 +02:00 committed by Commit Bot
parent 1262eb02ca
commit a3228bfcab
32 changed files with 763 additions and 708 deletions

View File

@ -2725,7 +2725,7 @@ bool ClassScope::ResolvePrivateNames(ParseInfo* info) {
if (var == nullptr) {
// It's only possible to fail to resolve private names here if
// this is at the top level or the private name is accessed through eval.
DCHECK(info->is_eval() || outer_scope_->is_script_scope());
DCHECK(info->flags().is_eval() || outer_scope_->is_script_scope());
Scanner::Location loc = proxy->location();
info->pending_error_handler()->ReportMessageAt(
loc.beg_pos, loc.end_pos,

View File

@ -496,7 +496,7 @@ template <typename LocalIsolate>
void EnsureSharedFunctionInfosArrayOnScript(Handle<Script> script,
ParseInfo* parse_info,
LocalIsolate* isolate) {
DCHECK(parse_info->is_toplevel());
DCHECK(parse_info->flags().is_toplevel());
if (script->shared_function_infos().length() > 0) {
DCHECK_EQ(script->shared_function_infos().length(),
parse_info->max_function_literal_id() + 1);
@ -529,6 +529,7 @@ CompilationJob::Status FinalizeUnoptimizedCompilationJob(
Isolate* isolate) {
UnoptimizedCompilationInfo* compilation_info = job->compilation_info();
ParseInfo* parse_info = job->parse_info();
const UnoptimizedCompileFlags flags = parse_info->flags();
SetSharedFunctionFlagsFromLiteral(compilation_info->literal(), *shared_info);
@ -540,18 +541,18 @@ CompilationJob::Status FinalizeUnoptimizedCompilationJob(
// background compile was started in which the compiled bytecode will not be
// missing source positions (for instance by enabling the cpu profiler). So
// force source position collection now in that case.
if (!parse_info->collect_source_positions() &&
if (!flags.collect_source_positions() &&
isolate->NeedsDetailedOptimizedCodeLineInfo()) {
SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared_info);
}
CodeEventListener::LogEventsAndTags log_tag;
if (parse_info->is_toplevel()) {
log_tag = compilation_info->is_eval() ? CodeEventListener::EVAL_TAG
: CodeEventListener::SCRIPT_TAG;
if (flags.is_toplevel()) {
log_tag = flags.is_eval() ? CodeEventListener::EVAL_TAG
: CodeEventListener::SCRIPT_TAG;
} else {
log_tag = parse_info->lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG
: CodeEventListener::FUNCTION_TAG;
log_tag = flags.is_lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG
: CodeEventListener::FUNCTION_TAG;
}
job->RecordFunctionCompilation(log_tag, shared_info, isolate);
job->RecordCompilationStats(isolate);
@ -580,7 +581,7 @@ std::unique_ptr<UnoptimizedCompilationJob> ExecuteUnoptimizedCompileJobs(
ParseInfo* parse_info, FunctionLiteral* literal,
AccountingAllocator* allocator,
UnoptimizedCompilationJobList* inner_function_jobs) {
if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken())) {
if (UseAsmWasm(literal, parse_info->flags().is_asm_wasm_broken())) {
std::unique_ptr<UnoptimizedCompilationJob> asm_job(
AsmJs::NewCompilationJob(parse_info, literal, allocator));
if (asm_job->ExecuteJob() == CompilationJob::SUCCEEDED) {
@ -657,7 +658,7 @@ MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel(
Handle<SharedFunctionInfo> shared_info =
Compiler::GetSharedFunctionInfo(literal, script, isolate);
if (shared_info->is_compiled()) continue;
if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken())) {
if (UseAsmWasm(literal, parse_info->flags().is_asm_wasm_broken())) {
std::unique_ptr<UnoptimizedCompilationJob> asm_job(
AsmJs::NewCompilationJob(parse_info, literal, allocator));
if (asm_job->ExecuteJob() == CompilationJob::SUCCEEDED &&
@ -1086,8 +1087,9 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
PostponeInterruptsScope postpone(isolate);
DCHECK(!isolate->native_context().is_null());
RuntimeCallTimerScope runtimeTimer(
isolate, parse_info->is_eval() ? RuntimeCallCounterId::kCompileEval
: RuntimeCallCounterId::kCompileScript);
isolate, parse_info->flags().is_eval()
? RuntimeCallCounterId::kCompileEval
: RuntimeCallCounterId::kCompileScript);
VMState<BYTECODE_COMPILER> state(isolate);
if (parse_info->literal() == nullptr &&
!parsing::ParseProgram(parse_info, script, maybe_outer_scope_info,
@ -1097,12 +1099,12 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
// Measure how long it takes to do the compilation; only take the
// rest of the function into account to avoid overlap with the
// parsing statistics.
HistogramTimer* rate = parse_info->is_eval()
HistogramTimer* rate = parse_info->flags().is_eval()
? isolate->counters()->compile_eval()
: isolate->counters()->compile();
HistogramTimerScope timer(rate);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
parse_info->is_eval() ? "V8.CompileEval" : "V8.Compile");
parse_info->flags().is_eval() ? "V8.CompileEval" : "V8.Compile");
// Generate the unoptimized bytecode or asm-js data.
MaybeHandle<SharedFunctionInfo> shared_info =
@ -1126,8 +1128,8 @@ std::unique_ptr<UnoptimizedCompilationJob> CompileOnBackgroundThread(
"V8.CompileCodeBackground");
RuntimeCallTimerScope runtimeTimer(
parse_info->runtime_call_stats(),
parse_info->is_toplevel()
? parse_info->is_eval()
parse_info->flags().is_toplevel()
? parse_info->flags().is_eval()
? RuntimeCallCounterId::kCompileBackgroundEval
: RuntimeCallCounterId::kCompileBackgroundScript
: RuntimeCallCounterId::kCompileBackgroundFunction);
@ -1149,32 +1151,37 @@ MaybeHandle<SharedFunctionInfo> CompileToplevel(
BackgroundCompileTask::BackgroundCompileTask(ScriptStreamingData* streamed_data,
Isolate* isolate)
: info_(new ParseInfo(isolate)),
off_thread_isolate_(FLAG_finalize_streaming_on_background
? new OffThreadIsolate(isolate, info_->zone())
: nullptr),
: flags_(UnoptimizedCompileFlags::ForToplevelCompile(
isolate, true, construct_language_mode(FLAG_use_strict),
REPLMode::kNo)),
info_(std::make_unique<ParseInfo>(isolate, flags_)),
start_position_(0),
end_position_(0),
function_literal_id_(kFunctionLiteralIdTopLevel),
stack_size_(i::FLAG_stack_size),
worker_thread_runtime_call_stats_(
isolate->counters()->worker_thread_runtime_call_stats()),
allocator_(isolate->allocator()),
timer_(isolate->counters()->compile_script_on_background()),
language_mode_(info_->language_mode()),
collected_source_positions_(false) {
VMState<PARSER> state(isolate);
// Prepare the data for the internalization phase and compilation phase, which
// will happen in the main thread after parsing.
LOG(isolate, ScriptEvent(Logger::ScriptEventType::kStreamingCompile,
info_->script_id()));
info_->SetFlagsForToplevelCompile(isolate->is_collecting_type_profile(), true,
construct_language_mode(FLAG_use_strict),
REPLMode::kNo);
language_mode_ = info_->language_mode();
info_->flags().script_id()));
std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For(
streamed_data->source_stream.get(), streamed_data->encoding));
info_->set_character_stream(std::move(stream));
finalize_on_background_thread_ = FLAG_finalize_streaming_on_background;
if (finalize_on_background_thread()) {
off_thread_isolate_ =
std::make_unique<OffThreadIsolate>(isolate, info_->zone());
}
}
BackgroundCompileTask::BackgroundCompileTask(
@ -1182,8 +1189,13 @@ BackgroundCompileTask::BackgroundCompileTask(
const AstRawString* function_name, const FunctionLiteral* function_literal,
WorkerThreadRuntimeCallStats* worker_thread_runtime_stats,
TimedHistogram* timer, int max_stack_size)
: info_(ParseInfo::FromParent(outer_parse_info, allocator, function_literal,
function_name)),
: flags_(UnoptimizedCompileFlags::ForToplevelFunction(
outer_parse_info->flags(), function_literal)),
info_(ParseInfo::FromParent(outer_parse_info, flags_, allocator,
function_literal, function_name)),
start_position_(function_literal->start_position()),
end_position_(function_literal->end_position()),
function_literal_id_(function_literal->function_literal_id()),
stack_size_(max_stack_size),
worker_thread_runtime_call_stats_(worker_thread_runtime_stats),
allocator_(allocator),
@ -1191,13 +1203,13 @@ BackgroundCompileTask::BackgroundCompileTask(
language_mode_(info_->language_mode()),
collected_source_positions_(false),
finalize_on_background_thread_(false) {
DCHECK(outer_parse_info->is_toplevel());
DCHECK(outer_parse_info->flags().is_toplevel());
DCHECK(!function_literal->is_toplevel());
// Clone the character stream so both can be accessed independently.
std::unique_ptr<Utf16CharacterStream> character_stream =
outer_parse_info->character_stream()->Clone();
character_stream->Seek(function_literal->start_position());
character_stream->Seek(start_position_);
info_->set_character_stream(std::move(character_stream));
// Get preparsed scope data from the function literal.
@ -1270,17 +1282,18 @@ void BackgroundCompileTask::Run() {
parser_.reset(new Parser(info_.get()));
parser_->InitializeEmptyScopeChain(info_.get());
parser_->ParseOnBackground(info_.get());
parser_->ParseOnBackground(info_.get(), start_position_, end_position_,
function_literal_id_);
if (info_->literal() != nullptr) {
// Parsing has succeeded, compile.
outer_function_job_ = CompileOnBackgroundThread(info_.get(), allocator_,
&inner_function_jobs_);
// Save the language mode and record whether we collected source positions.
language_mode_ = info_->language_mode();
collected_source_positions_ = info_->collect_source_positions();
collected_source_positions_ = info_->flags().collect_source_positions();
if (finalize_on_background_thread_) {
DCHECK(info_->is_toplevel());
DCHECK(info_->flags().is_toplevel());
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.FinalizeCodeBackground");
@ -1292,10 +1305,10 @@ void BackgroundCompileTask::Run() {
// We don't have the script source or the script origin yet, so use a few
// default values for them. These will be fixed up during the main-thread
// merge.
Handle<Script> script =
info_->CreateScript(off_thread_isolate_.get(),
off_thread_isolate_->factory()->empty_string(),
ScriptOriginOptions(), NOT_NATIVES_CODE);
Handle<Script> script = info_->CreateScript(
off_thread_isolate_.get(),
off_thread_isolate_->factory()->empty_string(), kNullMaybeHandle,
ScriptOriginOptions(), NOT_NATIVES_CODE);
Handle<SharedFunctionInfo> outer_function_sfi =
FinalizeTopLevel(info_.get(), script, off_thread_isolate_.get(),
@ -1385,10 +1398,13 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
HistogramTimerScope timer(isolate->counters()->collect_source_positions());
// Set up parse info.
ParseInfo parse_info(isolate, *shared_info);
parse_info.set_lazy_compile();
parse_info.set_collect_source_positions();
if (FLAG_allow_natives_syntax) parse_info.set_allow_natives_syntax();
UnoptimizedCompileFlags flags =
UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info);
flags.set_is_lazy_compile(true);
flags.set_collect_source_positions(true);
flags.set_allow_natives_syntax(FLAG_allow_natives_syntax);
ParseInfo parse_info(isolate, flags);
// Parse and update ParseInfo with the results. Don't update parsing
// statistics since we've already parsed the code before.
@ -1430,7 +1446,7 @@ bool Compiler::CollectSourcePositions(Isolate* isolate,
}
}
DCHECK(job->compilation_info()->collect_source_positions());
DCHECK(job->compilation_info()->flags().collect_source_positions());
// If debugging, make sure that instrumented bytecode has the source position
// table set on it as well.
@ -1468,8 +1484,11 @@ bool Compiler::Compile(Handle<SharedFunctionInfo> shared_info,
AggregatedHistogramTimerScope timer(isolate->counters()->compile_lazy());
// Set up parse info.
ParseInfo parse_info(isolate, *shared_info);
parse_info.set_lazy_compile();
UnoptimizedCompileFlags flags =
UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared_info);
flags.set_is_lazy_compile(true);
ParseInfo parse_info(isolate, flags);
// Check if the compiler dispatcher has shared_info enqueued for compile.
CompilerDispatcher* dispatcher = isolate->compiler_dispatcher();
@ -1607,7 +1626,7 @@ bool Compiler::FinalizeBackgroundCompileTask(
isolate, RuntimeCallCounterId::kCompileFinalizeBackgroundCompileTask);
HandleScope scope(isolate);
ParseInfo* parse_info = task->info();
DCHECK(!parse_info->is_toplevel());
DCHECK(!parse_info->flags().is_toplevel());
DCHECK(!shared_info->is_compiled());
Handle<Script> script(Script::cast(shared_info->script()), isolate);
@ -1717,22 +1736,22 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
is_compiled_scope = shared_info->is_compiled_scope();
allow_eval_cache = true;
} else {
ParseInfo parse_info(isolate);
parse_info.SetFlagsForToplevelCompile(isolate->is_collecting_type_profile(),
true, language_mode, REPLMode::kNo);
UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile(
isolate, true, language_mode, REPLMode::kNo);
flags.set_is_eval(true);
flags.set_parse_restriction(restriction);
parse_info.set_eval();
parse_info.set_parse_restriction(restriction);
ParseInfo parse_info(isolate, flags);
parse_info.set_parameters_end_pos(parameters_end_pos);
DCHECK(!parse_info.is_module());
DCHECK(!parse_info.flags().is_module());
MaybeHandle<ScopeInfo> maybe_outer_scope_info;
if (!context->IsNativeContext()) {
maybe_outer_scope_info = handle(context->scope_info(), isolate);
}
script = parse_info.CreateScript(
isolate, source, OriginOptionsForEval(outer_info->script()));
script =
parse_info.CreateScript(isolate, source, kNullMaybeHandle,
OriginOptionsForEval(outer_info->script()));
script->set_eval_from_shared(*outer_info);
if (eval_position == kNoSourcePosition) {
// If the position is missing, attempt to get the code offset by
@ -2156,14 +2175,14 @@ void SetScriptFieldsFromDetails(Script script,
}
}
Handle<Script> NewScript(Isolate* isolate, ParseInfo* parse_info,
Handle<String> source,
Compiler::ScriptDetails script_details,
ScriptOriginOptions origin_options,
NativesFlag natives) {
Handle<Script> NewScript(
Isolate* isolate, ParseInfo* parse_info, Handle<String> source,
Compiler::ScriptDetails script_details, ScriptOriginOptions origin_options,
NativesFlag natives,
MaybeHandle<FixedArray> maybe_wrapped_arguments = kNullMaybeHandle) {
// Create a script object describing the script to be compiled.
Handle<Script> script =
parse_info->CreateScript(isolate, source, origin_options, natives);
Handle<Script> script = parse_info->CreateScript(
isolate, source, maybe_wrapped_arguments, origin_options, natives);
SetScriptFieldsFromDetails(*script, script_details);
LOG(isolate, ScriptDetails(*script));
return script;
@ -2254,21 +2273,21 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
if (maybe_result.is_null()) {
// No cache entry found compile the script.
ParseInfo parse_info(isolate);
UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile(
isolate, natives == NOT_NATIVES_CODE, language_mode,
script_details.repl_mode);
parse_info.SetFlagsForToplevelCompile(
isolate->is_collecting_type_profile(), natives == NOT_NATIVES_CODE,
language_mode, script_details.repl_mode);
flags.set_is_module(origin_options.IsModule());
flags.set_is_eager(compile_options == ScriptCompiler::kEagerCompile);
parse_info.set_module(origin_options.IsModule());
ParseInfo parse_info(isolate, flags);
parse_info.set_extension(extension);
parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile);
Handle<Script> script = NewScript(isolate, &parse_info, source,
script_details, origin_options, natives);
DCHECK_IMPLIES(parse_info.collect_type_profile(),
DCHECK_IMPLIES(parse_info.flags().collect_type_profile(),
script->IsUserJavaScript());
DCHECK_EQ(parse_info.is_repl_mode(), script->is_repl_mode());
DCHECK_EQ(parse_info.flags().is_repl_mode(), script->is_repl_mode());
// Compile the function and add it to the isolate cache.
maybe_result =
@ -2331,27 +2350,24 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
Handle<Script> script;
IsCompiledScope is_compiled_scope;
if (!maybe_result.ToHandle(&wrapped)) {
ParseInfo parse_info(isolate);
parse_info.SetFlagsForToplevelCompile(isolate->is_collecting_type_profile(),
true, language_mode,
script_details.repl_mode);
parse_info.set_eval(); // Use an eval scope as declaration scope.
parse_info.set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile(
isolate, true, language_mode, script_details.repl_mode);
flags.set_is_eval(true); // Use an eval scope as declaration scope.
flags.set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
// TODO(delphick): Remove this and instead make the wrapped and wrapper
// functions fully non-lazy instead thus preventing source positions from
// being omitted.
parse_info.set_collect_source_positions(true);
// parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile);
flags.set_collect_source_positions(true);
// flags.set_eager(compile_options == ScriptCompiler::kEagerCompile);
ParseInfo parse_info(isolate, flags);
MaybeHandle<ScopeInfo> maybe_outer_scope_info;
if (!context->IsNativeContext()) {
maybe_outer_scope_info = handle(context->scope_info(), isolate);
}
script = NewScript(isolate, &parse_info, source, script_details,
origin_options, NOT_NATIVES_CODE);
script->set_wrapped_arguments(*arguments);
origin_options, NOT_NATIVES_CODE, arguments);
Handle<SharedFunctionInfo> top_level;
maybe_result = CompileToplevel(&parse_info, script, maybe_outer_scope_info,
@ -2446,7 +2462,7 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
maybe_result = sfi;
} else {
ParseInfo* parse_info = task->info();
DCHECK(parse_info->is_toplevel());
DCHECK(parse_info->flags().is_toplevel());
// No cache entry found, finalize compilation of the script and add it to
// the isolate cache.

View File

@ -14,6 +14,7 @@
#include "src/execution/isolate.h"
#include "src/logging/code-events.h"
#include "src/objects/contexts.h"
#include "src/parsing/parse-info.h"
#include "src/utils/allocation.h"
#include "src/zone/zone.h"
@ -399,6 +400,7 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
// Data needed for parsing, and data needed to to be passed between thread
// between parsing and compilation. These need to be initialized before the
// compilation starts.
UnoptimizedCompileFlags flags_;
std::unique_ptr<ParseInfo> info_;
std::unique_ptr<Parser> parser_;
@ -414,6 +416,11 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
// This is a raw pointer to the off-thread allocated SharedFunctionInfo.
SharedFunctionInfo outer_function_sfi_;
// Single function data for top-level function compilation.
int start_position_;
int end_position_;
int function_literal_id_;
int stack_size_;
WorkerThreadRuntimeCallStats* worker_thread_runtime_call_stats_;
AccountingAllocator* allocator_;

View File

@ -18,7 +18,7 @@ namespace internal {
UnoptimizedCompilationInfo::UnoptimizedCompilationInfo(Zone* zone,
ParseInfo* parse_info,
FunctionLiteral* literal)
: flags_(0), zone_(zone), feedback_vector_spec_(zone) {
: flags_(parse_info->flags()), zone_(zone), feedback_vector_spec_(zone) {
// NOTE: The parse_info passed here represents the global information gathered
// during parsing, but does not represent specific details of the actual
// function literal being compiled for this OptimizedCompilationInfo. As such,
@ -28,13 +28,6 @@ UnoptimizedCompilationInfo::UnoptimizedCompilationInfo(Zone* zone,
DCHECK_NOT_NULL(literal);
literal_ = literal;
source_range_map_ = parse_info->source_range_map();
if (parse_info->is_eval()) MarkAsEval();
if (parse_info->collect_type_profile()) MarkAsCollectTypeProfile();
if (parse_info->might_always_opt()) MarkAsMightAlwaysOpt();
if (parse_info->collect_source_positions()) {
MarkAsForceCollectSourcePositions();
}
}
DeclarationScope* UnoptimizedCompilationInfo::scope() const {
@ -52,7 +45,7 @@ int UnoptimizedCompilationInfo::num_parameters_including_this() const {
SourcePositionTableBuilder::RecordingMode
UnoptimizedCompilationInfo::SourcePositionRecordingMode() const {
if (collect_source_positions()) {
if (flags().collect_source_positions()) {
return SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS;
}

View File

@ -12,6 +12,7 @@
#include "src/handles/handles.h"
#include "src/objects/feedback-vector.h"
#include "src/objects/objects.h"
#include "src/parsing/parse-info.h"
#include "src/utils/utils.h"
namespace v8 {
@ -35,21 +36,7 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final {
Zone* zone() { return zone_; }
// Compilation flag accessors.
void MarkAsEval() { SetFlag(kIsEval); }
bool is_eval() const { return GetFlag(kIsEval); }
void MarkAsCollectTypeProfile() { SetFlag(kCollectTypeProfile); }
bool collect_type_profile() const { return GetFlag(kCollectTypeProfile); }
void MarkAsForceCollectSourcePositions() { SetFlag(kCollectSourcePositions); }
bool collect_source_positions() const {
return GetFlag(kCollectSourcePositions);
}
void MarkAsMightAlwaysOpt() { SetFlag(kMightAlwaysOpt); }
bool might_always_opt() const { return GetFlag(kMightAlwaysOpt); }
const UnoptimizedCompileFlags& flags() const { return flags_; }
// Accessors for the input data of the function being compiled.
@ -97,20 +84,8 @@ class V8_EXPORT_PRIVATE UnoptimizedCompilationInfo final {
FeedbackVectorSpec* feedback_vector_spec() { return &feedback_vector_spec_; }
private:
// Various configuration flags for a compilation, as well as some properties
// of the compiled code produced by a compilation.
enum Flag {
kIsEval = 1 << 0,
kCollectTypeProfile = 1 << 1,
kMightAlwaysOpt = 1 << 2,
kCollectSourcePositions = 1 << 3,
};
void SetFlag(Flag flag) { flags_ |= flag; }
bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; }
// Compilation flags.
unsigned flags_;
const UnoptimizedCompileFlags flags_;
// The zone from which the compilation pipeline working on this
// OptimizedCompilationInfo allocates.

View File

@ -837,7 +837,7 @@ enum NativesFlag { NOT_NATIVES_CODE, EXTENSION_CODE, INSPECTOR_CODE };
// ParseRestriction is used to restrict the set of valid statements in a
// unit of compilation. Restriction violations cause a syntax error.
enum ParseRestriction {
enum ParseRestriction : bool {
NO_PARSE_RESTRICTION, // All expressions are allowed.
ONLY_SINGLE_FUNCTION_LITERAL // Only a single FunctionLiteral expression.
};

View File

@ -544,16 +544,16 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
i::Handle<i::String> str = Utils::OpenHandle(*(source));
// Set up ParseInfo.
i::ParseInfo parse_info(i_isolate);
parse_info.set_toplevel();
parse_info.set_allow_lazy_parsing();
parse_info.set_language_mode(
i::construct_language_mode(i::FLAG_use_strict));
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForToplevelCompile(
i_isolate, true, i::construct_language_mode(i::FLAG_use_strict),
i::REPLMode::kNo);
i::Handle<i::Script> script =
parse_info.CreateScript(i_isolate, str, options.compile_options);
if (!i::parsing::ParseProgram(&parse_info, script, i::kNullMaybeHandle,
i_isolate)) {
i::ParseInfo parse_info(i_isolate, flags);
i::Handle<i::Script> script = parse_info.CreateScript(
i_isolate, str, i::kNullMaybeHandle, options.compile_options);
if (!i::parsing::ParseProgram(&parse_info, script, i_isolate)) {
fprintf(stderr, "Failed parsing\n");
return false;
}

View File

@ -40,7 +40,7 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
TryParseAndRetrieveScopes(strategy);
}
ScopeIterator::~ScopeIterator() { delete info_; }
ScopeIterator::~ScopeIterator() = default;
Handle<Object> ScopeIterator::GetFunctionDebugName() const {
if (!function_.is_null()) return JSFunction::GetDebugName(function_);
@ -236,36 +236,41 @@ void ScopeIterator::TryParseAndRetrieveScopes(ReparseStrategy strategy) {
// Depending on the choosen strategy, the whole script or just
// the closure is re-parsed for function scopes.
Handle<Script> script(Script::cast(shared_info->script()), isolate_);
if (scope_info->scope_type() == FUNCTION_SCOPE &&
strategy == ReparseStrategy::kFunctionLiteral) {
info_ = new ParseInfo(isolate_, *shared_info);
} else {
info_ = new ParseInfo(isolate_, *script);
info_->set_eager();
}
// Pick between flags for a single function compilation, or an eager
// compilation of the whole script.
UnoptimizedCompileFlags flags =
(scope_info->scope_type() == FUNCTION_SCOPE &&
strategy == ReparseStrategy::kFunctionLiteral)
? UnoptimizedCompileFlags::ForFunctionCompile(isolate_, *shared_info)
: UnoptimizedCompileFlags::ForScriptCompile(isolate_, *script)
.set_is_eager(true);
MaybeHandle<ScopeInfo> maybe_outer_scope;
if (scope_info->scope_type() == EVAL_SCOPE || script->is_wrapped()) {
info_->set_eval();
flags.set_is_eval(true);
if (!context_->IsNativeContext()) {
maybe_outer_scope = handle(context_->scope_info(), isolate_);
}
// Language mode may be inherited from the eval caller.
// Retrieve it from shared function info.
info_->set_language_mode(shared_info->language_mode());
flags.set_outer_language_mode(shared_info->language_mode());
} else if (scope_info->scope_type() == MODULE_SCOPE) {
DCHECK(info_->is_module());
DCHECK(flags.is_module());
} else {
DCHECK(scope_info->scope_type() == SCRIPT_SCOPE ||
scope_info->scope_type() == FUNCTION_SCOPE);
}
const bool parse_result =
info_->is_toplevel()
? parsing::ParseProgram(info_, script, maybe_outer_scope, isolate_)
: parsing::ParseFunction(info_, shared_info, isolate_);
info_ = std::make_unique<ParseInfo>(isolate_, flags);
if (parse_result && Rewriter::Rewrite(info_)) {
const bool parse_result =
flags.is_toplevel()
? parsing::ParseProgram(info_.get(), script, maybe_outer_scope,
isolate_)
: parsing::ParseFunction(info_.get(), shared_info, isolate_);
if (parse_result && Rewriter::Rewrite(info_.get())) {
info_->ast_value_factory()->Internalize(isolate_);
DeclarationScope* literal_scope = info_->literal()->scope();
@ -280,7 +285,7 @@ void ScopeIterator::TryParseAndRetrieveScopes(ReparseStrategy strategy) {
? scope_chain_retriever.ClosureScope()
: literal_scope;
CHECK(DeclarationScope::Analyze(info_));
CHECK(DeclarationScope::Analyze(info_.get()));
if (ignore_nested_scopes) {
current_scope_ = closure_scope_;
start_scope_ = current_scope_;

View File

@ -109,7 +109,7 @@ class ScopeIterator {
private:
Isolate* isolate_;
ParseInfo* info_ = nullptr;
std::unique_ptr<ParseInfo> info_;
FrameInspector* const frame_inspector_ = nullptr;
Handle<JSGeneratorObject> generator_;
Handle<JSFunction> function_;

View File

@ -750,7 +750,6 @@ class CollectFunctionLiterals final
bool ParseScript(Isolate* isolate, Handle<Script> script, ParseInfo* parse_info,
bool compile_as_well, std::vector<FunctionLiteral*>* literals,
debug::LiveEditResult* result) {
parse_info->set_eager();
v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
Handle<SharedFunctionInfo> shared;
bool success = false;
@ -1058,15 +1057,21 @@ void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
return;
}
ParseInfo parse_info(isolate, *script);
UnoptimizedCompileFlags flags =
UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_is_eager(true);
ParseInfo parse_info(isolate, flags);
std::vector<FunctionLiteral*> literals;
if (!ParseScript(isolate, script, &parse_info, false, &literals, result))
return;
Handle<Script> new_script = isolate->factory()->CloneScript(script);
new_script->set_source(*new_source);
UnoptimizedCompileFlags new_flags =
UnoptimizedCompileFlags::ForScriptCompile(isolate, *new_script);
new_flags.set_is_eager(true);
ParseInfo new_parse_info(isolate, new_flags);
std::vector<FunctionLiteral*> new_literals;
ParseInfo new_parse_info(isolate, *new_script);
if (!ParseScript(isolate, new_script, &new_parse_info, true, &new_literals,
result)) {
return;

View File

@ -1252,7 +1252,8 @@ Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object,
MessageLocation* location,
CallPrinter::ErrorHint* hint) {
if (ComputeLocation(isolate, location)) {
ParseInfo info(isolate, *location->shared());
ParseInfo info(isolate, i::UnoptimizedCompileFlags::ForFunctionCompile(
isolate, *location->shared()));
if (parsing::ParseAny(&info, location->shared(), isolate)) {
info.ast_value_factory()->Internalize(isolate);
CallPrinter printer(isolate, location->shared()->IsUserJavaScript());
@ -1310,7 +1311,8 @@ Object ErrorUtils::ThrowSpreadArgIsNullOrUndefinedError(Isolate* isolate,
MessageLocation location;
Handle<String> callsite;
if (ComputeLocation(isolate, &location)) {
ParseInfo info(isolate, *location.shared());
ParseInfo info(isolate, i::UnoptimizedCompileFlags::ForFunctionCompile(
isolate, *location.shared()));
if (parsing::ParseAny(&info, location.shared(), isolate)) {
info.ast_value_factory()->Internalize(isolate);
CallPrinter printer(isolate, location.shared()->IsUserJavaScript(),
@ -1385,7 +1387,8 @@ Object ErrorUtils::ThrowLoadFromNullOrUndefined(Isolate* isolate,
if (ComputeLocation(isolate, &location)) {
location_computed = true;
ParseInfo info(isolate, *location.shared());
ParseInfo info(isolate, i::UnoptimizedCompileFlags::ForFunctionCompile(
isolate, *location.shared()));
if (parsing::ParseAny(&info, location.shared(), isolate)) {
info.ast_value_factory()->Internalize(isolate);
CallPrinter printer(isolate, location.shared()->IsUserJavaScript());

View File

@ -1332,7 +1332,7 @@ void BytecodeGenerator::GenerateBytecodeBody() {
if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter);
// Emit type profile call.
if (info()->collect_type_profile()) {
if (info()->flags().collect_type_profile()) {
feedback_spec()->AddTypeProfileSlot();
int num_parameters = closure_scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
@ -2134,7 +2134,7 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
DCHECK(expr->scope()->outer_scope() == current_scope());
uint8_t flags = CreateClosureFlags::Encode(
expr->pretenure(), closure_scope()->is_function_scope(),
info()->might_always_opt());
info()->flags().might_always_opt());
size_t entry = builder()->AllocateDeferredConstantPoolEntry();
builder()->CreateClosure(entry, GetCachedCreateClosureSlot(expr), flags);
function_literals_.push_back(std::make_pair(expr, entry));
@ -3197,7 +3197,7 @@ void BytecodeGenerator::BuildReturn(int source_position) {
builder()->StoreAccumulatorInRegister(result).CallRuntime(
Runtime::kTraceExit, result);
}
if (info()->collect_type_profile()) {
if (info()->flags().collect_type_profile()) {
builder()->CollectTypeProfile(info()->literal()->return_position());
}
builder()->SetReturnPosition(source_position, info()->literal());

View File

@ -191,17 +191,18 @@ void InterpreterCompilationJob::CheckAndPrintBytecodeMismatch(
std::cerr << "Bytecode mismatch";
#ifdef OBJECT_PRINT
std::cerr << " found for function: ";
Handle<String> name = parse_info()->function_name()->string();
if (name->length() == 0) {
std::cerr << "anonymous";
} else {
MaybeHandle<String> maybe_name = parse_info()->literal()->GetName(isolate);
Handle<String> name;
if (maybe_name.ToHandle(&name) && name->length() != 0) {
name->StringPrint(std::cerr);
} else {
std::cerr << "anonymous";
}
Object script_name = script->GetNameOrSourceURL();
if (script_name.IsString()) {
std::cerr << " ";
String::cast(script_name).StringPrint(std::cerr);
std::cerr << ":" << parse_info()->start_position();
std::cerr << ":" << parse_info()->literal()->start_position();
}
#endif
std::cerr << "\nOriginal bytecode:\n";

View File

@ -6,6 +6,7 @@
#define V8_OBJECTS_FUNCTION_KIND_H_
#include "src/base/bounds.h"
#include "src/base/macros.h"
namespace v8 {
namespace internal {
@ -56,6 +57,9 @@ enum FunctionKind : uint8_t {
kLastFunctionKind = kClassMembersInitializerFunction,
};
constexpr int kFunctionKindBitSize = 5;
STATIC_ASSERT(kLastFunctionKind < (1 << kFunctionKindBitSize));
inline bool IsArrowFunction(FunctionKind kind) {
return base::IsInRange(kind, FunctionKind::kArrowFunction,
FunctionKind::kAsyncArrowFunction);

View File

@ -5,6 +5,7 @@
#ifndef V8_OBJECTS_SHARED_FUNCTION_INFO_INL_H_
#define V8_OBJECTS_SHARED_FUNCTION_INFO_INL_H_
#include "src/base/macros.h"
#include "src/objects/shared-function-info.h"
#include "src/handles/handles-inl.h"
@ -250,6 +251,7 @@ void SharedFunctionInfo::set_language_mode(LanguageMode language_mode) {
}
FunctionKind SharedFunctionInfo::kind() const {
STATIC_ASSERT(FunctionKindBits::kSize == kFunctionKindBitSize);
return FunctionKindBits::decode(flags());
}

View File

@ -20,62 +20,107 @@
namespace v8 {
namespace internal {
ParseInfo::ParseInfo(AccountingAllocator* zone_allocator, int script_id)
: zone_(std::make_unique<Zone>(zone_allocator, ZONE_NAME)),
flags_(0),
extension_(nullptr),
script_scope_(nullptr),
stack_limit_(0),
hash_seed_(0),
function_kind_(FunctionKind::kNormalFunction),
function_syntax_kind_(FunctionSyntaxKind::kDeclaration),
UnoptimizedCompileFlags::UnoptimizedCompileFlags(Isolate* isolate,
int script_id)
: flags_(0),
script_id_(script_id),
start_position_(0),
end_position_(0),
parameters_end_pos_(kNoSourcePosition),
function_literal_id_(kFunctionLiteralIdInvalid),
max_function_literal_id_(kFunctionLiteralIdInvalid),
character_stream_(nullptr),
ast_value_factory_(nullptr),
ast_string_constants_(nullptr),
function_name_(nullptr),
runtime_call_stats_(nullptr),
source_range_map_(nullptr),
literal_(nullptr) {}
ParseInfo::ParseInfo(Isolate* isolate, AccountingAllocator* zone_allocator,
int script_id)
: ParseInfo(zone_allocator, script_id) {
set_hash_seed(HashSeed(isolate));
set_stack_limit(isolate->stack_guard()->real_climit());
set_runtime_call_stats(isolate->counters()->runtime_call_stats());
set_logger(isolate->logger());
set_ast_string_constants(isolate->ast_string_constants());
set_collect_source_positions(!FLAG_enable_lazy_source_positions ||
isolate->NeedsDetailedOptimizedCodeLineInfo());
if (!isolate->is_best_effort_code_coverage()) set_coverage_enabled();
if (isolate->is_block_code_coverage()) set_block_coverage_enabled();
if (isolate->is_collecting_type_profile()) set_collect_type_profile();
if (isolate->compiler_dispatcher()->IsEnabled()) {
parallel_tasks_.reset(new ParallelTasks(isolate->compiler_dispatcher()));
}
function_kind_(FunctionKind::kNormalFunction),
function_syntax_kind_(FunctionSyntaxKind::kDeclaration) {
set_collect_type_profile(isolate->is_collecting_type_profile());
set_coverage_enabled(!isolate->is_best_effort_code_coverage());
set_block_coverage_enabled(isolate->is_block_code_coverage());
set_might_always_opt(FLAG_always_opt || FLAG_prepare_always_opt);
set_allow_lazy_compile(FLAG_lazy);
set_allow_natives_syntax(FLAG_allow_natives_syntax);
set_allow_lazy_compile(FLAG_lazy);
set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import);
set_allow_harmony_import_meta(FLAG_harmony_import_meta);
set_allow_harmony_private_methods(FLAG_harmony_private_methods);
set_collect_source_positions(!FLAG_enable_lazy_source_positions ||
isolate->NeedsDetailedOptimizedCodeLineInfo());
set_allow_harmony_top_level_await(FLAG_harmony_top_level_await);
}
ParseInfo::ParseInfo(Isolate* isolate)
: ParseInfo(isolate, isolate->allocator(), isolate->GetNextScriptId()) {
LOG(isolate, ScriptEvent(Logger::ScriptEventType::kReserveId, script_id()));
// static
UnoptimizedCompileFlags UnoptimizedCompileFlags::ForFunctionCompile(
Isolate* isolate, SharedFunctionInfo shared) {
Script script = Script::cast(shared.script());
UnoptimizedCompileFlags flags(isolate, script.id());
flags.SetFlagsFromFunction(&shared);
flags.SetFlagsForFunctionFromScript(script);
flags.set_allow_lazy_parsing(true);
flags.set_is_asm_wasm_broken(shared.is_asm_wasm_broken());
flags.set_is_repl_mode(shared.is_repl_mode());
// CollectTypeProfile uses its own feedback slots. If we have existing
// FeedbackMetadata, we can only collect type profile if the feedback vector
// has the appropriate slots.
flags.set_collect_type_profile(
isolate->is_collecting_type_profile() &&
(shared.HasFeedbackMetadata()
? shared.feedback_metadata().HasTypeProfileSlot()
: script.IsUserJavaScript()));
// Do not support re-parsing top-level function of a wrapped script.
DCHECK_IMPLIES(flags.is_toplevel(), !script.is_wrapped());
return flags;
}
// static
UnoptimizedCompileFlags UnoptimizedCompileFlags::ForScriptCompile(
Isolate* isolate, Script script) {
UnoptimizedCompileFlags flags(isolate, script.id());
flags.SetFlagsForFunctionFromScript(script);
flags.SetFlagsForToplevelCompile(
isolate->is_collecting_type_profile(), script.IsUserJavaScript(),
flags.outer_language_mode(), construct_repl_mode(script.is_repl_mode()));
if (script.is_wrapped()) {
flags.set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
}
return flags;
}
// static
UnoptimizedCompileFlags UnoptimizedCompileFlags::ForToplevelCompile(
Isolate* isolate, bool is_user_javascript, LanguageMode language_mode,
REPLMode repl_mode) {
UnoptimizedCompileFlags flags(isolate, isolate->GetNextScriptId());
flags.SetFlagsForToplevelCompile(isolate->is_collecting_type_profile(),
is_user_javascript, language_mode,
repl_mode);
LOG(isolate,
ScriptEvent(Logger::ScriptEventType::kReserveId, flags.script_id()));
return flags;
}
// static
UnoptimizedCompileFlags UnoptimizedCompileFlags::ForToplevelFunction(
const UnoptimizedCompileFlags toplevel_flags,
const FunctionLiteral* literal) {
DCHECK(toplevel_flags.is_toplevel());
DCHECK(!literal->is_toplevel());
// Replicate the toplevel flags, then setup the function-specific flags.
UnoptimizedCompileFlags flags = toplevel_flags;
flags.SetFlagsFromFunction(literal);
return flags;
}
// static
UnoptimizedCompileFlags UnoptimizedCompileFlags::ForTest(Isolate* isolate) {
return UnoptimizedCompileFlags(isolate, -1);
}
template <typename T>
void ParseInfo::SetFunctionInfo(T function) {
set_language_mode(function->language_mode());
void UnoptimizedCompileFlags::SetFlagsFromFunction(T function) {
set_outer_language_mode(function->language_mode());
set_function_kind(function->kind());
set_function_syntax_kind(function->syntax_kind());
set_requires_instance_members_initializer(
@ -83,55 +128,79 @@ void ParseInfo::SetFunctionInfo(T function) {
set_class_scope_has_private_brand(function->class_scope_has_private_brand());
set_has_static_private_methods_or_accessors(
function->has_static_private_methods_or_accessors());
set_toplevel(function->is_toplevel());
set_is_toplevel(function->is_toplevel());
set_is_oneshot_iife(function->is_oneshot_iife());
}
ParseInfo::ParseInfo(Isolate* isolate, SharedFunctionInfo shared)
: ParseInfo(isolate, isolate->allocator(),
Script::cast(shared.script()).id()) {
// Do not support re-parsing top-level function of a wrapped script.
DCHECK_IMPLIES(is_toplevel(), !Script::cast(shared.script()).is_wrapped());
void UnoptimizedCompileFlags::SetFlagsForToplevelCompile(
bool is_collecting_type_profile, bool is_user_javascript,
LanguageMode language_mode, REPLMode repl_mode) {
set_allow_lazy_parsing(true);
set_asm_wasm_broken(shared.is_asm_wasm_broken());
set_is_toplevel(true);
set_collect_type_profile(is_user_javascript && is_collecting_type_profile);
set_outer_language_mode(
stricter_language_mode(outer_language_mode(), language_mode));
set_is_repl_mode((repl_mode == REPLMode::kYes));
set_start_position(shared.StartPosition());
set_end_position(shared.EndPosition());
function_literal_id_ = shared.function_literal_id();
SetFunctionInfo(&shared);
Script script = Script::cast(shared.script());
SetFlagsForFunctionFromScript(script);
set_repl_mode(shared.is_repl_mode());
// CollectTypeProfile uses its own feedback slots. If we have existing
// FeedbackMetadata, we can only collect type profile if the feedback vector
// has the appropriate slots.
set_collect_type_profile(
isolate->is_collecting_type_profile() &&
(shared.HasFeedbackMetadata()
? shared.feedback_metadata().HasTypeProfileSlot()
: script.IsUserJavaScript()));
set_block_coverage_enabled(block_coverage_enabled() && is_user_javascript);
}
ParseInfo::ParseInfo(Isolate* isolate, Script script)
: ParseInfo(isolate, isolate->allocator(), script.id()) {
SetFlagsForToplevelCompileFromScript(isolate, script,
isolate->is_collecting_type_profile());
void UnoptimizedCompileFlags::SetFlagsForFunctionFromScript(Script script) {
DCHECK_EQ(script_id(), script.id());
set_is_eval(script.compilation_type() == Script::COMPILATION_TYPE_EVAL);
set_is_module(script.origin_options().IsModule());
DCHECK(!(is_eval() && is_module()));
set_block_coverage_enabled(block_coverage_enabled() &&
script.IsUserJavaScript());
}
ParseInfo::ParseInfo(AccountingAllocator* zone_allocator,
UnoptimizedCompileFlags flags)
: flags_(flags),
zone_(std::make_unique<Zone>(zone_allocator, ZONE_NAME)),
extension_(nullptr),
script_scope_(nullptr),
stack_limit_(0),
hash_seed_(0),
parameters_end_pos_(kNoSourcePosition),
max_function_literal_id_(kFunctionLiteralIdInvalid),
character_stream_(nullptr),
ast_value_factory_(nullptr),
ast_string_constants_(nullptr),
function_name_(nullptr),
runtime_call_stats_(nullptr),
source_range_map_(nullptr),
literal_(nullptr),
allow_eval_cache_(false),
contains_asm_module_(false),
language_mode_(flags.outer_language_mode()) {
if (flags.block_coverage_enabled()) {
AllocateSourceRangeMap();
}
}
ParseInfo::ParseInfo(Isolate* isolate, UnoptimizedCompileFlags flags)
: ParseInfo(isolate->allocator(), flags) {
set_hash_seed(HashSeed(isolate));
set_stack_limit(isolate->stack_guard()->real_climit());
set_runtime_call_stats(isolate->counters()->runtime_call_stats());
set_logger(isolate->logger());
set_ast_string_constants(isolate->ast_string_constants());
if (isolate->compiler_dispatcher()->IsEnabled()) {
parallel_tasks_.reset(new ParallelTasks(isolate->compiler_dispatcher()));
}
}
// static
std::unique_ptr<ParseInfo> ParseInfo::FromParent(
const ParseInfo* outer_parse_info, AccountingAllocator* zone_allocator,
const FunctionLiteral* literal, const AstRawString* function_name) {
// Can't use make_unique because the constructor is private.
std::unique_ptr<ParseInfo> result(
new ParseInfo(zone_allocator, outer_parse_info->script_id_));
const ParseInfo* outer_parse_info, const UnoptimizedCompileFlags flags,
AccountingAllocator* zone_allocator, const FunctionLiteral* literal,
const AstRawString* function_name) {
std::unique_ptr<ParseInfo> result(new ParseInfo(zone_allocator, flags));
// Replicate shared state of the outer_parse_info.
result->flags_ = outer_parse_info->flags_;
result->set_logger(outer_parse_info->logger());
result->set_ast_string_constants(outer_parse_info->ast_string_constants());
result->set_hash_seed(outer_parse_info->hash_seed());
@ -148,10 +217,6 @@ std::unique_ptr<ParseInfo> ParseInfo::FromParent(
// Setup function specific details.
DCHECK(!literal->is_toplevel());
result->set_function_name(cloned_function_name);
result->set_start_position(literal->start_position());
result->set_end_position(literal->end_position());
result->set_function_literal_id(literal->function_literal_id());
result->SetFunctionInfo(literal);
return result;
}
@ -161,14 +226,14 @@ ParseInfo::~ParseInfo() = default;
DeclarationScope* ParseInfo::scope() const { return literal()->scope(); }
template <typename LocalIsolate>
Handle<Script> ParseInfo::CreateScript(LocalIsolate* isolate,
Handle<String> source,
ScriptOriginOptions origin_options,
NativesFlag natives) {
Handle<Script> ParseInfo::CreateScript(
LocalIsolate* isolate, Handle<String> source,
MaybeHandle<FixedArray> maybe_wrapped_arguments,
ScriptOriginOptions origin_options, NativesFlag natives) {
// Create a script object describing the script to be compiled.
DCHECK_GE(script_id_, 0);
DCHECK_GE(flags().script_id(), 0);
Handle<Script> script =
isolate->factory()->NewScriptWithId(source, script_id_);
isolate->factory()->NewScriptWithId(source, flags().script_id());
if (isolate->NeedsSourcePositionsForProfiling()) {
Script::InitLineEnds(isolate, script);
}
@ -183,8 +248,12 @@ Handle<Script> ParseInfo::CreateScript(LocalIsolate* isolate,
break;
}
script->set_origin_options(origin_options);
script->set_is_repl_mode(is_repl_mode());
if (is_eval() && !is_wrapped_as_function()) {
script->set_is_repl_mode(flags().is_repl_mode());
DCHECK_EQ(is_wrapped_as_function(), !maybe_wrapped_arguments.is_null());
if (is_wrapped_as_function()) {
script->set_wrapped_arguments(*maybe_wrapped_arguments.ToHandleChecked());
} else if (flags().is_eval()) {
script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
}
@ -194,15 +263,15 @@ Handle<Script> ParseInfo::CreateScript(LocalIsolate* isolate,
}
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
Handle<Script> ParseInfo::CreateScript(Isolate* isolate,
Handle<String> source,
ScriptOriginOptions origin_options,
NativesFlag natives);
Handle<Script> ParseInfo::CreateScript(
Isolate* isolate, Handle<String> source,
MaybeHandle<FixedArray> maybe_wrapped_arguments,
ScriptOriginOptions origin_options, NativesFlag natives);
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
Handle<Script> ParseInfo::CreateScript(OffThreadIsolate* isolate,
Handle<String> source,
ScriptOriginOptions origin_options,
NativesFlag natives);
Handle<Script> ParseInfo::CreateScript(
OffThreadIsolate* isolate, Handle<String> source,
MaybeHandle<FixedArray> maybe_wrapped_arguments,
ScriptOriginOptions origin_options, NativesFlag natives);
AstValueFactory* ParseInfo::GetOrCreateAstValueFactory() {
if (!ast_value_factory_.get()) {
@ -213,7 +282,7 @@ AstValueFactory* ParseInfo::GetOrCreateAstValueFactory() {
}
void ParseInfo::AllocateSourceRangeMap() {
DCHECK(block_coverage_enabled());
DCHECK(flags().block_coverage_enabled());
DCHECK_NULL(source_range_map());
set_source_range_map(new (zone()) SourceRangeMap(zone()));
}
@ -226,69 +295,28 @@ void ParseInfo::set_character_stream(
character_stream_.swap(character_stream);
}
void ParseInfo::SetFlagsForToplevelCompile(bool is_collecting_type_profile,
bool is_user_javascript,
LanguageMode language_mode,
REPLMode repl_mode) {
set_allow_lazy_parsing();
set_toplevel();
set_collect_type_profile(is_user_javascript && is_collecting_type_profile);
set_language_mode(
stricter_language_mode(this->language_mode(), language_mode));
set_repl_mode(repl_mode == REPLMode::kYes);
if (V8_UNLIKELY(is_user_javascript && block_coverage_enabled())) {
AllocateSourceRangeMap();
}
}
template <typename LocalIsolate>
void ParseInfo::SetFlagsForToplevelCompileFromScript(
LocalIsolate* isolate, Script script, bool is_collecting_type_profile) {
SetFlagsForFunctionFromScript(script);
SetFlagsForToplevelCompile(is_collecting_type_profile,
script.IsUserJavaScript(), language_mode(),
construct_repl_mode(script.is_repl_mode()));
if (script.is_wrapped()) {
set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
}
}
void ParseInfo::CheckFlagsForToplevelCompileFromScript(
Script script, bool is_collecting_type_profile) {
CheckFlagsForFunctionFromScript(script);
DCHECK(allow_lazy_parsing());
DCHECK(is_toplevel());
DCHECK_EQ(collect_type_profile(),
DCHECK(flags().allow_lazy_parsing());
DCHECK(flags().is_toplevel());
DCHECK_EQ(flags().collect_type_profile(),
is_collecting_type_profile && script.IsUserJavaScript());
DCHECK_EQ(is_repl_mode(), script.is_repl_mode());
DCHECK_EQ(flags().is_repl_mode(), script.is_repl_mode());
if (script.is_wrapped()) {
DCHECK_EQ(function_syntax_kind(), FunctionSyntaxKind::kWrapped);
}
}
void ParseInfo::SetFlagsForFunctionFromScript(Script script) {
DCHECK_EQ(script_id_, script.id());
set_eval(script.compilation_type() == Script::COMPILATION_TYPE_EVAL);
set_module(script.origin_options().IsModule());
DCHECK(!(is_eval() && is_module()));
if (block_coverage_enabled() && script.IsUserJavaScript()) {
AllocateSourceRangeMap();
DCHECK_EQ(flags().function_syntax_kind(), FunctionSyntaxKind::kWrapped);
}
}
void ParseInfo::CheckFlagsForFunctionFromScript(Script script) {
DCHECK_EQ(script_id_, script.id());
// We set "is_eval" for wrapped functions to get an outer declaration scope.
DCHECK_EQ(flags().script_id(), script.id());
// We set "is_eval" for wrapped scripts to get an outer declaration scope.
// This is a bit hacky, but ok since we can't be both eval and wrapped.
DCHECK_EQ(is_eval() && !is_wrapped_as_function(),
DCHECK_EQ(flags().is_eval() && !script.is_wrapped(),
script.compilation_type() == Script::COMPILATION_TYPE_EVAL);
DCHECK_EQ(is_module(), script.origin_options().IsModule());
DCHECK_IMPLIES(block_coverage_enabled() && script.IsUserJavaScript(),
DCHECK_EQ(flags().is_module(), script.origin_options().IsModule());
DCHECK_IMPLIES(flags().block_coverage_enabled() && script.IsUserJavaScript(),
source_range_map() != nullptr);
}

View File

@ -10,6 +10,7 @@
#include <vector>
#include "include/v8.h"
#include "src/base/bit-field.h"
#include "src/base/export-template.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
@ -38,24 +39,132 @@ class SourceRangeMap;
class Utf16CharacterStream;
class Zone;
// The flags for a parse + unoptimized compile operation.
#define FLAG_FIELDS(V, _) \
V(is_toplevel, bool, 1, _) \
V(is_eager, bool, 1, _) \
V(is_eval, bool, 1, _) \
V(outer_language_mode, LanguageMode, 1, _) \
V(parse_restriction, ParseRestriction, 1, _) \
V(is_module, bool, 1, _) \
V(allow_lazy_parsing, bool, 1, _) \
V(is_lazy_compile, bool, 1, _) \
V(collect_type_profile, bool, 1, _) \
V(coverage_enabled, bool, 1, _) \
V(block_coverage_enabled, bool, 1, _) \
V(is_asm_wasm_broken, bool, 1, _) \
V(class_scope_has_private_brand, bool, 1, _) \
V(requires_instance_members_initializer, bool, 1, _) \
V(has_static_private_methods_or_accessors, bool, 1, _) \
V(might_always_opt, bool, 1, _) \
V(allow_natives_syntax, bool, 1, _) \
V(allow_lazy_compile, bool, 1, _) \
V(allow_harmony_dynamic_import, bool, 1, _) \
V(allow_harmony_import_meta, bool, 1, _) \
V(allow_harmony_private_methods, bool, 1, _) \
V(is_oneshot_iife, bool, 1, _) \
V(collect_source_positions, bool, 1, _) \
V(allow_harmony_top_level_await, bool, 1, _) \
V(is_repl_mode, bool, 1, _)
class V8_EXPORT_PRIVATE UnoptimizedCompileFlags {
public:
// Set-up flags for a toplevel compilation.
static UnoptimizedCompileFlags ForToplevelCompile(Isolate* isolate,
bool is_user_javascript,
LanguageMode language_mode,
REPLMode repl_mode);
// Set-up flags for a compiling a particular function (either a lazy compile
// or a recompile).
static UnoptimizedCompileFlags ForFunctionCompile(Isolate* isolate,
SharedFunctionInfo shared);
// Set-up flags for a full compilation of a given script.
static UnoptimizedCompileFlags ForScriptCompile(Isolate* isolate,
Script script);
// Set-up flags for a parallel toplevel function compilation, based on the
// flags of an existing toplevel compilation.
static UnoptimizedCompileFlags ForToplevelFunction(
const UnoptimizedCompileFlags toplevel_flags,
const FunctionLiteral* literal);
// Create flags for a test.
static UnoptimizedCompileFlags ForTest(Isolate* isolate);
#define FLAG_GET_SET(NAME, TYPE, SIZE, _) \
TYPE NAME() const { return BitFields::NAME::decode(flags_); } \
UnoptimizedCompileFlags& set_##NAME(TYPE value) { \
flags_ = BitFields::NAME::update(flags_, value); \
return *this; \
}
FLAG_FIELDS(FLAG_GET_SET, _)
int script_id() const { return script_id_; }
UnoptimizedCompileFlags& set_script_id(int value) {
script_id_ = value;
return *this;
}
FunctionKind function_kind() const { return function_kind_; }
UnoptimizedCompileFlags& set_function_kind(FunctionKind value) {
function_kind_ = value;
return *this;
}
FunctionSyntaxKind function_syntax_kind() const {
return function_syntax_kind_;
}
UnoptimizedCompileFlags& set_function_syntax_kind(FunctionSyntaxKind value) {
function_syntax_kind_ = value;
return *this;
}
private:
struct BitFields {
DEFINE_BIT_FIELDS(FLAG_FIELDS)
};
UnoptimizedCompileFlags(Isolate* isolate, int script_id);
// Set function info flags based on those in either FunctionLiteral or
// SharedFunctionInfo |function|
template <typename T>
void SetFlagsFromFunction(T function);
void SetFlagsForToplevelCompile(bool is_collecting_type_profile,
bool is_user_javascript,
LanguageMode language_mode,
REPLMode repl_mode);
void SetFlagsForFunctionFromScript(Script script);
uint32_t flags_;
int script_id_;
FunctionKind function_kind_;
FunctionSyntaxKind function_syntax_kind_;
};
#undef FLAG_FIELDS
// A container for the inputs, configuration options, and outputs of parsing.
class V8_EXPORT_PRIVATE ParseInfo {
public:
explicit ParseInfo(Isolate*);
ParseInfo(Isolate* isolate, Script script);
ParseInfo(Isolate* isolate, SharedFunctionInfo shared);
ParseInfo(Isolate*, const UnoptimizedCompileFlags flags);
// Creates a new parse info based on parent top-level |outer_parse_info| for
// function |literal|.
static std::unique_ptr<ParseInfo> FromParent(
const ParseInfo* outer_parse_info, AccountingAllocator* zone_allocator,
const FunctionLiteral* literal, const AstRawString* function_name);
const ParseInfo* outer_parse_info, const UnoptimizedCompileFlags flags,
AccountingAllocator* zone_allocator, const FunctionLiteral* literal,
const AstRawString* function_name);
~ParseInfo();
template <typename LocalIsolate>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
Handle<Script> CreateScript(LocalIsolate* isolate, Handle<String> source,
MaybeHandle<FixedArray> maybe_wrapped_arguments,
ScriptOriginOptions origin_options,
NativesFlag natives = NOT_NATIVES_CODE);
@ -65,65 +174,15 @@ class V8_EXPORT_PRIVATE ParseInfo {
Zone* zone() const { return zone_.get(); }
// Convenience accessor methods for flags.
#define FLAG_ACCESSOR(flag, getter, setter) \
bool getter() const { return GetFlag(flag); } \
void setter() { SetFlag(flag); } \
void setter(bool val) { SetFlag(flag, val); }
const UnoptimizedCompileFlags& flags() const { return flags_; }
FLAG_ACCESSOR(kToplevel, is_toplevel, set_toplevel)
FLAG_ACCESSOR(kEager, is_eager, set_eager)
FLAG_ACCESSOR(kEval, is_eval, set_eval)
FLAG_ACCESSOR(kStrictMode, is_strict_mode, set_strict_mode)
FLAG_ACCESSOR(kModule, is_module, set_module)
FLAG_ACCESSOR(kAllowLazyParsing, allow_lazy_parsing, set_allow_lazy_parsing)
FLAG_ACCESSOR(kLazyCompile, lazy_compile, set_lazy_compile)
FLAG_ACCESSOR(kCollectTypeProfile, collect_type_profile,
set_collect_type_profile)
FLAG_ACCESSOR(kIsAsmWasmBroken, is_asm_wasm_broken, set_asm_wasm_broken)
FLAG_ACCESSOR(kContainsAsmModule, contains_asm_module,
set_contains_asm_module)
FLAG_ACCESSOR(kCoverageEnabled, coverage_enabled, set_coverage_enabled)
FLAG_ACCESSOR(kBlockCoverageEnabled, block_coverage_enabled,
set_block_coverage_enabled)
FLAG_ACCESSOR(kAllowEvalCache, allow_eval_cache, set_allow_eval_cache)
FLAG_ACCESSOR(kRequiresInstanceMembersInitializer,
requires_instance_members_initializer,
set_requires_instance_members_initializer)
FLAG_ACCESSOR(kClassScopeHasPrivateBrand, class_scope_has_private_brand,
set_class_scope_has_private_brand)
FLAG_ACCESSOR(kHasStaticPrivateMethodsOrAccessors,
has_static_private_methods_or_accessors,
set_has_static_private_methods_or_accessors)
FLAG_ACCESSOR(kMightAlwaysOpt, might_always_opt, set_might_always_opt)
FLAG_ACCESSOR(kAllowNativeSyntax, allow_natives_syntax,
set_allow_natives_syntax)
FLAG_ACCESSOR(kAllowLazyCompile, allow_lazy_compile, set_allow_lazy_compile)
FLAG_ACCESSOR(kAllowNativeSyntax, allow_native_syntax,
set_allow_native_syntax)
FLAG_ACCESSOR(kAllowHarmonyDynamicImport, allow_harmony_dynamic_import,
set_allow_harmony_dynamic_import)
FLAG_ACCESSOR(kAllowHarmonyImportMeta, allow_harmony_import_meta,
set_allow_harmony_import_meta)
FLAG_ACCESSOR(kAllowHarmonyPrivateMethods, allow_harmony_private_methods,
set_allow_harmony_private_methods)
FLAG_ACCESSOR(kIsOneshotIIFE, is_oneshot_iife, set_is_oneshot_iife)
FLAG_ACCESSOR(kCollectSourcePositions, collect_source_positions,
set_collect_source_positions)
FLAG_ACCESSOR(kAllowHarmonyTopLevelAwait, allow_harmony_top_level_await,
set_allow_harmony_top_level_await)
FLAG_ACCESSOR(kREPLMode, is_repl_mode, set_repl_mode)
#undef FLAG_ACCESSOR
void set_parse_restriction(ParseRestriction restriction) {
SetFlag(kParseRestriction, restriction != NO_PARSE_RESTRICTION);
}
ParseRestriction parse_restriction() const {
return GetFlag(kParseRestriction) ? ONLY_SINGLE_FUNCTION_LITERAL
: NO_PARSE_RESTRICTION;
}
// Accessor methods for output flags.
bool allow_eval_cache() const { return allow_eval_cache_; }
void set_allow_eval_cache(bool value) { allow_eval_cache_ = value; }
bool contains_asm_module() const { return contains_asm_module_; }
void set_contains_asm_module(bool value) { contains_asm_module_ = value; }
LanguageMode language_mode() const { return language_mode_; }
void set_language_mode(LanguageMode value) { language_mode_ = value; }
Utf16CharacterStream* character_stream() const {
return character_stream_.get();
@ -168,38 +227,13 @@ class V8_EXPORT_PRIVATE ParseInfo {
uint64_t hash_seed() const { return hash_seed_; }
void set_hash_seed(uint64_t hash_seed) { hash_seed_ = hash_seed; }
int start_position() const { return start_position_; }
void set_start_position(int start_position) {
start_position_ = start_position;
}
int end_position() const { return end_position_; }
void set_end_position(int end_position) { end_position_ = end_position; }
int parameters_end_pos() const { return parameters_end_pos_; }
void set_parameters_end_pos(int parameters_end_pos) {
parameters_end_pos_ = parameters_end_pos;
}
int function_literal_id() const { return function_literal_id_; }
void set_function_literal_id(int function_literal_id) {
function_literal_id_ = function_literal_id;
}
FunctionKind function_kind() const { return function_kind_; }
void set_function_kind(FunctionKind function_kind) {
function_kind_ = function_kind;
}
FunctionSyntaxKind function_syntax_kind() const {
return function_syntax_kind_;
}
void set_function_syntax_kind(FunctionSyntaxKind function_syntax_kind) {
function_syntax_kind_ = function_syntax_kind;
}
bool is_wrapped_as_function() const {
return function_syntax_kind() == FunctionSyntaxKind::kWrapped;
return flags().function_syntax_kind() == FunctionSyntaxKind::kWrapped;
}
int max_function_literal_id() const { return max_function_literal_id_; }
@ -257,93 +291,22 @@ class V8_EXPORT_PRIVATE ParseInfo {
ParallelTasks* parallel_tasks() { return parallel_tasks_.get(); }
void SetFlagsForToplevelCompile(bool is_collecting_type_profile,
bool is_user_javascript,
LanguageMode language_mode,
REPLMode repl_mode);
void CheckFlagsForFunctionFromScript(Script script);
int script_id() const { return script_id_; }
//--------------------------------------------------------------------------
LanguageMode language_mode() const {
return construct_language_mode(is_strict_mode());
}
void set_language_mode(LanguageMode language_mode) {
STATIC_ASSERT(LanguageModeSize == 2);
set_strict_mode(is_strict(language_mode));
}
private:
ParseInfo(AccountingAllocator* zone_allocator, int script_id);
ParseInfo(Isolate*, AccountingAllocator* zone_allocator, int script_id);
ParseInfo(AccountingAllocator* zone_allocator, UnoptimizedCompileFlags flags);
void SetFlagsForFunctionFromScript(Script script);
template <typename LocalIsolate>
void SetFlagsForToplevelCompileFromScript(LocalIsolate* isolate,
Script script,
bool is_collecting_type_profile);
void CheckFlagsForToplevelCompileFromScript(Script script,
bool is_collecting_type_profile);
// Set function info flags based on those in either FunctionLiteral or
// SharedFunctionInfo |function|
template <typename T>
void SetFunctionInfo(T function);
// Various configuration flags for parsing.
enum Flag : uint32_t {
// ---------- Input flags ---------------------------
kToplevel = 1u << 0,
kEager = 1u << 1,
kEval = 1u << 2,
kStrictMode = 1u << 3,
kNative = 1u << 4,
kParseRestriction = 1u << 5,
kModule = 1u << 6,
kAllowLazyParsing = 1u << 7,
kLazyCompile = 1u << 8,
kCollectTypeProfile = 1u << 9,
kCoverageEnabled = 1u << 10,
kBlockCoverageEnabled = 1u << 11,
kIsAsmWasmBroken = 1u << 12,
kAllowEvalCache = 1u << 13,
kRequiresInstanceMembersInitializer = 1u << 14,
kContainsAsmModule = 1u << 15,
kMightAlwaysOpt = 1u << 16,
kAllowLazyCompile = 1u << 17,
kAllowNativeSyntax = 1u << 18,
kAllowHarmonyPublicFields = 1u << 19,
kAllowHarmonyStaticFields = 1u << 20,
kAllowHarmonyDynamicImport = 1u << 21,
kAllowHarmonyImportMeta = 1u << 22,
kAllowHarmonyOptionalChaining = 1u << 23,
kHasStaticPrivateMethodsOrAccessors = 1u << 24,
kAllowHarmonyPrivateMethods = 1u << 25,
kIsOneshotIIFE = 1u << 26,
kCollectSourcePositions = 1u << 27,
kAllowHarmonyNullish = 1u << 28,
kAllowHarmonyTopLevelAwait = 1u << 29,
kREPLMode = 1u << 30,
kClassScopeHasPrivateBrand = 1u << 31,
};
//------------- Inputs to parsing and scope analysis -----------------------
const UnoptimizedCompileFlags flags_;
std::unique_ptr<Zone> zone_;
uint32_t flags_;
v8::Extension* extension_;
DeclarationScope* script_scope_;
uintptr_t stack_limit_;
uint64_t hash_seed_;
FunctionKind function_kind_;
FunctionSyntaxKind function_syntax_kind_;
int script_id_;
int start_position_;
int end_position_;
int parameters_end_pos_;
int function_literal_id_;
int max_function_literal_id_;
//----------- Inputs+Outputs of parsing and scope analysis -----------------
@ -360,10 +323,9 @@ class V8_EXPORT_PRIVATE ParseInfo {
//----------- Output of parsing and scope analysis ------------------------
FunctionLiteral* literal_;
PendingCompilationErrorHandler pending_error_handler_;
void SetFlag(Flag f) { flags_ |= f; }
void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; }
bool GetFlag(Flag f) const { return (flags_ & f) != 0; }
bool allow_eval_cache_ : 1;
bool contains_asm_module_ : 1;
LanguageMode language_mode_ : 1;
};
} // namespace internal

View File

@ -23,6 +23,7 @@
#include "src/objects/function-kind.h"
#include "src/parsing/expression-scope.h"
#include "src/parsing/func-name-inferrer.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/scanner.h"
#include "src/parsing/token.h"
#include "src/utils/pointer-with-payload.h"
@ -241,7 +242,7 @@ class ParserBase {
v8::Extension* extension, AstValueFactory* ast_value_factory,
PendingCompilationErrorHandler* pending_error_handler,
RuntimeCallStats* runtime_call_stats, Logger* logger,
int script_id, bool parsing_module, bool parsing_on_main_thread)
UnoptimizedCompileFlags flags, bool parsing_on_main_thread)
: scope_(nullptr),
original_scope_(nullptr),
function_state_(nullptr),
@ -252,37 +253,22 @@ class ParserBase {
runtime_call_stats_(runtime_call_stats),
logger_(logger),
parsing_on_main_thread_(parsing_on_main_thread),
parsing_module_(parsing_module),
stack_limit_(stack_limit),
pending_error_handler_(pending_error_handler),
zone_(zone),
expression_scope_(nullptr),
scanner_(scanner),
flags_(flags),
function_literal_id_(0),
script_id_(script_id),
default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile),
allow_natives_(false),
allow_harmony_dynamic_import_(false),
allow_harmony_import_meta_(false),
allow_harmony_private_methods_(false),
allow_harmony_top_level_await_(false),
allow_eval_cache_(true) {
default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile) {
pointer_buffer_.reserve(32);
variable_buffer_.reserve(32);
}
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
void set_allow_##name(bool allow) { allow_##name##_ = allow; }
const UnoptimizedCompileFlags& flags() const { return flags_; }
ALLOW_ACCESSORS(natives)
ALLOW_ACCESSORS(harmony_dynamic_import)
ALLOW_ACCESSORS(harmony_import_meta)
ALLOW_ACCESSORS(harmony_private_methods)
ALLOW_ACCESSORS(harmony_top_level_await)
ALLOW_ACCESSORS(eval_cache)
#undef ALLOW_ACCESSORS
bool allow_eval_cache() const { return allow_eval_cache_; }
void set_allow_eval_cache(bool allow) { allow_eval_cache_ = allow; }
V8_INLINE bool has_error() const { return scanner()->has_parser_error(); }
@ -869,8 +855,6 @@ class ParserBase {
// Any further calls to Next or peek will return the illegal token.
if (GetCurrentStackPosition() < stack_limit_) set_stack_overflow();
}
int script_id() { return script_id_; }
void set_script_id(int id) { script_id_ = id; }
V8_INLINE Token::Value peek() { return scanner()->peek(); }
@ -1061,7 +1045,7 @@ class ParserBase {
return IsResumableFunction(function_state_->kind());
}
bool is_await_allowed() const {
return is_async_function() || (allow_harmony_top_level_await() &&
return is_async_function() || (flags().allow_harmony_top_level_await() &&
IsModule(function_state_->kind()));
}
const PendingCompilationErrorHandler* pending_error_handler() const {
@ -1516,7 +1500,6 @@ class ParserBase {
RuntimeCallStats* runtime_call_stats_;
internal::Logger* logger_;
bool parsing_on_main_thread_;
const bool parsing_module_;
uintptr_t stack_limit_;
PendingCompilationErrorHandler* pending_error_handler_;
@ -1531,8 +1514,8 @@ class ParserBase {
Scanner* scanner_;
const UnoptimizedCompileFlags flags_;
int function_literal_id_;
int script_id_;
FunctionLiteral::EagerCompileHint default_eager_compile_hint_;
@ -1571,12 +1554,7 @@ class ParserBase {
bool accept_IN_ = true;
bool allow_natives_;
bool allow_harmony_dynamic_import_;
bool allow_harmony_import_meta_;
bool allow_harmony_private_methods_;
bool allow_harmony_top_level_await_;
bool allow_eval_cache_;
bool allow_eval_cache_ = true;
};
template <typename Impl>
@ -1626,7 +1604,7 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(Token::Value next) {
}
if (!Token::IsValidIdentifier(next, language_mode(), is_generator(),
parsing_module_ || is_async_function())) {
flags().is_module() || is_async_function())) {
ReportUnexpectedToken(next);
return impl()->EmptyIdentifierString();
}
@ -1650,7 +1628,7 @@ typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifier(
if (!Token::IsValidIdentifier(
next, language_mode(), IsGeneratorFunction(function_kind),
parsing_module_ || IsAsyncFunction(function_kind))) {
flags().is_module() || IsAsyncFunction(function_kind))) {
ReportUnexpectedToken(next);
return impl()->EmptyIdentifierString();
}
@ -1861,7 +1839,7 @@ ParserBase<Impl>::ParsePrimaryExpression() {
return ParseSuperExpression(is_new);
}
case Token::IMPORT:
if (!allow_harmony_dynamic_import()) break;
if (!flags().allow_harmony_dynamic_import()) break;
return ParseImportExpressions();
case Token::LBRACK:
@ -1924,7 +1902,7 @@ ParserBase<Impl>::ParsePrimaryExpression() {
return ParseTemplateLiteral(impl()->NullExpression(), beg_pos, false);
case Token::MOD:
if (allow_natives() || extension_ != nullptr) {
if (flags().allow_natives_syntax() || extension_ != nullptr) {
return ParseV8Intrinsic();
}
break;
@ -2170,7 +2148,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty(
prop_info->kind = ParsePropertyKind::kNotSet;
return impl()->FailureExpression();
}
if (V8_UNLIKELY(!allow_harmony_private_methods() &&
if (V8_UNLIKELY(!flags().allow_harmony_private_methods() &&
(IsAccessor(prop_info->kind) ||
prop_info->kind == ParsePropertyKind::kMethod))) {
ReportUnexpectedToken(Next());
@ -2517,8 +2495,9 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info,
// IdentifierReference Initializer?
DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
if (!Token::IsValidIdentifier(name_token, language_mode(), is_generator(),
parsing_module_ || is_async_function())) {
if (!Token::IsValidIdentifier(
name_token, language_mode(), is_generator(),
flags().is_module() || is_async_function())) {
ReportUnexpectedToken(Next());
return impl()->NullLiteralProperty();
}
@ -3432,8 +3411,10 @@ ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression() {
if (peek() == Token::SUPER) {
const bool is_new = true;
result = ParseSuperExpression(is_new);
} else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT &&
(!allow_harmony_import_meta() || PeekAhead() == Token::LPAREN)) {
} else if (flags().allow_harmony_dynamic_import() &&
peek() == Token::IMPORT &&
(!flags().allow_harmony_import_meta() ||
PeekAhead() == Token::LPAREN)) {
impl()->ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kImportCallNotNewExpression);
return impl()->FailureExpression();
@ -3531,14 +3512,14 @@ ParserBase<Impl>::ParseMemberExpression() {
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseImportExpressions() {
DCHECK(allow_harmony_dynamic_import());
DCHECK(flags().allow_harmony_dynamic_import());
Consume(Token::IMPORT);
int pos = position();
if (allow_harmony_import_meta() && Check(Token::PERIOD)) {
if (flags().allow_harmony_import_meta() && Check(Token::PERIOD)) {
ExpectContextualKeyword(ast_value_factory()->meta_string(), "import.meta",
pos);
if (!parsing_module_) {
if (!flags().is_module()) {
impl()->ReportMessageAt(scanner()->location(),
MessageTemplate::kImportMetaOutsideModule);
return impl()->FailureExpression();
@ -3548,7 +3529,7 @@ ParserBase<Impl>::ParseImportExpressions() {
}
if (V8_UNLIKELY(peek() != Token::LPAREN)) {
if (!parsing_module_) {
if (!flags().is_module()) {
impl()->ReportMessageAt(scanner()->location(),
MessageTemplate::kImportOutsideModule);
} else {
@ -4470,8 +4451,9 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
const char* event_name =
is_lazy_top_level_function ? "preparse-no-resolution" : "parse";
const char* name = "arrow function";
logger_->FunctionEvent(event_name, script_id(), ms, scope->start_position(),
scope->end_position(), name, strlen(name));
logger_->FunctionEvent(event_name, flags().script_id(), ms,
scope->start_position(), scope->end_position(), name,
strlen(name));
}
return function_literal;

View File

@ -15,6 +15,7 @@
#include "src/base/overflowing-math.h"
#include "src/base/platform/platform.h"
#include "src/codegen/bailout-reason.h"
#include "src/common/globals.h"
#include "src/common/message-template.h"
#include "src/compiler-dispatcher/compiler-dispatcher.h"
#include "src/logging/counters.h"
@ -416,13 +417,12 @@ Expression* Parser::NewV8RuntimeFunctionForFuzzing(
}
Parser::Parser(ParseInfo* info)
: ParserBase<Parser>(info->zone(), &scanner_, info->stack_limit(),
info->extension(), info->GetOrCreateAstValueFactory(),
info->pending_error_handler(),
info->runtime_call_stats(), info->logger(),
info->script_id(), info->is_module(), true),
: ParserBase<Parser>(
info->zone(), &scanner_, info->stack_limit(), info->extension(),
info->GetOrCreateAstValueFactory(), info->pending_error_handler(),
info->runtime_call_stats(), info->logger(), info->flags(), true),
info_(info),
scanner_(info->character_stream(), info->is_module()),
scanner_(info->character_stream(), flags()),
preparser_zone_(info->zone()->allocator(), ZONE_NAME),
reusable_preparser_(nullptr),
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
@ -445,18 +445,13 @@ Parser::Parser(ParseInfo* info)
// of functions without an outer context when setting a breakpoint through
// Debug::FindSharedFunctionInfoInScript
// We also compile eagerly for kProduceExhaustiveCodeCache.
bool can_compile_lazily = info->allow_lazy_compile() && !info->is_eager();
bool can_compile_lazily = flags().allow_lazy_compile() && !flags().is_eager();
set_default_eager_compile_hint(can_compile_lazily
? FunctionLiteral::kShouldLazyCompile
: FunctionLiteral::kShouldEagerCompile);
allow_lazy_ = info->allow_lazy_compile() && info->allow_lazy_parsing() &&
allow_lazy_ = flags().allow_lazy_compile() && flags().allow_lazy_parsing() &&
info->extension() == nullptr && can_compile_lazily;
set_allow_natives(info->allow_natives_syntax());
set_allow_harmony_dynamic_import(info->allow_harmony_dynamic_import());
set_allow_harmony_import_meta(info->allow_harmony_import_meta());
set_allow_harmony_private_methods(info->allow_harmony_private_methods());
set_allow_harmony_top_level_await(info->allow_harmony_top_level_await());
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
@ -467,7 +462,7 @@ void Parser::InitializeEmptyScopeChain(ParseInfo* info) {
DCHECK_NULL(original_scope_);
DCHECK_NULL(info->script_scope());
DeclarationScope* script_scope =
NewScriptScope(info->is_repl_mode() ? REPLMode::kYes : REPLMode::kNo);
NewScriptScope(flags().is_repl_mode() ? REPLMode::kYes : REPLMode::kNo);
info->set_script_scope(script_scope);
original_scope_ = script_scope;
}
@ -483,7 +478,7 @@ void Parser::DeserializeScopeChain(
original_scope_ = Scope::DeserializeScopeChain(
isolate, zone(), *outer_scope_info, info->script_scope(),
ast_value_factory(), mode);
if (info->is_eval() || IsArrowFunction(info->function_kind())) {
if (flags().is_eval() || IsArrowFunction(flags().function_kind())) {
original_scope_->GetReceiverScope()->DeserializeReceiver(
ast_value_factory());
}
@ -518,13 +513,13 @@ FunctionLiteral* Parser::ParseProgram(
MaybeHandle<ScopeInfo> maybe_outer_scope_info) {
// TODO(bmeurer): We temporarily need to pass allow_nesting = true here,
// see comment for HistogramTimerScope class.
DCHECK_EQ(script->id(), script_id());
DCHECK_EQ(script->id(), flags().script_id());
// It's OK to use the Isolate & counters here, since this function is only
// called in the main thread.
DCHECK(parsing_on_main_thread_);
RuntimeCallTimerScope runtime_timer(
runtime_call_stats_, info->is_eval()
runtime_call_stats_, flags().is_eval()
? RuntimeCallCounterId::kParseEval
: RuntimeCallCounterId::kParseProgram);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseProgram");
@ -552,12 +547,13 @@ FunctionLiteral* Parser::ParseProgram(
const char* event_name = "parse-eval";
int start = -1;
int end = -1;
if (!info->is_eval()) {
if (!flags().is_eval()) {
event_name = "parse-script";
start = 0;
end = String::cast(script->source()).length();
}
LOG(isolate, FunctionEvent(event_name, script_id(), ms, start, end, "", 0));
LOG(isolate,
FunctionEvent(event_name, flags().script_id(), ms, start, end, "", 0));
}
return result;
}
@ -572,16 +568,14 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
ParsingModeScope mode(this, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY);
ResetFunctionLiteralId();
DCHECK(info->function_literal_id() == kFunctionLiteralIdTopLevel ||
info->function_literal_id() == kFunctionLiteralIdInvalid);
FunctionLiteral* result = nullptr;
{
Scope* outer = original_scope_;
DCHECK_NOT_NULL(outer);
if (info->is_eval()) {
if (flags().is_eval()) {
outer = NewEvalScope(outer);
} else if (parsing_module_) {
} else if (flags().is_module()) {
DCHECK_EQ(outer, info->script_scope());
outer = NewModuleScope(info->script_scope());
}
@ -592,15 +586,15 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
FunctionState function_state(&function_state_, &scope_, scope);
ScopedPtrList<Statement> body(pointer_buffer());
int beg_pos = scanner()->location().beg_pos;
if (parsing_module_) {
DCHECK(info->is_module());
if (flags().is_module()) {
DCHECK(flags().is_module());
PrepareGeneratorVariables();
Expression* initial_yield =
BuildInitialYield(kNoSourcePosition, kGeneratorFunction);
body.Add(
factory()->NewExpressionStatement(initial_yield, kNoSourcePosition));
if (allow_harmony_top_level_await()) {
if (flags().allow_harmony_top_level_await()) {
// First parse statements into a buffer. Then, if there was a
// top level await, create an inner block and rewrite the body of the
// module as an async function. Otherwise merge the statements back
@ -634,7 +628,7 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
} else if (info->is_wrapped_as_function()) {
DCHECK(parsing_on_main_thread_);
ParseWrapped(isolate, info, &body, scope, zone());
} else if (info->is_repl_mode()) {
} else if (flags().is_repl_mode()) {
ParseREPLProgram(info, &body, scope);
} else {
// Don't count the mode in the use counters--give the program a chance
@ -659,13 +653,13 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
}
// Internalize the ast strings in the case of eval so we can check for
// conflicting var declarations with outer scope-info-backed scopes.
if (info->is_eval()) {
if (flags().is_eval()) {
DCHECK(parsing_on_main_thread_);
info->ast_value_factory()->Internalize(isolate);
}
CheckConflictingVarDeclarations(scope);
if (info->parse_restriction() == ONLY_SINGLE_FUNCTION_LITERAL) {
if (flags().parse_restriction() == ONLY_SINGLE_FUNCTION_LITERAL) {
if (body.length() != 1 || !body.at(0)->IsExpressionStatement() ||
!body.at(0)
->AsExpressionStatement()
@ -743,7 +737,7 @@ void Parser::ParseREPLProgram(ParseInfo* info, ScopedPtrList<Statement>* body,
// completion value of the script is obtained by manually invoking
// the {Rewriter} which will return a VariableProxy referencing the
// result.
DCHECK(info->is_repl_mode());
DCHECK(flags().is_repl_mode());
this->scope()->SetLanguageMode(info->language_mode());
PrepareGeneratorVariables();
@ -813,6 +807,10 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
Script::cast(shared_info->script()).wrapped_arguments(), isolate);
}
int start_position = shared_info->StartPosition();
int end_position = shared_info->EndPosition();
int function_literal_id = shared_info->function_literal_id();
// Initialize parser state.
Handle<String> name(shared_info->Name(), isolate);
info->set_function_name(ast_value_factory()->GetString(name));
@ -825,9 +823,11 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
// function is in heritage position. Otherwise the function scope's skip bit
// will be correctly inherited from the outer scope.
ClassScope::HeritageParsingScope heritage(original_scope_->AsClassScope());
result = DoParseFunction(isolate, info, info->function_name());
result = DoParseFunction(isolate, info, start_position, end_position,
function_literal_id, info->function_name());
} else {
result = DoParseFunction(isolate, info, info->function_name());
result = DoParseFunction(isolate, info, start_position, end_position,
function_literal_id, info->function_name());
}
MaybeResetCharacterStream(info, result);
MaybeProcessSourceRanges(info, result, stack_limit_);
@ -843,7 +843,7 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
DeclarationScope* function_scope = result->scope();
std::unique_ptr<char[]> function_name = result->GetDebugName();
LOG(isolate,
FunctionEvent("parse-function", script_id(), ms,
FunctionEvent("parse-function", flags().script_id(), ms,
function_scope->start_position(),
function_scope->end_position(), function_name.get(),
strlen(function_name.get())));
@ -852,6 +852,8 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
}
FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
int start_position, int end_position,
int function_literal_id,
const AstRawString* raw_name) {
DCHECK_EQ(parsing_on_main_thread_, isolate != nullptr);
DCHECK_NOT_NULL(raw_name);
@ -861,8 +863,8 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
fni_.PushEnclosingName(raw_name);
ResetFunctionLiteralId();
DCHECK_LT(0, info->function_literal_id());
SkipFunctionLiterals(info->function_literal_id() - 1);
DCHECK_LT(0, function_literal_id);
SkipFunctionLiterals(function_literal_id - 1);
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
@ -878,10 +880,10 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
BlockState block_state(&scope_, outer);
DCHECK(is_sloppy(outer->language_mode()) ||
is_strict(info->language_mode()));
FunctionKind kind = info->function_kind();
DCHECK_IMPLIES(
IsConciseMethod(kind) || IsAccessorFunction(kind),
info->function_syntax_kind() == FunctionSyntaxKind::kAccessorOrMethod);
FunctionKind kind = flags().function_kind();
DCHECK_IMPLIES(IsConciseMethod(kind) || IsAccessorFunction(kind),
flags().function_syntax_kind() ==
FunctionSyntaxKind::kAccessorOrMethod);
if (IsArrowFunction(kind)) {
if (IsAsyncFunction(kind)) {
@ -904,7 +906,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
// not passing the ScopeInfo to the Scope constructor.
SetLanguageMode(scope, info->language_mode());
scope->set_start_position(info->start_position());
scope->set_start_position(start_position);
ParserFormalParameters formals(scope);
{
ParameterDeclarationParsingScope formals_scope(this);
@ -925,14 +927,14 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
formals.duplicate_loc = formals_scope.duplicate_location();
}
if (GetLastFunctionLiteralId() != info->function_literal_id() - 1) {
if (GetLastFunctionLiteralId() != function_literal_id - 1) {
if (has_error()) return nullptr;
// If there were FunctionLiterals in the parameters, we need to
// renumber them to shift down so the next function literal id for
// the arrow function is the one requested.
AstFunctionLiteralIdReindexer reindexer(
stack_limit_,
(info->function_literal_id() - 1) - GetLastFunctionLiteralId());
(function_literal_id - 1) - GetLastFunctionLiteralId());
for (auto p : formals.params) {
if (p->pattern != nullptr) reindexer.Reindex(p->pattern);
if (p->initializer() != nullptr) {
@ -940,7 +942,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
}
}
ResetFunctionLiteralId();
SkipFunctionLiterals(info->function_literal_id() - 1);
SkipFunctionLiterals(function_literal_id - 1);
}
Expression* expression = ParseArrowFunctionLiteral(formals);
@ -950,7 +952,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
// concise body happens to be a valid expression. This is a problem
// only for arrow functions with single expression bodies, since there
// is no end token such as "}" for normal functions.
if (scanner()->location().end_pos == info->end_position()) {
if (scanner()->location().end_pos == end_position) {
// The pre-parser saw an arrow function here, so the full parser
// must produce a FunctionLiteral.
DCHECK(expression->IsFunctionLiteral());
@ -959,7 +961,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
} else if (IsDefaultConstructor(kind)) {
DCHECK_EQ(scope(), outer);
result = DefaultConstructor(raw_name, IsDerivedConstructor(kind),
info->start_position(), info->end_position());
start_position, end_position);
} else {
ZonePtrList<const AstRawString>* arguments_for_wrapped_function =
info->is_wrapped_as_function()
@ -967,24 +969,23 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
: nullptr;
result = ParseFunctionLiteral(
raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind,
kNoSourcePosition, info->function_syntax_kind(),
kNoSourcePosition, flags().function_syntax_kind(),
info->language_mode(), arguments_for_wrapped_function);
}
if (has_error()) return nullptr;
result->set_requires_instance_members_initializer(
info->requires_instance_members_initializer());
flags().requires_instance_members_initializer());
result->set_class_scope_has_private_brand(
info->class_scope_has_private_brand());
flags().class_scope_has_private_brand());
result->set_has_static_private_methods_or_accessors(
info->has_static_private_methods_or_accessors());
if (info->is_oneshot_iife()) {
flags().has_static_private_methods_or_accessors());
if (flags().is_oneshot_iife()) {
result->mark_as_oneshot_iife();
}
}
DCHECK_IMPLIES(result,
info->function_literal_id() == result->function_literal_id());
DCHECK_IMPLIES(result, function_literal_id == result->function_literal_id());
return result;
}
@ -1005,8 +1006,9 @@ Statement* Parser::ParseModuleItem() {
// We must be careful not to parse a dynamic import expression as an import
// declaration. Same for import.meta expressions.
Token::Value peek_ahead = PeekAhead();
if ((!allow_harmony_dynamic_import() || peek_ahead != Token::LPAREN) &&
(!allow_harmony_import_meta() || peek_ahead != Token::PERIOD)) {
if ((!flags().allow_harmony_dynamic_import() ||
peek_ahead != Token::LPAREN) &&
(!flags().allow_harmony_import_meta() || peek_ahead != Token::PERIOD)) {
ParseImportDeclaration();
return factory()->EmptyStatement();
}
@ -1066,7 +1068,7 @@ ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause(
// caller needs to report an error.
if (!reserved_loc->IsValid() &&
!Token::IsValidIdentifier(name_tok, LanguageMode::kStrict, false,
parsing_module_)) {
flags().is_module())) {
*reserved_loc = scanner()->location();
}
const AstRawString* local_name = ParsePropertyName();
@ -1122,7 +1124,7 @@ ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos) {
}
if (!Token::IsValidIdentifier(scanner()->current_token(),
LanguageMode::kStrict, false,
parsing_module_)) {
flags().is_module())) {
ReportMessage(MessageTemplate::kUnexpectedReserved);
return nullptr;
} else if (IsEvalOrArguments(local_name)) {
@ -1560,7 +1562,7 @@ Statement* Parser::DeclareFunction(const AstRawString* variable_name,
bool was_added;
Declare(declaration, variable_name, kind, mode, kCreatedInitialized, scope(),
&was_added, beg_pos);
if (info()->coverage_enabled()) {
if (info()->flags().coverage_enabled()) {
// Force the function to be allocated when collecting source coverage, so
// that even dead functions get source coverage data.
declaration->var()->set_is_used();
@ -2376,7 +2378,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// parenthesis before the function means that it will be called
// immediately). bar can be parsed lazily, but we need to parse it in a mode
// that tracks unresolved variables.
DCHECK_IMPLIES(parse_lazily(), info()->allow_lazy_compile());
DCHECK_IMPLIES(parse_lazily(), info()->flags().allow_lazy_compile());
DCHECK_IMPLIES(parse_lazily(), has_error() || allow_lazy_);
DCHECK_IMPLIES(parse_lazily(), extension_ == nullptr);
@ -2475,7 +2477,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
? (is_top_level ? "preparse-no-resolution" : "preparse-resolution")
: "full-parse";
logger_->FunctionEvent(
event_name, script_id(), ms, scope->start_position(),
event_name, flags().script_id(), ms, scope->start_position(),
scope->end_position(),
reinterpret_cast<const char*>(function_name->raw_data()),
function_name->byte_length());
@ -2582,7 +2584,7 @@ bool Parser::SkipFunction(const AstRawString* function_name, FunctionKind kind,
PreParser::PreParseResult result = reusable_preparser()->PreParseFunction(
function_name, kind, function_syntax_kind, function_scope, use_counts_,
produced_preparse_data, this->script_id());
produced_preparse_data);
if (result == PreParser::kPreParseStackOverflow) {
// Propagate stack overflow.
@ -2879,7 +2881,7 @@ void Parser::DeclarePrivateClassMember(ClassScope* scope,
ClassLiteralProperty::Kind kind,
bool is_static, ClassInfo* class_info) {
DCHECK_IMPLIES(kind != ClassLiteralProperty::Kind::FIELD,
allow_harmony_private_methods());
flags().allow_harmony_private_methods());
if (kind == ClassLiteralProperty::Kind::FIELD) {
if (is_static) {
@ -3084,11 +3086,11 @@ void Parser::UpdateStatistics(Isolate* isolate, Handle<Script> script) {
total_preparse_skipped_);
}
void Parser::ParseOnBackground(ParseInfo* info) {
void Parser::ParseOnBackground(ParseInfo* info, int start_position,
int end_position, int function_literal_id) {
RuntimeCallTimerScope runtimeTimer(
runtime_call_stats_, RuntimeCallCounterId::kParseBackgroundProgram);
parsing_on_main_thread_ = false;
set_script_id(info->script_id());
DCHECK_NULL(info->literal());
FunctionLiteral* result = nullptr;
@ -3103,11 +3105,15 @@ void Parser::ParseOnBackground(ParseInfo* info) {
// don't). We work around this by storing all the scopes which need their end
// position set at the end of the script (the top scope and possible eval
// scopes) and set their end position after we know the script length.
if (info->is_toplevel()) {
if (flags().is_toplevel()) {
DCHECK_EQ(start_position, 0);
DCHECK_EQ(end_position, 0);
DCHECK_EQ(function_literal_id, kFunctionLiteralIdTopLevel);
result = DoParseProgram(/* isolate = */ nullptr, info);
} else {
result =
DoParseFunction(/* isolate = */ nullptr, info, info->function_name());
result = DoParseFunction(/* isolate = */ nullptr, info, start_position,
end_position, function_literal_id,
info->function_name());
}
MaybeResetCharacterStream(info, result);
MaybeProcessSourceRanges(info, result, stack_limit_);

View File

@ -14,6 +14,7 @@
#include "src/base/compiler-specific.h"
#include "src/base/threaded-list.h"
#include "src/common/globals.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparser.h"
@ -134,7 +135,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
static bool IsPreParser() { return false; }
void ParseOnBackground(ParseInfo* info);
void ParseOnBackground(ParseInfo* info, int start_position, int end_position,
int function_literal_id);
// Initializes an empty scope chain for top-level scripts, or scopes which
// consist of only the native context.
@ -215,6 +217,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
FunctionLiteral* ParseFunction(Isolate* isolate, ParseInfo* info,
Handle<SharedFunctionInfo> shared_info);
FunctionLiteral* DoParseFunction(Isolate* isolate, ParseInfo* info,
int start_position, int end_position,
int function_literal_id,
const AstRawString* raw_name);
// Called by ParseProgram after setting up the scanner.
@ -239,15 +243,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
if (reusable_preparser_ == nullptr) {
reusable_preparser_ = new PreParser(
&preparser_zone_, &scanner_, stack_limit_, ast_value_factory(),
pending_error_handler(), runtime_call_stats_, logger_, -1,
parsing_module_, parsing_on_main_thread_);
#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name());
SET_ALLOW(natives);
SET_ALLOW(harmony_dynamic_import);
SET_ALLOW(harmony_import_meta);
SET_ALLOW(harmony_private_methods);
SET_ALLOW(eval_cache);
#undef SET_ALLOW
pending_error_handler(), runtime_call_stats_, logger_, flags(),
parsing_on_main_thread_);
reusable_preparser_->set_allow_eval_cache(allow_eval_cache());
preparse_data_buffer_.reserve(128);
}
return reusable_preparser_;

View File

@ -22,7 +22,7 @@ namespace parsing {
bool ParseProgram(ParseInfo* info, Handle<Script> script,
MaybeHandle<ScopeInfo> maybe_outer_scope_info,
Isolate* isolate, ReportErrorsAndStatisticsMode mode) {
DCHECK(info->is_toplevel());
DCHECK(info->flags().is_toplevel());
DCHECK_NULL(info->literal());
VMState<PARSER> state(isolate);
@ -44,7 +44,7 @@ bool ParseProgram(ParseInfo* info, Handle<Script> script,
info->set_literal(result);
if (result) {
info->set_language_mode(info->literal()->language_mode());
if (info->is_eval()) {
if (info->flags().is_eval()) {
info->set_allow_eval_cache(parser.allow_eval_cache());
}
}
@ -66,7 +66,7 @@ bool ParseProgram(ParseInfo* info, Handle<Script> script, Isolate* isolate,
bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate, ReportErrorsAndStatisticsMode mode) {
DCHECK(!info->is_toplevel());
DCHECK(!info->flags().is_toplevel());
DCHECK(!shared_info.is_null());
DCHECK_NULL(info->literal());
@ -91,7 +91,7 @@ bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
info->set_literal(result);
if (result) {
info->ast_value_factory()->Internalize(isolate);
if (info->is_eval()) {
if (info->flags().is_eval()) {
info->set_allow_eval_cache(parser.allow_eval_cache());
}
}
@ -109,7 +109,7 @@ bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
bool ParseAny(ParseInfo* info, Handle<SharedFunctionInfo> shared_info,
Isolate* isolate, ReportErrorsAndStatisticsMode mode) {
DCHECK(!shared_info.is_null());
if (info->is_toplevel()) {
if (info->flags().is_toplevel()) {
MaybeHandle<ScopeInfo> maybe_outer_scope_info;
if (shared_info->HasOuterScopeInfo()) {
maybe_outer_scope_info =

View File

@ -78,7 +78,7 @@ PreParser::PreParseResult PreParser::PreParseProgram() {
// ModuleDeclarationInstantiation for Source Text Module Records creates a
// new Module Environment Record whose outer lexical environment record is
// the global scope.
if (parsing_module_) scope = NewModuleScope(scope);
if (flags().is_module()) scope = NewModuleScope(scope);
FunctionState top_scope(&function_state_, &scope_, scope);
original_scope_ = scope_;
@ -105,11 +105,9 @@ void PreParserFormalParameters::ValidateStrictMode(PreParser* preparser) const {
PreParser::PreParseResult PreParser::PreParseFunction(
const AstRawString* function_name, FunctionKind kind,
FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope,
int* use_counts, ProducedPreparseData** produced_preparse_data,
int script_id) {
int* use_counts, ProducedPreparseData** produced_preparse_data) {
DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
use_counts_ = use_counts;
set_script_id(script_id);
#ifdef DEBUG
function_scope->set_is_being_lazily_parsed(true);
#endif
@ -359,7 +357,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
name_byte_length = string->byte_length();
}
logger_->FunctionEvent(
event_name, script_id(), ms, function_scope->start_position(),
event_name, flags().script_id(), ms, function_scope->start_position(),
function_scope->end_position(), name, name_byte_length);
}

View File

@ -8,6 +8,7 @@
#include "src/ast/ast-value-factory.h"
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/pending-compilation-error-handler.h"
#include "src/parsing/preparser-logger.h"
@ -921,12 +922,11 @@ class PreParser : public ParserBase<PreParser> {
AstValueFactory* ast_value_factory,
PendingCompilationErrorHandler* pending_error_handler,
RuntimeCallStats* runtime_call_stats, Logger* logger,
int script_id = -1, bool parsing_module = false,
bool parsing_on_main_thread = true)
UnoptimizedCompileFlags flags, bool parsing_on_main_thread = true)
: ParserBase<PreParser>(zone, scanner, stack_limit, nullptr,
ast_value_factory, pending_error_handler,
runtime_call_stats, logger, script_id,
parsing_module, parsing_on_main_thread),
runtime_call_stats, logger, flags,
parsing_on_main_thread),
use_counts_(nullptr),
preparse_data_builder_(nullptr),
preparse_data_builder_buffer_() {
@ -954,8 +954,7 @@ class PreParser : public ParserBase<PreParser> {
PreParseResult PreParseFunction(
const AstRawString* function_name, FunctionKind kind,
FunctionSyntaxKind function_syntax_kind, DeclarationScope* function_scope,
int* use_counts, ProducedPreparseData** produced_preparser_scope_data,
int script_id);
int* use_counts, ProducedPreparseData** produced_preparser_scope_data);
PreparseDataBuilder* preparse_data_builder() const {
return preparse_data_builder_;

View File

@ -400,7 +400,7 @@ base::Optional<VariableProxy*> Rewriter::RewriteBody(
int pos = kNoSourcePosition;
VariableProxy* result_value =
processor.factory()->NewVariableProxy(result, pos);
if (!info->is_repl_mode()) {
if (!info->flags().is_repl_mode()) {
Statement* result_statement =
processor.factory()->NewReturnStatement(result_value, pos);
body->Add(result_statement, info->zone());

View File

@ -13,6 +13,7 @@
#include "src/ast/ast-value-factory.h"
#include "src/numbers/conversions-inl.h"
#include "src/objects/bigint.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/scanner-inl.h"
#include "src/zone/zone.h"
@ -89,10 +90,10 @@ bool Scanner::BookmarkScope::HasBeenApplied() const {
// ----------------------------------------------------------------------------
// Scanner
Scanner::Scanner(Utf16CharacterStream* source, bool is_module)
: source_(source),
Scanner::Scanner(Utf16CharacterStream* source, UnoptimizedCompileFlags flags)
: flags_(flags),
source_(source),
found_html_comment_(false),
is_module_(is_module),
octal_pos_(Location::invalid()),
octal_message_(MessageTemplate::kNone) {
DCHECK_NOT_NULL(source);
@ -188,7 +189,7 @@ Token::Value Scanner::PeekAhead() {
}
Token::Value Scanner::SkipSingleHTMLComment() {
if (is_module_) {
if (flags_.is_module()) {
ReportScannerError(source_pos(), MessageTemplate::kHtmlCommentInModule);
return Token::ILLEGAL;
}

View File

@ -15,6 +15,7 @@
#include "src/common/globals.h"
#include "src/common/message-template.h"
#include "src/parsing/literal-buffer.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/token.h"
#include "src/strings/char-predicates.h"
#include "src/strings/unicode.h"
@ -269,7 +270,7 @@ class V8_EXPORT_PRIVATE Scanner {
static const int kNoOctalLocation = -1;
static const uc32 kEndOfInput = Utf16CharacterStream::kEndOfInput;
explicit Scanner(Utf16CharacterStream* source, bool is_module);
explicit Scanner(Utf16CharacterStream* source, UnoptimizedCompileFlags flags);
void Initialize();
@ -703,6 +704,8 @@ class V8_EXPORT_PRIVATE Scanner {
const TokenDesc& next() const { return *next_; }
const TokenDesc& next_next() const { return *next_next_; }
UnoptimizedCompileFlags flags_;
TokenDesc* current_; // desc for current token (as returned by Next())
TokenDesc* next_; // desc for next token (one token look-ahead)
TokenDesc* next_next_; // desc for the token after next (after PeakAhead())
@ -718,8 +721,6 @@ class V8_EXPORT_PRIVATE Scanner {
// Whether this scanner encountered an HTML comment.
bool found_html_comment_;
const bool is_module_;
// Values parsed from magic comments.
LiteralBuffer source_url_;
LiteralBuffer source_mapping_url_;

View File

@ -707,9 +707,12 @@ TEST(PreParserScopeAnalysis) {
shared->uncompiled_data_with_preparse_data().preparse_data(),
isolate);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared);
flags.set_is_lazy_compile(true);
// Parse the lazy function using the scope data.
i::ParseInfo using_scope_data(isolate, *shared);
using_scope_data.set_lazy_compile();
i::ParseInfo using_scope_data(isolate, flags);
using_scope_data.set_consumed_preparse_data(
i::ConsumedPreparseData::For(isolate, produced_data_on_heap));
CHECK(i::parsing::ParseFunction(&using_scope_data, shared, isolate));
@ -724,8 +727,7 @@ TEST(PreParserScopeAnalysis) {
CHECK(i::DeclarationScope::Analyze(&using_scope_data));
// Parse the lazy function again eagerly to produce baseline data.
i::ParseInfo not_using_scope_data(isolate, *shared);
not_using_scope_data.set_lazy_compile();
i::ParseInfo not_using_scope_data(isolate, flags);
CHECK(i::parsing::ParseFunction(&not_using_scope_data, shared, isolate));
// Verify that we didn't skip anything (there's no preparsed scope data,
@ -759,7 +761,9 @@ TEST(Regress753896) {
i::Handle<i::String> source = factory->InternalizeUtf8String(
"function lazy() { let v = 0; if (true) { var v = 0; } }");
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
i::ParseInfo info(isolate, flags);
// We don't assert that parsing succeeded or that it failed; currently the
// error is not detected inside lazy functions, but it might be in the future.

View File

@ -7,6 +7,7 @@
#include "src/handles/handles-inl.h"
#include "src/objects/objects-inl.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/scanner-character-streams.h"
#include "src/parsing/scanner.h"
#include "test/cctest/cctest.h"
@ -34,8 +35,9 @@ struct ScannerTestHelper {
ScannerTestHelper make_scanner(const char* src) {
ScannerTestHelper helper;
helper.stream = ScannerStream::ForTesting(src);
helper.scanner =
std::unique_ptr<Scanner>(new Scanner(helper.stream.get(), false));
helper.scanner = std::unique_ptr<Scanner>(
new Scanner(helper.stream.get(),
UnoptimizedCompileFlags::ForTest(CcTest::i_isolate())));
helper.scanner->Initialize();
return helper;
}

View File

@ -515,6 +515,8 @@ TEST(ScanKeywords) {
#undef KEYWORD
{nullptr, i::Token::IDENTIFIER}};
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForTest(CcTest::i_isolate());
KeywordToken key_token;
char buffer[32];
for (int i = 0; (key_token = keywords[i]).keyword != nullptr; i++) {
@ -523,7 +525,7 @@ TEST(ScanKeywords) {
CHECK(static_cast<int>(sizeof(buffer)) >= length);
{
auto stream = i::ScannerStream::ForTesting(keyword, length);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
CHECK_EQ(key_token.token, scanner.Next());
CHECK_EQ(i::Token::EOS, scanner.Next());
@ -531,7 +533,7 @@ TEST(ScanKeywords) {
// Removing characters will make keyword matching fail.
{
auto stream = i::ScannerStream::ForTesting(keyword, length - 1);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
CHECK_EQ(i::Token::EOS, scanner.Next());
@ -542,7 +544,7 @@ TEST(ScanKeywords) {
i::MemMove(buffer, keyword, length);
buffer[length] = chars_to_append[j];
auto stream = i::ScannerStream::ForTesting(buffer, length + 1);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
CHECK_EQ(i::Token::EOS, scanner.Next());
@ -552,7 +554,7 @@ TEST(ScanKeywords) {
i::MemMove(buffer, keyword, length);
buffer[length - 1] = '_';
auto stream = i::ScannerStream::ForTesting(buffer, length);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
CHECK_EQ(i::Token::EOS, scanner.Next());
@ -566,6 +568,8 @@ TEST(ScanHTMLEndComments) {
v8::Isolate* isolate = CcTest::isolate();
i::Isolate* i_isolate = CcTest::i_isolate();
v8::HandleScope handles(isolate);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForTest(i_isolate);
// Regression test. See:
// http://code.google.com/p/chromium/issues/detail?id=53548
@ -619,7 +623,7 @@ TEST(ScanHTMLEndComments) {
for (int i = 0; tests[i]; i++) {
const char* source = tests[i];
auto stream = i::ScannerStream::ForTesting(source);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
i::Zone zone(i_isolate->allocator(), ZONE_NAME);
i::AstValueFactory ast_value_factory(
@ -628,7 +632,7 @@ TEST(ScanHTMLEndComments) {
i::PreParser preparser(&zone, &scanner, stack_limit, &ast_value_factory,
&pending_error_handler,
i_isolate->counters()->runtime_call_stats(),
i_isolate->logger());
i_isolate->logger(), flags);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
CHECK(!pending_error_handler.has_pending_error());
@ -637,7 +641,7 @@ TEST(ScanHTMLEndComments) {
for (int i = 0; fail_tests[i]; i++) {
const char* source = fail_tests[i];
auto stream = i::ScannerStream::ForTesting(source);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
i::Zone zone(i_isolate->allocator(), ZONE_NAME);
i::AstValueFactory ast_value_factory(
@ -646,7 +650,7 @@ TEST(ScanHTMLEndComments) {
i::PreParser preparser(&zone, &scanner, stack_limit, &ast_value_factory,
&pending_error_handler,
i_isolate->counters()->runtime_call_stats(),
i_isolate->logger());
i_isolate->logger(), flags);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
// Even in the case of a syntax error, kPreParseSuccess is returned.
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
@ -656,11 +660,15 @@ TEST(ScanHTMLEndComments) {
}
TEST(ScanHtmlComments) {
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForTest(CcTest::i_isolate());
const char* src = "a <!-- b --> c";
// Disallow HTML comments.
{
flags.set_is_module(true);
auto stream = i::ScannerStream::ForTesting(src);
i::Scanner scanner(stream.get(), true);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
CHECK_EQ(i::Token::ILLEGAL, scanner.Next());
@ -668,8 +676,9 @@ TEST(ScanHtmlComments) {
// Skip HTML comments:
{
flags.set_is_module(false);
auto stream = i::ScannerStream::ForTesting(src);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
CHECK_EQ(i::Token::EOS, scanner.Next());
@ -693,6 +702,9 @@ class ScriptResource : public v8::String::ExternalOneByteStringResource {
TEST(StandAlonePreParser) {
v8::V8::Initialize();
i::Isolate* i_isolate = CcTest::i_isolate();
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForTest(i_isolate);
flags.set_allow_natives_syntax(true);
i_isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
128 * 1024);
@ -708,7 +720,7 @@ TEST(StandAlonePreParser) {
uintptr_t stack_limit = i_isolate->stack_guard()->real_climit();
for (int i = 0; programs[i]; i++) {
auto stream = i::ScannerStream::ForTesting(programs[i]);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
i::Zone zone(i_isolate->allocator(), ZONE_NAME);
@ -718,8 +730,7 @@ TEST(StandAlonePreParser) {
i::PreParser preparser(&zone, &scanner, stack_limit, &ast_value_factory,
&pending_error_handler,
i_isolate->counters()->runtime_call_stats(),
i_isolate->logger());
preparser.set_allow_natives(true);
i_isolate->logger(), flags);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
CHECK(!pending_error_handler.has_pending_error());
@ -729,8 +740,10 @@ TEST(StandAlonePreParser) {
TEST(StandAlonePreParserNoNatives) {
v8::V8::Initialize();
i::Isolate* isolate = CcTest::i_isolate();
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForTest(isolate);
isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
128 * 1024);
@ -740,7 +753,7 @@ TEST(StandAlonePreParserNoNatives) {
uintptr_t stack_limit = isolate->stack_guard()->real_climit();
for (int i = 0; programs[i]; i++) {
auto stream = i::ScannerStream::ForTesting(programs[i]);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
// Preparser defaults to disallowing natives syntax.
@ -751,7 +764,7 @@ TEST(StandAlonePreParserNoNatives) {
i::PreParser preparser(&zone, &scanner, stack_limit, &ast_value_factory,
&pending_error_handler,
isolate->counters()->runtime_call_stats(),
isolate->logger());
isolate->logger(), flags);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
CHECK(pending_error_handler.has_pending_error() ||
@ -763,6 +776,8 @@ TEST(StandAlonePreParserNoNatives) {
TEST(RegressChromium62639) {
v8::V8::Initialize();
i::Isolate* isolate = CcTest::i_isolate();
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForTest(isolate);
isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
128 * 1024);
@ -775,7 +790,7 @@ TEST(RegressChromium62639) {
// failed in debug mode, and sometimes crashed in release mode.
auto stream = i::ScannerStream::ForTesting(program);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
i::Zone zone(isolate->allocator(), ZONE_NAME);
i::AstValueFactory ast_value_factory(&zone, isolate->ast_string_constants(),
@ -784,7 +799,7 @@ TEST(RegressChromium62639) {
i::PreParser preparser(&zone, &scanner, isolate->stack_guard()->real_climit(),
&ast_value_factory, &pending_error_handler,
isolate->counters()->runtime_call_stats(),
isolate->logger());
isolate->logger(), flags);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
// Even in the case of a syntax error, kPreParseSuccess is returned.
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
@ -796,6 +811,8 @@ TEST(RegressChromium62639) {
TEST(PreParseOverflow) {
v8::V8::Initialize();
i::Isolate* isolate = CcTest::i_isolate();
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForTest(isolate);
isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
128 * 1024);
@ -808,7 +825,7 @@ TEST(PreParseOverflow) {
uintptr_t stack_limit = isolate->stack_guard()->real_climit();
auto stream = i::ScannerStream::ForTesting(program.get(), kProgramSize);
i::Scanner scanner(stream.get(), false);
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
i::Zone zone(isolate->allocator(), ZONE_NAME);
@ -817,7 +834,7 @@ TEST(PreParseOverflow) {
i::PendingCompilationErrorHandler pending_error_handler;
i::PreParser preparser(
&zone, &scanner, stack_limit, &ast_value_factory, &pending_error_handler,
isolate->counters()->runtime_call_stats(), isolate->logger());
isolate->counters()->runtime_call_stats(), isolate->logger(), flags);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
}
@ -826,7 +843,10 @@ void TestStreamScanner(i::Utf16CharacterStream* stream,
i::Token::Value* expected_tokens,
int skip_pos = 0, // Zero means not skipping.
int skip_to = 0) {
i::Scanner scanner(stream, false);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForTest(CcTest::i_isolate());
i::Scanner scanner(stream, flags);
scanner.Initialize();
int i = 0;
@ -894,7 +914,9 @@ TEST(StreamScanner) {
void TestScanRegExp(const char* re_source, const char* expected) {
auto stream = i::ScannerStream::ForTesting(re_source);
i::HandleScope scope(CcTest::i_isolate());
i::Scanner scanner(stream.get(), false);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForTest(CcTest::i_isolate());
i::Scanner scanner(stream.get(), flags);
scanner.Initialize();
i::Token::Value start = scanner.peek();
@ -1056,9 +1078,11 @@ TEST(ScopeUsesArgumentsSuperThis) {
factory->NewStringFromUtf8(i::CStrVector(program.begin()))
.ToHandleChecked();
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
// The information we're checking is only produced when eager parsing.
info.set_allow_lazy_parsing(false);
flags.set_allow_lazy_parsing(false);
i::ParseInfo info(isolate, flags);
CHECK(i::parsing::ParseProgram(&info, script, isolate));
CHECK(i::Rewriter::Rewrite(&info));
info.ast_value_factory()->Internalize(isolate);
@ -1121,9 +1145,11 @@ static void CheckParsesToNumber(const char* source) {
i::Handle<i::Script> script = factory->NewScript(source_code);
i::ParseInfo info(isolate, *script);
info.set_allow_lazy_parsing(false);
info.set_toplevel(true);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_allow_lazy_parsing(false);
flags.set_is_toplevel(true);
i::ParseInfo info(isolate, flags);
CHECK(i::parsing::ParseProgram(&info, script, isolate));
@ -1431,8 +1457,11 @@ TEST(ScopePositions) {
.ToHandleChecked();
CHECK_EQ(source->length(), kProgramSize);
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
info.set_language_mode(source_data[i].language_mode);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_outer_language_mode(source_data[i].language_mode);
i::ParseInfo info(isolate, flags);
i::parsing::ParseProgram(&info, script, isolate);
CHECK_NOT_NULL(info.literal());
@ -1477,7 +1506,9 @@ TEST(DiscardFunctionBody) {
i::Handle<i::String> source_code =
factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked();
i::Handle<i::Script> script = factory->NewScript(source_code);
i::ParseInfo info(isolate, *script);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
i::ParseInfo info(isolate, flags);
i::parsing::ParseProgram(&info, script, isolate);
function = info.literal();
CHECK_NOT_NULL(function);
@ -1549,13 +1580,14 @@ void SetGlobalFlags(base::EnumSet<ParserFlag> flags) {
i::FLAG_harmony_import_meta = flags.contains(kAllowHarmonyImportMeta);
}
void SetParserFlags(i::PreParser* parser, base::EnumSet<ParserFlag> flags) {
parser->set_allow_natives(flags.contains(kAllowNatives));
parser->set_allow_harmony_private_methods(
void SetParserFlags(i::UnoptimizedCompileFlags* compile_flags,
base::EnumSet<ParserFlag> flags) {
compile_flags->set_allow_natives_syntax(flags.contains(kAllowNatives));
compile_flags->set_allow_harmony_private_methods(
flags.contains(kAllowHarmonyPrivateMethods));
parser->set_allow_harmony_dynamic_import(
compile_flags->set_allow_harmony_dynamic_import(
flags.contains(kAllowHarmonyDynamicImport));
parser->set_allow_harmony_import_meta(
compile_flags->set_allow_harmony_import_meta(
flags.contains(kAllowHarmonyImportMeta));
}
@ -1566,6 +1598,11 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
bool ignore_error_msg = false) {
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
i::UnoptimizedCompileFlags compile_flags =
i::UnoptimizedCompileFlags::ForToplevelCompile(
isolate, true, LanguageMode::kSloppy, REPLMode::kNo);
SetParserFlags(&compile_flags, flags);
compile_flags.set_is_module(is_module);
uintptr_t stack_limit = isolate->stack_guard()->real_climit();
@ -1574,15 +1611,14 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
if (test_preparser) {
std::unique_ptr<i::Utf16CharacterStream> stream(
i::ScannerStream::For(isolate, source));
i::Scanner scanner(stream.get(), is_module);
i::Scanner scanner(stream.get(), compile_flags);
i::Zone zone(isolate->allocator(), ZONE_NAME);
i::AstValueFactory ast_value_factory(&zone, isolate->ast_string_constants(),
HashSeed(isolate));
i::PreParser preparser(&zone, &scanner, stack_limit, &ast_value_factory,
&pending_error_handler,
isolate->counters()->runtime_call_stats(),
isolate->logger(), -1, is_module);
SetParserFlags(&preparser, flags);
isolate->logger(), compile_flags);
scanner.Initialize();
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
@ -1592,10 +1628,9 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
i::FunctionLiteral* function;
{
SetGlobalFlags(flags);
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
info.set_allow_lazy_parsing(flags.contains(kAllowLazy));
if (is_module) info.set_module();
i::Handle<i::Script> script =
factory->NewScriptWithId(source, compile_flags.script_id());
i::ParseInfo info(isolate, compile_flags);
i::parsing::ParseProgram(&info, script, isolate);
function = info.literal();
}
@ -3472,8 +3507,9 @@ TEST(InnerAssignment) {
i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
i::Handle<i::SharedFunctionInfo> shared =
i::handle(f->shared(), isolate);
info =
std::unique_ptr<i::ParseInfo>(new i::ParseInfo(isolate, *shared));
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared);
info = std::make_unique<i::ParseInfo>(isolate, flags);
CHECK(i::parsing::ParseFunction(info.get(), shared, isolate));
} else {
i::Handle<i::String> source =
@ -3481,9 +3517,10 @@ TEST(InnerAssignment) {
source->PrintOn(stdout);
printf("\n");
i::Handle<i::Script> script = factory->NewScript(source);
info =
std::unique_ptr<i::ParseInfo>(new i::ParseInfo(isolate, *script));
info->set_allow_lazy_parsing(false);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_allow_lazy_parsing(false);
info = std::make_unique<i::ParseInfo>(isolate, flags);
CHECK(i::parsing::ParseProgram(info.get(), script, isolate));
}
CHECK(i::Compiler::Analyze(info.get()));
@ -3590,8 +3627,10 @@ TEST(MaybeAssignedParameters) {
i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
i::Handle<i::SharedFunctionInfo> shared = i::handle(f->shared(), isolate);
info = std::unique_ptr<i::ParseInfo>(new i::ParseInfo(isolate, *shared));
info->set_allow_lazy_parsing(allow_lazy);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared);
flags.set_allow_lazy_parsing(allow_lazy);
info = std::make_unique<i::ParseInfo>(isolate, flags);
CHECK(i::parsing::ParseFunction(info.get(), shared, isolate));
CHECK(i::Compiler::Analyze(info.get()));
CHECK_NOT_NULL(info->literal());
@ -3626,10 +3665,12 @@ static void TestMaybeAssigned(Input input, const char* variable, bool module,
printf("\n");
i::Handle<i::Script> script = factory->NewScript(string);
std::unique_ptr<i::ParseInfo> info;
info = std::unique_ptr<i::ParseInfo>(new i::ParseInfo(isolate, *script));
info->set_module(module);
info->set_allow_lazy_parsing(allow_lazy_parsing);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_is_module(module);
flags.set_allow_lazy_parsing(allow_lazy_parsing);
std::unique_ptr<i::ParseInfo> info =
std::make_unique<i::ParseInfo>(isolate, flags);
CHECK(i::parsing::ParseProgram(info.get(), script, isolate));
CHECK(i::Compiler::Analyze(info.get()));
@ -7382,8 +7423,10 @@ TEST(BasicImportExportParsing) {
// Show that parsing as a module works
{
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
info.set_module();
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_is_module(true);
i::ParseInfo info(isolate, flags);
if (!i::parsing::ParseProgram(&info, script, isolate)) {
i::Handle<i::JSObject> exception_handle(
i::JSObject::cast(isolate->pending_exception()), isolate);
@ -7405,7 +7448,9 @@ TEST(BasicImportExportParsing) {
// And that parsing a script does not.
{
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
i::ParseInfo info(isolate, flags);
CHECK(!i::parsing::ParseProgram(&info, script, isolate));
isolate->clear_pending_exception();
}
@ -7442,8 +7487,10 @@ TEST(NamespaceExportParsing) {
i::Handle<i::String> source =
factory->NewStringFromAsciiChecked(kSources[i]);
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
info.set_module();
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_is_module(true);
i::ParseInfo info(isolate, flags);
CHECK(i::parsing::ParseProgram(&info, script, isolate));
}
}
@ -7537,8 +7584,10 @@ TEST(ImportExportParsingErrors) {
factory->NewStringFromAsciiChecked(kErrorSources[i]);
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
info.set_module();
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_is_module(true);
i::ParseInfo info(isolate, flags);
CHECK(!i::parsing::ParseProgram(&info, script, isolate));
isolate->clear_pending_exception();
}
@ -7573,8 +7622,10 @@ TEST(ModuleTopLevelFunctionDecl) {
factory->NewStringFromAsciiChecked(kErrorSources[i]);
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
info.set_module();
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_is_module(true);
i::ParseInfo info(isolate, flags);
CHECK(!i::parsing::ParseProgram(&info, script, isolate));
isolate->clear_pending_exception();
}
@ -7770,8 +7821,10 @@ TEST(ModuleParsingInternals) {
"export {foob};";
i::Handle<i::String> source = factory->NewStringFromAsciiChecked(kSource);
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
info.set_module();
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_is_module(true);
i::ParseInfo info(isolate, flags);
CHECK(i::parsing::ParseProgram(&info, script, isolate));
CHECK(i::Compiler::Analyze(&info));
i::FunctionLiteral* func = info.literal();
@ -8013,7 +8066,9 @@ void TestLanguageMode(const char* source,
i::Handle<i::Script> script =
factory->NewScript(factory->NewStringFromAsciiChecked(source));
i::ParseInfo info(isolate, *script);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
i::ParseInfo info(isolate, flags);
i::parsing::ParseProgram(&info, script, isolate);
CHECK_NOT_NULL(info.literal());
CHECK_EQ(expected_language_mode, info.literal()->language_mode());
@ -10794,7 +10849,9 @@ TEST(NoPessimisticContextAllocation) {
printf("\n");
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
i::ParseInfo info(isolate, flags);
CHECK(i::parsing::ParseProgram(&info, script, isolate));
CHECK(i::Compiler::Analyze(&info));
@ -11354,9 +11411,10 @@ TEST(LexicalLoopVariable) {
i::Handle<i::String> source =
factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(isolate, *script);
info.set_allow_lazy_parsing(false);
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
flags.set_allow_lazy_parsing(false);
i::ParseInfo info(isolate, flags);
CHECK(i::parsing::ParseProgram(&info, script, isolate));
CHECK(i::Rewriter::Rewrite(&info));
CHECK(i::DeclarationScope::Analyze(&info));

View File

@ -80,7 +80,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
v8::internal::Handle<v8::internal::Script> script =
factory->NewScript(source.ToHandleChecked());
v8::internal::ParseInfo info(i_isolate, *script);
v8::internal::UnoptimizedCompileFlags flags =
v8::internal::UnoptimizedCompileFlags::ForScriptCompile(i_isolate,
*script);
v8::internal::ParseInfo info(i_isolate, flags);
if (!v8::internal::parsing::ParseProgram(&info, script, i_isolate)) {
i_isolate->OptionalRescheduleException(true);
}

View File

@ -15,6 +15,7 @@
#include "src/execution/off-thread-isolate.h"
#include "src/handles/handles-inl.h"
#include "src/handles/handles.h"
#include "src/handles/maybe-handles.h"
#include "src/heap/off-thread-factory-inl.h"
#include "src/objects/fixed-array.h"
#include "src/objects/script.h"
@ -55,7 +56,10 @@ class OffThreadFactoryTest : public TestWithIsolateAndZone {
public:
OffThreadFactoryTest()
: TestWithIsolateAndZone(),
parse_info_(isolate()),
parse_info_(isolate(), UnoptimizedCompileFlags::ForToplevelCompile(
isolate(), true,
construct_language_mode(FLAG_use_strict),
REPLMode::kNo)),
off_thread_isolate_(isolate(), parse_info_.zone()) {}
FunctionLiteral* ParseProgram(const char* source) {
@ -68,8 +72,6 @@ class OffThreadFactoryTest : public TestWithIsolateAndZone {
parse_info_.set_character_stream(
ScannerStream::ForTesting(utf16_source.data(), utf16_source.size()));
parse_info_.set_toplevel();
parse_info_.set_allow_lazy_parsing();
{
DisallowHeapAllocation no_allocation;
@ -78,7 +80,7 @@ class OffThreadFactoryTest : public TestWithIsolateAndZone {
Parser parser(parse_info());
parser.InitializeEmptyScopeChain(parse_info());
parser.ParseOnBackground(parse_info());
parser.ParseOnBackground(parse_info(), 0, 0, kFunctionLiteralIdTopLevel);
CHECK(DeclarationScope::Analyze(parse_info()));
}
@ -88,7 +90,7 @@ class OffThreadFactoryTest : public TestWithIsolateAndZone {
script_ = parse_info_.CreateScript(off_thread_isolate(),
off_thread_factory()->empty_string(),
ScriptOriginOptions());
kNullMaybeHandle, ScriptOriginOptions());
// Create the SFI list on the script so that SFI SetScript works.
Handle<WeakFixedArray> infos = off_thread_factory()->NewWeakFixedArray(

View File

@ -56,8 +56,8 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
std::unique_ptr<ParseInfo> OuterParseInfoForShared(
Isolate* isolate, Handle<SharedFunctionInfo> shared) {
Script script = Script::cast(shared->script());
std::unique_ptr<ParseInfo> result =
std::make_unique<ParseInfo>(isolate, script);
std::unique_ptr<ParseInfo> result = std::make_unique<ParseInfo>(
isolate, i::UnoptimizedCompileFlags::ForScriptCompile(isolate, script));
// Create a character stream to simulate the parser having done so for the
// to-level ParseProgram.