1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "frontend/BytecodeCompiler.h"
8 
9 #include "mozilla/Attributes.h"
10 #include "mozilla/IntegerPrintfMacros.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/Utf8.h"  // mozilla::Utf8Unit
13 
14 #include "builtin/ModuleObject.h"
15 #if defined(JS_BUILD_BINAST)
16 #  include "frontend/BinASTParser.h"
17 #endif  // JS_BUILD_BINAST
18 #include "frontend/BytecodeCompilation.h"
19 #include "frontend/BytecodeEmitter.h"
20 #include "frontend/EitherParser.h"
21 #include "frontend/ErrorReporter.h"
22 #include "frontend/FoldConstants.h"
23 #ifdef JS_ENABLE_SMOOSH
24 #  include "frontend/Frontend2.h"  // Smoosh
25 #endif
26 #include "frontend/ModuleSharedContext.h"
27 #include "frontend/Parser.h"
28 #include "js/SourceText.h"
29 #include "vm/GeneratorAndAsyncKind.h"  // js::GeneratorKind, js::FunctionAsyncKind
30 #include "vm/GlobalObject.h"
31 #include "vm/JSContext.h"
32 #include "vm/JSScript.h"
33 #include "vm/ModuleBuilder.h"  // js::ModuleBuilder
34 #include "vm/TraceLogging.h"
35 #include "wasm/AsmJS.h"
36 
37 #include "debugger/DebugAPI-inl.h"  // DebugAPI
38 #include "vm/EnvironmentObject-inl.h"
39 #include "vm/GeckoProfiler-inl.h"
40 #include "vm/JSContext-inl.h"
41 
42 using namespace js;
43 using namespace js::frontend;
44 
45 using mozilla::Maybe;
46 using mozilla::Nothing;
47 using mozilla::Utf8Unit;
48 
49 using JS::CompileOptions;
50 using JS::ReadOnlyCompileOptions;
51 using JS::SourceText;
52 
53 // RAII class to check the frontend reports an exception when it fails to
54 // compile a script.
55 class MOZ_RAII AutoAssertReportedException {
56 #ifdef DEBUG
57   JSContext* cx_;
58   bool check_;
59 
60  public:
AutoAssertReportedException(JSContext * cx)61   explicit AutoAssertReportedException(JSContext* cx) : cx_(cx), check_(true) {}
reset()62   void reset() { check_ = false; }
~AutoAssertReportedException()63   ~AutoAssertReportedException() {
64     if (!check_) {
65       return;
66     }
67 
68     if (!cx_->isHelperThreadContext()) {
69       MOZ_ASSERT(cx_->isExceptionPending());
70       return;
71     }
72 
73     ParseTask* task = cx_->parseTask();
74     MOZ_ASSERT(task->outOfMemory || task->overRecursed ||
75                !task->errors.empty());
76   }
77 #else
78  public:
79   explicit AutoAssertReportedException(JSContext*) {}
80   void reset() {}
81 #endif
82 };
83 
84 static bool EmplaceEmitter(CompilationInfo& compilationInfo,
85                            Maybe<BytecodeEmitter>& emitter,
86                            const EitherParser& parser, SharedContext* sc);
87 
88 template <typename Unit>
89 class MOZ_STACK_CLASS frontend::SourceAwareCompiler {
90  protected:
91   SourceText<Unit>& sourceBuffer_;
92 
93   Maybe<Parser<SyntaxParseHandler, Unit>> syntaxParser;
94   Maybe<Parser<FullParseHandler, Unit>> parser;
95 
96   using TokenStreamPosition = frontend::TokenStreamPosition<Unit>;
97 
98  protected:
SourceAwareCompiler(SourceText<Unit> & sourceBuffer)99   explicit SourceAwareCompiler(SourceText<Unit>& sourceBuffer)
100       : sourceBuffer_(sourceBuffer) {
101     MOZ_ASSERT(sourceBuffer_.get() != nullptr);
102   }
103 
104   // Call this before calling compile{Global,Eval}Script.
105   MOZ_MUST_USE bool createSourceAndParser(LifoAllocScope& allocScope,
106                                           CompilationInfo& compilationInfo);
107 
assertSourceAndParserCreated(CompilationInfo & compilationInfo) const108   void assertSourceAndParserCreated(CompilationInfo& compilationInfo) const {
109     MOZ_ASSERT(compilationInfo.sourceObject != nullptr);
110     MOZ_ASSERT(compilationInfo.sourceObject->source() != nullptr);
111     MOZ_ASSERT(parser.isSome());
112   }
113 
assertSourceParserAndScriptCreated(CompilationInfo & compilationInfo)114   void assertSourceParserAndScriptCreated(CompilationInfo& compilationInfo) {
115     assertSourceAndParserCreated(compilationInfo);
116   }
117 
emplaceEmitter(CompilationInfo & compilationInfo,Maybe<BytecodeEmitter> & emitter,SharedContext * sharedContext)118   MOZ_MUST_USE bool emplaceEmitter(CompilationInfo& compilationInfo,
119                                    Maybe<BytecodeEmitter>& emitter,
120                                    SharedContext* sharedContext) {
121     return EmplaceEmitter(compilationInfo, emitter, EitherParser(parser.ptr()),
122                           sharedContext);
123   }
124 
125   bool canHandleParseFailure(CompilationInfo& compilationInfo,
126                              const Directives& newDirectives);
127 
128   void handleParseFailure(CompilationInfo& compilationInfo,
129                           const Directives& newDirectives,
130                           TokenStreamPosition& startPosition,
131                           CompilationInfo::RewindToken& startObj);
132 };
133 
134 template <typename Unit>
135 class MOZ_STACK_CLASS frontend::ScriptCompiler
136     : public SourceAwareCompiler<Unit> {
137   using Base = SourceAwareCompiler<Unit>;
138 
139  protected:
140   using Base::parser;
141   using Base::sourceBuffer_;
142 
143   using Base::assertSourceParserAndScriptCreated;
144   using Base::canHandleParseFailure;
145   using Base::emplaceEmitter;
146   using Base::handleParseFailure;
147 
148   using typename Base::TokenStreamPosition;
149 
150  public:
ScriptCompiler(SourceText<Unit> & srcBuf)151   explicit ScriptCompiler(SourceText<Unit>& srcBuf) : Base(srcBuf) {}
152 
153   using Base::createSourceAndParser;
154 
155   JSScript* compileScript(CompilationInfo& compilationInfo, SharedContext* sc);
156 };
157 
158 /* If we're on main thread, tell the Debugger about a newly compiled script.
159  *
160  * See: finishSingleParseTask/finishMultiParseTask for the off-thread case.
161  */
tellDebuggerAboutCompiledScript(JSContext * cx,bool hideScript,Handle<JSScript * > script)162 static void tellDebuggerAboutCompiledScript(JSContext* cx, bool hideScript,
163                                             Handle<JSScript*> script) {
164   if (cx->isHelperThreadContext()) {
165     return;
166   }
167 
168   // If hideScript then script may not be ready to be interrogated by the
169   // debugger.
170   if (!hideScript) {
171     DebugAPI::onNewScript(cx, script);
172   }
173 }
174 
175 template <typename Unit>
CreateGlobalScript(CompilationInfo & compilationInfo,GlobalSharedContext & globalsc,JS::SourceText<Unit> & srcBuf)176 static JSScript* CreateGlobalScript(CompilationInfo& compilationInfo,
177                                     GlobalSharedContext& globalsc,
178                                     JS::SourceText<Unit>& srcBuf) {
179   AutoAssertReportedException assertException(compilationInfo.cx);
180 
181   LifoAllocScope allocScope(&compilationInfo.cx->tempLifoAlloc());
182   frontend::ScriptCompiler<Unit> compiler(srcBuf);
183 
184   if (!compiler.createSourceAndParser(allocScope, compilationInfo)) {
185     return nullptr;
186   }
187 
188   if (!compiler.compileScript(compilationInfo, &globalsc)) {
189     return nullptr;
190   }
191 
192   tellDebuggerAboutCompiledScript(
193       compilationInfo.cx, compilationInfo.options.hideScriptFromDebugger,
194       compilationInfo.script);
195 
196   assertException.reset();
197   return compilationInfo.script;
198 }
199 
CompileGlobalScript(CompilationInfo & compilationInfo,GlobalSharedContext & globalsc,JS::SourceText<char16_t> & srcBuf)200 JSScript* frontend::CompileGlobalScript(CompilationInfo& compilationInfo,
201                                         GlobalSharedContext& globalsc,
202                                         JS::SourceText<char16_t>& srcBuf) {
203   return CreateGlobalScript(compilationInfo, globalsc, srcBuf);
204 }
205 
CompileGlobalScript(CompilationInfo & compilationInfo,GlobalSharedContext & globalsc,JS::SourceText<Utf8Unit> & srcBuf)206 JSScript* frontend::CompileGlobalScript(CompilationInfo& compilationInfo,
207                                         GlobalSharedContext& globalsc,
208                                         JS::SourceText<Utf8Unit>& srcBuf) {
209 #ifdef JS_ENABLE_SMOOSH
210   if (compilationInfo.cx->options().trySmoosh()) {
211     bool unimplemented = false;
212     JSContext* cx = compilationInfo.cx;
213     JSRuntime* rt = cx->runtime();
214     auto script =
215         Smoosh::compileGlobalScript(compilationInfo, srcBuf, &unimplemented);
216     if (!unimplemented) {
217       if (compilationInfo.cx->options().trackNotImplemented()) {
218         rt->parserWatcherFile.put("1");
219       }
220       return script;
221     }
222 
223     if (compilationInfo.cx->options().trackNotImplemented()) {
224       rt->parserWatcherFile.put("0");
225     }
226     fprintf(stderr, "Falling back!\n");
227   }
228 #endif  // JS_ENABLE_SMOOSH
229 
230   return CreateGlobalScript(compilationInfo, globalsc, srcBuf);
231 }
232 
233 template <typename Unit>
CreateEvalScript(CompilationInfo & compilationInfo,EvalSharedContext & evalsc,SourceText<Unit> & srcBuf)234 static JSScript* CreateEvalScript(CompilationInfo& compilationInfo,
235                                   EvalSharedContext& evalsc,
236                                   SourceText<Unit>& srcBuf) {
237   AutoAssertReportedException assertException(compilationInfo.cx);
238   LifoAllocScope allocScope(&compilationInfo.cx->tempLifoAlloc());
239 
240   frontend::ScriptCompiler<Unit> compiler(srcBuf);
241   if (!compiler.createSourceAndParser(allocScope, compilationInfo)) {
242     return nullptr;
243   }
244 
245   if (!compiler.compileScript(compilationInfo, &evalsc)) {
246     return nullptr;
247   }
248 
249   tellDebuggerAboutCompiledScript(
250       compilationInfo.cx, compilationInfo.options.hideScriptFromDebugger,
251       compilationInfo.script);
252 
253   assertException.reset();
254   return compilationInfo.script;
255 }
256 
CompileEvalScript(CompilationInfo & compilationInfo,EvalSharedContext & evalsc,JS::SourceText<char16_t> & srcBuf)257 JSScript* frontend::CompileEvalScript(CompilationInfo& compilationInfo,
258                                       EvalSharedContext& evalsc,
259                                       JS::SourceText<char16_t>& srcBuf) {
260   return CreateEvalScript(compilationInfo, evalsc, srcBuf);
261 }
262 
263 template <typename Unit>
264 class MOZ_STACK_CLASS frontend::ModuleCompiler final
265     : public SourceAwareCompiler<Unit> {
266   using Base = SourceAwareCompiler<Unit>;
267 
268   using Base::assertSourceParserAndScriptCreated;
269   using Base::createSourceAndParser;
270   using Base::emplaceEmitter;
271   using Base::parser;
272 
273  public:
ModuleCompiler(SourceText<Unit> & srcBuf)274   explicit ModuleCompiler(SourceText<Unit>& srcBuf) : Base(srcBuf) {}
275 
276   ModuleObject* compile(CompilationInfo& compilationInfo);
277 };
278 
279 template <typename Unit>
280 class MOZ_STACK_CLASS frontend::StandaloneFunctionCompiler final
281     : public SourceAwareCompiler<Unit> {
282   using Base = SourceAwareCompiler<Unit>;
283 
284   using Base::assertSourceAndParserCreated;
285   using Base::canHandleParseFailure;
286   using Base::emplaceEmitter;
287   using Base::handleParseFailure;
288   using Base::parser;
289   using Base::sourceBuffer_;
290 
291   using typename Base::TokenStreamPosition;
292 
293  public:
StandaloneFunctionCompiler(SourceText<Unit> & srcBuf)294   explicit StandaloneFunctionCompiler(SourceText<Unit>& srcBuf)
295       : Base(srcBuf) {}
296 
297   using Base::createSourceAndParser;
298 
299   FunctionNode* parse(CompilationInfo& compilationInfo, HandleFunction fun,
300                       HandleScope enclosingScope, GeneratorKind generatorKind,
301                       FunctionAsyncKind asyncKind,
302                       const Maybe<uint32_t>& parameterListEnd);
303 
304   MOZ_MUST_USE bool compile(MutableHandleFunction fun, CompilationInfo& info,
305                             FunctionNode* parsedFunction);
306 };
307 
AutoFrontendTraceLog(JSContext * cx,const TraceLoggerTextId id,const ErrorReporter & errorReporter)308 AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx,
309                                            const TraceLoggerTextId id,
310                                            const ErrorReporter& errorReporter)
311 #ifdef JS_TRACE_LOGGING
312     : logger_(TraceLoggerForCurrentThread(cx)) {
313   if (!logger_) {
314     return;
315   }
316 
317   // If the tokenizer hasn't yet gotten any tokens, use the line and column
318   // numbers from CompileOptions.
319   uint32_t line, column;
320   if (errorReporter.hasTokenizationStarted()) {
321     line = errorReporter.options().lineno;
322     column = errorReporter.options().column;
323   } else {
324     errorReporter.currentLineAndColumn(&line, &column);
325   }
326   frontendEvent_.emplace(TraceLogger_Frontend, errorReporter.getFilename(),
327                          line, column);
328   frontendLog_.emplace(logger_, *frontendEvent_);
329   typeLog_.emplace(logger_, id);
330 }
331 #else
332 {
333 }
334 #endif
335 
AutoFrontendTraceLog(JSContext * cx,const TraceLoggerTextId id,const ErrorReporter & errorReporter,FunctionBox * funbox)336 AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx,
337                                            const TraceLoggerTextId id,
338                                            const ErrorReporter& errorReporter,
339                                            FunctionBox* funbox)
340 #ifdef JS_TRACE_LOGGING
341     : logger_(TraceLoggerForCurrentThread(cx)) {
342   if (!logger_) {
343     return;
344   }
345 
346   frontendEvent_.emplace(TraceLogger_Frontend, errorReporter.getFilename(),
347                          funbox->extent.lineno, funbox->extent.column);
348   frontendLog_.emplace(logger_, *frontendEvent_);
349   typeLog_.emplace(logger_, id);
350 }
351 #else
352 {
353 }
354 #endif
355 
AutoFrontendTraceLog(JSContext * cx,const TraceLoggerTextId id,const ErrorReporter & errorReporter,ParseNode * pn)356 AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx,
357                                            const TraceLoggerTextId id,
358                                            const ErrorReporter& errorReporter,
359                                            ParseNode* pn)
360 #ifdef JS_TRACE_LOGGING
361     : logger_(TraceLoggerForCurrentThread(cx)) {
362   if (!logger_) {
363     return;
364   }
365 
366   uint32_t line, column;
367   errorReporter.lineAndColumnAt(pn->pn_pos.begin, &line, &column);
368   frontendEvent_.emplace(TraceLogger_Frontend, errorReporter.getFilename(),
369                          line, column);
370   frontendLog_.emplace(logger_, *frontendEvent_);
371   typeLog_.emplace(logger_, id);
372 }
373 #else
374 {
375 }
376 #endif
377 
CanLazilyParse(const CompilationInfo & compilationInfo)378 static bool CanLazilyParse(const CompilationInfo& compilationInfo) {
379   return !compilationInfo.options.discardSource &&
380          !compilationInfo.options.sourceIsLazy &&
381          !compilationInfo.options.forceFullParse();
382 }
383 
384 template <typename Unit>
createSourceAndParser(LifoAllocScope & allocScope,CompilationInfo & compilationInfo)385 bool frontend::SourceAwareCompiler<Unit>::createSourceAndParser(
386     LifoAllocScope& allocScope, CompilationInfo& compilationInfo) {
387   if (!compilationInfo.assignSource(sourceBuffer_)) {
388     return false;
389   }
390 
391   if (CanLazilyParse(compilationInfo)) {
392     syntaxParser.emplace(compilationInfo.cx, compilationInfo.options,
393                          sourceBuffer_.units(), sourceBuffer_.length(),
394                          /* foldConstants = */ false, compilationInfo, nullptr,
395                          nullptr);
396     if (!syntaxParser->checkOptions()) {
397       return false;
398     }
399   }
400 
401   parser.emplace(compilationInfo.cx, compilationInfo.options,
402                  sourceBuffer_.units(), sourceBuffer_.length(),
403                  /* foldConstants = */ true, compilationInfo,
404                  syntaxParser.ptrOr(nullptr), nullptr);
405   parser->ss = compilationInfo.sourceObject->source();
406   return parser->checkOptions();
407 }
408 
EmplaceEmitter(CompilationInfo & compilationInfo,Maybe<BytecodeEmitter> & emitter,const EitherParser & parser,SharedContext * sc)409 static bool EmplaceEmitter(CompilationInfo& compilationInfo,
410                            Maybe<BytecodeEmitter>& emitter,
411                            const EitherParser& parser, SharedContext* sc) {
412   BytecodeEmitter::EmitterMode emitterMode =
413       sc->selfHosted() ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal;
414   emitter.emplace(/* parent = */ nullptr, parser, sc, compilationInfo,
415                   emitterMode);
416   return emitter->init();
417 }
418 
419 template <typename Unit>
canHandleParseFailure(CompilationInfo & compilationInfo,const Directives & newDirectives)420 bool frontend::SourceAwareCompiler<Unit>::canHandleParseFailure(
421     CompilationInfo& compilationInfo, const Directives& newDirectives) {
422   // Try to reparse if no parse errors were thrown and the directives changed.
423   //
424   // NOTE:
425   // Only the following two directive changes force us to reparse the script:
426   // - The "use asm" directive was encountered.
427   // - The "use strict" directive was encountered and duplicate parameter names
428   //   are present. We reparse in this case to display the error at the correct
429   //   source location. See |Parser::hasValidSimpleStrictParameterNames()|.
430   return !parser->anyChars.hadError() &&
431          compilationInfo.directives != newDirectives;
432 }
433 
434 template <typename Unit>
handleParseFailure(CompilationInfo & compilationInfo,const Directives & newDirectives,TokenStreamPosition & startPosition,CompilationInfo::RewindToken & startObj)435 void frontend::SourceAwareCompiler<Unit>::handleParseFailure(
436     CompilationInfo& compilationInfo, const Directives& newDirectives,
437     TokenStreamPosition& startPosition,
438     CompilationInfo::RewindToken& startObj) {
439   MOZ_ASSERT(canHandleParseFailure(compilationInfo, newDirectives));
440 
441   // Rewind to starting position to retry.
442   parser->tokenStream.rewind(startPosition);
443   compilationInfo.rewind(startObj);
444 
445   // Assignment must be monotonic to prevent reparsing iloops
446   MOZ_ASSERT_IF(compilationInfo.directives.strict(), newDirectives.strict());
447   MOZ_ASSERT_IF(compilationInfo.directives.asmJS(), newDirectives.asmJS());
448   compilationInfo.directives = newDirectives;
449 }
450 
451 template <typename Unit>
compileScript(CompilationInfo & compilationInfo,SharedContext * sc)452 JSScript* frontend::ScriptCompiler<Unit>::compileScript(
453     CompilationInfo& compilationInfo, SharedContext* sc) {
454   assertSourceParserAndScriptCreated(compilationInfo);
455 
456   TokenStreamPosition startPosition(compilationInfo.keepAtoms,
457                                     parser->tokenStream);
458 
459   JSContext* cx = compilationInfo.cx;
460 
461   ParseNode* pn;
462   {
463     AutoGeckoProfilerEntry pseudoFrame(cx, "script parsing",
464                                        JS::ProfilingCategoryPair::JS_Parsing);
465     if (sc->isEvalContext()) {
466       pn = parser->evalBody(sc->asEvalContext());
467     } else {
468       pn = parser->globalBody(sc->asGlobalContext());
469     }
470   }
471 
472   if (!pn) {
473     // Global and eval scripts don't get reparsed after a new directive was
474     // encountered:
475     // - "use strict" doesn't require any special error reporting for scripts.
476     // - "use asm" directives don't have an effect in global/eval contexts.
477     MOZ_ASSERT(
478         !canHandleParseFailure(compilationInfo, compilationInfo.directives));
479     return nullptr;
480   }
481 
482   {
483     // Successfully parsed. Emit the script.
484     AutoGeckoProfilerEntry pseudoFrame(cx, "script emit",
485                                        JS::ProfilingCategoryPair::JS_Parsing);
486 
487     Maybe<BytecodeEmitter> emitter;
488     if (!emplaceEmitter(compilationInfo, emitter, sc)) {
489       return nullptr;
490     }
491 
492     if (!emitter->emitScript(pn)) {
493       return nullptr;
494     }
495 
496     if (!compilationInfo.instantiateStencils()) {
497       return nullptr;
498     }
499 
500     MOZ_ASSERT(compilationInfo.script);
501   }
502 
503   // We have just finished parsing the source. Inform the source so that we
504   // can compute statistics (e.g. how much time our functions remain lazy).
505   compilationInfo.sourceObject->source()->recordParseEnded();
506 
507   // Enqueue an off-thread source compression task after finishing parsing.
508   if (!compilationInfo.sourceObject->source()->tryCompressOffThread(cx)) {
509     return nullptr;
510   }
511 
512   MOZ_ASSERT_IF(!cx->isHelperThreadContext(), !cx->isExceptionPending());
513 
514   return compilationInfo.script;
515 }
516 
517 template <typename Unit>
compile(CompilationInfo & compilationInfo)518 ModuleObject* frontend::ModuleCompiler<Unit>::compile(
519     CompilationInfo& compilationInfo) {
520   if (!createSourceAndParser(compilationInfo.allocScope, compilationInfo)) {
521     return nullptr;
522   }
523   JSContext* cx = compilationInfo.cx;
524 
525   Rooted<ModuleObject*> module(cx, ModuleObject::create(cx));
526   if (!module) {
527     return nullptr;
528   }
529 
530   ModuleBuilder builder(cx, parser.ptr());
531 
532   RootedScope enclosingScope(cx, &cx->global()->emptyGlobalScope());
533   uint32_t len = this->sourceBuffer_.length();
534   SourceExtent extent =
535       SourceExtent::makeGlobalExtent(len, compilationInfo.options);
536   ModuleSharedContext modulesc(cx, module, compilationInfo, enclosingScope,
537                                builder, extent);
538 
539   ParseNode* pn = parser->moduleBody(&modulesc);
540   if (!pn) {
541     return nullptr;
542   }
543 
544   Maybe<BytecodeEmitter> emitter;
545   if (!emplaceEmitter(compilationInfo, emitter, &modulesc)) {
546     return nullptr;
547   }
548 
549   if (!emitter->emitScript(pn->as<ModuleNode>().body())) {
550     return nullptr;
551   }
552 
553   if (!compilationInfo.instantiateStencils()) {
554     return nullptr;
555   }
556 
557   MOZ_ASSERT(compilationInfo.script);
558 
559   if (!builder.initModule(module)) {
560     return nullptr;
561   }
562 
563   module->initScriptSlots(compilationInfo.script);
564   module->initStatusSlot();
565 
566   if (!ModuleObject::createEnvironment(cx, module)) {
567     return nullptr;
568   }
569 
570   // Enqueue an off-thread source compression task after finishing parsing.
571   if (!compilationInfo.sourceObject->source()->tryCompressOffThread(cx)) {
572     return nullptr;
573   }
574 
575   MOZ_ASSERT_IF(!cx->isHelperThreadContext(), !cx->isExceptionPending());
576   return module;
577 }
578 
579 // Parse a standalone JS function, which might appear as the value of an
580 // event handler attribute in an HTML <INPUT> tag, or in a Function()
581 // constructor.
582 template <typename Unit>
parse(CompilationInfo & compilationInfo,HandleFunction fun,HandleScope enclosingScope,GeneratorKind generatorKind,FunctionAsyncKind asyncKind,const Maybe<uint32_t> & parameterListEnd)583 FunctionNode* frontend::StandaloneFunctionCompiler<Unit>::parse(
584     CompilationInfo& compilationInfo, HandleFunction fun,
585     HandleScope enclosingScope, GeneratorKind generatorKind,
586     FunctionAsyncKind asyncKind, const Maybe<uint32_t>& parameterListEnd) {
587   MOZ_ASSERT(fun);
588   MOZ_ASSERT(fun->isTenured());
589 
590   assertSourceAndParserCreated(compilationInfo);
591 
592   TokenStreamPosition startPosition(compilationInfo.keepAtoms,
593                                     parser->tokenStream);
594   CompilationInfo::RewindToken startObj = compilationInfo.getRewindToken();
595 
596   // Speculatively parse using the default directives implied by the context.
597   // If a directive is encountered (e.g., "use strict") that changes how the
598   // function should have been parsed, we backup and reparse with the new set
599   // of directives.
600 
601   FunctionNode* fn;
602   for (;;) {
603     Directives newDirectives = compilationInfo.directives;
604     fn = parser->standaloneFunction(fun, enclosingScope, parameterListEnd,
605                                     generatorKind, asyncKind,
606                                     compilationInfo.directives, &newDirectives);
607     if (fn) {
608       break;
609     }
610 
611     // Maybe we encountered a new directive. See if we can try again.
612     if (!canHandleParseFailure(compilationInfo, newDirectives)) {
613       return nullptr;
614     }
615 
616     handleParseFailure(compilationInfo, newDirectives, startPosition, startObj);
617   }
618 
619   return fn;
620 }
621 
622 // Compile a standalone JS function.
623 template <typename Unit>
compile(MutableHandleFunction fun,CompilationInfo & compilationInfo,FunctionNode * parsedFunction)624 bool frontend::StandaloneFunctionCompiler<Unit>::compile(
625     MutableHandleFunction fun, CompilationInfo& compilationInfo,
626     FunctionNode* parsedFunction) {
627   FunctionBox* funbox = parsedFunction->funbox();
628   if (funbox->isInterpreted()) {
629     MOZ_ASSERT(fun == funbox->function());
630 
631     // The parser extent has stripped off the leading `function...` but
632     // we want the SourceExtent used in the final standalone script to
633     // start from the beginning of the buffer, and use the provided
634     // line and column.
635     compilationInfo.topLevelExtent =
636         SourceExtent{/* sourceStart = */ 0,
637                      sourceBuffer_.length(),
638                      funbox->extent.toStringStart,
639                      funbox->extent.toStringEnd,
640                      compilationInfo.options.lineno,
641                      compilationInfo.options.column};
642 
643     Maybe<BytecodeEmitter> emitter;
644     if (!emplaceEmitter(compilationInfo, emitter, funbox)) {
645       return false;
646     }
647 
648     if (!emitter->emitFunctionScript(parsedFunction, TopLevelFunction::Yes)) {
649       return false;
650     }
651 
652     funbox->synchronizeArgCount();
653 
654     if (!compilationInfo.instantiateStencils()) {
655       return false;
656     }
657 
658     MOZ_ASSERT(compilationInfo.script);
659   } else {
660     fun.set(funbox->function());
661     MOZ_ASSERT(IsAsmJSModule(fun));
662   }
663 
664   // Enqueue an off-thread source compression task after finishing parsing.
665   return compilationInfo.sourceObject->source()->tryCompressOffThread(
666       compilationInfo.cx);
667 }
668 
CreateScriptSourceObject(JSContext * cx,const ReadOnlyCompileOptions & options)669 ScriptSourceObject* frontend::CreateScriptSourceObject(
670     JSContext* cx, const ReadOnlyCompileOptions& options) {
671   ScriptSource* ss = cx->new_<ScriptSource>();
672   if (!ss) {
673     return nullptr;
674   }
675   ScriptSourceHolder ssHolder(ss);
676 
677   if (!ss->initFromOptions(cx, options)) {
678     return nullptr;
679   }
680 
681   RootedScriptSourceObject sso(cx, ScriptSourceObject::create(cx, ss));
682   if (!sso) {
683     return nullptr;
684   }
685 
686   // Off-thread compilations do all their GC heap allocation, including the
687   // SSO, in a temporary compartment. Hence, for the SSO to refer to the
688   // gc-heap-allocated values in |options|, it would need cross-compartment
689   // wrappers from the temporary compartment to the real compartment --- which
690   // would then be inappropriate once we merged the temporary and real
691   // compartments.
692   //
693   // Instead, we put off populating those SSO slots in off-thread compilations
694   // until after we've merged compartments.
695   if (!cx->isHelperThreadContext()) {
696     if (!ScriptSourceObject::initFromOptions(cx, sso, options)) {
697       return nullptr;
698     }
699   }
700 
701   return sso;
702 }
703 
704 #if defined(JS_BUILD_BINAST)
705 
706 template <class ParserT>
CompileGlobalBinASTScriptImpl(JSContext * cx,const ReadOnlyCompileOptions & options,const uint8_t * src,size_t len,JS::BinASTFormat format,ScriptSourceObject ** sourceObjectOut)707 static JSScript* CompileGlobalBinASTScriptImpl(
708     JSContext* cx, const ReadOnlyCompileOptions& options, const uint8_t* src,
709     size_t len, JS::BinASTFormat format, ScriptSourceObject** sourceObjectOut) {
710   AutoAssertReportedException assertException(cx);
711 
712   LifoAllocScope allocScope(&cx->tempLifoAlloc());
713   CompilationInfo compilationInfo(cx, allocScope, options);
714   if (!compilationInfo.init(cx)) {
715     return nullptr;
716   }
717 
718   if (!compilationInfo.sourceObject->source()->setBinASTSourceCopy(cx, src,
719                                                                    len)) {
720     return nullptr;
721   }
722 
723   SourceExtent extent = SourceExtent::makeGlobalExtent(len);
724   extent.lineno = 0;
725   GlobalSharedContext globalsc(cx, ScopeKind::Global, compilationInfo,
726                                compilationInfo.directives, extent);
727 
728   frontend::BinASTParser<ParserT> parser(cx, compilationInfo, options);
729 
730   // Metadata stores internal pointers, so we must use the same buffer every
731   // time, including for lazy parses
732   ScriptSource* ss = compilationInfo.sourceObject->source();
733   BinASTSourceMetadata* metadata = nullptr;
734   auto parsed =
735       parser.parse(&globalsc, ss->binASTSource(), ss->length(), &metadata);
736 
737   if (parsed.isErr()) {
738     return nullptr;
739   }
740 
741   compilationInfo.sourceObject->source()->setBinASTSourceMetadata(metadata);
742 
743   BytecodeEmitter bce(nullptr, &parser, &globalsc, compilationInfo);
744 
745   if (!bce.init()) {
746     return nullptr;
747   }
748 
749   ParseNode* pn = parsed.unwrap();
750   if (!bce.emitScript(pn)) {
751     return nullptr;
752   }
753 
754   if (!compilationInfo.instantiateStencils()) {
755     return nullptr;
756   }
757 
758   if (sourceObjectOut) {
759     *sourceObjectOut = compilationInfo.sourceObject;
760   }
761 
762   tellDebuggerAboutCompiledScript(cx, options.hideScriptFromDebugger,
763                                   compilationInfo.script);
764 
765   assertException.reset();
766   return compilationInfo.script;
767 }
768 
CompileGlobalBinASTScript(JSContext * cx,const ReadOnlyCompileOptions & options,const uint8_t * src,size_t len,JS::BinASTFormat format,ScriptSourceObject ** sourceObjectOut)769 JSScript* frontend::CompileGlobalBinASTScript(
770     JSContext* cx, const ReadOnlyCompileOptions& options, const uint8_t* src,
771     size_t len, JS::BinASTFormat format, ScriptSourceObject** sourceObjectOut) {
772   if (format == JS::BinASTFormat::Multipart) {
773     return CompileGlobalBinASTScriptImpl<BinASTTokenReaderMultipart>(
774         cx, options, src, len, format, sourceObjectOut);
775   }
776 
777   MOZ_ASSERT(format == JS::BinASTFormat::Context);
778   return CompileGlobalBinASTScriptImpl<BinASTTokenReaderContext>(
779       cx, options, src, len, format, sourceObjectOut);
780 }
781 
782 #endif  // JS_BUILD_BINAST
783 
784 template <typename Unit>
InternalParseModule(JSContext * cx,const ReadOnlyCompileOptions & optionsInput,SourceText<Unit> & srcBuf,ScriptSourceObject ** sourceObjectOut)785 static ModuleObject* InternalParseModule(
786     JSContext* cx, const ReadOnlyCompileOptions& optionsInput,
787     SourceText<Unit>& srcBuf, ScriptSourceObject** sourceObjectOut) {
788   MOZ_ASSERT(srcBuf.get());
789   MOZ_ASSERT_IF(sourceObjectOut, *sourceObjectOut == nullptr);
790 
791   AutoAssertReportedException assertException(cx);
792 
793   CompileOptions options(cx, optionsInput);
794   options.setForceStrictMode();  // ES6 10.2.1 Module code is always strict mode
795                                  // code.
796   options.setIsRunOnce(true);
797   options.allowHTMLComments = false;
798 
799   LifoAllocScope allocScope(&cx->tempLifoAlloc());
800   CompilationInfo compilationInfo(cx, allocScope, options);
801   if (!compilationInfo.init(cx)) {
802     return nullptr;
803   }
804 
805   if (sourceObjectOut) {
806     *sourceObjectOut = compilationInfo.sourceObject;
807   }
808 
809   ModuleCompiler<Unit> compiler(srcBuf);
810   Rooted<ModuleObject*> module(cx, compiler.compile(compilationInfo));
811   if (!module) {
812     return nullptr;
813   }
814 
815   tellDebuggerAboutCompiledScript(cx, options.hideScriptFromDebugger,
816                                   compilationInfo.script);
817 
818   assertException.reset();
819   return module;
820 }
821 
ParseModule(JSContext * cx,const ReadOnlyCompileOptions & optionsInput,SourceText<char16_t> & srcBuf,ScriptSourceObject ** sourceObjectOut)822 ModuleObject* frontend::ParseModule(JSContext* cx,
823                                     const ReadOnlyCompileOptions& optionsInput,
824                                     SourceText<char16_t>& srcBuf,
825                                     ScriptSourceObject** sourceObjectOut) {
826   return InternalParseModule(cx, optionsInput, srcBuf, sourceObjectOut);
827 }
828 
ParseModule(JSContext * cx,const ReadOnlyCompileOptions & optionsInput,SourceText<Utf8Unit> & srcBuf,ScriptSourceObject ** sourceObjectOut)829 ModuleObject* frontend::ParseModule(JSContext* cx,
830                                     const ReadOnlyCompileOptions& optionsInput,
831                                     SourceText<Utf8Unit>& srcBuf,
832                                     ScriptSourceObject** sourceObjectOut) {
833   return InternalParseModule(cx, optionsInput, srcBuf, sourceObjectOut);
834 }
835 
836 template <typename Unit>
CreateModule(JSContext * cx,const JS::ReadOnlyCompileOptions & options,SourceText<Unit> & srcBuf)837 static ModuleObject* CreateModule(JSContext* cx,
838                                   const JS::ReadOnlyCompileOptions& options,
839                                   SourceText<Unit>& srcBuf) {
840   AutoAssertReportedException assertException(cx);
841 
842   if (!GlobalObject::ensureModulePrototypesCreated(cx, cx->global())) {
843     return nullptr;
844   }
845 
846   RootedModuleObject module(cx, ParseModule(cx, options, srcBuf, nullptr));
847   if (!module) {
848     return nullptr;
849   }
850 
851   // This happens in GlobalHelperThreadState::finishModuleParseTask() when a
852   // module is compiled off thread.
853   if (!ModuleObject::Freeze(cx, module)) {
854     return nullptr;
855   }
856 
857   assertException.reset();
858   return module;
859 }
860 
CompileModule(JSContext * cx,const JS::ReadOnlyCompileOptions & options,SourceText<char16_t> & srcBuf)861 ModuleObject* frontend::CompileModule(JSContext* cx,
862                                       const JS::ReadOnlyCompileOptions& options,
863                                       SourceText<char16_t>& srcBuf) {
864   return CreateModule(cx, options, srcBuf);
865 }
866 
CompileModule(JSContext * cx,const JS::ReadOnlyCompileOptions & options,SourceText<Utf8Unit> & srcBuf)867 ModuleObject* frontend::CompileModule(JSContext* cx,
868                                       const JS::ReadOnlyCompileOptions& options,
869                                       SourceText<Utf8Unit>& srcBuf) {
870   return CreateModule(cx, options, srcBuf);
871 }
872 
873 template <typename Unit>
CompileLazyFunctionImpl(JSContext * cx,Handle<BaseScript * > lazy,const Unit * units,size_t length)874 static bool CompileLazyFunctionImpl(JSContext* cx, Handle<BaseScript*> lazy,
875                                     const Unit* units, size_t length) {
876   MOZ_ASSERT(cx->compartment() == lazy->compartment());
877 
878   // We can only compile functions whose parents have previously been
879   // compiled, because compilation requires full information about the
880   // function's immediately enclosing scope.
881   MOZ_ASSERT(lazy->isReadyForDelazification());
882   MOZ_ASSERT(!lazy->isBinAST());
883 
884   AutoAssertReportedException assertException(cx);
885   Rooted<JSFunction*> fun(cx, lazy->function());
886 
887   JS::CompileOptions options(cx);
888   options.setMutedErrors(lazy->mutedErrors())
889       .setFileAndLine(lazy->filename(), lazy->lineno())
890       .setColumn(lazy->column())
891       .setScriptSourceOffset(lazy->sourceStart())
892       .setNoScriptRval(false)
893       .setSelfHostingMode(false);
894 
895   // Update statistics to find out if we are delazifying just after having
896   // lazified. Note that we are interested in the delta between end of
897   // syntax parsing and start of full parsing, so we do this now rather than
898   // after parsing below.
899   if (!lazy->scriptSource()->parseEnded().IsNull()) {
900     const mozilla::TimeDuration delta =
901         ReallyNow() - lazy->scriptSource()->parseEnded();
902 
903     // Differentiate between web-facing and privileged code, to aid
904     // with optimization. Due to the number of calls to this function,
905     // we use `cx->runningWithTrustedPrincipals`, which is fast but
906     // will classify addons alongside with web-facing code.
907     const int HISTOGRAM =
908         cx->runningWithTrustedPrincipals()
909             ? JS_TELEMETRY_PRIVILEGED_PARSER_COMPILE_LAZY_AFTER_MS
910             : JS_TELEMETRY_WEB_PARSER_COMPILE_LAZY_AFTER_MS;
911     cx->runtime()->addTelemetry(HISTOGRAM, delta.ToMilliseconds());
912   }
913 
914   LifoAllocScope allocScope(&cx->tempLifoAlloc());
915   CompilationInfo compilationInfo(cx, allocScope, options,
916                                   fun->enclosingScope());
917   compilationInfo.initFromLazy(lazy);
918 
919   Parser<FullParseHandler, Unit> parser(cx, options, units, length,
920                                         /* foldConstants = */ true,
921                                         compilationInfo, nullptr, lazy);
922   if (!parser.checkOptions()) {
923     return false;
924   }
925 
926   FunctionNode* pn =
927       parser.standaloneLazyFunction(fun, lazy->toStringStart(), lazy->strict(),
928                                     lazy->generatorKind(), lazy->asyncKind());
929   if (!pn) {
930     return false;
931   }
932 
933   mozilla::DebugOnly<uint32_t> lazyFlags =
934       static_cast<uint32_t>(lazy->immutableFlags());
935 
936   BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->funbox(),
937                       compilationInfo, BytecodeEmitter::LazyFunction);
938   if (!bce.init(pn->pn_pos)) {
939     return false;
940   }
941 
942   if (!bce.emitFunctionScript(pn, TopLevelFunction::Yes)) {
943     return false;
944   }
945 
946   if (!compilationInfo.instantiateStencils()) {
947     return false;
948   }
949 
950   MOZ_ASSERT(lazyFlags == compilationInfo.script->immutableFlags());
951   MOZ_ASSERT(compilationInfo.script->outermostScope()->hasOnChain(
952                  ScopeKind::NonSyntactic) ==
953              compilationInfo.script->immutableFlags().hasFlag(
954                  JSScript::ImmutableFlags::HasNonSyntacticScope));
955 
956   assertException.reset();
957   return true;
958 }
959 
CompileLazyFunction(JSContext * cx,Handle<BaseScript * > lazy,const char16_t * units,size_t length)960 bool frontend::CompileLazyFunction(JSContext* cx, Handle<BaseScript*> lazy,
961                                    const char16_t* units, size_t length) {
962   return CompileLazyFunctionImpl(cx, lazy, units, length);
963 }
964 
CompileLazyFunction(JSContext * cx,Handle<BaseScript * > lazy,const Utf8Unit * units,size_t length)965 bool frontend::CompileLazyFunction(JSContext* cx, Handle<BaseScript*> lazy,
966                                    const Utf8Unit* units, size_t length) {
967   return CompileLazyFunctionImpl(cx, lazy, units, length);
968 }
969 
970 #ifdef JS_BUILD_BINAST
971 
972 template <class ParserT>
CompileLazyBinASTFunctionImpl(JSContext * cx,Handle<BaseScript * > lazy,const uint8_t * buf,size_t length)973 static bool CompileLazyBinASTFunctionImpl(JSContext* cx,
974                                           Handle<BaseScript*> lazy,
975                                           const uint8_t* buf, size_t length) {
976   MOZ_ASSERT(cx->compartment() == lazy->compartment());
977 
978   // We can only compile functions whose parents have previously been
979   // compiled, because compilation requires full information about the
980   // function's immediately enclosing scope.
981   MOZ_ASSERT(lazy->isReadyForDelazification());
982   MOZ_ASSERT(lazy->isBinAST());
983 
984   AutoAssertReportedException assertException(cx);
985   Rooted<JSFunction*> fun(cx, lazy->function());
986 
987   mozilla::DebugOnly<bool> lazyIsLikelyConstructorWrapper =
988       lazy->isLikelyConstructorWrapper();
989 
990   CompileOptions options(cx);
991   options.setMutedErrors(lazy->mutedErrors())
992       .setFileAndLine(lazy->filename(), lazy->lineno())
993       .setColumn(lazy->column())
994       .setScriptSourceOffset(lazy->sourceStart())
995       .setNoScriptRval(false)
996       .setSelfHostingMode(false);
997 
998   LifoAllocScope allocScope(&cx->tempLifoAlloc());
999   CompilationInfo compilationInfo(cx, allocScope, options);
1000   compilationInfo.initFromLazy(lazy);
1001 
1002   frontend::BinASTParser<ParserT> parser(cx, compilationInfo, options, lazy);
1003 
1004   auto parsed =
1005       parser.parseLazyFunction(lazy->scriptSource(), lazy->sourceStart());
1006 
1007   if (parsed.isErr()) {
1008     return false;
1009   }
1010 
1011   FunctionNode* pn = parsed.unwrap();
1012 
1013   BytecodeEmitter bce(nullptr, &parser, pn->funbox(), compilationInfo,
1014                       BytecodeEmitter::LazyFunction);
1015 
1016   if (!bce.init(pn->pn_pos)) {
1017     return false;
1018   }
1019 
1020   if (!bce.emitFunctionScript(pn, TopLevelFunction::Yes)) {
1021     return false;
1022   }
1023 
1024   if (!compilationInfo.instantiateStencils()) {
1025     return false;
1026   }
1027 
1028   // This value *must* not change after the lazy function is first created.
1029   MOZ_ASSERT(lazyIsLikelyConstructorWrapper ==
1030              compilationInfo.script->isLikelyConstructorWrapper());
1031 
1032   assertException.reset();
1033   return true;
1034 }
1035 
CompileLazyBinASTFunction(JSContext * cx,Handle<BaseScript * > lazy,const uint8_t * buf,size_t length)1036 bool frontend::CompileLazyBinASTFunction(JSContext* cx,
1037                                          Handle<BaseScript*> lazy,
1038                                          const uint8_t* buf, size_t length) {
1039   if (lazy->scriptSource()->binASTSourceMetadata()->isMultipart()) {
1040     return CompileLazyBinASTFunctionImpl<BinASTTokenReaderMultipart>(
1041         cx, lazy, buf, length);
1042   }
1043 
1044   MOZ_ASSERT(lazy->scriptSource()->binASTSourceMetadata()->isContext());
1045   return CompileLazyBinASTFunctionImpl<BinASTTokenReaderContext>(cx, lazy, buf,
1046                                                                  length);
1047 }
1048 
1049 #endif  // JS_BUILD_BINAST
1050 
CompileStandaloneFunction(JSContext * cx,MutableHandleFunction fun,const JS::ReadOnlyCompileOptions & options,JS::SourceText<char16_t> & srcBuf,const Maybe<uint32_t> & parameterListEnd,GeneratorKind generatorKind,FunctionAsyncKind asyncKind,HandleScope enclosingScope=nullptr)1051 static bool CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
1052                                       const JS::ReadOnlyCompileOptions& options,
1053                                       JS::SourceText<char16_t>& srcBuf,
1054                                       const Maybe<uint32_t>& parameterListEnd,
1055                                       GeneratorKind generatorKind,
1056                                       FunctionAsyncKind asyncKind,
1057                                       HandleScope enclosingScope = nullptr) {
1058   AutoAssertReportedException assertException(cx);
1059 
1060   LifoAllocScope allocScope(&cx->tempLifoAlloc());
1061   CompilationInfo compilationInfo(cx, allocScope, options, enclosingScope);
1062   if (!compilationInfo.init(cx)) {
1063     return false;
1064   }
1065 
1066   StandaloneFunctionCompiler<char16_t> compiler(srcBuf);
1067   if (!compiler.createSourceAndParser(allocScope, compilationInfo)) {
1068     return false;
1069   }
1070 
1071   RootedScope scope(cx, enclosingScope);
1072   if (!scope) {
1073     scope = &cx->global()->emptyGlobalScope();
1074   }
1075 
1076   FunctionNode* parsedFunction = compiler.parse(
1077       compilationInfo, fun, scope, generatorKind, asyncKind, parameterListEnd);
1078   if (!parsedFunction ||
1079       !compiler.compile(fun, compilationInfo, parsedFunction)) {
1080     return false;
1081   }
1082 
1083   // Note: If AsmJS successfully compiles, the into.script will still be
1084   // nullptr. In this case we have compiled to a native function instead of an
1085   // interpreted script.
1086   if (compilationInfo.script) {
1087     if (parameterListEnd) {
1088       compilationInfo.sourceObject->source()->setParameterListEnd(
1089           *parameterListEnd);
1090     }
1091     tellDebuggerAboutCompiledScript(cx, options.hideScriptFromDebugger,
1092                                     compilationInfo.script);
1093   }
1094 
1095   assertException.reset();
1096   return true;
1097 }
1098 
CompileStandaloneFunction(JSContext * cx,MutableHandleFunction fun,const JS::ReadOnlyCompileOptions & options,JS::SourceText<char16_t> & srcBuf,const Maybe<uint32_t> & parameterListEnd,HandleScope enclosingScope)1099 bool frontend::CompileStandaloneFunction(
1100     JSContext* cx, MutableHandleFunction fun,
1101     const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf,
1102     const Maybe<uint32_t>& parameterListEnd,
1103     HandleScope enclosingScope /* = nullptr */) {
1104   return CompileStandaloneFunction(
1105       cx, fun, options, srcBuf, parameterListEnd, GeneratorKind::NotGenerator,
1106       FunctionAsyncKind::SyncFunction, enclosingScope);
1107 }
1108 
CompileStandaloneGenerator(JSContext * cx,MutableHandleFunction fun,const JS::ReadOnlyCompileOptions & options,JS::SourceText<char16_t> & srcBuf,const Maybe<uint32_t> & parameterListEnd)1109 bool frontend::CompileStandaloneGenerator(
1110     JSContext* cx, MutableHandleFunction fun,
1111     const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf,
1112     const Maybe<uint32_t>& parameterListEnd) {
1113   return CompileStandaloneFunction(cx, fun, options, srcBuf, parameterListEnd,
1114                                    GeneratorKind::Generator,
1115                                    FunctionAsyncKind::SyncFunction);
1116 }
1117 
CompileStandaloneAsyncFunction(JSContext * cx,MutableHandleFunction fun,const ReadOnlyCompileOptions & options,JS::SourceText<char16_t> & srcBuf,const Maybe<uint32_t> & parameterListEnd)1118 bool frontend::CompileStandaloneAsyncFunction(
1119     JSContext* cx, MutableHandleFunction fun,
1120     const ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf,
1121     const Maybe<uint32_t>& parameterListEnd) {
1122   return CompileStandaloneFunction(cx, fun, options, srcBuf, parameterListEnd,
1123                                    GeneratorKind::NotGenerator,
1124                                    FunctionAsyncKind::AsyncFunction);
1125 }
1126 
CompileStandaloneAsyncGenerator(JSContext * cx,MutableHandleFunction fun,const ReadOnlyCompileOptions & options,JS::SourceText<char16_t> & srcBuf,const Maybe<uint32_t> & parameterListEnd)1127 bool frontend::CompileStandaloneAsyncGenerator(
1128     JSContext* cx, MutableHandleFunction fun,
1129     const ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf,
1130     const Maybe<uint32_t>& parameterListEnd) {
1131   return CompileStandaloneFunction(cx, fun, options, srcBuf, parameterListEnd,
1132                                    GeneratorKind::Generator,
1133                                    FunctionAsyncKind::AsyncFunction);
1134 }
1135 
init(JSContext * cx)1136 bool frontend::CompilationInfo::init(JSContext* cx) {
1137   sourceObject = CreateScriptSourceObject(cx, options);
1138   return !!sourceObject;
1139 }
1140