• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/parsing/parse-info.h"
6 
7 #include "src/ast/ast-source-ranges.h"
8 #include "src/ast/ast-value-factory.h"
9 #include "src/ast/ast.h"
10 #include "src/common/globals.h"
11 #include "src/compiler-dispatcher/compiler-dispatcher.h"
12 #include "src/heap/heap-inl.h"
13 #include "src/logging/counters.h"
14 #include "src/logging/log.h"
15 #include "src/numbers/hash-seed-inl.h"
16 #include "src/objects/objects-inl.h"
17 #include "src/objects/scope-info.h"
18 #include "src/zone/zone.h"
19 
20 namespace v8 {
21 namespace internal {
22 
UnoptimizedCompileFlags(Isolate * isolate,int script_id)23 UnoptimizedCompileFlags::UnoptimizedCompileFlags(Isolate* isolate,
24                                                  int script_id)
25     : flags_(0),
26       script_id_(script_id),
27       function_kind_(FunctionKind::kNormalFunction),
28       function_syntax_kind_(FunctionSyntaxKind::kDeclaration) {
29   set_collect_type_profile(isolate->is_collecting_type_profile());
30   set_coverage_enabled(!isolate->is_best_effort_code_coverage());
31   set_block_coverage_enabled(isolate->is_block_code_coverage());
32   set_might_always_opt(FLAG_always_opt || FLAG_prepare_always_opt);
33   set_allow_natives_syntax(FLAG_allow_natives_syntax);
34   set_allow_lazy_compile(FLAG_lazy);
35   set_allow_harmony_private_methods(FLAG_harmony_private_methods);
36   set_collect_source_positions(!FLAG_enable_lazy_source_positions ||
37                                isolate->NeedsDetailedOptimizedCodeLineInfo());
38   set_allow_harmony_top_level_await(FLAG_harmony_top_level_await);
39   set_allow_harmony_logical_assignment(FLAG_harmony_logical_assignment);
40 }
41 
42 // static
ForFunctionCompile(Isolate * isolate,SharedFunctionInfo shared)43 UnoptimizedCompileFlags UnoptimizedCompileFlags::ForFunctionCompile(
44     Isolate* isolate, SharedFunctionInfo shared) {
45   Script script = Script::cast(shared.script());
46 
47   UnoptimizedCompileFlags flags(isolate, script.id());
48 
49   flags.SetFlagsFromFunction(&shared);
50   flags.SetFlagsForFunctionFromScript(script);
51 
52   flags.set_allow_lazy_parsing(true);
53   flags.set_is_asm_wasm_broken(shared.is_asm_wasm_broken());
54   flags.set_is_repl_mode(shared.is_repl_mode());
55 
56   // CollectTypeProfile uses its own feedback slots. If we have existing
57   // FeedbackMetadata, we can only collect type profile if the feedback vector
58   // has the appropriate slots.
59   flags.set_collect_type_profile(
60       isolate->is_collecting_type_profile() &&
61       (shared.HasFeedbackMetadata()
62            ? shared.feedback_metadata().HasTypeProfileSlot()
63            : script.IsUserJavaScript()));
64 
65   // Do not support re-parsing top-level function of a wrapped script.
66   DCHECK_IMPLIES(flags.is_toplevel(), !script.is_wrapped());
67 
68   return flags;
69 }
70 
71 // static
ForScriptCompile(Isolate * isolate,Script script)72 UnoptimizedCompileFlags UnoptimizedCompileFlags::ForScriptCompile(
73     Isolate* isolate, Script script) {
74   UnoptimizedCompileFlags flags(isolate, script.id());
75 
76   flags.SetFlagsForFunctionFromScript(script);
77   flags.SetFlagsForToplevelCompile(
78       isolate->is_collecting_type_profile(), script.IsUserJavaScript(),
79       flags.outer_language_mode(), construct_repl_mode(script.is_repl_mode()));
80   if (script.is_wrapped()) {
81     flags.set_function_syntax_kind(FunctionSyntaxKind::kWrapped);
82   }
83 
84   return flags;
85 }
86 
87 // static
ForToplevelCompile(Isolate * isolate,bool is_user_javascript,LanguageMode language_mode,REPLMode repl_mode)88 UnoptimizedCompileFlags UnoptimizedCompileFlags::ForToplevelCompile(
89     Isolate* isolate, bool is_user_javascript, LanguageMode language_mode,
90     REPLMode repl_mode) {
91   UnoptimizedCompileFlags flags(isolate, isolate->GetNextScriptId());
92   flags.SetFlagsForToplevelCompile(isolate->is_collecting_type_profile(),
93                                    is_user_javascript, language_mode,
94                                    repl_mode);
95 
96   LOG(isolate,
97       ScriptEvent(Logger::ScriptEventType::kReserveId, flags.script_id()));
98   return flags;
99 }
100 
101 // static
ForToplevelFunction(const UnoptimizedCompileFlags toplevel_flags,const FunctionLiteral * literal)102 UnoptimizedCompileFlags UnoptimizedCompileFlags::ForToplevelFunction(
103     const UnoptimizedCompileFlags toplevel_flags,
104     const FunctionLiteral* literal) {
105   DCHECK(toplevel_flags.is_toplevel());
106   DCHECK(!literal->is_toplevel());
107 
108   // Replicate the toplevel flags, then setup the function-specific flags.
109   UnoptimizedCompileFlags flags = toplevel_flags;
110   flags.SetFlagsFromFunction(literal);
111 
112   return flags;
113 }
114 
115 // static
ForTest(Isolate * isolate)116 UnoptimizedCompileFlags UnoptimizedCompileFlags::ForTest(Isolate* isolate) {
117   return UnoptimizedCompileFlags(isolate, Script::kTemporaryScriptId);
118 }
119 
120 template <typename T>
SetFlagsFromFunction(T function)121 void UnoptimizedCompileFlags::SetFlagsFromFunction(T function) {
122   set_outer_language_mode(function->language_mode());
123   set_function_kind(function->kind());
124   set_function_syntax_kind(function->syntax_kind());
125   set_requires_instance_members_initializer(
126       function->requires_instance_members_initializer());
127   set_class_scope_has_private_brand(function->class_scope_has_private_brand());
128   set_has_static_private_methods_or_accessors(
129       function->has_static_private_methods_or_accessors());
130   set_is_toplevel(function->is_toplevel());
131   set_is_oneshot_iife(function->is_oneshot_iife());
132 }
133 
SetFlagsForToplevelCompile(bool is_collecting_type_profile,bool is_user_javascript,LanguageMode language_mode,REPLMode repl_mode)134 void UnoptimizedCompileFlags::SetFlagsForToplevelCompile(
135     bool is_collecting_type_profile, bool is_user_javascript,
136     LanguageMode language_mode, REPLMode repl_mode) {
137   set_allow_lazy_parsing(true);
138   set_is_toplevel(true);
139   set_collect_type_profile(is_user_javascript && is_collecting_type_profile);
140   set_outer_language_mode(
141       stricter_language_mode(outer_language_mode(), language_mode));
142   set_is_repl_mode((repl_mode == REPLMode::kYes));
143 
144   set_block_coverage_enabled(block_coverage_enabled() && is_user_javascript);
145 }
146 
SetFlagsForFunctionFromScript(Script script)147 void UnoptimizedCompileFlags::SetFlagsForFunctionFromScript(Script script) {
148   DCHECK_EQ(script_id(), script.id());
149 
150   set_is_eval(script.compilation_type() == Script::COMPILATION_TYPE_EVAL);
151   set_is_module(script.origin_options().IsModule());
152   DCHECK(!(is_eval() && is_module()));
153 
154   set_block_coverage_enabled(block_coverage_enabled() &&
155                              script.IsUserJavaScript());
156 }
157 
UnoptimizedCompileState(Isolate * isolate)158 UnoptimizedCompileState::UnoptimizedCompileState(Isolate* isolate)
159     : hash_seed_(HashSeed(isolate)),
160       allocator_(isolate->allocator()),
161       ast_string_constants_(isolate->ast_string_constants()),
162       logger_(isolate->logger()),
163       parallel_tasks_(isolate->compiler_dispatcher()->IsEnabled()
164                           ? new ParallelTasks(isolate->compiler_dispatcher())
165                           : nullptr) {}
166 
UnoptimizedCompileState(const UnoptimizedCompileState & other)167 UnoptimizedCompileState::UnoptimizedCompileState(
168     const UnoptimizedCompileState& other) V8_NOEXCEPT
169     : hash_seed_(other.hash_seed()),
170       allocator_(other.allocator()),
171       ast_string_constants_(other.ast_string_constants()),
172       logger_(other.logger()),
173       // TODO(leszeks): Should this create a new ParallelTasks instance?
174       parallel_tasks_(nullptr) {}
175 
ParseInfo(const UnoptimizedCompileFlags flags,UnoptimizedCompileState * state)176 ParseInfo::ParseInfo(const UnoptimizedCompileFlags flags,
177                      UnoptimizedCompileState* state)
178     : flags_(flags),
179       state_(state),
180       zone_(std::make_unique<Zone>(state->allocator(), "parser-zone")),
181       extension_(nullptr),
182       script_scope_(nullptr),
183       stack_limit_(0),
184       parameters_end_pos_(kNoSourcePosition),
185       max_function_literal_id_(kFunctionLiteralIdInvalid),
186       character_stream_(nullptr),
187       ast_value_factory_(nullptr),
188       function_name_(nullptr),
189       runtime_call_stats_(nullptr),
190       source_range_map_(nullptr),
191       literal_(nullptr),
192       allow_eval_cache_(false),
193       contains_asm_module_(false),
194       language_mode_(flags.outer_language_mode()) {
195   if (flags.block_coverage_enabled()) {
196     AllocateSourceRangeMap();
197   }
198 }
199 
ParseInfo(Isolate * isolate,const UnoptimizedCompileFlags flags,UnoptimizedCompileState * state)200 ParseInfo::ParseInfo(Isolate* isolate, const UnoptimizedCompileFlags flags,
201                      UnoptimizedCompileState* state)
202     : ParseInfo(flags, state) {
203   SetPerThreadState(isolate->stack_guard()->real_climit(),
204                     isolate->counters()->runtime_call_stats());
205 }
206 
207 // static
ForToplevelFunction(const UnoptimizedCompileFlags flags,UnoptimizedCompileState * compile_state,const FunctionLiteral * literal,const AstRawString * function_name)208 std::unique_ptr<ParseInfo> ParseInfo::ForToplevelFunction(
209     const UnoptimizedCompileFlags flags, UnoptimizedCompileState* compile_state,
210     const FunctionLiteral* literal, const AstRawString* function_name) {
211   std::unique_ptr<ParseInfo> result(new ParseInfo(flags, compile_state));
212 
213   // Clone the function_name AstRawString into the ParseInfo's own
214   // AstValueFactory.
215   const AstRawString* cloned_function_name =
216       result->GetOrCreateAstValueFactory()->CloneFromOtherFactory(
217           function_name);
218 
219   // Setup function specific details.
220   DCHECK(!literal->is_toplevel());
221   result->set_function_name(cloned_function_name);
222 
223   return result;
224 }
225 
226 ParseInfo::~ParseInfo() = default;
227 
scope() const228 DeclarationScope* ParseInfo::scope() const { return literal()->scope(); }
229 
230 template <typename LocalIsolate>
CreateScript(LocalIsolate * isolate,Handle<String> source,MaybeHandle<FixedArray> maybe_wrapped_arguments,ScriptOriginOptions origin_options,NativesFlag natives)231 Handle<Script> ParseInfo::CreateScript(
232     LocalIsolate* isolate, Handle<String> source,
233     MaybeHandle<FixedArray> maybe_wrapped_arguments,
234     ScriptOriginOptions origin_options, NativesFlag natives) {
235   // Create a script object describing the script to be compiled.
236   DCHECK(flags().script_id() >= 0 ||
237          flags().script_id() == Script::kTemporaryScriptId);
238   Handle<Script> script =
239       isolate->factory()->NewScriptWithId(source, flags().script_id());
240   switch (natives) {
241     case EXTENSION_CODE:
242       script->set_type(Script::TYPE_EXTENSION);
243       break;
244     case INSPECTOR_CODE:
245       script->set_type(Script::TYPE_INSPECTOR);
246       break;
247     case NOT_NATIVES_CODE:
248       break;
249   }
250   script->set_origin_options(origin_options);
251   script->set_is_repl_mode(flags().is_repl_mode());
252 
253   DCHECK_EQ(is_wrapped_as_function(), !maybe_wrapped_arguments.is_null());
254   if (is_wrapped_as_function()) {
255     script->set_wrapped_arguments(*maybe_wrapped_arguments.ToHandleChecked());
256   } else if (flags().is_eval()) {
257     script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
258   }
259 
260   CheckFlagsForToplevelCompileFromScript(*script,
261                                          isolate->is_collecting_type_profile());
262   return script;
263 }
264 
265 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
266     Handle<Script> ParseInfo::CreateScript(
267         Isolate* isolate, Handle<String> source,
268         MaybeHandle<FixedArray> maybe_wrapped_arguments,
269         ScriptOriginOptions origin_options, NativesFlag natives);
270 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
271     Handle<Script> ParseInfo::CreateScript(
272         LocalIsolate* isolate, Handle<String> source,
273         MaybeHandle<FixedArray> maybe_wrapped_arguments,
274         ScriptOriginOptions origin_options, NativesFlag natives);
275 
GetOrCreateAstValueFactory()276 AstValueFactory* ParseInfo::GetOrCreateAstValueFactory() {
277   if (!ast_value_factory_.get()) {
278     ast_value_factory_.reset(
279         new AstValueFactory(zone(), ast_string_constants(), hash_seed()));
280   }
281   return ast_value_factory();
282 }
283 
AllocateSourceRangeMap()284 void ParseInfo::AllocateSourceRangeMap() {
285   DCHECK(flags().block_coverage_enabled());
286   DCHECK_NULL(source_range_map());
287   set_source_range_map(zone()->New<SourceRangeMap>(zone()));
288 }
289 
ResetCharacterStream()290 void ParseInfo::ResetCharacterStream() { character_stream_.reset(); }
291 
set_character_stream(std::unique_ptr<Utf16CharacterStream> character_stream)292 void ParseInfo::set_character_stream(
293     std::unique_ptr<Utf16CharacterStream> character_stream) {
294   DCHECK_NULL(character_stream_);
295   character_stream_.swap(character_stream);
296 }
297 
CheckFlagsForToplevelCompileFromScript(Script script,bool is_collecting_type_profile)298 void ParseInfo::CheckFlagsForToplevelCompileFromScript(
299     Script script, bool is_collecting_type_profile) {
300   CheckFlagsForFunctionFromScript(script);
301   DCHECK(flags().allow_lazy_parsing());
302   DCHECK(flags().is_toplevel());
303   DCHECK_EQ(flags().collect_type_profile(),
304             is_collecting_type_profile && script.IsUserJavaScript());
305   DCHECK_EQ(flags().is_repl_mode(), script.is_repl_mode());
306 
307   if (script.is_wrapped()) {
308     DCHECK_EQ(flags().function_syntax_kind(), FunctionSyntaxKind::kWrapped);
309   }
310 }
311 
CheckFlagsForFunctionFromScript(Script script)312 void ParseInfo::CheckFlagsForFunctionFromScript(Script script) {
313   DCHECK_EQ(flags().script_id(), script.id());
314   // We set "is_eval" for wrapped scripts to get an outer declaration scope.
315   // This is a bit hacky, but ok since we can't be both eval and wrapped.
316   DCHECK_EQ(flags().is_eval() && !script.is_wrapped(),
317             script.compilation_type() == Script::COMPILATION_TYPE_EVAL);
318   DCHECK_EQ(flags().is_module(), script.origin_options().IsModule());
319   DCHECK_IMPLIES(flags().block_coverage_enabled() && script.IsUserJavaScript(),
320                  source_range_map() != nullptr);
321 }
322 
Enqueue(ParseInfo * outer_parse_info,const AstRawString * function_name,FunctionLiteral * literal)323 void UnoptimizedCompileState::ParallelTasks::Enqueue(
324     ParseInfo* outer_parse_info, const AstRawString* function_name,
325     FunctionLiteral* literal) {
326   base::Optional<CompilerDispatcher::JobId> job_id =
327       dispatcher_->Enqueue(outer_parse_info, function_name, literal);
328   if (job_id) {
329     enqueued_jobs_.emplace_front(std::make_pair(literal, *job_id));
330   }
331 }
332 
333 }  // namespace internal
334 }  // namespace v8
335