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