BytecodeCompiler.cpp (63464B)
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/Maybe.h" 11 #include "mozilla/Utf8.h" // mozilla::Utf8Unit 12 #include "mozilla/Variant.h" // mozilla::Variant 13 14 #include "debugger/DebugAPI.h" 15 #include "ds/LifoAlloc.h" 16 #include "frontend/BytecodeEmitter.h" 17 #include "frontend/CompilationStencil.h" // ExtensibleCompilationStencil, ExtraBindingInfoVector, CompilationInput, CompilationGCOutput 18 #include "frontend/EitherParser.h" 19 #include "frontend/FrontendContext.h" // AutoReportFrontendContext 20 #include "frontend/ModuleSharedContext.h" 21 #include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex 22 #include "frontend/SharedContext.h" // SharedContext, GlobalSharedContext 23 #include "frontend/Stencil.h" // ParserBindingIter 24 #include "frontend/UsedNameTracker.h" // UsedNameTracker, UsedNameMap 25 #include "js/AllocPolicy.h" // js::SystemAllocPolicy, ReportOutOfMemory 26 #include "js/CharacterEncoding.h" // JS_EncodeStringToUTF8 27 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin 28 #include "js/EnvironmentChain.h" // JS::SupportUnscopables 29 #include "js/ErrorReport.h" // JS_ReportErrorASCII 30 #include "js/experimental/CompileScript.h" // JS::CompileGlobalScriptToStencil, JS::CompileModuleScriptToStencil 31 #include "js/experimental/JSStencil.h" 32 #include "js/GCVector.h" // JS::StackGCVector 33 #include "js/Id.h" // JS::PropertyKey 34 #include "js/Modules.h" // JS::ImportAssertionVector 35 #include "js/RootingAPI.h" // JS::Handle, JS::MutableHandle 36 #include "js/SourceText.h" // JS::SourceText 37 #include "js/UniquePtr.h" 38 #include "js/Utility.h" // UniqueChars 39 #include "js/Value.h" // JS::Value 40 #include "vm/EnvironmentObject.h" // WithEnvironmentObject 41 #include "vm/FunctionFlags.h" // FunctionFlags 42 #include "vm/GeneratorAndAsyncKind.h" // js::GeneratorKind, js::FunctionAsyncKind 43 #include "vm/HelperThreads.h" // StartOffThreadDelazification, WaitForAllDelazifyTasks 44 #include "vm/JSContext.h" // JSContext 45 #include "vm/JSObject.h" // SetIntegrityLevel, IntegrityLevel 46 #include "vm/JSScript.h" // ScriptSource, UncompressedSourceCache 47 #include "vm/ModuleBuilder.h" // js::ModuleBuilder 48 #include "vm/NativeObject.h" // NativeDefineDataProperty 49 #include "vm/PlainObject.h" // NewPlainObjectWithProto 50 #include "vm/Time.h" // AutoIncrementalTimer 51 #include "wasm/AsmJS.h" 52 53 #include "vm/Compartment-inl.h" // JS::Compartment::wrap 54 #include "vm/GeckoProfiler-inl.h" 55 #include "vm/JSContext-inl.h" 56 #include "vm/JSObject-inl.h" // JSObject::maybeHasInterestingSymbolProperty for ObjectOperations-inl.h 57 #include "vm/ObjectOperations-inl.h" // HasProperty 58 59 using namespace js; 60 using namespace js::frontend; 61 62 using mozilla::Maybe; 63 using mozilla::Utf8Unit; 64 65 using JS::CompileOptions; 66 using JS::ReadOnlyCompileOptions; 67 using JS::SourceText; 68 69 // RAII class to check the frontend reports an exception when it fails to 70 // compile a script. 71 class MOZ_RAII AutoAssertReportedException { 72 #ifdef DEBUG 73 JSContext* maybeCx_; 74 FrontendContext* fc_; 75 bool check_; 76 77 public: 78 explicit AutoAssertReportedException(JSContext* maybeCx, FrontendContext* fc) 79 : maybeCx_(maybeCx), fc_(fc), check_(true) {} 80 void reset() { check_ = false; } 81 ~AutoAssertReportedException() { 82 if (!check_) { 83 return; 84 } 85 86 // Error while compiling self-hosted code isn't set as an exception. 87 // TODO: Remove this once all errors are added to frontend context. 88 if (maybeCx_ && !maybeCx_->runtime()->hasInitializedSelfHosting()) { 89 return; 90 } 91 92 // TODO: Remove this once JSContext is removed from frontend. 93 if (maybeCx_) { 94 MOZ_ASSERT(maybeCx_->isExceptionPending() || fc_->hadErrors()); 95 } else { 96 MOZ_ASSERT(fc_->hadErrors()); 97 } 98 } 99 #else 100 public: 101 explicit AutoAssertReportedException(JSContext*, FrontendContext*) {} 102 void reset() {} 103 #endif 104 }; 105 106 static bool EmplaceEmitter(CompilationState& compilationState, 107 Maybe<BytecodeEmitter>& emitter, FrontendContext* fc, 108 const EitherParser& parser, SharedContext* sc); 109 110 template <typename Unit> 111 class MOZ_STACK_CLASS SourceAwareCompiler { 112 protected: 113 SourceText<Unit>& sourceBuffer_; 114 115 CompilationState compilationState_; 116 117 Maybe<Parser<SyntaxParseHandler, Unit>> syntaxParser; 118 Maybe<Parser<FullParseHandler, Unit>> parser; 119 FrontendContext* fc_ = nullptr; 120 121 using TokenStreamPosition = frontend::TokenStreamPosition<Unit>; 122 123 protected: 124 explicit SourceAwareCompiler(FrontendContext* fc, 125 LifoAllocScope& parserAllocScope, 126 CompilationInput& input, 127 SourceText<Unit>& sourceBuffer) 128 : sourceBuffer_(sourceBuffer), 129 compilationState_(fc, parserAllocScope, input) { 130 MOZ_ASSERT(sourceBuffer_.get() != nullptr); 131 } 132 133 [[nodiscard]] bool init(FrontendContext* fc, ScopeBindingCache* scopeCache, 134 InheritThis inheritThis = InheritThis::No, 135 JSObject* enclosingEnv = nullptr) { 136 if (!compilationState_.init(fc, scopeCache, inheritThis, enclosingEnv)) { 137 return false; 138 } 139 140 return createSourceAndParser(fc); 141 } 142 143 // Call this before calling compile{Global,Eval}Script. 144 [[nodiscard]] bool createSourceAndParser(FrontendContext* fc); 145 146 void assertSourceAndParserCreated() const { 147 MOZ_ASSERT(compilationState_.source != nullptr); 148 MOZ_ASSERT(parser.isSome()); 149 } 150 151 void assertSourceParserAndScriptCreated() { assertSourceAndParserCreated(); } 152 153 [[nodiscard]] bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, 154 SharedContext* sharedContext) { 155 return EmplaceEmitter(compilationState_, emitter, fc_, 156 EitherParser(parser.ptr()), sharedContext); 157 } 158 159 bool canHandleParseFailure(const Directives& newDirectives); 160 161 void handleParseFailure( 162 const Directives& newDirectives, TokenStreamPosition& startPosition, 163 CompilationState::CompilationStatePosition& startStatePosition); 164 165 public: 166 CompilationState& compilationState() { return compilationState_; }; 167 168 ExtensibleCompilationStencil& stencil() { return compilationState_; } 169 }; 170 171 template <typename Unit> 172 class MOZ_STACK_CLASS ScriptCompiler : public SourceAwareCompiler<Unit> { 173 using Base = SourceAwareCompiler<Unit>; 174 175 protected: 176 using Base::compilationState_; 177 using Base::parser; 178 using Base::sourceBuffer_; 179 180 using Base::assertSourceParserAndScriptCreated; 181 using Base::canHandleParseFailure; 182 using Base::emplaceEmitter; 183 using Base::handleParseFailure; 184 185 using typename Base::TokenStreamPosition; 186 187 public: 188 explicit ScriptCompiler(FrontendContext* fc, LifoAllocScope& parserAllocScope, 189 CompilationInput& input, 190 SourceText<Unit>& sourceBuffer) 191 : Base(fc, parserAllocScope, input, sourceBuffer) {} 192 193 using Base::init; 194 using Base::stencil; 195 196 [[nodiscard]] bool compile(JSContext* cx, SharedContext* sc); 197 198 private: 199 [[nodiscard]] bool popupateExtraBindingsFields(GlobalSharedContext* globalsc); 200 }; 201 202 static already_AddRefed<JS::Stencil> CreateInitialStencilAndDelazifications( 203 FrontendContext* fc, CompilationStencil* initial) { 204 RefPtr stencils = 205 fc->getAllocator()->new_<frontend::InitialStencilAndDelazifications>(); 206 if (!stencils) { 207 return nullptr; 208 } 209 if (!stencils->init(fc, initial)) { 210 return nullptr; 211 } 212 return stencils.forget(); 213 } 214 215 using BytecodeCompilerOutput = 216 mozilla::Variant<RefPtr<CompilationStencil>, CompilationGCOutput*>; 217 218 static bool ConvertGlobalScriptStencilMaybeInstantiate( 219 JSContext* maybeCx, FrontendContext* fc, CompilationInput& input, 220 ExtensibleCompilationStencil&& extensibleStencil, 221 CompilationStencil** initialStencilOut, 222 InitialStencilAndDelazifications** stencilsOut, 223 CompilationGCOutput* gcOutput) { 224 RefPtr<CompilationStencil> initialStencil; 225 if (input.options.populateDelazificationCache() || initialStencilOut || 226 stencilsOut) { 227 auto extensibleStencilOnHeap = 228 fc->getAllocator()->make_unique<frontend::ExtensibleCompilationStencil>( 229 std::move(extensibleStencil)); 230 if (!extensibleStencilOnHeap) { 231 return false; 232 } 233 234 initialStencil = fc->getAllocator()->new_<CompilationStencil>( 235 std::move(extensibleStencilOnHeap)); 236 if (!initialStencil) { 237 return false; 238 } 239 240 if (initialStencilOut) { 241 *initialStencilOut = initialStencil.get(); 242 (*initialStencilOut)->AddRef(); 243 } 244 } 245 246 RefPtr<InitialStencilAndDelazifications> stencils; 247 if (input.options.populateDelazificationCache() || stencilsOut) { 248 stencils = CreateInitialStencilAndDelazifications(fc, initialStencil.get()); 249 if (!stencils) { 250 return false; 251 } 252 253 if (stencilsOut) { 254 *stencilsOut = stencils.get(); 255 (*stencilsOut)->AddRef(); 256 } 257 } 258 259 if (input.options.populateDelazificationCache()) { 260 // NOTE: Delazification can be triggered from off-thread compilation. 261 StartOffThreadDelazification(maybeCx, input.options, stencils.get()); 262 263 // When we are trying to validate whether on-demand delazification 264 // generate the same stencil as concurrent delazification, we want to 265 // parse everything eagerly off-thread ahead of re-parsing everything on 266 // demand, to compare the outcome. 267 // 268 // This option works only from main-thread compilation, to avoid 269 // dead-lock. 270 if (input.options.waitForDelazificationCache() && maybeCx) { 271 WaitForAllDelazifyTasks(maybeCx->runtime()); 272 } 273 } 274 275 if (gcOutput) { 276 MOZ_ASSERT(maybeCx); 277 if (stencils) { 278 if (!InstantiateStencils(maybeCx, input, *stencils.get(), *gcOutput)) { 279 return false; 280 } 281 } else { 282 MOZ_ASSERT(!initialStencilOut); 283 BorrowingCompilationStencil borrowingStencil(extensibleStencil); 284 if (!InstantiateStencils(maybeCx, input, borrowingStencil, *gcOutput)) { 285 return false; 286 } 287 } 288 } 289 290 return true; 291 } 292 293 static constexpr ExtraBindingInfoVector* NoExtraBindings = nullptr; 294 static constexpr CompilationStencil** NoInitialStencilOut = nullptr; 295 static constexpr InitialStencilAndDelazifications** NoStencilsOut = nullptr; 296 static constexpr CompilationGCOutput* NoGCOutput = nullptr; 297 298 // Compile global script, and return it as one of: 299 // * ExtensibleCompilationStencil (without instantiation) 300 // * CompilationStencil (without instantiation, has no external dependency) 301 // * CompilationGCOutput (with instantiation). 302 template <typename Unit> 303 [[nodiscard]] static bool CompileGlobalScriptToStencilAndMaybeInstantiate( 304 JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc, 305 CompilationInput& input, ScopeBindingCache* scopeCache, 306 JS::SourceText<Unit>& srcBuf, ScopeKind scopeKind, 307 ExtraBindingInfoVector* maybeExtraBindings, 308 CompilationStencil** initialStencilOut, 309 InitialStencilAndDelazifications** stencilsOut, 310 CompilationGCOutput* gcOutput) { 311 if (input.options.selfHostingMode) { 312 if (!input.initForSelfHostingGlobal(fc)) { 313 return false; 314 } 315 } else if (maybeExtraBindings) { 316 if (!input.initForGlobalWithExtraBindings(fc, maybeExtraBindings)) { 317 return false; 318 } 319 } else { 320 if (!input.initForGlobal(fc)) { 321 return false; 322 } 323 } 324 325 AutoAssertReportedException assertException(maybeCx, fc); 326 327 LifoAllocScope parserAllocScope(&tempLifoAlloc); 328 ScriptCompiler<Unit> compiler(fc, parserAllocScope, input, srcBuf); 329 if (!compiler.init(fc, scopeCache)) { 330 return false; 331 } 332 333 SourceExtent extent = SourceExtent::makeGlobalExtent( 334 srcBuf.length(), input.options.lineno, 335 JS::LimitedColumnNumberOneOrigin::fromUnlimited( 336 JS::ColumnNumberOneOrigin(input.options.column))); 337 338 GlobalSharedContext globalsc(fc, scopeKind, input.options, 339 compiler.compilationState().directives, extent); 340 341 if (!compiler.compile(maybeCx, &globalsc)) { 342 return false; 343 } 344 345 if (!ConvertGlobalScriptStencilMaybeInstantiate( 346 maybeCx, fc, input, std::move(compiler.stencil()), initialStencilOut, 347 stencilsOut, gcOutput)) { 348 return false; 349 } 350 351 assertException.reset(); 352 return true; 353 } 354 355 template <typename Unit> 356 static already_AddRefed<CompilationStencil> 357 CompileGlobalScriptToStencilWithInputImpl( 358 JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc, 359 CompilationInput& input, ScopeBindingCache* scopeCache, 360 JS::SourceText<Unit>& srcBuf, ScopeKind scopeKind) { 361 RefPtr<CompilationStencil> stencil; 362 if (!CompileGlobalScriptToStencilAndMaybeInstantiate( 363 maybeCx, fc, tempLifoAlloc, input, scopeCache, srcBuf, scopeKind, 364 NoExtraBindings, getter_AddRefs(stencil), NoGCOutput)) { 365 return nullptr; 366 } 367 return stencil.forget(); 368 } 369 370 already_AddRefed<CompilationStencil> 371 frontend::CompileGlobalScriptToStencilWithInput( 372 JSContext* cx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc, 373 CompilationInput& input, ScopeBindingCache* scopeCache, 374 JS::SourceText<Utf8Unit>& srcBuf, ScopeKind scopeKind) { 375 RefPtr<CompilationStencil> stencil; 376 if (!CompileGlobalScriptToStencilAndMaybeInstantiate( 377 cx, fc, tempLifoAlloc, input, scopeCache, srcBuf, scopeKind, 378 NoExtraBindings, getter_AddRefs(stencil), NoStencilsOut, 379 NoGCOutput)) { 380 return nullptr; 381 } 382 return stencil.forget(); 383 } 384 385 template <typename CharT> 386 static already_AddRefed<JS::Stencil> CompileGlobalScriptToStencilImpl( 387 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 388 JS::SourceText<CharT>& srcBuf) { 389 ScopeKind scopeKind = 390 options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global; 391 392 AutoReportFrontendContext fc(cx); 393 394 NoScopeBindingCache scopeCache; 395 Rooted<CompilationInput> input(cx, CompilationInput(options)); 396 RefPtr<InitialStencilAndDelazifications> stencils; 397 if (!CompileGlobalScriptToStencilAndMaybeInstantiate( 398 cx, &fc, cx->tempLifoAlloc(), input.get(), &scopeCache, srcBuf, 399 scopeKind, NoExtraBindings, NoInitialStencilOut, 400 getter_AddRefs(stencils), NoGCOutput)) { 401 return nullptr; 402 } 403 return stencils.forget(); 404 } 405 406 already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil( 407 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 408 JS::SourceText<mozilla::Utf8Unit>& srcBuf) { 409 return CompileGlobalScriptToStencilImpl(cx, options, srcBuf); 410 } 411 412 already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil( 413 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 414 JS::SourceText<char16_t>& srcBuf) { 415 return CompileGlobalScriptToStencilImpl(cx, options, srcBuf); 416 } 417 418 template <typename CharT> 419 static already_AddRefed<JS::Stencil> CompileGlobalScriptToStencilImpl( 420 JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options, 421 JS::SourceText<CharT>& srcBuf) { 422 ScopeKind scopeKind = 423 options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global; 424 425 NoScopeBindingCache scopeCache; 426 js::LifoAlloc tempLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE, 427 js::BackgroundMallocArena); 428 CompilationInput compilationInput(options); 429 RefPtr<InitialStencilAndDelazifications> stencils; 430 if (!CompileGlobalScriptToStencilAndMaybeInstantiate( 431 nullptr, fc, tempLifoAlloc, compilationInput, &scopeCache, srcBuf, 432 scopeKind, NoExtraBindings, NoInitialStencilOut, 433 getter_AddRefs(stencils), NoGCOutput)) { 434 JS_HAZ_VALUE_IS_GC_SAFE(compilationInput); 435 return nullptr; 436 } 437 // CompilationInput initialized with CompileGlobalScriptToStencil only 438 // references information from the JS::Stencil context and the 439 // ref-counted ScriptSource, which are both GC-free. 440 JS_HAZ_VALUE_IS_GC_SAFE(compilationInput); 441 return stencils.forget(); 442 } 443 444 already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil( 445 JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options, 446 JS::SourceText<mozilla::Utf8Unit>& srcBuf) { 447 #ifdef DEBUG 448 fc->assertNativeStackLimitThread(); 449 #endif 450 return CompileGlobalScriptToStencilImpl(fc, options, srcBuf); 451 } 452 453 already_AddRefed<JS::Stencil> JS::CompileGlobalScriptToStencil( 454 JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options, 455 JS::SourceText<char16_t>& srcBuf) { 456 #ifdef DEBUG 457 fc->assertNativeStackLimitThread(); 458 #endif 459 return CompileGlobalScriptToStencilImpl(fc, options, srcBuf); 460 } 461 462 static void FireOnNewScript(JSContext* cx, 463 const JS::InstantiateOptions& options, 464 JS::Handle<JSScript*> script) { 465 if (!options.hideFromNewScriptInitial()) { 466 DebugAPI::onNewScript(cx, script); 467 } 468 } 469 470 static inline ScriptSource* getSource(const CompilationStencil& stencil) { 471 return stencil.source; 472 } 473 474 static inline ScriptSource* getSource( 475 const InitialStencilAndDelazifications& stencils) { 476 return stencils.getInitial()->source; 477 } 478 479 template <typename T> 480 bool InstantiateStencilsImpl(JSContext* cx, CompilationInput& input, T& stencil, 481 CompilationGCOutput& gcOutput) { 482 { 483 AutoGeckoProfilerEntry pseudoFrame(cx, "stencil instantiate", 484 JS::ProfilingCategoryPair::JS_Parsing); 485 486 if (!T::instantiateStencils(cx, input, stencil, gcOutput)) { 487 return false; 488 } 489 } 490 491 // Enqueue an off-thread source compression task after finishing parsing. 492 if (!getSource(stencil)->tryCompressOffThread(cx)) { 493 return false; 494 } 495 496 Rooted<JSScript*> script(cx, gcOutput.script); 497 const JS::InstantiateOptions instantiateOptions(input.options); 498 FireOnNewScript(cx, instantiateOptions, script); 499 500 return true; 501 } 502 503 bool frontend::InstantiateStencils(JSContext* cx, CompilationInput& input, 504 const CompilationStencil& stencil, 505 CompilationGCOutput& gcOutput) { 506 return InstantiateStencilsImpl(cx, input, stencil, gcOutput); 507 } 508 509 bool frontend::InstantiateStencils(JSContext* cx, CompilationInput& input, 510 InitialStencilAndDelazifications& stencils, 511 CompilationGCOutput& gcOutput) { 512 return InstantiateStencilsImpl(cx, input, stencils, gcOutput); 513 } 514 515 template <typename Unit> 516 static JSScript* CompileGlobalScriptImpl( 517 JSContext* cx, FrontendContext* fc, 518 const JS::ReadOnlyCompileOptions& options, JS::SourceText<Unit>& srcBuf, 519 ScopeKind scopeKind, ExtraBindingInfoVector* maybeExtraBindings) { 520 Rooted<CompilationInput> input(cx, CompilationInput(options)); 521 Rooted<CompilationGCOutput> gcOutput(cx); 522 NoScopeBindingCache scopeCache; 523 if (!CompileGlobalScriptToStencilAndMaybeInstantiate( 524 cx, fc, cx->tempLifoAlloc(), input.get(), &scopeCache, srcBuf, 525 scopeKind, maybeExtraBindings, NoInitialStencilOut, NoStencilsOut, 526 gcOutput.address())) { 527 return nullptr; 528 } 529 return gcOutput.get().script; 530 } 531 532 JSScript* frontend::CompileGlobalScript( 533 JSContext* cx, FrontendContext* fc, 534 const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf, 535 ScopeKind scopeKind) { 536 return CompileGlobalScriptImpl(cx, fc, options, srcBuf, scopeKind, 537 NoExtraBindings); 538 } 539 540 static bool CreateExtraBindingInfoVector( 541 JSContext* cx, 542 JS::Handle<JS::StackGCVector<JS::PropertyKey>> unwrappedBindingKeys, 543 JS::Handle<JS::StackGCVector<JS::Value>> unwrappedBindingValues, 544 ExtraBindingInfoVector& extraBindings) { 545 MOZ_ASSERT(unwrappedBindingKeys.length() == unwrappedBindingValues.length()); 546 547 if (!extraBindings.reserve(unwrappedBindingKeys.length())) { 548 ReportOutOfMemory(cx); 549 return false; 550 } 551 552 JS::Rooted<JSObject*> globalLexical(cx, &cx->global()->lexicalEnvironment()); 553 JS::Rooted<JS::PropertyKey> id(cx); 554 for (size_t i = 0; i < unwrappedBindingKeys.length(); i++) { 555 if (!unwrappedBindingKeys[i].isString()) { 556 JS_ReportErrorASCII(cx, "The bindings key should be a string."); 557 return false; 558 } 559 560 JS::Rooted<JSString*> str(cx, unwrappedBindingKeys[i].toString()); 561 562 UniqueChars utf8chars = JS_EncodeStringToUTF8(cx, str); 563 if (!utf8chars) { 564 return false; 565 } 566 567 bool isShadowed = false; 568 569 id = unwrappedBindingKeys[i]; 570 cx->markId(id); 571 572 bool found; 573 if (!HasProperty(cx, cx->global(), id, &found)) { 574 return false; 575 } 576 if (found) { 577 isShadowed = true; 578 } else { 579 if (!HasProperty(cx, globalLexical, id, &found)) { 580 return false; 581 } 582 if (found) { 583 isShadowed = true; 584 } 585 } 586 587 extraBindings.infallibleEmplaceBack(std::move(utf8chars), isShadowed); 588 } 589 590 return true; 591 } 592 593 static WithEnvironmentObject* CreateExtraBindingsEnvironment( 594 JSContext* cx, 595 JS::Handle<JS::StackGCVector<JS::PropertyKey>> unwrappedBindingKeys, 596 JS::Handle<JS::StackGCVector<JS::Value>> unwrappedBindingValues, 597 const ExtraBindingInfoVector& extraBindings) { 598 JS::Rooted<PlainObject*> extraBindingsObj( 599 cx, NewPlainObjectWithProto(cx, nullptr)); 600 if (!extraBindingsObj) { 601 return nullptr; 602 } 603 604 MOZ_ASSERT(unwrappedBindingKeys.length() == extraBindings.length()); 605 606 JS::Rooted<JS::PropertyKey> id(cx); 607 size_t i = 0; 608 for (const auto& bindingInfo : extraBindings) { 609 if (bindingInfo.isShadowed) { 610 i++; 611 continue; 612 } 613 614 id = unwrappedBindingKeys[i]; 615 cx->markId(id); 616 JS::Rooted<JS::Value> val(cx, unwrappedBindingValues[i]); 617 if (!cx->compartment()->wrap(cx, &val) || 618 !NativeDefineDataProperty(cx, extraBindingsObj, id, val, 0)) { 619 return nullptr; 620 } 621 i++; 622 } 623 624 // The list of bindings shouldn't be modified. 625 if (!SetIntegrityLevel(cx, extraBindingsObj, IntegrityLevel::Sealed)) { 626 return nullptr; 627 } 628 629 JS::Rooted<JSObject*> globalLexical(cx, &cx->global()->lexicalEnvironment()); 630 return WithEnvironmentObject::createNonSyntactic( 631 cx, extraBindingsObj, globalLexical, JS::SupportUnscopables::No); 632 } 633 634 JSScript* frontend::CompileGlobalScriptWithExtraBindings( 635 JSContext* cx, FrontendContext* fc, 636 const JS::ReadOnlyCompileOptions& options, JS::SourceText<char16_t>& srcBuf, 637 JS::Handle<JS::StackGCVector<JS::PropertyKey>> unwrappedBindingKeys, 638 JS::Handle<JS::StackGCVector<JS::Value>> unwrappedBindingValues, 639 JS::MutableHandle<JSObject*> env) { 640 ExtraBindingInfoVector extraBindings; 641 if (!CreateExtraBindingInfoVector(cx, unwrappedBindingKeys, 642 unwrappedBindingValues, extraBindings)) { 643 return nullptr; 644 } 645 646 JS::Rooted<JSScript*> script( 647 cx, CompileGlobalScriptImpl(cx, fc, options, srcBuf, 648 ScopeKind::NonSyntactic, &extraBindings)); 649 if (!script) { 650 if (fc->extraBindingsAreNotUsed()) { 651 // Compile the script as regular global script in global lexical. 652 653 fc->clearNoExtraBindingReferencesFound(); 654 655 // Warnings can be reported. Clear them to avoid reporting twice. 656 fc->clearWarnings(); 657 658 // No other error should be reported. 659 MOZ_ASSERT(!fc->hadErrors()); 660 MOZ_ASSERT(!cx->isExceptionPending()); 661 662 env.set(&cx->global()->lexicalEnvironment()); 663 664 JS::CompileOptions copiedOptions(nullptr, options); 665 copiedOptions.setNonSyntacticScope(false); 666 667 return CompileGlobalScript(cx, fc, copiedOptions, srcBuf, 668 ScopeKind::Global); 669 } 670 671 return nullptr; 672 } 673 674 WithEnvironmentObject* extraBindingsEnv = CreateExtraBindingsEnvironment( 675 cx, unwrappedBindingKeys, unwrappedBindingValues, extraBindings); 676 if (!extraBindingsEnv) { 677 return nullptr; 678 } 679 680 env.set(extraBindingsEnv); 681 682 return script; 683 } 684 685 JSScript* frontend::CompileGlobalScript( 686 JSContext* cx, FrontendContext* fc, 687 const JS::ReadOnlyCompileOptions& options, JS::SourceText<Utf8Unit>& srcBuf, 688 ScopeKind scopeKind) { 689 return CompileGlobalScriptImpl(cx, fc, options, srcBuf, scopeKind, 690 NoExtraBindings); 691 } 692 693 template <typename Unit> 694 static JSScript* CompileEvalScriptImpl( 695 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 696 SourceText<Unit>& srcBuf, JS::Handle<js::Scope*> enclosingScope, 697 JS::Handle<JSObject*> enclosingEnv) { 698 JS::Rooted<JSScript*> script(cx); 699 { 700 AutoReportFrontendContext fc(cx); 701 AutoAssertReportedException assertException(cx, &fc); 702 703 Rooted<CompilationInput> input(cx, CompilationInput(options)); 704 if (!input.get().initForEval(&fc, enclosingScope)) { 705 return nullptr; 706 } 707 708 LifoAllocScope parserAllocScope(&cx->tempLifoAlloc()); 709 710 ScopeBindingCache* scopeCache = &cx->caches().scopeCache; 711 ScriptCompiler<Unit> compiler(&fc, parserAllocScope, input.get(), srcBuf); 712 if (!compiler.init(&fc, scopeCache, InheritThis::Yes, enclosingEnv)) { 713 return nullptr; 714 } 715 716 uint32_t len = srcBuf.length(); 717 SourceExtent extent = SourceExtent::makeGlobalExtent( 718 len, options.lineno, 719 JS::LimitedColumnNumberOneOrigin::fromUnlimited( 720 JS::ColumnNumberOneOrigin(options.column))); 721 EvalSharedContext evalsc(&fc, compiler.compilationState(), extent); 722 if (!compiler.compile(cx, &evalsc)) { 723 return nullptr; 724 } 725 726 Rooted<CompilationGCOutput> gcOutput(cx); 727 { 728 BorrowingCompilationStencil borrowingStencil(compiler.stencil()); 729 if (!InstantiateStencils(cx, input.get(), borrowingStencil, 730 gcOutput.get())) { 731 return nullptr; 732 } 733 } 734 735 assertException.reset(); 736 script = gcOutput.get().script; 737 } 738 return script; 739 } 740 741 JSScript* frontend::CompileEvalScript(JSContext* cx, 742 const JS::ReadOnlyCompileOptions& options, 743 JS::SourceText<char16_t>& srcBuf, 744 JS::Handle<js::Scope*> enclosingScope, 745 JS::Handle<JSObject*> enclosingEnv) { 746 return CompileEvalScriptImpl(cx, options, srcBuf, enclosingScope, 747 enclosingEnv); 748 } 749 750 template <typename Unit> 751 class MOZ_STACK_CLASS ModuleCompiler final : public SourceAwareCompiler<Unit> { 752 using Base = SourceAwareCompiler<Unit>; 753 754 using Base::assertSourceParserAndScriptCreated; 755 using Base::compilationState_; 756 using Base::emplaceEmitter; 757 using Base::parser; 758 759 public: 760 explicit ModuleCompiler(FrontendContext* fc, LifoAllocScope& parserAllocScope, 761 CompilationInput& input, 762 SourceText<Unit>& sourceBuffer) 763 : Base(fc, parserAllocScope, input, sourceBuffer) {} 764 765 using Base::init; 766 using Base::stencil; 767 768 [[nodiscard]] bool compile(JSContext* maybeCx, FrontendContext* fc); 769 }; 770 771 template <typename Unit> 772 class MOZ_STACK_CLASS StandaloneFunctionCompiler final 773 : public SourceAwareCompiler<Unit> { 774 using Base = SourceAwareCompiler<Unit>; 775 776 using Base::assertSourceAndParserCreated; 777 using Base::canHandleParseFailure; 778 using Base::compilationState_; 779 using Base::emplaceEmitter; 780 using Base::handleParseFailure; 781 using Base::parser; 782 using Base::sourceBuffer_; 783 784 using typename Base::TokenStreamPosition; 785 786 public: 787 explicit StandaloneFunctionCompiler(FrontendContext* fc, 788 LifoAllocScope& parserAllocScope, 789 CompilationInput& input, 790 SourceText<Unit>& sourceBuffer) 791 : Base(fc, parserAllocScope, input, sourceBuffer) {} 792 793 using Base::init; 794 using Base::stencil; 795 796 private: 797 FunctionNode* parse(JSContext* cx, FunctionSyntaxKind syntaxKind, 798 GeneratorKind generatorKind, FunctionAsyncKind asyncKind, 799 const Maybe<uint32_t>& parameterListEnd); 800 801 public: 802 [[nodiscard]] bool compile(JSContext* cx, FunctionSyntaxKind syntaxKind, 803 GeneratorKind generatorKind, 804 FunctionAsyncKind asyncKind, 805 const Maybe<uint32_t>& parameterListEnd); 806 }; 807 808 template <typename Unit> 809 bool SourceAwareCompiler<Unit>::createSourceAndParser(FrontendContext* fc) { 810 const auto& options = compilationState_.input.options; 811 812 fc_ = fc; 813 814 if (!compilationState_.source->assignSource(fc, options, sourceBuffer_)) { 815 return false; 816 } 817 818 MOZ_ASSERT(compilationState_.canLazilyParse == 819 CanLazilyParse(compilationState_.input.options)); 820 if (compilationState_.canLazilyParse) { 821 syntaxParser.emplace(fc_, options, sourceBuffer_.units(), 822 sourceBuffer_.length(), compilationState_, 823 /* syntaxParser = */ nullptr); 824 if (!syntaxParser->checkOptions()) { 825 return false; 826 } 827 } 828 829 parser.emplace(fc_, options, sourceBuffer_.units(), sourceBuffer_.length(), 830 compilationState_, syntaxParser.ptrOr(nullptr)); 831 parser->ss = compilationState_.source.get(); 832 return parser->checkOptions(); 833 } 834 835 static bool EmplaceEmitter(CompilationState& compilationState, 836 Maybe<BytecodeEmitter>& emitter, FrontendContext* fc, 837 const EitherParser& parser, SharedContext* sc) { 838 BytecodeEmitter::EmitterMode emitterMode = 839 sc->selfHosted() ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal; 840 emitter.emplace(fc, parser, sc, compilationState, emitterMode); 841 return emitter->init(); 842 } 843 844 template <typename Unit> 845 bool SourceAwareCompiler<Unit>::canHandleParseFailure( 846 const Directives& newDirectives) { 847 // Try to reparse if no parse errors were thrown and the directives changed. 848 // 849 // NOTE: 850 // Only the following two directive changes force us to reparse the script: 851 // - The "use asm" directive was encountered. 852 // - The "use strict" directive was encountered and duplicate parameter names 853 // are present. We reparse in this case to display the error at the correct 854 // source location. See |Parser::hasValidSimpleStrictParameterNames()|. 855 return !parser->anyChars.hadError() && 856 compilationState_.directives != newDirectives; 857 } 858 859 template <typename Unit> 860 void SourceAwareCompiler<Unit>::handleParseFailure( 861 const Directives& newDirectives, TokenStreamPosition& startPosition, 862 CompilationState::CompilationStatePosition& startStatePosition) { 863 MOZ_ASSERT(canHandleParseFailure(newDirectives)); 864 865 // Rewind to starting position to retry. 866 parser->tokenStream.rewind(startPosition); 867 compilationState_.rewind(startStatePosition); 868 869 // Assignment must be monotonic to prevent reparsing iloops 870 MOZ_ASSERT_IF(compilationState_.directives.strict(), newDirectives.strict()); 871 MOZ_ASSERT_IF(compilationState_.directives.asmJS(), newDirectives.asmJS()); 872 compilationState_.directives = newDirectives; 873 } 874 875 static bool UsesExtraBindings(GlobalSharedContext* globalsc, 876 const ExtraBindingInfoVector& extraBindings, 877 const UsedNameTracker::UsedNameMap& usedNameMap) { 878 for (const auto& bindingInfo : extraBindings) { 879 if (bindingInfo.isShadowed) { 880 continue; 881 } 882 883 for (auto r = usedNameMap.all(); !r.empty(); r.popFront()) { 884 const auto& item = r.front(); 885 const auto& name = item.key(); 886 if (bindingInfo.nameIndex != name) { 887 continue; 888 } 889 890 const auto& nameInfo = item.value(); 891 if (nameInfo.empty()) { 892 continue; 893 } 894 895 // This name is free, and uses the extra binding. 896 return true; 897 } 898 } 899 900 return false; 901 } 902 903 template <typename Unit> 904 bool ScriptCompiler<Unit>::popupateExtraBindingsFields( 905 GlobalSharedContext* globalsc) { 906 if (!compilationState_.input.internExtraBindings( 907 this->fc_, compilationState_.parserAtoms)) { 908 return false; 909 } 910 911 bool hasNonShadowedBinding = false; 912 for (auto& bindingInfo : compilationState_.input.extraBindings()) { 913 if (bindingInfo.isShadowed) { 914 continue; 915 } 916 917 bool isShadowed = false; 918 919 if (globalsc->bindings) { 920 for (ParserBindingIter bi(*globalsc->bindings); bi; bi++) { 921 if (bindingInfo.nameIndex == bi.name()) { 922 isShadowed = true; 923 break; 924 } 925 } 926 } 927 928 bindingInfo.isShadowed = isShadowed; 929 if (!isShadowed) { 930 hasNonShadowedBinding = true; 931 } 932 } 933 934 if (!hasNonShadowedBinding) { 935 // All bindings are shadowed. 936 this->fc_->reportExtraBindingsAreNotUsed(); 937 return false; 938 } 939 940 if (globalsc->hasDirectEval()) { 941 // Direct eval can contain reference. 942 return true; 943 } 944 945 if (!UsesExtraBindings(globalsc, compilationState_.input.extraBindings(), 946 parser->usedNames().map())) { 947 this->fc_->reportExtraBindingsAreNotUsed(); 948 return false; 949 } 950 951 return true; 952 } 953 954 template <typename Unit> 955 bool ScriptCompiler<Unit>::compile(JSContext* maybeCx, SharedContext* sc) { 956 assertSourceParserAndScriptCreated(); 957 958 TokenStreamPosition startPosition(parser->tokenStream); 959 960 // Emplace the topLevel stencil 961 MOZ_ASSERT(compilationState_.scriptData.length() == 962 CompilationStencil::TopLevelIndex); 963 if (!compilationState_.appendScriptStencilAndData(sc->fc_)) { 964 return false; 965 } 966 967 ParseNode* pn; 968 { 969 Maybe<AutoGeckoProfilerEntry> pseudoFrame; 970 if (maybeCx) { 971 pseudoFrame.emplace(maybeCx, "script parsing", 972 JS::ProfilingCategoryPair::JS_Parsing); 973 } 974 if (sc->isEvalContext()) { 975 pn = parser->evalBody(sc->asEvalContext()).unwrapOr(nullptr); 976 } else { 977 pn = parser->globalBody(sc->asGlobalContext()).unwrapOr(nullptr); 978 } 979 } 980 981 if (!pn) { 982 // Global and eval scripts don't get reparsed after a new directive was 983 // encountered: 984 // - "use strict" doesn't require any special error reporting for scripts. 985 // - "use asm" directives don't have an effect in global/eval contexts. 986 MOZ_ASSERT(!canHandleParseFailure(compilationState_.directives)); 987 return false; 988 } 989 990 if (sc->isGlobalContext() && compilationState_.input.hasExtraBindings()) { 991 if (!popupateExtraBindingsFields(sc->asGlobalContext())) { 992 return false; 993 } 994 } 995 996 { 997 // Successfully parsed. Emit the script. 998 Maybe<AutoGeckoProfilerEntry> pseudoFrame; 999 if (maybeCx) { 1000 pseudoFrame.emplace(maybeCx, "script emit", 1001 JS::ProfilingCategoryPair::JS_Parsing); 1002 } 1003 1004 Maybe<BytecodeEmitter> emitter; 1005 if (!emplaceEmitter(emitter, sc)) { 1006 return false; 1007 } 1008 1009 if (!emitter->emitScript(pn)) { 1010 return false; 1011 } 1012 } 1013 1014 MOZ_ASSERT(!this->fc_->hadErrors()); 1015 1016 return true; 1017 } 1018 1019 template <typename Unit> 1020 bool ModuleCompiler<Unit>::compile(JSContext* maybeCx, FrontendContext* fc) { 1021 // Emplace the topLevel stencil 1022 MOZ_ASSERT(compilationState_.scriptData.length() == 1023 CompilationStencil::TopLevelIndex); 1024 if (!compilationState_.appendScriptStencilAndData(fc)) { 1025 return false; 1026 } 1027 1028 ModuleBuilder builder(fc, parser.ptr()); 1029 1030 const auto& options = compilationState_.input.options; 1031 1032 uint32_t len = this->sourceBuffer_.length(); 1033 SourceExtent extent = SourceExtent::makeGlobalExtent( 1034 len, options.lineno, 1035 JS::LimitedColumnNumberOneOrigin::fromUnlimited( 1036 JS::ColumnNumberOneOrigin(options.column))); 1037 ModuleSharedContext modulesc(fc, options, builder, extent); 1038 1039 ParseNode* pn = parser->moduleBody(&modulesc).unwrapOr(nullptr); 1040 if (!pn) { 1041 return false; 1042 } 1043 1044 Maybe<BytecodeEmitter> emitter; 1045 if (!emplaceEmitter(emitter, &modulesc)) { 1046 return false; 1047 } 1048 1049 if (!emitter->emitScript(pn->as<ModuleNode>().body())) { 1050 return false; 1051 } 1052 1053 StencilModuleMetadata& moduleMetadata = *compilationState_.moduleMetadata; 1054 1055 builder.finishFunctionDecls(moduleMetadata); 1056 1057 MOZ_ASSERT(!this->fc_->hadErrors()); 1058 1059 return true; 1060 } 1061 1062 // Parse a standalone JS function, which might appear as the value of an 1063 // event handler attribute in an HTML <INPUT> tag, or in a Function() 1064 // constructor. 1065 template <typename Unit> 1066 FunctionNode* StandaloneFunctionCompiler<Unit>::parse( 1067 JSContext* cx, FunctionSyntaxKind syntaxKind, GeneratorKind generatorKind, 1068 FunctionAsyncKind asyncKind, const Maybe<uint32_t>& parameterListEnd) { 1069 assertSourceAndParserCreated(); 1070 1071 TokenStreamPosition startPosition(parser->tokenStream); 1072 auto startStatePosition = compilationState_.getPosition(); 1073 1074 // Speculatively parse using the default directives implied by the context. 1075 // If a directive is encountered (e.g., "use strict") that changes how the 1076 // function should have been parsed, we backup and reparse with the new set 1077 // of directives. 1078 1079 FunctionNode* fn; 1080 for (;;) { 1081 Directives newDirectives = compilationState_.directives; 1082 fn = parser 1083 ->standaloneFunction(parameterListEnd, syntaxKind, generatorKind, 1084 asyncKind, compilationState_.directives, 1085 &newDirectives) 1086 .unwrapOr(nullptr); 1087 if (fn) { 1088 break; 1089 } 1090 1091 // Maybe we encountered a new directive. See if we can try again. 1092 if (!canHandleParseFailure(newDirectives)) { 1093 return nullptr; 1094 } 1095 1096 handleParseFailure(newDirectives, startPosition, startStatePosition); 1097 } 1098 1099 return fn; 1100 } 1101 1102 // Compile a standalone JS function. 1103 template <typename Unit> 1104 bool StandaloneFunctionCompiler<Unit>::compile( 1105 JSContext* cx, FunctionSyntaxKind syntaxKind, GeneratorKind generatorKind, 1106 FunctionAsyncKind asyncKind, const Maybe<uint32_t>& parameterListEnd) { 1107 FunctionNode* parsedFunction = 1108 parse(cx, syntaxKind, generatorKind, asyncKind, parameterListEnd); 1109 if (!parsedFunction) { 1110 return false; 1111 } 1112 1113 FunctionBox* funbox = parsedFunction->funbox(); 1114 1115 if (funbox->isInterpreted()) { 1116 Maybe<BytecodeEmitter> emitter; 1117 if (!emplaceEmitter(emitter, funbox)) { 1118 return false; 1119 } 1120 1121 if (!emitter->emitFunctionScript(parsedFunction)) { 1122 return false; 1123 } 1124 1125 // The parser extent has stripped off the leading `function...` but 1126 // we want the SourceExtent used in the final standalone script to 1127 // start from the beginning of the buffer, and use the provided 1128 // line and column. 1129 const auto& options = compilationState_.input.options; 1130 compilationState_.scriptExtra[CompilationStencil::TopLevelIndex].extent = 1131 SourceExtent{/* sourceStart = */ 0, 1132 sourceBuffer_.length(), 1133 funbox->extent().toStringStart, 1134 funbox->extent().toStringEnd, 1135 options.lineno, 1136 JS::LimitedColumnNumberOneOrigin::fromUnlimited( 1137 JS::ColumnNumberOneOrigin(options.column))}; 1138 } else { 1139 // The asm.js module was created by parser. Instantiation below will 1140 // allocate the JSFunction that wraps it. 1141 MOZ_ASSERT(funbox->isAsmJSModule()); 1142 MOZ_ASSERT(compilationState_.asmJS->moduleMap.has(funbox->index())); 1143 MOZ_ASSERT(compilationState_.scriptData[CompilationStencil::TopLevelIndex] 1144 .functionFlags.isAsmJSNative()); 1145 } 1146 1147 return true; 1148 } 1149 1150 // Compile module, and return it as one of: 1151 // * ExtensibleCompilationStencil (without instantiation) 1152 // * CompilationStencil (without instantiation, has no external dependency) 1153 // * CompilationGCOutput (with instantiation). 1154 template <typename Unit> 1155 [[nodiscard]] static bool ParseModuleToStencilAndMaybeInstantiate( 1156 JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc, 1157 CompilationInput& input, ScopeBindingCache* scopeCache, 1158 SourceText<Unit>& srcBuf, BytecodeCompilerOutput& output) { 1159 MOZ_ASSERT(srcBuf.get()); 1160 MOZ_ASSERT(input.options.lineno != 0, 1161 "Module cannot be compiled with lineNumber == 0"); 1162 1163 if (!input.initForModule(fc)) { 1164 return false; 1165 } 1166 1167 AutoAssertReportedException assertException(maybeCx, fc); 1168 1169 LifoAllocScope parserAllocScope(&tempLifoAlloc); 1170 ModuleCompiler<Unit> compiler(fc, parserAllocScope, input, srcBuf); 1171 if (!compiler.init(fc, scopeCache)) { 1172 return false; 1173 } 1174 1175 if (!compiler.compile(maybeCx, fc)) { 1176 return false; 1177 } 1178 1179 if (output.is<RefPtr<CompilationStencil>>()) { 1180 Maybe<AutoGeckoProfilerEntry> pseudoFrame; 1181 if (maybeCx) { 1182 pseudoFrame.emplace(maybeCx, "script emit", 1183 JS::ProfilingCategoryPair::JS_Parsing); 1184 } 1185 1186 auto extensibleStencil = 1187 fc->getAllocator()->make_unique<frontend::ExtensibleCompilationStencil>( 1188 std::move(compiler.stencil())); 1189 if (!extensibleStencil) { 1190 return false; 1191 } 1192 1193 RefPtr<CompilationStencil> stencil = 1194 fc->getAllocator()->new_<CompilationStencil>( 1195 std::move(extensibleStencil)); 1196 if (!stencil) { 1197 return false; 1198 } 1199 1200 output.as<RefPtr<CompilationStencil>>() = std::move(stencil); 1201 } else { 1202 MOZ_ASSERT(maybeCx); 1203 BorrowingCompilationStencil borrowingStencil(compiler.stencil()); 1204 if (!InstantiateStencils(maybeCx, input, borrowingStencil, 1205 *(output.as<CompilationGCOutput*>()))) { 1206 return false; 1207 } 1208 } 1209 1210 assertException.reset(); 1211 return true; 1212 } 1213 1214 template <typename Unit> 1215 already_AddRefed<CompilationStencil> ParseModuleToStencilImpl( 1216 JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc, 1217 CompilationInput& input, ScopeBindingCache* scopeCache, 1218 SourceText<Unit>& srcBuf) { 1219 using OutputType = RefPtr<CompilationStencil>; 1220 BytecodeCompilerOutput output((OutputType())); 1221 if (!ParseModuleToStencilAndMaybeInstantiate( 1222 maybeCx, fc, tempLifoAlloc, input, scopeCache, srcBuf, output)) { 1223 return nullptr; 1224 } 1225 return output.as<OutputType>().forget(); 1226 } 1227 1228 template <typename CharT> 1229 static already_AddRefed<JS::Stencil> CompileModuleScriptToStencilImpl( 1230 JSContext* cx, const JS::ReadOnlyCompileOptions& optionsInput, 1231 JS::SourceText<CharT>& srcBuf) { 1232 JS::CompileOptions options(cx, optionsInput); 1233 options.setModule(); 1234 1235 AutoReportFrontendContext fc(cx); 1236 1237 NoScopeBindingCache scopeCache; 1238 Rooted<CompilationInput> input(cx, CompilationInput(options)); 1239 RefPtr<CompilationStencil> stencil = ParseModuleToStencilImpl( 1240 cx, &fc, cx->tempLifoAlloc(), input.get(), &scopeCache, srcBuf); 1241 if (!stencil) { 1242 return nullptr; 1243 } 1244 return CreateInitialStencilAndDelazifications(&fc, stencil.get()); 1245 } 1246 1247 already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil( 1248 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 1249 JS::SourceText<mozilla::Utf8Unit>& srcBuf) { 1250 return CompileModuleScriptToStencilImpl(cx, options, srcBuf); 1251 } 1252 1253 already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil( 1254 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 1255 JS::SourceText<char16_t>& srcBuf) { 1256 return CompileModuleScriptToStencilImpl(cx, options, srcBuf); 1257 } 1258 1259 template <typename CharT> 1260 static already_AddRefed<JS::Stencil> CompileModuleScriptToStencilImpl( 1261 JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput, 1262 JS::SourceText<CharT>& srcBuf) { 1263 JS::CompileOptions options(nullptr, optionsInput); 1264 options.setModule(); 1265 1266 frontend::CompilationInput compilationInput(options); 1267 1268 NoScopeBindingCache scopeCache; 1269 js::LifoAlloc tempLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE, 1270 js::BackgroundMallocArena); 1271 RefPtr<CompilationStencil> stencil = ParseModuleToStencilImpl( 1272 nullptr, fc, tempLifoAlloc, compilationInput, &scopeCache, srcBuf); 1273 if (!stencil) { 1274 JS_HAZ_VALUE_IS_GC_SAFE(compilationInput); 1275 return nullptr; 1276 } 1277 // CompilationInput initialized with ParseModuleToStencil only 1278 // references information from the JS::Stencil context and the 1279 // ref-counted ScriptSource, which are both GC-free. 1280 JS_HAZ_VALUE_IS_GC_SAFE(compilationInput); 1281 return CreateInitialStencilAndDelazifications(fc, stencil.get()); 1282 } 1283 1284 already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil( 1285 JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput, 1286 JS::SourceText<mozilla::Utf8Unit>& srcBuf) { 1287 #ifdef DEBUG 1288 fc->assertNativeStackLimitThread(); 1289 #endif 1290 return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf); 1291 } 1292 1293 already_AddRefed<JS::Stencil> JS::CompileModuleScriptToStencil( 1294 JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& optionsInput, 1295 JS::SourceText<char16_t>& srcBuf) { 1296 #ifdef DEBUG 1297 fc->assertNativeStackLimitThread(); 1298 #endif 1299 return CompileModuleScriptToStencilImpl(fc, optionsInput, srcBuf); 1300 } 1301 1302 template <typename Unit> 1303 static ModuleObject* CompileModuleImpl( 1304 JSContext* cx, FrontendContext* fc, 1305 const JS::ReadOnlyCompileOptions& optionsInput, SourceText<Unit>& srcBuf) { 1306 AutoAssertReportedException assertException(cx, fc); 1307 1308 CompileOptions options(cx, optionsInput); 1309 options.setModule(); 1310 1311 Rooted<CompilationInput> input(cx, CompilationInput(options)); 1312 Rooted<CompilationGCOutput> gcOutput(cx); 1313 BytecodeCompilerOutput output(gcOutput.address()); 1314 1315 NoScopeBindingCache scopeCache; 1316 if (!ParseModuleToStencilAndMaybeInstantiate(cx, fc, cx->tempLifoAlloc(), 1317 input.get(), &scopeCache, srcBuf, 1318 output)) { 1319 return nullptr; 1320 } 1321 1322 assertException.reset(); 1323 return gcOutput.get().module; 1324 } 1325 1326 ModuleObject* frontend::CompileModule(JSContext* cx, FrontendContext* fc, 1327 const JS::ReadOnlyCompileOptions& options, 1328 SourceText<char16_t>& srcBuf) { 1329 return CompileModuleImpl(cx, fc, options, srcBuf); 1330 } 1331 1332 ModuleObject* frontend::CompileModule(JSContext* cx, FrontendContext* fc, 1333 const JS::ReadOnlyCompileOptions& options, 1334 SourceText<Utf8Unit>& srcBuf) { 1335 return CompileModuleImpl(cx, fc, options, srcBuf); 1336 } 1337 1338 static bool InstantiateLazyFunction(JSContext* cx, CompilationInput& input, 1339 const CompilationStencil& stencil) { 1340 mozilla::DebugOnly<uint32_t> lazyFlags = 1341 static_cast<uint32_t>(input.immutableFlags()); 1342 1343 Rooted<CompilationGCOutput> gcOutput(cx); 1344 1345 if (!CompilationStencil::instantiateStencils(cx, input, stencil, 1346 gcOutput.get())) { 1347 return false; 1348 } 1349 1350 // NOTE: After instantiation succeeds and bytecode is attached, the rest of 1351 // this operation should be infallible. Any failure during 1352 // delazification should restore the function back to a consistent 1353 // lazy state. 1354 1355 MOZ_ASSERT(lazyFlags == gcOutput.get().script->immutableFlags()); 1356 MOZ_ASSERT(gcOutput.get().script->outermostScope()->hasOnChain( 1357 ScopeKind::NonSyntactic) == 1358 gcOutput.get().script->immutableFlags().hasFlag( 1359 JSScript::ImmutableFlags::HasNonSyntacticScope)); 1360 1361 return true; 1362 } 1363 1364 // Compile lazy functinn specified by a pair of `units` + `length`, and 1365 // optionally instantiate. 1366 // 1367 // If `stencils` is provided, the result of delazification is stored into it. 1368 // 1369 // If `borrowOut` is provided, a borrowing pointer is returned. 1370 // 1371 // If `borrowOut` is not provided, the function is instantiated. 1372 // In this case, `maybeCx` should be provided and `input` should be initialized 1373 // with a BaseScript. 1374 template <typename Unit> 1375 static bool CompileLazyFunctionToStencilMaybeInstantiate( 1376 JSContext* maybeCx, FrontendContext* fc, js::LifoAlloc& tempLifoAlloc, 1377 CompilationInput& input, ScopeBindingCache* scopeCache, const Unit* units, 1378 size_t length, InitialStencilAndDelazifications* stencils, 1379 const CompilationStencil** borrowOut) { 1380 MOZ_ASSERT(input.source); 1381 1382 AutoAssertReportedException assertException(maybeCx, fc); 1383 1384 InheritThis inheritThis = 1385 input.functionFlags().isArrow() ? InheritThis::Yes : InheritThis::No; 1386 1387 LifoAllocScope parserAllocScope(&tempLifoAlloc); 1388 CompilationState compilationState(fc, parserAllocScope, input); 1389 compilationState.setFunctionKey(input.extent()); 1390 MOZ_ASSERT(!compilationState.isInitialStencil()); 1391 if (!compilationState.init(fc, scopeCache, inheritThis)) { 1392 return false; 1393 } 1394 1395 Parser<FullParseHandler, Unit> parser(fc, input.options, units, length, 1396 compilationState, 1397 /* syntaxParser = */ nullptr); 1398 if (!parser.checkOptions()) { 1399 return false; 1400 } 1401 1402 FunctionNode* pn = 1403 parser 1404 .standaloneLazyFunction(input, input.extent().toStringStart, 1405 input.strict(), input.generatorKind(), 1406 input.asyncKind()) 1407 .unwrapOr(nullptr); 1408 if (!pn) { 1409 return false; 1410 } 1411 1412 BytecodeEmitter bce(fc, &parser, pn->funbox(), compilationState, 1413 BytecodeEmitter::LazyFunction); 1414 if (!bce.init(pn->pn_pos)) { 1415 return false; 1416 } 1417 1418 if (!bce.emitFunctionScript(pn)) { 1419 return false; 1420 } 1421 1422 // NOTE: Only allow relazification if there was no lazy PrivateScriptData. 1423 // This excludes non-leaf functions and all script class constructors. 1424 bool hadLazyScriptData = input.hasPrivateScriptData(); 1425 bool isRelazifiableAfterDelazify = input.isRelazifiable(); 1426 if (isRelazifiableAfterDelazify && !hadLazyScriptData) { 1427 compilationState.scriptData[CompilationStencil::TopLevelIndex] 1428 .setAllowRelazify(); 1429 } 1430 1431 if (stencils && input.options.checkDelazificationCache()) { 1432 const CompilationStencil* cached = 1433 stencils->getDelazificationFor(input.extent()); 1434 if (cached) { 1435 auto& concurrentSharedData = cached->sharedData; 1436 auto concurrentData = 1437 concurrentSharedData.isSingle() 1438 ? concurrentSharedData.asSingle()->get()->immutableData() 1439 : concurrentSharedData.asBorrow() 1440 ->asSingle() 1441 ->get() 1442 ->immutableData(); 1443 auto ondemandData = 1444 compilationState.sharedData.asSingle()->get()->immutableData(); 1445 MOZ_RELEASE_ASSERT(concurrentData.Length() == ondemandData.Length(), 1446 "Non-deterministic stencils"); 1447 for (size_t i = 0; i < concurrentData.Length(); i++) { 1448 MOZ_RELEASE_ASSERT(concurrentData[i] == ondemandData[i], 1449 "Non-deterministic stencils"); 1450 } 1451 } 1452 } 1453 1454 if (borrowOut) { 1455 auto extensibleStencil = 1456 fc->getAllocator()->make_unique<frontend::ExtensibleCompilationStencil>( 1457 std::move(compilationState)); 1458 if (!extensibleStencil) { 1459 return false; 1460 } 1461 1462 RefPtr<CompilationStencil> stencil = 1463 fc->getAllocator()->new_<CompilationStencil>( 1464 std::move(extensibleStencil)); 1465 if (!stencil) { 1466 return false; 1467 } 1468 1469 *borrowOut = stencils->storeDelazification(std::move(stencil)); 1470 } else { 1471 MOZ_ASSERT(maybeCx); 1472 if (stencils) { 1473 auto extensibleStencil = 1474 maybeCx->make_unique<frontend::ExtensibleCompilationStencil>( 1475 std::move(compilationState)); 1476 if (!extensibleStencil) { 1477 return false; 1478 } 1479 1480 RefPtr<CompilationStencil> stencil = 1481 maybeCx->new_<CompilationStencil>(std::move(extensibleStencil)); 1482 if (!stencil) { 1483 return false; 1484 } 1485 1486 const CompilationStencil* borrowed = 1487 stencils->storeDelazification(std::move(stencil)); 1488 1489 if (!InstantiateLazyFunction(maybeCx, input, *borrowed)) { 1490 return false; 1491 } 1492 } else { 1493 BorrowingCompilationStencil borrowingStencil(compilationState); 1494 if (!InstantiateLazyFunction(maybeCx, input, borrowingStencil)) { 1495 return false; 1496 } 1497 } 1498 } 1499 1500 assertException.reset(); 1501 return true; 1502 } 1503 1504 template <typename Unit> 1505 static bool DelazifyCanonicalScriptedFunctionImpl(JSContext* cx, 1506 FrontendContext* fc, 1507 ScopeBindingCache* scopeCache, 1508 JS::Handle<JSFunction*> fun, 1509 JS::Handle<BaseScript*> lazy, 1510 ScriptSource* ss) { 1511 MOZ_ASSERT(!lazy->hasBytecode(), "Script is already compiled!"); 1512 MOZ_ASSERT(lazy->function() == fun); 1513 1514 MOZ_DIAGNOSTIC_ASSERT(!fun->isGhost()); 1515 1516 AutoIncrementalTimer timer(cx->realm()->timers.delazificationTime); 1517 1518 JS::CompileOptions options(cx); 1519 options.setMutedErrors(lazy->mutedErrors()) 1520 .setFileAndLine(lazy->filename(), lazy->lineno()) 1521 .setColumn(JS::ColumnNumberOneOrigin(lazy->column())) 1522 .setScriptSourceOffset(lazy->sourceStart()) 1523 .setNoScriptRval(false) 1524 .setSelfHostingMode(false) 1525 .setEagerDelazificationStrategy(lazy->delazificationMode()) 1526 .setEagerBaselineStrategy(JS::EagerBaselineOption::None); 1527 1528 Rooted<CompilationInput> input(cx, CompilationInput(options)); 1529 input.get().initFromLazy(cx, lazy, ss); 1530 1531 RefPtr<InitialStencilAndDelazifications> stencils = 1532 lazy->sourceObject()->maybeGetStencils(); 1533 1534 if (stencils && input.get().options.consumeDelazificationCache()) { 1535 const CompilationStencil* cached = 1536 stencils->getDelazificationFor(input.get().extent()); 1537 if (cached) { 1538 return InstantiateLazyFunction(cx, input.get(), *cached); 1539 } 1540 } 1541 1542 size_t sourceStart = lazy->sourceStart(); 1543 size_t sourceLength = lazy->sourceEnd() - lazy->sourceStart(); 1544 1545 MOZ_ASSERT(ss->hasSourceText()); 1546 1547 // Parse and compile the script from source. 1548 UncompressedSourceCache::AutoHoldEntry holder; 1549 1550 MOZ_ASSERT(ss->hasSourceType<Unit>()); 1551 1552 ScriptSource::PinnedUnits<Unit> units(cx, ss, holder, sourceStart, 1553 sourceLength); 1554 if (!units.get()) { 1555 return false; 1556 } 1557 1558 return CompileLazyFunctionToStencilMaybeInstantiate( 1559 cx, fc, cx->tempLifoAlloc(), input.get(), scopeCache, units.get(), 1560 sourceLength, stencils, nullptr); 1561 } 1562 1563 bool frontend::DelazifyCanonicalScriptedFunction(JSContext* cx, 1564 FrontendContext* fc, 1565 JS::Handle<JSFunction*> fun) { 1566 Maybe<AutoGeckoProfilerEntry> pseudoFrame; 1567 if (cx) { 1568 pseudoFrame.emplace(cx, "script delazify", 1569 JS::ProfilingCategoryPair::JS_Parsing); 1570 } 1571 1572 Rooted<BaseScript*> lazy(cx, fun->baseScript()); 1573 ScriptSource* ss = lazy->scriptSource(); 1574 ScopeBindingCache* scopeCache = &cx->caches().scopeCache; 1575 1576 if (ss->hasSourceType<Utf8Unit>()) { 1577 // UTF-8 source text. 1578 return DelazifyCanonicalScriptedFunctionImpl<Utf8Unit>(cx, fc, scopeCache, 1579 fun, lazy, ss); 1580 } 1581 1582 MOZ_ASSERT(ss->hasSourceType<char16_t>()); 1583 1584 // UTF-16 source text. 1585 return DelazifyCanonicalScriptedFunctionImpl<char16_t>(cx, fc, scopeCache, 1586 fun, lazy, ss); 1587 } 1588 1589 template <typename Unit> 1590 static const CompilationStencil* DelazifyCanonicalScriptedFunctionImpl( 1591 FrontendContext* fc, js::LifoAlloc& tempLifoAlloc, 1592 const JS::PrefableCompileOptions& prefableOptions, 1593 ScopeBindingCache* scopeCache, ScriptIndex scriptIndex, 1594 InitialStencilAndDelazifications* stencils, 1595 DelazifyFailureReason* failureReason) { 1596 MOZ_ASSERT(stencils); 1597 1598 ScriptStencilRef script{*stencils, scriptIndex}; 1599 const CompilationStencil* cached = script.maybeContext(); 1600 if (cached) { 1601 return cached; 1602 } 1603 1604 const ScriptStencilExtra& extra = script.scriptExtra(); 1605 1606 #if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG) 1607 MOZ_ASSERT(!script.isEagerlyCompiledInInitial(), 1608 "Script is already compiled in initial stencil!"); 1609 const ScriptStencil& data = script.scriptDataFromEnclosing(); 1610 MOZ_DIAGNOSTIC_ASSERT(!data.isGhost()); 1611 MOZ_DIAGNOSTIC_ASSERT(data.wasEmittedByEnclosingScript()); 1612 #endif 1613 1614 size_t sourceStart = extra.extent.sourceStart; 1615 size_t sourceLength = extra.extent.sourceEnd - sourceStart; 1616 1617 ScriptSource* ss = stencils->getInitial()->source; 1618 MOZ_ASSERT(ss->hasSourceText()); 1619 1620 MOZ_ASSERT(ss->hasSourceType<Unit>()); 1621 1622 ScriptSource::PinnedUnitsIfUncompressed<Unit> units(ss, sourceStart, 1623 sourceLength); 1624 if (!units.get()) { 1625 *failureReason = DelazifyFailureReason::Compressed; 1626 return nullptr; 1627 } 1628 1629 JS::CompileOptions options(prefableOptions); 1630 options.setMutedErrors(ss->mutedErrors()) 1631 .setFileAndLine(ss->filename(), extra.extent.lineno) 1632 .setColumn(JS::ColumnNumberOneOrigin(extra.extent.column)) 1633 .setScriptSourceOffset(sourceStart) 1634 .setNoScriptRval(false) 1635 .setSelfHostingMode(false); 1636 1637 // CompilationInput initialized with initFromStencil only reference 1638 // information from the CompilationStencil context and the ref-counted 1639 // ScriptSource, which are both GC-free. 1640 JS_HAZ_NON_GC_POINTER CompilationInput input(options); 1641 input.initFromStencil(*stencils, scriptIndex, ss); 1642 1643 const CompilationStencil* borrow; 1644 if (!CompileLazyFunctionToStencilMaybeInstantiate( 1645 nullptr, fc, tempLifoAlloc, input, scopeCache, units.get(), 1646 sourceLength, stencils, &borrow)) { 1647 *failureReason = DelazifyFailureReason::Other; 1648 return nullptr; 1649 } 1650 1651 return borrow; 1652 } 1653 1654 const CompilationStencil* frontend::DelazifyCanonicalScriptedFunction( 1655 FrontendContext* fc, js::LifoAlloc& tempLifoAlloc, 1656 const JS::PrefableCompileOptions& prefableOptions, 1657 ScopeBindingCache* scopeCache, ScriptIndex scriptIndex, 1658 InitialStencilAndDelazifications* stencils, 1659 DelazifyFailureReason* failureReason) { 1660 ScriptSource* ss = stencils->getInitial()->source; 1661 if (ss->hasSourceType<Utf8Unit>()) { 1662 // UTF-8 source text. 1663 return DelazifyCanonicalScriptedFunctionImpl<Utf8Unit>( 1664 fc, tempLifoAlloc, prefableOptions, scopeCache, scriptIndex, stencils, 1665 failureReason); 1666 } 1667 1668 // UTF-16 source text. 1669 MOZ_ASSERT(ss->hasSourceType<char16_t>()); 1670 return DelazifyCanonicalScriptedFunctionImpl<char16_t>( 1671 fc, tempLifoAlloc, prefableOptions, scopeCache, scriptIndex, stencils, 1672 failureReason); 1673 } 1674 1675 static JSFunction* CompileStandaloneFunction( 1676 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 1677 JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd, 1678 FunctionSyntaxKind syntaxKind, GeneratorKind generatorKind, 1679 FunctionAsyncKind asyncKind, JS::Handle<Scope*> enclosingScope = nullptr) { 1680 JS::Rooted<JSFunction*> fun(cx); 1681 { 1682 AutoReportFrontendContext fc(cx); 1683 AutoAssertReportedException assertException(cx, &fc); 1684 1685 Rooted<CompilationInput> input(cx, CompilationInput(options)); 1686 if (enclosingScope) { 1687 if (!input.get().initForStandaloneFunctionInNonSyntacticScope( 1688 &fc, enclosingScope)) { 1689 return nullptr; 1690 } 1691 } else { 1692 if (!input.get().initForStandaloneFunction(cx, &fc)) { 1693 return nullptr; 1694 } 1695 } 1696 1697 LifoAllocScope parserAllocScope(&cx->tempLifoAlloc()); 1698 InheritThis inheritThis = (syntaxKind == FunctionSyntaxKind::Arrow) 1699 ? InheritThis::Yes 1700 : InheritThis::No; 1701 ScopeBindingCache* scopeCache = &cx->caches().scopeCache; 1702 StandaloneFunctionCompiler<char16_t> compiler(&fc, parserAllocScope, 1703 input.get(), srcBuf); 1704 if (!compiler.init(&fc, scopeCache, inheritThis)) { 1705 return nullptr; 1706 } 1707 1708 if (!compiler.compile(cx, syntaxKind, generatorKind, asyncKind, 1709 parameterListEnd)) { 1710 return nullptr; 1711 } 1712 1713 Rooted<CompilationGCOutput> gcOutput(cx); 1714 RefPtr<ScriptSource> source; 1715 { 1716 BorrowingCompilationStencil borrowingStencil(compiler.stencil()); 1717 if (!CompilationStencil::instantiateStencils( 1718 cx, input.get(), borrowingStencil, gcOutput.get())) { 1719 return nullptr; 1720 } 1721 source = borrowingStencil.source; 1722 } 1723 1724 fun = gcOutput.get().getFunctionNoBaseIndex( 1725 CompilationStencil::TopLevelIndex); 1726 MOZ_ASSERT(fun->hasBytecode() || IsAsmJSModule(fun)); 1727 1728 // Enqueue an off-thread source compression task after finishing parsing. 1729 if (!source->tryCompressOffThread(cx)) { 1730 return nullptr; 1731 } 1732 1733 // Note: If AsmJS successfully compiles, the into.script will still be 1734 // nullptr. In this case we have compiled to a native function instead of an 1735 // interpreted script. 1736 if (gcOutput.get().script) { 1737 if (parameterListEnd) { 1738 source->setParameterListEnd(*parameterListEnd); 1739 } 1740 1741 const JS::InstantiateOptions instantiateOptions(options); 1742 Rooted<JSScript*> script(cx, gcOutput.get().script); 1743 FireOnNewScript(cx, instantiateOptions, script); 1744 } 1745 1746 assertException.reset(); 1747 } 1748 return fun; 1749 } 1750 1751 JSFunction* frontend::CompileStandaloneFunction( 1752 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 1753 JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd, 1754 FunctionSyntaxKind syntaxKind) { 1755 return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd, 1756 syntaxKind, GeneratorKind::NotGenerator, 1757 FunctionAsyncKind::SyncFunction); 1758 } 1759 1760 JSFunction* frontend::CompileStandaloneGenerator( 1761 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 1762 JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd, 1763 FunctionSyntaxKind syntaxKind) { 1764 return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd, 1765 syntaxKind, GeneratorKind::Generator, 1766 FunctionAsyncKind::SyncFunction); 1767 } 1768 1769 JSFunction* frontend::CompileStandaloneAsyncFunction( 1770 JSContext* cx, const ReadOnlyCompileOptions& options, 1771 JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd, 1772 FunctionSyntaxKind syntaxKind) { 1773 return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd, 1774 syntaxKind, GeneratorKind::NotGenerator, 1775 FunctionAsyncKind::AsyncFunction); 1776 } 1777 1778 JSFunction* frontend::CompileStandaloneAsyncGenerator( 1779 JSContext* cx, const ReadOnlyCompileOptions& options, 1780 JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd, 1781 FunctionSyntaxKind syntaxKind) { 1782 return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd, 1783 syntaxKind, GeneratorKind::Generator, 1784 FunctionAsyncKind::AsyncFunction); 1785 } 1786 1787 JSFunction* frontend::CompileStandaloneFunctionInNonSyntacticScope( 1788 JSContext* cx, const JS::ReadOnlyCompileOptions& options, 1789 JS::SourceText<char16_t>& srcBuf, const Maybe<uint32_t>& parameterListEnd, 1790 FunctionSyntaxKind syntaxKind, JS::Handle<Scope*> enclosingScope) { 1791 MOZ_ASSERT(enclosingScope); 1792 return CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd, 1793 syntaxKind, GeneratorKind::NotGenerator, 1794 FunctionAsyncKind::SyncFunction, 1795 enclosingScope); 1796 }