ModuleObject.cpp (80659B)
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 "builtin/ModuleObject.h" 8 9 #include "mozilla/DebugOnly.h" 10 #include "mozilla/ScopeExit.h" 11 12 #include "builtin/Promise.h" 13 #include "builtin/SelfHostingDefines.h" 14 #include "frontend/ParseNode.h" 15 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex, ParserAtomsTable, ParserAtom 16 #include "frontend/SharedContext.h" 17 #include "frontend/Stencil.h" 18 #include "gc/GCContext.h" 19 #include "gc/Tracer.h" 20 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin, JS::LimitedColumnNumberOneOrigin 21 #include "js/friend/ErrorMessages.h" // JSMSG_* 22 #include "js/Modules.h" // JS::GetModulePrivate, JS::ModuleDynamicImportHook, JS::ModuleType 23 #include "vm/EqualityOperations.h" // js::SameValue 24 #include "vm/Interpreter.h" // Execute, Lambda, ReportRuntimeLexicalError 25 #include "vm/ModuleBuilder.h" // js::ModuleBuilder 26 #include "vm/Modules.h" 27 #include "vm/PlainObject.h" // js::PlainObject 28 #include "vm/PromiseObject.h" // js::PromiseObject 29 #include "vm/SharedStencil.h" // js::GCThingIndex 30 31 #include "gc/GCContext-inl.h" 32 #include "vm/EnvironmentObject-inl.h" // EnvironmentObject::setAliasedBinding 33 #include "vm/JSObject-inl.h" 34 #include "vm/JSScript-inl.h" 35 #include "vm/List-inl.h" 36 #include "vm/NativeObject-inl.h" 37 38 using namespace js; 39 40 using mozilla::Maybe; 41 using mozilla::Nothing; 42 using mozilla::Some; 43 using mozilla::Span; 44 45 static_assert(ModuleStatus::New < ModuleStatus::Unlinked && 46 ModuleStatus::Unlinked < ModuleStatus::Linking && 47 ModuleStatus::Linking < ModuleStatus::Linked && 48 ModuleStatus::Linked < ModuleStatus::Evaluating && 49 ModuleStatus::Evaluating < ModuleStatus::EvaluatingAsync && 50 ModuleStatus::EvaluatingAsync < ModuleStatus::Evaluated && 51 ModuleStatus::Evaluated < ModuleStatus::Evaluated_Error, 52 "Module statuses are ordered incorrectly"); 53 54 static Value StringOrNullValue(JSString* maybeString) { 55 return maybeString ? StringValue(maybeString) : NullValue(); 56 } 57 58 static Value ModuleTypeToValue(JS::ModuleType moduleType) { 59 static_assert(size_t(JS::ModuleType::Limit) <= INT32_MAX); 60 return Int32Value(int32_t(moduleType)); 61 } 62 63 static JS::ModuleType ValueToModuleType(const Value& value) { 64 int32_t i = value.toInt32(); 65 MOZ_ASSERT(i >= 0 && i <= int32_t(JS::ModuleType::Limit)); 66 return static_cast<JS::ModuleType>(i); 67 } 68 69 static Value ImportPhaseToValue(ImportPhase phase) { 70 static_assert(size_t(ImportPhase::Limit) <= INT32_MAX); 71 return Int32Value(int32_t(phase)); 72 } 73 74 static ImportPhase ValueToImportPhase(const Value& value) { 75 int32_t i = value.toInt32(); 76 MOZ_ASSERT(i >= 0 && i <= int32_t(ImportPhase::Limit)); 77 return static_cast<ImportPhase>(i); 78 } 79 80 #define DEFINE_ATOM_ACCESSOR_METHOD(cls, name, slot) \ 81 JSAtom* cls::name() const { \ 82 Value value = getReservedSlot(slot); \ 83 return &value.toString()->asAtom(); \ 84 } 85 86 #define DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(cls, name, slot) \ 87 JSAtom* cls::name() const { \ 88 Value value = getReservedSlot(slot); \ 89 if (value.isNull()) { \ 90 return nullptr; \ 91 } \ 92 return &value.toString()->asAtom(); \ 93 } 94 95 #define DEFINE_UINT32_ACCESSOR_METHOD(cls, name, slot) \ 96 uint32_t cls::name() const { \ 97 Value value = getReservedSlot(slot); \ 98 MOZ_ASSERT(value.toNumber() >= 0); \ 99 if (value.isInt32()) { \ 100 return value.toInt32(); \ 101 } \ 102 return JS::ToUint32(value.toDouble()); \ 103 } 104 105 /////////////////////////////////////////////////////////////////////////// 106 // ImportEntry 107 108 ImportEntry::ImportEntry(Handle<ModuleRequestObject*> moduleRequest, 109 Handle<JSAtom*> maybeImportName, 110 Handle<JSAtom*> localName, uint32_t lineNumber, 111 JS::ColumnNumberOneOrigin columnNumber) 112 : moduleRequest_(moduleRequest), 113 importName_(maybeImportName), 114 localName_(localName), 115 lineNumber_(lineNumber), 116 columnNumber_(columnNumber) {} 117 118 void ImportEntry::trace(JSTracer* trc) { 119 TraceEdge(trc, &moduleRequest_, "ImportEntry::moduleRequest_"); 120 TraceNullableEdge(trc, &importName_, "ImportEntry::importName_"); 121 TraceNullableEdge(trc, &localName_, "ImportEntry::localName_"); 122 } 123 124 /////////////////////////////////////////////////////////////////////////// 125 // ExportEntry 126 127 ExportEntry::ExportEntry(Handle<JSAtom*> maybeExportName, 128 Handle<ModuleRequestObject*> moduleRequest, 129 Handle<JSAtom*> maybeImportName, 130 Handle<JSAtom*> maybeLocalName, uint32_t lineNumber, 131 JS::ColumnNumberOneOrigin columnNumber) 132 : exportName_(maybeExportName), 133 moduleRequest_(moduleRequest), 134 importName_(maybeImportName), 135 localName_(maybeLocalName), 136 lineNumber_(lineNumber), 137 columnNumber_(columnNumber) { 138 // Line and column numbers are optional for export entries since direct 139 // entries are checked at parse time. 140 } 141 142 void ExportEntry::trace(JSTracer* trc) { 143 TraceNullableEdge(trc, &exportName_, "ExportEntry::exportName_"); 144 TraceNullableEdge(trc, &moduleRequest_, "ExportEntry::moduleRequest_"); 145 TraceNullableEdge(trc, &importName_, "ExportEntry::importName_"); 146 TraceNullableEdge(trc, &localName_, "ExportEntry::localName_"); 147 } 148 149 /////////////////////////////////////////////////////////////////////////// 150 // RequestedModule 151 152 /* static */ 153 RequestedModule::RequestedModule(Handle<ModuleRequestObject*> moduleRequest, 154 uint32_t lineNumber, 155 JS::ColumnNumberOneOrigin columnNumber) 156 : moduleRequest_(moduleRequest), 157 lineNumber_(lineNumber), 158 columnNumber_(columnNumber) {} 159 160 void RequestedModule::trace(JSTracer* trc) { 161 TraceEdge(trc, &moduleRequest_, "ExportEntry::moduleRequest_"); 162 } 163 164 /////////////////////////////////////////////////////////////////////////// 165 // ResolvedBindingObject 166 167 /* static */ const JSClass ResolvedBindingObject::class_ = { 168 "ResolvedBinding", 169 JSCLASS_HAS_RESERVED_SLOTS(ResolvedBindingObject::SlotCount), 170 }; 171 172 ModuleObject* ResolvedBindingObject::module() const { 173 Value value = getReservedSlot(ModuleSlot); 174 return &value.toObject().as<ModuleObject>(); 175 } 176 177 JSAtom* ResolvedBindingObject::bindingName() const { 178 Value value = getReservedSlot(BindingNameSlot); 179 return &value.toString()->asAtom(); 180 } 181 182 /* static */ 183 bool ResolvedBindingObject::isInstance(HandleValue value) { 184 return value.isObject() && value.toObject().is<ResolvedBindingObject>(); 185 } 186 187 /* static */ 188 ResolvedBindingObject* ResolvedBindingObject::create( 189 JSContext* cx, Handle<ModuleObject*> module, Handle<JSAtom*> bindingName) { 190 ResolvedBindingObject* self = 191 NewObjectWithGivenProto<ResolvedBindingObject>(cx, nullptr); 192 if (!self) { 193 return nullptr; 194 } 195 196 self->initReservedSlot(ModuleSlot, ObjectValue(*module)); 197 self->initReservedSlot(BindingNameSlot, StringValue(bindingName)); 198 return self; 199 } 200 201 /////////////////////////////////////////////////////////////////////////// 202 // ImportAttribute 203 204 ImportAttribute::ImportAttribute(Handle<JSAtom*> key, Handle<JSString*> value) 205 : key_(key), value_(value) {} 206 207 void ImportAttribute::trace(JSTracer* trc) { 208 TraceNullableEdge(trc, &key_, "ImportAttribute::key_"); 209 TraceNullableEdge(trc, &value_, "ImportAttribute::value_"); 210 } 211 212 /////////////////////////////////////////////////////////////////////////// 213 // ModuleRequestObject 214 /* static */ const JSClass ModuleRequestObject::class_ = { 215 "ModuleRequest", 216 JSCLASS_HAS_RESERVED_SLOTS(ModuleRequestObject::SlotCount), 217 }; 218 219 DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ModuleRequestObject, specifier, 220 SpecifierSlot) 221 222 JS::ModuleType ModuleRequestObject::moduleType() const { 223 return ValueToModuleType(getReservedSlot(ModuleTypeSlot)); 224 } 225 226 ImportPhase ModuleRequestObject::phase() const { 227 return ValueToImportPhase(getReservedSlot(PhaseSlot)); 228 } 229 230 static bool GetModuleType(JSContext* cx, 231 Handle<ImportAttributeVector> maybeAttributes, 232 JS::ModuleType& moduleType) { 233 for (const ImportAttribute& importAttribute : maybeAttributes) { 234 if (importAttribute.key() == cx->names().type) { 235 Rooted<JSLinearString*> typeStr( 236 cx, importAttribute.value()->ensureLinear(cx)); 237 if (!typeStr) { 238 return false; 239 } 240 241 if (js::EqualStrings(typeStr, cx->names().json)) { 242 moduleType = JS::ModuleType::JSON; 243 } else if (js::EqualStrings(typeStr, cx->names().css)) { 244 moduleType = JS::ModuleType::CSS; 245 } else if (js::EqualStrings(typeStr, cx->names().bytes)) { 246 moduleType = JS::ModuleType::Bytes; 247 } else { 248 moduleType = JS::ModuleType::Unknown; 249 } 250 251 return true; 252 } 253 } 254 255 moduleType = JS::ModuleType::JavaScript; 256 return true; 257 } 258 259 /* static */ 260 bool ModuleRequestObject::isInstance(HandleValue value) { 261 return value.isObject() && value.toObject().is<ModuleRequestObject>(); 262 } 263 264 /* static */ 265 ModuleRequestObject* ModuleRequestObject::create( 266 JSContext* cx, Handle<JSAtom*> specifier, 267 Handle<ImportAttributeVector> maybeAttributes, ImportPhase phase) { 268 JS::ModuleType moduleType = JS::ModuleType::JavaScript; 269 if (!GetModuleType(cx, maybeAttributes, moduleType)) { 270 return nullptr; 271 } 272 273 return create(cx, specifier, moduleType, phase); 274 } 275 276 /* static */ 277 ModuleRequestObject* ModuleRequestObject::create(JSContext* cx, 278 Handle<JSAtom*> specifier, 279 JS::ModuleType moduleType, 280 ImportPhase phase) { 281 ModuleRequestObject* self = 282 NewObjectWithGivenProto<ModuleRequestObject>(cx, nullptr); 283 if (!self) { 284 return nullptr; 285 } 286 287 self->initReservedSlot(SpecifierSlot, StringOrNullValue(specifier)); 288 self->initReservedSlot(ModuleTypeSlot, ModuleTypeToValue(moduleType)); 289 self->initReservedSlot(PhaseSlot, ImportPhaseToValue(phase)); 290 291 return self; 292 } 293 294 void ModuleRequestObject::setFirstUnsupportedAttributeKey(Handle<JSAtom*> key) { 295 initReservedSlot(FirstUnsupportedAttributeKeySlot, StringOrNullValue(key)); 296 } 297 298 bool ModuleRequestObject::hasFirstUnsupportedAttributeKey() const { 299 return !getReservedSlot(FirstUnsupportedAttributeKeySlot).isNullOrUndefined(); 300 } 301 302 JSAtom* ModuleRequestObject::getFirstUnsupportedAttributeKey() const { 303 if (!hasFirstUnsupportedAttributeKey()) { 304 return nullptr; 305 } 306 return &getReservedSlot(FirstUnsupportedAttributeKeySlot) 307 .toString() 308 ->asAtom(); 309 } 310 311 /////////////////////////////////////////////////////////////////////////// 312 // IndirectBindingMap 313 314 IndirectBindingMap::Binding::Binding(ModuleEnvironmentObject* environment, 315 jsid targetName, PropertyInfo prop) 316 : environment(environment), 317 #ifdef DEBUG 318 targetName(targetName), 319 #endif 320 prop(prop) { 321 } 322 323 void IndirectBindingMap::trace(JSTracer* trc) { 324 if (!map_) { 325 return; 326 } 327 328 for (Map::Enum e(*map_); !e.empty(); e.popFront()) { 329 Binding& b = e.front().value(); 330 TraceEdge(trc, &b.environment, "module bindings environment"); 331 #ifdef DEBUG 332 TraceEdge(trc, &b.targetName, "module bindings target name"); 333 #endif 334 mozilla::DebugOnly<jsid> prev(e.front().key()); 335 TraceEdge(trc, &e.front().mutableKey(), "module bindings binding name"); 336 MOZ_ASSERT(e.front().key() == prev); 337 } 338 } 339 340 bool IndirectBindingMap::put(JSContext* cx, HandleId name, 341 Handle<ModuleEnvironmentObject*> environment, 342 HandleId targetName) { 343 if (!map_) { 344 map_.emplace(cx->zone()); 345 } 346 347 mozilla::Maybe<PropertyInfo> prop = environment->lookup(cx, targetName); 348 MOZ_ASSERT(prop.isSome()); 349 if (!map_->put(name, Binding(environment, targetName, *prop))) { 350 ReportOutOfMemory(cx); 351 return false; 352 } 353 354 return true; 355 } 356 357 bool IndirectBindingMap::lookup(jsid name, ModuleEnvironmentObject** envOut, 358 mozilla::Maybe<PropertyInfo>* propOut) const { 359 if (!map_) { 360 return false; 361 } 362 363 auto ptr = map_->lookup(name); 364 if (!ptr) { 365 return false; 366 } 367 368 const Binding& binding = ptr->value(); 369 MOZ_ASSERT(binding.environment); 370 MOZ_ASSERT( 371 binding.environment->containsPure(binding.targetName, binding.prop)); 372 *envOut = binding.environment; 373 *propOut = Some(binding.prop); 374 return true; 375 } 376 377 /////////////////////////////////////////////////////////////////////////// 378 // ModuleNamespaceObject 379 380 /* static */ 381 constexpr ModuleNamespaceObject::ProxyHandler 382 ModuleNamespaceObject::proxyHandler; 383 384 /* static */ 385 bool ModuleNamespaceObject::isInstance(HandleValue value) { 386 return value.isObject() && value.toObject().is<ModuleNamespaceObject>(); 387 } 388 389 /* static */ 390 ModuleNamespaceObject* ModuleNamespaceObject::create( 391 JSContext* cx, Handle<ModuleObject*> module, 392 MutableHandle<UniquePtr<ExportNameVector>> exports, 393 MutableHandle<UniquePtr<IndirectBindingMap>> bindings) { 394 RootedValue priv(cx, ObjectValue(*module)); 395 ProxyOptions options; 396 options.setLazyProto(true); 397 398 RootedObject object( 399 cx, NewProxyObject(cx, &proxyHandler, priv, nullptr, options)); 400 if (!object) { 401 return nullptr; 402 } 403 404 SetProxyReservedSlot(object, ExportsSlot, 405 PrivateValue(exports.get().release())); 406 AddCellMemory(object, sizeof(ExportNameVector), MemoryUse::ModuleExports); 407 408 SetProxyReservedSlot(object, BindingsSlot, 409 PrivateValue(bindings.get().release())); 410 AddCellMemory(object, sizeof(IndirectBindingMap), 411 MemoryUse::ModuleBindingMap); 412 413 return &object->as<ModuleNamespaceObject>(); 414 } 415 416 ModuleObject& ModuleNamespaceObject::module() { 417 return GetProxyPrivate(this).toObject().as<ModuleObject>(); 418 } 419 420 const ExportNameVector& ModuleNamespaceObject::exports() const { 421 Value value = GetProxyReservedSlot(this, ExportsSlot); 422 auto* exports = static_cast<ExportNameVector*>(value.toPrivate()); 423 MOZ_ASSERT(exports); 424 return *exports; 425 } 426 427 ExportNameVector& ModuleNamespaceObject::mutableExports() { 428 // Get a non-const reference for tracing/destruction. Do not actually mutate 429 // this vector! This would be incorrect without adding barriers. 430 return const_cast<ExportNameVector&>(exports()); 431 } 432 433 IndirectBindingMap& ModuleNamespaceObject::bindings() { 434 Value value = GetProxyReservedSlot(this, BindingsSlot); 435 auto* bindings = static_cast<IndirectBindingMap*>(value.toPrivate()); 436 MOZ_ASSERT(bindings); 437 return *bindings; 438 } 439 440 bool ModuleNamespaceObject::hasExports() const { 441 // Exports may not be present if we hit OOM in initialization. 442 return !GetProxyReservedSlot(this, ExportsSlot).isUndefined(); 443 } 444 445 bool ModuleNamespaceObject::hasBindings() const { 446 // Import bindings may not be present if we hit OOM in initialization. 447 return !GetProxyReservedSlot(this, BindingsSlot).isUndefined(); 448 } 449 450 bool ModuleNamespaceObject::addBinding(JSContext* cx, 451 Handle<JSAtom*> exportedName, 452 Handle<ModuleObject*> targetModule, 453 Handle<JSAtom*> targetName) { 454 Rooted<ModuleEnvironmentObject*> environment( 455 cx, &targetModule->initialEnvironment()); 456 RootedId exportedNameId(cx, AtomToId(exportedName)); 457 RootedId targetNameId(cx, AtomToId(targetName)); 458 return bindings().put(cx, exportedNameId, environment, targetNameId); 459 } 460 461 constexpr char ModuleNamespaceObject::ProxyHandler::family = 0; 462 463 bool ModuleNamespaceObject::ProxyHandler::getPrototype( 464 JSContext* cx, HandleObject proxy, MutableHandleObject protop) const { 465 protop.set(nullptr); 466 return true; 467 } 468 469 bool ModuleNamespaceObject::ProxyHandler::setPrototype( 470 JSContext* cx, HandleObject proxy, HandleObject proto, 471 ObjectOpResult& result) const { 472 if (!proto) { 473 return result.succeed(); 474 } 475 return result.failCantSetProto(); 476 } 477 478 bool ModuleNamespaceObject::ProxyHandler::getPrototypeIfOrdinary( 479 JSContext* cx, HandleObject proxy, bool* isOrdinary, 480 MutableHandleObject protop) const { 481 *isOrdinary = false; 482 return true; 483 } 484 485 bool ModuleNamespaceObject::ProxyHandler::setImmutablePrototype( 486 JSContext* cx, HandleObject proxy, bool* succeeded) const { 487 *succeeded = true; 488 return true; 489 } 490 491 bool ModuleNamespaceObject::ProxyHandler::isExtensible(JSContext* cx, 492 HandleObject proxy, 493 bool* extensible) const { 494 *extensible = false; 495 return true; 496 } 497 498 bool ModuleNamespaceObject::ProxyHandler::preventExtensions( 499 JSContext* cx, HandleObject proxy, ObjectOpResult& result) const { 500 result.succeed(); 501 return true; 502 } 503 504 bool ModuleNamespaceObject::ProxyHandler::getOwnPropertyDescriptor( 505 JSContext* cx, HandleObject proxy, HandleId id, 506 MutableHandle<mozilla::Maybe<PropertyDescriptor>> desc) const { 507 Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); 508 if (id.isSymbol()) { 509 if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) { 510 desc.set(Some(PropertyDescriptor::Data(StringValue(cx->names().Module)))); 511 return true; 512 } 513 514 desc.reset(); 515 return true; 516 } 517 518 const IndirectBindingMap& bindings = ns->bindings(); 519 ModuleEnvironmentObject* env; 520 mozilla::Maybe<PropertyInfo> prop; 521 if (!bindings.lookup(id, &env, &prop)) { 522 // Not found. 523 desc.reset(); 524 return true; 525 } 526 527 RootedValue value(cx, env->getSlot(prop->slot())); 528 if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) { 529 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id); 530 return false; 531 } 532 533 desc.set( 534 Some(PropertyDescriptor::Data(value, {JS::PropertyAttribute::Enumerable, 535 JS::PropertyAttribute::Writable}))); 536 return true; 537 } 538 539 static bool ValidatePropertyDescriptor( 540 JSContext* cx, Handle<PropertyDescriptor> desc, bool expectedWritable, 541 bool expectedEnumerable, bool expectedConfigurable, 542 HandleValue expectedValue, ObjectOpResult& result) { 543 if (desc.isAccessorDescriptor()) { 544 return result.fail(JSMSG_CANT_REDEFINE_PROP); 545 } 546 547 if (desc.hasWritable() && desc.writable() != expectedWritable) { 548 return result.fail(JSMSG_CANT_REDEFINE_PROP); 549 } 550 551 if (desc.hasEnumerable() && desc.enumerable() != expectedEnumerable) { 552 return result.fail(JSMSG_CANT_REDEFINE_PROP); 553 } 554 555 if (desc.hasConfigurable() && desc.configurable() != expectedConfigurable) { 556 return result.fail(JSMSG_CANT_REDEFINE_PROP); 557 } 558 559 if (desc.hasValue()) { 560 bool same; 561 if (!SameValue(cx, desc.value(), expectedValue, &same)) { 562 return false; 563 } 564 if (!same) { 565 return result.fail(JSMSG_CANT_REDEFINE_PROP); 566 } 567 } 568 569 return result.succeed(); 570 } 571 572 bool ModuleNamespaceObject::ProxyHandler::defineProperty( 573 JSContext* cx, HandleObject proxy, HandleId id, 574 Handle<PropertyDescriptor> desc, ObjectOpResult& result) const { 575 if (id.isSymbol()) { 576 if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) { 577 RootedValue value(cx, StringValue(cx->names().Module)); 578 return ValidatePropertyDescriptor(cx, desc, false, false, false, value, 579 result); 580 } 581 return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE); 582 } 583 584 const IndirectBindingMap& bindings = 585 proxy->as<ModuleNamespaceObject>().bindings(); 586 ModuleEnvironmentObject* env; 587 mozilla::Maybe<PropertyInfo> prop; 588 if (!bindings.lookup(id, &env, &prop)) { 589 return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE); 590 } 591 592 RootedValue value(cx, env->getSlot(prop->slot())); 593 if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) { 594 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id); 595 return false; 596 } 597 598 return ValidatePropertyDescriptor(cx, desc, true, true, false, value, result); 599 } 600 601 bool ModuleNamespaceObject::ProxyHandler::has(JSContext* cx, HandleObject proxy, 602 HandleId id, bool* bp) const { 603 Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); 604 if (id.isSymbol()) { 605 *bp = id.isWellKnownSymbol(JS::SymbolCode::toStringTag); 606 return true; 607 } 608 609 *bp = ns->bindings().has(id); 610 return true; 611 } 612 613 bool ModuleNamespaceObject::ProxyHandler::get(JSContext* cx, HandleObject proxy, 614 HandleValue receiver, HandleId id, 615 MutableHandleValue vp) const { 616 Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); 617 if (id.isSymbol()) { 618 if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) { 619 vp.setString(cx->names().Module); 620 return true; 621 } 622 623 vp.setUndefined(); 624 return true; 625 } 626 627 ModuleEnvironmentObject* env; 628 mozilla::Maybe<PropertyInfo> prop; 629 if (!ns->bindings().lookup(id, &env, &prop)) { 630 vp.setUndefined(); 631 return true; 632 } 633 634 RootedValue value(cx, env->getSlot(prop->slot())); 635 if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) { 636 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id); 637 return false; 638 } 639 640 vp.set(value); 641 return true; 642 } 643 644 bool ModuleNamespaceObject::ProxyHandler::set(JSContext* cx, HandleObject proxy, 645 HandleId id, HandleValue v, 646 HandleValue receiver, 647 ObjectOpResult& result) const { 648 return result.failReadOnly(); 649 } 650 651 bool ModuleNamespaceObject::ProxyHandler::delete_( 652 JSContext* cx, HandleObject proxy, HandleId id, 653 ObjectOpResult& result) const { 654 Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); 655 if (id.isSymbol()) { 656 if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) { 657 return result.failCantDelete(); 658 } 659 660 return result.succeed(); 661 } 662 663 if (ns->bindings().has(id)) { 664 return result.failCantDelete(); 665 } 666 667 return result.succeed(); 668 } 669 670 bool ModuleNamespaceObject::ProxyHandler::ownPropertyKeys( 671 JSContext* cx, HandleObject proxy, MutableHandleIdVector props) const { 672 Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); 673 uint32_t count = ns->exports().length(); 674 if (!props.reserve(props.length() + count + 1)) { 675 return false; 676 } 677 678 for (JSAtom* atom : ns->exports()) { 679 props.infallibleAppend(AtomToId(atom)); 680 } 681 props.infallibleAppend( 682 PropertyKey::Symbol(cx->wellKnownSymbols().toStringTag)); 683 684 return true; 685 } 686 687 void ModuleNamespaceObject::ProxyHandler::trace(JSTracer* trc, 688 JSObject* proxy) const { 689 auto& self = proxy->as<ModuleNamespaceObject>(); 690 691 if (self.hasExports()) { 692 self.mutableExports().trace(trc); 693 } 694 695 if (self.hasBindings()) { 696 self.bindings().trace(trc); 697 } 698 } 699 700 void ModuleNamespaceObject::ProxyHandler::finalize(JS::GCContext* gcx, 701 JSObject* proxy) const { 702 auto& self = proxy->as<ModuleNamespaceObject>(); 703 704 if (self.hasExports()) { 705 gcx->delete_(proxy, &self.mutableExports(), MemoryUse::ModuleExports); 706 } 707 708 if (self.hasBindings()) { 709 gcx->delete_(proxy, &self.bindings(), MemoryUse::ModuleBindingMap); 710 } 711 } 712 713 // https://tc39.es/ecma262/#sec-IncrementModuleAsyncEvaluationCount 714 // 9.6.3 IncrementModuleAsyncEvaluationCount() 715 static uint32_t IncrementModuleAsyncEvaluationCount(JSRuntime* rt) { 716 if (rt->pendingAsyncModuleEvaluations == 0) { 717 // From the spec NOTE: 718 // An implementation may unobservably reset [[ModuleAsyncEvaluationCount]] 719 // to 0 whenever there are no pending modules. 720 rt->moduleAsyncEvaluatingPostOrder = 0; 721 } 722 723 uint32_t ordinal = rt->moduleAsyncEvaluatingPostOrder; 724 MOZ_ASSERT(ordinal != ASYNC_EVALUATING_POST_ORDER_DONE); 725 MOZ_ASSERT(ordinal != ASYNC_EVALUATING_POST_ORDER_UNSET); 726 MOZ_ASSERT(ordinal < ASYNC_EVALUATING_POST_ORDER_MAX_VALUE); 727 rt->moduleAsyncEvaluatingPostOrder++; 728 729 MOZ_ASSERT(rt->pendingAsyncModuleEvaluations < MAX_UINT32); 730 rt->pendingAsyncModuleEvaluations++; 731 732 return ordinal; 733 } 734 735 bool AsyncEvaluationOrder::isUnset() const { 736 return value == ASYNC_EVALUATING_POST_ORDER_UNSET; 737 } 738 739 bool AsyncEvaluationOrder::isDone() const { 740 return value == ASYNC_EVALUATING_POST_ORDER_DONE; 741 } 742 743 bool AsyncEvaluationOrder::isInteger() const { 744 return value <= ASYNC_EVALUATING_POST_ORDER_MAX_VALUE; 745 } 746 747 uint32_t AsyncEvaluationOrder::get() const { 748 MOZ_ASSERT(isInteger()); 749 return value; 750 } 751 752 void AsyncEvaluationOrder::set(JSRuntime* rt) { 753 MOZ_ASSERT(isUnset()); 754 value = IncrementModuleAsyncEvaluationCount(rt); 755 } 756 757 void AsyncEvaluationOrder::setDone(JSRuntime* rt) { 758 MOZ_ASSERT(isInteger()); 759 MOZ_ASSERT(rt->pendingAsyncModuleEvaluations > 0); 760 rt->pendingAsyncModuleEvaluations--; 761 value = ASYNC_EVALUATING_POST_ORDER_DONE; 762 } 763 764 /////////////////////////////////////////////////////////////////////////// 765 // SyntheticModuleFields 766 767 // The fields of a synthetic module record, as described in: 768 // https://tc39.es/proposal-json-modules/#sec-synthetic-module-records 769 class js::SyntheticModuleFields { 770 public: 771 ExportNameVector exportNames; 772 773 public: 774 void trace(JSTracer* trc); 775 }; 776 777 void SyntheticModuleFields::trace(JSTracer* trc) { exportNames.trace(trc); } 778 779 /////////////////////////////////////////////////////////////////////////// 780 // CyclicModuleFields 781 782 // The fields of a cyclic module record, as described in: 783 // https://tc39.es/ecma262/#sec-cyclic-module-records 784 class js::CyclicModuleFields { 785 public: 786 ModuleStatus status = ModuleStatus::New; 787 788 bool hasTopLevelAwait : 1; 789 790 private: 791 // Flag bits that determine whether other fields are present. 792 bool hasDfsAncestorIndex : 1; 793 bool hasPendingAsyncDependencies : 1; 794 795 // Fields whose presence is conditional on the flag bits above. 796 uint32_t dfsAncestorIndex = 0; 797 uint32_t pendingAsyncDependencies = 0; 798 799 // Fields describing the layout of exportEntries. 800 uint32_t indirectExportEntriesStart = 0; 801 uint32_t starExportEntriesStart = 0; 802 803 public: 804 HeapPtr<Value> evaluationError; 805 HeapPtr<JSObject*> metaObject; 806 HeapPtr<ScriptSourceObject*> scriptSourceObject; 807 RequestedModuleVector requestedModules; 808 LoadedModuleMap loadedModules; 809 ImportEntryVector importEntries; 810 ExportEntryVector exportEntries; 811 IndirectBindingMap importBindings; 812 UniquePtr<FunctionDeclarationVector> functionDeclarations; 813 AsyncEvaluationOrder asyncEvaluationOrder; 814 HeapPtr<PromiseObject*> topLevelCapability; 815 HeapPtr<ListObject*> asyncParentModules; 816 HeapPtr<ModuleObject*> cycleRoot; 817 818 public: 819 CyclicModuleFields(); 820 821 void trace(JSTracer* trc); 822 823 void initExportEntries(MutableHandle<ExportEntryVector> allEntries, 824 uint32_t localExportCount, 825 uint32_t indirectExportCount, 826 uint32_t starExportCount); 827 Span<const ExportEntry> localExportEntries() const; 828 Span<const ExportEntry> indirectExportEntries() const; 829 Span<const ExportEntry> starExportEntries() const; 830 831 void setDfsAncestorIndex(uint32_t index); 832 Maybe<uint32_t> maybeDfsAncestorIndex() const; 833 void clearDfsAncestorIndex(); 834 835 void setPendingAsyncDependencies(uint32_t newValue); 836 Maybe<uint32_t> maybePendingAsyncDependencies() const; 837 }; 838 839 CyclicModuleFields::CyclicModuleFields() 840 : hasTopLevelAwait(false), 841 hasDfsAncestorIndex(false), 842 hasPendingAsyncDependencies(false) {} 843 844 void CyclicModuleFields::trace(JSTracer* trc) { 845 TraceEdge(trc, &evaluationError, "CyclicModuleFields::evaluationError"); 846 TraceNullableEdge(trc, &metaObject, "CyclicModuleFields::metaObject"); 847 TraceNullableEdge(trc, &scriptSourceObject, 848 "CyclicModuleFields::scriptSourceObject"); 849 requestedModules.trace(trc); 850 loadedModules.trace(trc); 851 importEntries.trace(trc); 852 exportEntries.trace(trc); 853 importBindings.trace(trc); 854 TraceNullableEdge(trc, &topLevelCapability, 855 "CyclicModuleFields::topLevelCapability"); 856 TraceNullableEdge(trc, &asyncParentModules, 857 "CyclicModuleFields::asyncParentModules"); 858 TraceNullableEdge(trc, &cycleRoot, "CyclicModuleFields::cycleRoot"); 859 } 860 861 void CyclicModuleFields::initExportEntries( 862 MutableHandle<ExportEntryVector> allEntries, uint32_t localExportCount, 863 uint32_t indirectExportCount, uint32_t starExportCount) { 864 MOZ_ASSERT(allEntries.length() == 865 localExportCount + indirectExportCount + starExportCount); 866 867 exportEntries = std::move(allEntries.get()); 868 indirectExportEntriesStart = localExportCount; 869 starExportEntriesStart = indirectExportEntriesStart + indirectExportCount; 870 } 871 872 Span<const ExportEntry> CyclicModuleFields::localExportEntries() const { 873 MOZ_ASSERT(indirectExportEntriesStart <= exportEntries.length()); 874 return Span(exportEntries.begin(), 875 exportEntries.begin() + indirectExportEntriesStart); 876 } 877 878 Span<const ExportEntry> CyclicModuleFields::indirectExportEntries() const { 879 MOZ_ASSERT(indirectExportEntriesStart <= starExportEntriesStart); 880 MOZ_ASSERT(starExportEntriesStart <= exportEntries.length()); 881 return Span(exportEntries.begin() + indirectExportEntriesStart, 882 exportEntries.begin() + starExportEntriesStart); 883 } 884 885 Span<const ExportEntry> CyclicModuleFields::starExportEntries() const { 886 MOZ_ASSERT(starExportEntriesStart <= exportEntries.length()); 887 return Span(exportEntries.begin() + starExportEntriesStart, 888 exportEntries.end()); 889 } 890 891 void CyclicModuleFields::setDfsAncestorIndex(uint32_t index) { 892 dfsAncestorIndex = index; 893 hasDfsAncestorIndex = true; 894 } 895 896 Maybe<uint32_t> CyclicModuleFields::maybeDfsAncestorIndex() const { 897 return hasDfsAncestorIndex ? Some(dfsAncestorIndex) : Nothing(); 898 } 899 900 void CyclicModuleFields::clearDfsAncestorIndex() { 901 dfsAncestorIndex = 0; 902 hasDfsAncestorIndex = false; 903 } 904 905 void CyclicModuleFields::setPendingAsyncDependencies(uint32_t newValue) { 906 pendingAsyncDependencies = newValue; 907 hasPendingAsyncDependencies = true; 908 } 909 910 Maybe<uint32_t> CyclicModuleFields::maybePendingAsyncDependencies() const { 911 return hasPendingAsyncDependencies ? Some(pendingAsyncDependencies) 912 : Nothing(); 913 } 914 915 /////////////////////////////////////////////////////////////////////////// 916 // ModuleObject 917 918 /* static */ const JSClassOps ModuleObject::classOps_ = { 919 nullptr, // addProperty 920 nullptr, // delProperty 921 nullptr, // enumerate 922 nullptr, // newEnumerate 923 nullptr, // resolve 924 nullptr, // mayResolve 925 ModuleObject::finalize, // finalize 926 nullptr, // call 927 nullptr, // construct 928 ModuleObject::trace, // trace 929 }; 930 931 /* static */ const JSClass ModuleObject::class_ = { 932 "Module", 933 JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) | 934 JSCLASS_BACKGROUND_FINALIZE, 935 &ModuleObject::classOps_, 936 }; 937 938 /* static */ 939 bool ModuleObject::isInstance(HandleValue value) { 940 return value.isObject() && value.toObject().is<ModuleObject>(); 941 } 942 943 bool ModuleObject::hasCyclicModuleFields() const { 944 // This currently only returns false if we GC during initialization. 945 return !getReservedSlot(CyclicModuleFieldsSlot).isUndefined(); 946 } 947 948 CyclicModuleFields* ModuleObject::cyclicModuleFields() { 949 MOZ_ASSERT(hasCyclicModuleFields()); 950 void* ptr = getReservedSlot(CyclicModuleFieldsSlot).toPrivate(); 951 MOZ_ASSERT(ptr); 952 return static_cast<CyclicModuleFields*>(ptr); 953 } 954 const CyclicModuleFields* ModuleObject::cyclicModuleFields() const { 955 return const_cast<ModuleObject*>(this)->cyclicModuleFields(); 956 } 957 958 Span<const RequestedModule> ModuleObject::requestedModules() const { 959 return cyclicModuleFields()->requestedModules; 960 } 961 962 Span<const ImportEntry> ModuleObject::importEntries() const { 963 return cyclicModuleFields()->importEntries; 964 } 965 966 Span<const ExportEntry> ModuleObject::localExportEntries() const { 967 return cyclicModuleFields()->localExportEntries(); 968 } 969 970 Span<const ExportEntry> ModuleObject::indirectExportEntries() const { 971 return cyclicModuleFields()->indirectExportEntries(); 972 } 973 974 Span<const ExportEntry> ModuleObject::starExportEntries() const { 975 return cyclicModuleFields()->starExportEntries(); 976 } 977 978 const ExportNameVector& ModuleObject::syntheticExportNames() const { 979 return syntheticModuleFields()->exportNames; 980 } 981 982 void ModuleObject::initFunctionDeclarations( 983 UniquePtr<FunctionDeclarationVector> decls) { 984 cyclicModuleFields()->functionDeclarations = std::move(decls); 985 } 986 987 /* static */ 988 ModuleObject* ModuleObject::create(JSContext* cx) { 989 Rooted<UniquePtr<CyclicModuleFields>> fields(cx); 990 fields = cx->make_unique<CyclicModuleFields>(); 991 if (!fields) { 992 return nullptr; 993 } 994 995 ModuleObject* self = NewObjectWithGivenProto<ModuleObject>(cx, nullptr); 996 if (!self) { 997 return nullptr; 998 } 999 1000 InitReservedSlot(self, CyclicModuleFieldsSlot, fields.release(), 1001 MemoryUse::ModuleCyclicFields); 1002 1003 return self; 1004 } 1005 1006 /* static */ 1007 ModuleObject* ModuleObject::createSynthetic( 1008 JSContext* cx, MutableHandle<ExportNameVector> exportNames) { 1009 Rooted<UniquePtr<SyntheticModuleFields>> syntheticFields(cx); 1010 syntheticFields = cx->make_unique<SyntheticModuleFields>(); 1011 if (!syntheticFields) { 1012 return nullptr; 1013 } 1014 1015 ModuleObject* self = NewObjectWithGivenProto<ModuleObject>(cx, nullptr); 1016 if (!self) { 1017 return nullptr; 1018 } 1019 1020 InitReservedSlot(self, SyntheticModuleFieldsSlot, syntheticFields.release(), 1021 MemoryUse::ModuleSyntheticFields); 1022 1023 self->syntheticModuleFields()->exportNames = std::move(exportNames.get()); 1024 1025 return self; 1026 } 1027 1028 /* static */ 1029 void ModuleObject::finalize(JS::GCContext* gcx, JSObject* obj) { 1030 ModuleObject* self = &obj->as<ModuleObject>(); 1031 if (self->hasCyclicModuleFields()) { 1032 gcx->delete_(obj, self->cyclicModuleFields(), 1033 MemoryUse::ModuleCyclicFields); 1034 } 1035 if (self->hasSyntheticModuleFields()) { 1036 gcx->delete_(obj, self->syntheticModuleFields(), 1037 MemoryUse::ModuleSyntheticFields); 1038 } 1039 } 1040 1041 ModuleEnvironmentObject& ModuleObject::initialEnvironment() const { 1042 Value value = getReservedSlot(EnvironmentSlot); 1043 return value.toObject().as<ModuleEnvironmentObject>(); 1044 } 1045 1046 ModuleEnvironmentObject* ModuleObject::environment() const { 1047 // Note that this it's valid to call this even if there was an error 1048 // evaluating the module. 1049 1050 // According to the spec the environment record is created during linking, but 1051 // we create it earlier than that. 1052 if (status() < ModuleStatus::Linked) { 1053 return nullptr; 1054 } 1055 1056 return &initialEnvironment(); 1057 } 1058 1059 IndirectBindingMap& ModuleObject::importBindings() { 1060 return cyclicModuleFields()->importBindings; 1061 } 1062 1063 ModuleNamespaceObject* ModuleObject::namespace_() { 1064 Value value = getReservedSlot(NamespaceSlot); 1065 if (value.isUndefined()) { 1066 return nullptr; 1067 } 1068 return &value.toObject().as<ModuleNamespaceObject>(); 1069 } 1070 1071 ScriptSourceObject* ModuleObject::scriptSourceObject() const { 1072 return cyclicModuleFields()->scriptSourceObject; 1073 } 1074 1075 void ModuleObject::initAsyncSlots(JSContext* cx, bool hasTopLevelAwait, 1076 Handle<ListObject*> asyncParentModules) { 1077 cyclicModuleFields()->hasTopLevelAwait = hasTopLevelAwait; 1078 cyclicModuleFields()->asyncParentModules = asyncParentModules; 1079 } 1080 1081 void ModuleObject::initScriptSlots(HandleScript script) { 1082 MOZ_ASSERT(script); 1083 MOZ_ASSERT(script->sourceObject()); 1084 MOZ_ASSERT(script->filename()); 1085 initReservedSlot(ScriptSlot, PrivateGCThingValue(script)); 1086 cyclicModuleFields()->scriptSourceObject = script->sourceObject(); 1087 } 1088 1089 void ModuleObject::setInitialEnvironment( 1090 Handle<ModuleEnvironmentObject*> initialEnvironment) { 1091 initReservedSlot(EnvironmentSlot, ObjectValue(*initialEnvironment)); 1092 } 1093 1094 void ModuleObject::initImportExportData( 1095 MutableHandle<RequestedModuleVector> requestedModules, 1096 MutableHandle<ImportEntryVector> importEntries, 1097 MutableHandle<ExportEntryVector> exportEntries, uint32_t localExportCount, 1098 uint32_t indirectExportCount, uint32_t starExportCount) { 1099 cyclicModuleFields()->requestedModules = std::move(requestedModules.get()); 1100 cyclicModuleFields()->importEntries = std::move(importEntries.get()); 1101 cyclicModuleFields()->initExportEntries(exportEntries, localExportCount, 1102 indirectExportCount, starExportCount); 1103 } 1104 1105 /* static */ 1106 bool ModuleObject::Freeze(JSContext* cx, Handle<ModuleObject*> self) { 1107 return FreezeObject(cx, self); 1108 } 1109 1110 #ifdef DEBUG 1111 /* static */ inline bool ModuleObject::AssertFrozen( 1112 JSContext* cx, Handle<ModuleObject*> self) { 1113 bool frozen = false; 1114 if (!TestIntegrityLevel(cx, self, IntegrityLevel::Frozen, &frozen)) { 1115 return false; 1116 } 1117 MOZ_ASSERT(frozen); 1118 1119 return true; 1120 } 1121 #endif 1122 1123 JSScript* ModuleObject::maybeScript() const { 1124 Value value = getReservedSlot(ScriptSlot); 1125 if (value.isUndefined()) { 1126 return nullptr; 1127 } 1128 BaseScript* script = value.toGCThing()->as<BaseScript>(); 1129 MOZ_ASSERT(script->hasBytecode(), 1130 "Module scripts should always have bytecode"); 1131 return script->asJSScript(); 1132 } 1133 1134 JSScript* ModuleObject::script() const { 1135 JSScript* ptr = maybeScript(); 1136 MOZ_RELEASE_ASSERT(ptr); 1137 return ptr; 1138 } 1139 1140 const char* ModuleObject::filename() const { 1141 // The ScriptSlot will be cleared once the module is evaluated, so we try to 1142 // get the filename from cyclicModuleFields(). 1143 1144 // TODO: Bug 1885483: Provide filename for JSON modules 1145 if (!hasCyclicModuleFields()) { 1146 return "(JSON module)"; 1147 } 1148 return cyclicModuleFields()->scriptSourceObject->source()->filename(); 1149 } 1150 1151 static inline void AssertValidModuleStatus(ModuleStatus status) { 1152 MOZ_ASSERT(status >= ModuleStatus::New && 1153 status <= ModuleStatus::Evaluated_Error); 1154 } 1155 1156 ModuleStatus ModuleObject::status() const { 1157 // Always return `ModuleStatus::Evaluated` so we can assert a module's status 1158 // without checking which kind it is, even though synthetic modules don't have 1159 // this field according to the spec. 1160 if (hasSyntheticModuleFields()) { 1161 return ModuleStatus::Evaluated; 1162 } 1163 1164 ModuleStatus status = cyclicModuleFields()->status; 1165 AssertValidModuleStatus(status); 1166 1167 if (status == ModuleStatus::Evaluated_Error) { 1168 return ModuleStatus::Evaluated; 1169 } 1170 1171 return status; 1172 } 1173 1174 void ModuleObject::setStatus(ModuleStatus newStatus) { 1175 AssertValidModuleStatus(newStatus); 1176 1177 // Note that under OOM conditions we can fail the module linking process even 1178 // after modules have been marked as linked. 1179 MOZ_ASSERT((status() <= ModuleStatus::Linked && 1180 newStatus == ModuleStatus::Unlinked) || 1181 newStatus > status(), 1182 "New module status inconsistent with current status"); 1183 1184 cyclicModuleFields()->status = newStatus; 1185 } 1186 1187 bool ModuleObject::hasTopLevelAwait() const { 1188 return cyclicModuleFields()->hasTopLevelAwait; 1189 } 1190 1191 AsyncEvaluationOrder& ModuleObject::asyncEvaluationOrder() { 1192 return cyclicModuleFields()->asyncEvaluationOrder; 1193 } 1194 1195 AsyncEvaluationOrder const& ModuleObject::asyncEvaluationOrder() const { 1196 return cyclicModuleFields()->asyncEvaluationOrder; 1197 } 1198 1199 Maybe<uint32_t> ModuleObject::maybeDfsAncestorIndex() const { 1200 return cyclicModuleFields()->maybeDfsAncestorIndex(); 1201 } 1202 1203 uint32_t ModuleObject::dfsAncestorIndex() const { 1204 return maybeDfsAncestorIndex().value(); 1205 } 1206 1207 void ModuleObject::setDfsAncestorIndex(uint32_t index) { 1208 cyclicModuleFields()->setDfsAncestorIndex(index); 1209 } 1210 1211 void ModuleObject::clearDfsAncestorIndex() { 1212 cyclicModuleFields()->clearDfsAncestorIndex(); 1213 } 1214 1215 PromiseObject* ModuleObject::maybeTopLevelCapability() const { 1216 return cyclicModuleFields()->topLevelCapability; 1217 } 1218 1219 PromiseObject* ModuleObject::topLevelCapability() const { 1220 PromiseObject* capability = maybeTopLevelCapability(); 1221 MOZ_RELEASE_ASSERT(capability); 1222 return capability; 1223 } 1224 1225 // static 1226 PromiseObject* ModuleObject::createTopLevelCapability( 1227 JSContext* cx, Handle<ModuleObject*> module) { 1228 MOZ_ASSERT(!module->maybeTopLevelCapability()); 1229 1230 Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectForAsync(cx)); 1231 if (!resultPromise) { 1232 return nullptr; 1233 } 1234 1235 module->setInitialTopLevelCapability(resultPromise); 1236 return resultPromise; 1237 } 1238 1239 void ModuleObject::setInitialTopLevelCapability( 1240 Handle<PromiseObject*> capability) { 1241 cyclicModuleFields()->topLevelCapability = capability; 1242 } 1243 1244 ListObject* ModuleObject::asyncParentModules() const { 1245 return cyclicModuleFields()->asyncParentModules; 1246 } 1247 1248 bool ModuleObject::appendAsyncParentModule(JSContext* cx, 1249 Handle<ModuleObject*> self, 1250 Handle<ModuleObject*> parent) { 1251 Rooted<Value> parentValue(cx, ObjectValue(*parent)); 1252 return self->asyncParentModules()->append(cx, parentValue); 1253 } 1254 1255 Maybe<uint32_t> ModuleObject::maybePendingAsyncDependencies() const { 1256 return cyclicModuleFields()->maybePendingAsyncDependencies(); 1257 } 1258 1259 uint32_t ModuleObject::pendingAsyncDependencies() const { 1260 return maybePendingAsyncDependencies().value(); 1261 } 1262 1263 void ModuleObject::setPendingAsyncDependencies(uint32_t newValue) { 1264 cyclicModuleFields()->setPendingAsyncDependencies(newValue); 1265 } 1266 1267 void ModuleObject::setCycleRoot(ModuleObject* cycleRoot) { 1268 cyclicModuleFields()->cycleRoot = cycleRoot; 1269 } 1270 1271 ModuleObject* ModuleObject::getCycleRoot() const { 1272 MOZ_RELEASE_ASSERT(cyclicModuleFields()->cycleRoot); 1273 return cyclicModuleFields()->cycleRoot; 1274 } 1275 1276 LoadedModuleMap& ModuleObject::loadedModules() { 1277 return cyclicModuleFields()->loadedModules; 1278 } 1279 1280 const LoadedModuleMap& ModuleObject::loadedModules() const { 1281 return cyclicModuleFields()->loadedModules; 1282 } 1283 1284 bool ModuleObject::hasSyntheticModuleFields() const { 1285 bool result = !getReservedSlot(SyntheticModuleFieldsSlot).isUndefined(); 1286 MOZ_ASSERT_IF(result, !hasCyclicModuleFields()); 1287 return result; 1288 } 1289 1290 SyntheticModuleFields* ModuleObject::syntheticModuleFields() { 1291 MOZ_ASSERT(!hasCyclicModuleFields()); 1292 void* ptr = getReservedSlot(SyntheticModuleFieldsSlot).toPrivate(); 1293 MOZ_ASSERT(ptr); 1294 return static_cast<SyntheticModuleFields*>(ptr); 1295 } 1296 const SyntheticModuleFields* ModuleObject::syntheticModuleFields() const { 1297 return const_cast<ModuleObject*>(this)->syntheticModuleFields(); 1298 } 1299 1300 bool ModuleObject::hasTopLevelCapability() const { 1301 return cyclicModuleFields()->topLevelCapability; 1302 } 1303 1304 bool ModuleObject::hadEvaluationError() const { 1305 if (hasSyntheticModuleFields()) { 1306 return false; 1307 } 1308 1309 ModuleStatus fullStatus = cyclicModuleFields()->status; 1310 return fullStatus == ModuleStatus::Evaluated_Error; 1311 } 1312 1313 void ModuleObject::setEvaluationError(HandleValue newValue) { 1314 MOZ_ASSERT(status() != ModuleStatus::Unlinked && 1315 status() != ModuleStatus::New); 1316 MOZ_ASSERT(!hadEvaluationError()); 1317 1318 cyclicModuleFields()->status = ModuleStatus::Evaluated_Error; 1319 cyclicModuleFields()->evaluationError = newValue; 1320 1321 MOZ_ASSERT(status() == ModuleStatus::Evaluated); 1322 MOZ_ASSERT(hadEvaluationError()); 1323 } 1324 1325 Value ModuleObject::maybeEvaluationError() const { 1326 return cyclicModuleFields()->evaluationError; 1327 } 1328 1329 Value ModuleObject::evaluationError() const { 1330 MOZ_ASSERT(hadEvaluationError()); 1331 return maybeEvaluationError(); 1332 } 1333 1334 JSObject* ModuleObject::metaObject() const { 1335 return cyclicModuleFields()->metaObject; 1336 } 1337 1338 void ModuleObject::setMetaObject(JSObject* obj) { 1339 MOZ_ASSERT(obj); 1340 MOZ_ASSERT(!metaObject()); 1341 cyclicModuleFields()->metaObject = obj; 1342 } 1343 1344 /* static */ 1345 void ModuleObject::trace(JSTracer* trc, JSObject* obj) { 1346 ModuleObject& module = obj->as<ModuleObject>(); 1347 if (module.hasCyclicModuleFields()) { 1348 module.cyclicModuleFields()->trace(trc); 1349 } 1350 if (module.hasSyntheticModuleFields()) { 1351 module.syntheticModuleFields()->trace(trc); 1352 } 1353 } 1354 1355 /* static */ 1356 bool ModuleObject::instantiateFunctionDeclarations(JSContext* cx, 1357 Handle<ModuleObject*> self) { 1358 #ifdef DEBUG 1359 MOZ_ASSERT(self->status() == ModuleStatus::Linking); 1360 if (!AssertFrozen(cx, self)) { 1361 return false; 1362 } 1363 #endif 1364 // |self| initially manages this vector. 1365 UniquePtr<FunctionDeclarationVector>& funDecls = 1366 self->cyclicModuleFields()->functionDeclarations; 1367 if (!funDecls) { 1368 JS_ReportErrorASCII( 1369 cx, "Module function declarations have already been instantiated"); 1370 return false; 1371 } 1372 1373 Rooted<ModuleEnvironmentObject*> env(cx, &self->initialEnvironment()); 1374 RootedObject obj(cx); 1375 RootedValue value(cx); 1376 RootedFunction fun(cx); 1377 Rooted<PropertyName*> name(cx); 1378 1379 for (GCThingIndex funIndex : *funDecls) { 1380 fun.set(self->script()->getFunction(funIndex)); 1381 obj = Lambda(cx, fun, env); 1382 if (!obj) { 1383 return false; 1384 } 1385 1386 name = fun->fullExplicitName()->asPropertyName(); 1387 value = ObjectValue(*obj); 1388 if (!SetProperty(cx, env, name, value)) { 1389 return false; 1390 } 1391 } 1392 1393 // Free the vector, now its contents are no longer needed. 1394 funDecls.reset(); 1395 1396 return true; 1397 } 1398 1399 /* static */ 1400 bool ModuleObject::execute(JSContext* cx, Handle<ModuleObject*> self) { 1401 #ifdef DEBUG 1402 MOZ_ASSERT(self->status() == ModuleStatus::Evaluating || 1403 self->status() == ModuleStatus::EvaluatingAsync || 1404 self->status() == ModuleStatus::Evaluated); 1405 MOZ_ASSERT(!self->hadEvaluationError()); 1406 if (!AssertFrozen(cx, self)) { 1407 return false; 1408 } 1409 #endif 1410 1411 RootedScript script(cx, self->script()); 1412 1413 auto guardA = mozilla::MakeScopeExit([&] { 1414 if (self->hasTopLevelAwait()) { 1415 // Handled in AsyncModuleExecutionFulfilled and 1416 // AsyncModuleExecutionRejected. 1417 return; 1418 } 1419 ModuleObject::onTopLevelEvaluationFinished(self); 1420 }); 1421 1422 Rooted<ModuleEnvironmentObject*> env(cx, self->environment()); 1423 if (!env) { 1424 JS_ReportErrorASCII(cx, 1425 "Module declarations have not yet been instantiated"); 1426 return false; 1427 } 1428 1429 Rooted<Value> ignored(cx); 1430 return Execute(cx, script, env, &ignored); 1431 } 1432 1433 /* static */ 1434 void ModuleObject::onTopLevelEvaluationFinished(ModuleObject* module) { 1435 // ScriptSlot is used by debugger to access environments during evaluating 1436 // the top-level script. 1437 // Clear the reference at exit to prevent us keeping this alive unnecessarily. 1438 module->setReservedSlot(ScriptSlot, UndefinedValue()); 1439 } 1440 1441 /* static */ 1442 ModuleNamespaceObject* ModuleObject::createNamespace( 1443 JSContext* cx, Handle<ModuleObject*> self, 1444 MutableHandle<UniquePtr<ExportNameVector>> exports) { 1445 MOZ_ASSERT(!self->namespace_()); 1446 1447 Rooted<UniquePtr<IndirectBindingMap>> bindings(cx); 1448 bindings = cx->make_unique<IndirectBindingMap>(); 1449 if (!bindings) { 1450 return nullptr; 1451 } 1452 1453 auto* ns = ModuleNamespaceObject::create(cx, self, exports, &bindings); 1454 if (!ns) { 1455 return nullptr; 1456 } 1457 1458 self->initReservedSlot(NamespaceSlot, ObjectValue(*ns)); 1459 return ns; 1460 } 1461 1462 /* static */ 1463 bool ModuleObject::createEnvironment(JSContext* cx, 1464 Handle<ModuleObject*> self) { 1465 Rooted<ModuleEnvironmentObject*> env( 1466 cx, ModuleEnvironmentObject::create(cx, self)); 1467 if (!env) { 1468 return false; 1469 } 1470 1471 self->setInitialEnvironment(env); 1472 return true; 1473 } 1474 1475 /*static*/ 1476 bool ModuleObject::createSyntheticEnvironment(JSContext* cx, 1477 Handle<ModuleObject*> self, 1478 JS::HandleVector<Value> values) { 1479 Rooted<ModuleEnvironmentObject*> env( 1480 cx, ModuleEnvironmentObject::createSynthetic(cx, self)); 1481 if (!env) { 1482 return false; 1483 } 1484 1485 MOZ_ASSERT(env->shape()->propMapLength() == values.length()); 1486 1487 for (uint32_t i = 0; i < values.length(); i++) { 1488 env->setAliasedBinding(env->firstSyntheticValueSlot() + i, values[i]); 1489 } 1490 1491 self->setInitialEnvironment(env); 1492 1493 return true; 1494 } 1495 1496 /////////////////////////////////////////////////////////////////////////// 1497 // GraphLoadingStateRecordObject 1498 1499 GraphLoadingStateRecord::GraphLoadingStateRecord( 1500 JS::LoadModuleResolvedCallback resolved, 1501 JS::LoadModuleRejectedCallback rejected) 1502 : resolved(resolved), rejected(rejected) {} 1503 1504 void GraphLoadingStateRecord::trace(JSTracer* trc) { visited.trace(trc); } 1505 1506 /* static */ 1507 const JSClass GraphLoadingStateRecordObject::class_ = { 1508 "GraphLoadingStateRecordObject", 1509 JSCLASS_HAS_RESERVED_SLOTS(GraphLoadingStateRecordObject::SlotCount) | 1510 JSCLASS_BACKGROUND_FINALIZE, 1511 &GraphLoadingStateRecordObject::classOps_, 1512 }; 1513 static_assert(GraphLoadingStateRecordObject::StateSlot == 0); 1514 1515 /* static */ 1516 const JSClassOps GraphLoadingStateRecordObject::classOps_ = { 1517 nullptr, // addProperty 1518 nullptr, // delProperty 1519 nullptr, // enumerate 1520 nullptr, // newEnumerate 1521 nullptr, // resolve 1522 nullptr, // mayResolve 1523 GraphLoadingStateRecordObject::finalize, // finalize 1524 nullptr, // call 1525 nullptr, // construct 1526 GraphLoadingStateRecordObject::trace, // trace 1527 }; 1528 1529 /* static */ 1530 GraphLoadingStateRecordObject* GraphLoadingStateRecordObject::create( 1531 JSContext* cx, bool isLoading, uint32_t pendingModulesCount, 1532 JS::LoadModuleResolvedCallback resolved, 1533 JS::LoadModuleRejectedCallback rejected, Handle<Value> hostDefined) { 1534 Rooted<GraphLoadingStateRecordObject*> self( 1535 cx, NewObjectWithGivenProto<GraphLoadingStateRecordObject>(cx, nullptr)); 1536 if (!self) { 1537 return nullptr; 1538 } 1539 1540 auto* state = cx->new_<GraphLoadingStateRecord>(resolved, rejected); 1541 if (!state) { 1542 ReportOutOfMemory(cx); 1543 return nullptr; 1544 } 1545 1546 InitReservedSlot(self, StateSlot, state, MemoryUse::GraphLoadingStateRecord); 1547 self->initReservedSlot(IsLoadingSlot, Int32Value(isLoading)); 1548 self->initReservedSlot(PendingModulesCountSlot, 1549 Int32Value(pendingModulesCount)); 1550 self->initReservedSlot(HostDefinedSlot, hostDefined); 1551 return self; 1552 } 1553 1554 /* static */ 1555 GraphLoadingStateRecordObject* GraphLoadingStateRecordObject::create( 1556 JSContext* cx, bool isLoading, uint32_t pendingModulesCount, 1557 Handle<PromiseObject*> promise, Handle<Value> hostDefined) { 1558 Rooted<GraphLoadingStateRecordObject*> self( 1559 cx, NewObjectWithGivenProto<GraphLoadingStateRecordObject>(cx, nullptr)); 1560 if (!self) { 1561 return nullptr; 1562 } 1563 1564 auto* state = cx->new_<GraphLoadingStateRecord>(); 1565 if (!state) { 1566 ReportOutOfMemory(cx); 1567 return nullptr; 1568 } 1569 1570 InitReservedSlot(self, StateSlot, state, MemoryUse::GraphLoadingStateRecord); 1571 self->initReservedSlot(PromiseSlot, ObjectValue(*promise)); 1572 self->initReservedSlot(IsLoadingSlot, Int32Value(isLoading)); 1573 self->initReservedSlot(PendingModulesCountSlot, 1574 Int32Value(pendingModulesCount)); 1575 self->initReservedSlot(HostDefinedSlot, hostDefined); 1576 return self; 1577 } 1578 1579 VisitedModuleSet& GraphLoadingStateRecordObject::visited() { 1580 GraphLoadingStateRecord* state = static_cast<GraphLoadingStateRecord*>( 1581 getReservedSlot(StateSlot).toPrivate()); 1582 MOZ_ASSERT(state); 1583 return state->visited; 1584 } 1585 1586 PromiseObject* GraphLoadingStateRecordObject::promise() { 1587 if (getReservedSlot(PromiseSlot).isUndefined()) { 1588 return nullptr; 1589 } 1590 return &getReservedSlot(PromiseSlot).toObject().as<PromiseObject>(); 1591 } 1592 1593 bool GraphLoadingStateRecordObject::isLoading() { 1594 return getReservedSlot(IsLoadingSlot).toInt32(); 1595 } 1596 1597 void GraphLoadingStateRecordObject::setIsLoading(bool isLoading) { 1598 setReservedSlot(IsLoadingSlot, Int32Value(isLoading)); 1599 } 1600 1601 uint32_t GraphLoadingStateRecordObject::pendingModulesCount() { 1602 return getReservedSlot(PendingModulesCountSlot).toInt32(); 1603 } 1604 1605 void GraphLoadingStateRecordObject::setPendingModulesCount(uint32_t count) { 1606 setReservedSlot(PendingModulesCountSlot, Int32Value(count)); 1607 } 1608 1609 Value GraphLoadingStateRecordObject::hostDefined() { 1610 return getReservedSlot(HostDefinedSlot); 1611 } 1612 1613 bool GraphLoadingStateRecordObject::resolved( 1614 JSContext* cx, JS::Handle<JS::Value> hostDefined) { 1615 if (promise()) { 1616 Rooted<PromiseObject*> promiseObj(cx, promise()); 1617 return AsyncFunctionReturned(cx, promiseObj, UndefinedHandleValue); 1618 } 1619 1620 GraphLoadingStateRecord* state = static_cast<GraphLoadingStateRecord*>( 1621 getReservedSlot(StateSlot).toPrivate()); 1622 MOZ_ASSERT(state); 1623 MOZ_ASSERT(state->resolved); 1624 return state->resolved(cx, hostDefined); 1625 } 1626 1627 bool GraphLoadingStateRecordObject::rejected(JSContext* cx, 1628 JS::Handle<JS::Value> hostDefined, 1629 Handle<JS::Value> error) { 1630 if (promise()) { 1631 Rooted<PromiseObject*> promiseObj(cx, promise()); 1632 return AsyncFunctionThrown(cx, promiseObj, error); 1633 } 1634 1635 GraphLoadingStateRecord* state = static_cast<GraphLoadingStateRecord*>( 1636 getReservedSlot(StateSlot).toPrivate()); 1637 MOZ_ASSERT(state); 1638 MOZ_ASSERT(state->rejected); 1639 return state->rejected(cx, hostDefined, error); 1640 } 1641 1642 /* static */ 1643 void GraphLoadingStateRecordObject::finalize(JS::GCContext* gcx, 1644 JSObject* obj) { 1645 auto* self = &obj->as<GraphLoadingStateRecordObject>(); 1646 Value stateValue = self->getReservedSlot(StateSlot); 1647 if (!stateValue.isUndefined()) { 1648 auto* state = static_cast<GraphLoadingStateRecord*>(stateValue.toPrivate()); 1649 gcx->delete_(obj, state, MemoryUse::GraphLoadingStateRecord); 1650 } 1651 } 1652 1653 /* static */ 1654 void GraphLoadingStateRecordObject::trace(JSTracer* trc, JSObject* obj) { 1655 GraphLoadingStateRecordObject* self = 1656 &obj->as<GraphLoadingStateRecordObject>(); 1657 Value stateValue = self->getReservedSlot(StateSlot); 1658 if (!stateValue.isUndefined()) { 1659 GraphLoadingStateRecord* state = 1660 static_cast<GraphLoadingStateRecord*>(stateValue.toPrivate()); 1661 state->trace(trc); 1662 } 1663 } 1664 1665 /////////////////////////////////////////////////////////////////////////// 1666 // ModuleBuilder 1667 1668 ModuleBuilder::ModuleBuilder(FrontendContext* fc, 1669 const frontend::EitherParser& eitherParser) 1670 : fc_(fc), 1671 eitherParser_(eitherParser), 1672 requestedModuleIndexes_(fc), 1673 importEntries_(fc), 1674 exportEntries_(fc), 1675 exportNames_(fc) {} 1676 1677 bool ModuleBuilder::noteFunctionDeclaration(FrontendContext* fc, 1678 uint32_t funIndex) { 1679 if (!functionDecls_.emplaceBack(funIndex)) { 1680 js::ReportOutOfMemory(fc); 1681 return false; 1682 } 1683 return true; 1684 } 1685 1686 void ModuleBuilder::noteAsync(frontend::StencilModuleMetadata& metadata) { 1687 metadata.isAsync = true; 1688 } 1689 1690 bool ModuleBuilder::buildTables(frontend::StencilModuleMetadata& metadata) { 1691 // https://tc39.es/ecma262/#sec-parsemodule 1692 // 15.2.1.17.1 ParseModule, Steps 4-11. 1693 1694 // Step 4. 1695 metadata.moduleRequests = std::move(moduleRequests_); 1696 metadata.requestedModules = std::move(requestedModules_); 1697 1698 // Step 5. 1699 if (!metadata.importEntries.reserve(importEntries_.count())) { 1700 js::ReportOutOfMemory(fc_); 1701 return false; 1702 } 1703 for (auto r = importEntries_.all(); !r.empty(); r.popFront()) { 1704 frontend::StencilModuleEntry& entry = r.front().value(); 1705 metadata.importEntries.infallibleAppend(entry); 1706 } 1707 1708 // Steps 6-11. 1709 for (const frontend::StencilModuleEntry& exp : exportEntries_) { 1710 if (!exp.moduleRequest) { 1711 frontend::StencilModuleEntry* importEntry = importEntryFor(exp.localName); 1712 if (!importEntry) { 1713 if (!metadata.localExportEntries.append(exp)) { 1714 js::ReportOutOfMemory(fc_); 1715 return false; 1716 } 1717 } else { 1718 // All names should have already been marked as used-by-stencil. 1719 if (!importEntry->importName) { 1720 // This is a re-export of an imported module namespace object. 1721 auto entry = frontend::StencilModuleEntry::exportNamespaceFromEntry( 1722 importEntry->moduleRequest, exp.exportName, exp.lineno, 1723 exp.column); 1724 if (!metadata.indirectExportEntries.append(entry)) { 1725 js::ReportOutOfMemory(fc_); 1726 return false; 1727 } 1728 } else { 1729 auto entry = frontend::StencilModuleEntry::exportFromEntry( 1730 importEntry->moduleRequest, importEntry->importName, 1731 exp.exportName, exp.lineno, exp.column); 1732 if (!metadata.indirectExportEntries.append(entry)) { 1733 js::ReportOutOfMemory(fc_); 1734 return false; 1735 } 1736 } 1737 } 1738 } else if (!exp.importName && !exp.exportName) { 1739 if (!metadata.starExportEntries.append(exp)) { 1740 js::ReportOutOfMemory(fc_); 1741 return false; 1742 } 1743 } else { 1744 if (!metadata.indirectExportEntries.append(exp)) { 1745 js::ReportOutOfMemory(fc_); 1746 return false; 1747 } 1748 } 1749 } 1750 1751 return true; 1752 } 1753 1754 void ModuleBuilder::finishFunctionDecls( 1755 frontend::StencilModuleMetadata& metadata) { 1756 metadata.functionDecls = std::move(functionDecls_); 1757 } 1758 1759 bool frontend::StencilModuleMetadata::createModuleRequestObjects( 1760 JSContext* cx, CompilationAtomCache& atomCache, 1761 MutableHandle<ModuleRequestVector> output) const { 1762 if (!output.reserve(moduleRequests.length())) { 1763 ReportOutOfMemory(cx); 1764 return false; 1765 } 1766 1767 Rooted<ModuleRequestObject*> object(cx); 1768 for (const StencilModuleRequest& request : moduleRequests) { 1769 object = createModuleRequestObject(cx, atomCache, request); 1770 if (!object) { 1771 return false; 1772 } 1773 1774 output.infallibleEmplaceBack(object); 1775 } 1776 1777 return true; 1778 } 1779 1780 ModuleRequestObject* frontend::StencilModuleMetadata::createModuleRequestObject( 1781 JSContext* cx, CompilationAtomCache& atomCache, 1782 const StencilModuleRequest& request) const { 1783 uint32_t numberOfAttributes = request.attributes.length(); 1784 1785 Rooted<ImportAttributeVector> attributes(cx); 1786 if (numberOfAttributes > 0) { 1787 if (!attributes.reserve(numberOfAttributes)) { 1788 ReportOutOfMemory(cx); 1789 return nullptr; 1790 } 1791 1792 Rooted<JSAtom*> attributeKey(cx); 1793 Rooted<JSAtom*> attributeValue(cx); 1794 for (uint32_t j = 0; j < numberOfAttributes; ++j) { 1795 attributeKey = atomCache.getExistingAtomAt(cx, request.attributes[j].key); 1796 attributeValue = 1797 atomCache.getExistingAtomAt(cx, request.attributes[j].value); 1798 1799 attributes.infallibleEmplaceBack(attributeKey, attributeValue); 1800 } 1801 } 1802 1803 Rooted<JSAtom*> specifier(cx, 1804 atomCache.getExistingAtomAt(cx, request.specifier)); 1805 MOZ_ASSERT(specifier); 1806 1807 Rooted<ModuleRequestObject*> moduleRequestObject( 1808 cx, ModuleRequestObject::create(cx, specifier, attributes)); 1809 if (!moduleRequestObject) { 1810 return nullptr; 1811 } 1812 1813 if (request.firstUnsupportedAttributeKey) { 1814 Rooted<JSAtom*> unsupportedAttributeKey( 1815 cx, 1816 atomCache.getExistingAtomAt(cx, request.firstUnsupportedAttributeKey)); 1817 moduleRequestObject->setFirstUnsupportedAttributeKey( 1818 unsupportedAttributeKey); 1819 } 1820 1821 return moduleRequestObject; 1822 } 1823 1824 bool frontend::StencilModuleMetadata::createImportEntries( 1825 JSContext* cx, CompilationAtomCache& atomCache, 1826 Handle<ModuleRequestVector> moduleRequests, 1827 MutableHandle<ImportEntryVector> output) const { 1828 if (!output.reserve(importEntries.length())) { 1829 ReportOutOfMemory(cx); 1830 return false; 1831 } 1832 1833 for (const StencilModuleEntry& entry : importEntries) { 1834 Rooted<ModuleRequestObject*> moduleRequest(cx); 1835 moduleRequest = moduleRequests[entry.moduleRequest.value()].get(); 1836 MOZ_ASSERT(moduleRequest); 1837 1838 Rooted<JSAtom*> localName(cx); 1839 if (entry.localName) { 1840 localName = atomCache.getExistingAtomAt(cx, entry.localName); 1841 MOZ_ASSERT(localName); 1842 } 1843 1844 Rooted<JSAtom*> importName(cx); 1845 if (entry.importName) { 1846 importName = atomCache.getExistingAtomAt(cx, entry.importName); 1847 MOZ_ASSERT(importName); 1848 } 1849 1850 MOZ_ASSERT(!entry.exportName); 1851 1852 output.infallibleEmplaceBack(moduleRequest, importName, localName, 1853 entry.lineno, entry.column); 1854 } 1855 1856 return true; 1857 } 1858 1859 bool frontend::StencilModuleMetadata::createExportEntries( 1860 JSContext* cx, frontend::CompilationAtomCache& atomCache, 1861 Handle<ModuleRequestVector> moduleRequests, 1862 const frontend::StencilModuleMetadata::EntryVector& input, 1863 MutableHandle<ExportEntryVector> output) const { 1864 if (!output.reserve(output.length() + input.length())) { 1865 ReportOutOfMemory(cx); 1866 return false; 1867 } 1868 1869 for (const frontend::StencilModuleEntry& entry : input) { 1870 Rooted<JSAtom*> exportName(cx); 1871 if (entry.exportName) { 1872 exportName = atomCache.getExistingAtomAt(cx, entry.exportName); 1873 MOZ_ASSERT(exportName); 1874 } 1875 1876 Rooted<ModuleRequestObject*> moduleRequestObject(cx); 1877 if (entry.moduleRequest) { 1878 moduleRequestObject = moduleRequests[entry.moduleRequest.value()].get(); 1879 MOZ_ASSERT(moduleRequestObject); 1880 } 1881 1882 Rooted<JSAtom*> localName(cx); 1883 if (entry.localName) { 1884 localName = atomCache.getExistingAtomAt(cx, entry.localName); 1885 MOZ_ASSERT(localName); 1886 } 1887 1888 Rooted<JSAtom*> importName(cx); 1889 if (entry.importName) { 1890 importName = atomCache.getExistingAtomAt(cx, entry.importName); 1891 MOZ_ASSERT(importName); 1892 } 1893 1894 output.infallibleEmplaceBack(exportName, moduleRequestObject, importName, 1895 localName, entry.lineno, entry.column); 1896 } 1897 1898 return true; 1899 } 1900 1901 bool frontend::StencilModuleMetadata::createRequestedModules( 1902 JSContext* cx, CompilationAtomCache& atomCache, 1903 Handle<ModuleRequestVector> moduleRequests, 1904 MutableHandle<RequestedModuleVector> output) const { 1905 if (!output.reserve(requestedModules.length())) { 1906 ReportOutOfMemory(cx); 1907 return false; 1908 } 1909 1910 for (const frontend::StencilModuleEntry& entry : requestedModules) { 1911 Rooted<ModuleRequestObject*> moduleRequest(cx); 1912 moduleRequest = moduleRequests[entry.moduleRequest.value()].get(); 1913 MOZ_ASSERT(moduleRequest); 1914 1915 MOZ_ASSERT(!entry.localName); 1916 MOZ_ASSERT(!entry.importName); 1917 MOZ_ASSERT(!entry.exportName); 1918 1919 output.infallibleEmplaceBack(moduleRequest, entry.lineno, entry.column); 1920 } 1921 1922 return true; 1923 } 1924 1925 // Use StencilModuleMetadata data to fill in ModuleObject 1926 bool frontend::StencilModuleMetadata::initModule( 1927 JSContext* cx, FrontendContext* fc, 1928 frontend::CompilationAtomCache& atomCache, 1929 JS::Handle<ModuleObject*> module) const { 1930 Rooted<ModuleRequestVector> moduleRequestsVector(cx); 1931 if (!createModuleRequestObjects(cx, atomCache, &moduleRequestsVector)) { 1932 return false; 1933 } 1934 1935 Rooted<RequestedModuleVector> requestedModulesVector(cx); 1936 if (!createRequestedModules(cx, atomCache, moduleRequestsVector, 1937 &requestedModulesVector)) { 1938 return false; 1939 } 1940 1941 Rooted<ImportEntryVector> importEntriesVector(cx); 1942 if (!createImportEntries(cx, atomCache, moduleRequestsVector, 1943 &importEntriesVector)) { 1944 return false; 1945 } 1946 1947 Rooted<ExportEntryVector> exportEntriesVector(cx); 1948 if (!createExportEntries(cx, atomCache, moduleRequestsVector, 1949 localExportEntries, &exportEntriesVector)) { 1950 return false; 1951 } 1952 1953 Rooted<ExportEntryVector> indirectExportEntriesVector(cx); 1954 if (!createExportEntries(cx, atomCache, moduleRequestsVector, 1955 indirectExportEntries, &exportEntriesVector)) { 1956 return false; 1957 } 1958 1959 Rooted<ExportEntryVector> starExportEntriesVector(cx); 1960 if (!createExportEntries(cx, atomCache, moduleRequestsVector, 1961 starExportEntries, &exportEntriesVector)) { 1962 return false; 1963 } 1964 1965 // Copy the vector of declarations to the ModuleObject. 1966 auto functionDeclsCopy = MakeUnique<FunctionDeclarationVector>(); 1967 if (!functionDeclsCopy || !functionDeclsCopy->appendAll(functionDecls)) { 1968 js::ReportOutOfMemory(fc); 1969 return false; 1970 } 1971 module->initFunctionDeclarations(std::move(functionDeclsCopy)); 1972 1973 Rooted<ListObject*> asyncParentModulesList(cx, ListObject::create(cx)); 1974 if (!asyncParentModulesList) { 1975 return false; 1976 } 1977 1978 module->initAsyncSlots(cx, isAsync, asyncParentModulesList); 1979 1980 module->initImportExportData( 1981 &requestedModulesVector, &importEntriesVector, &exportEntriesVector, 1982 localExportEntries.length(), indirectExportEntries.length(), 1983 starExportEntries.length()); 1984 1985 return true; 1986 } 1987 1988 bool ModuleBuilder::processAttributes(frontend::StencilModuleRequest& request, 1989 frontend::ListNode* attributeList) { 1990 using namespace js::frontend; 1991 1992 for (ParseNode* attributeItem : attributeList->contents()) { 1993 BinaryNode* attribute = &attributeItem->as<BinaryNode>(); 1994 MOZ_ASSERT(attribute->isKind(ParseNodeKind::ImportAttribute)); 1995 1996 auto key = attribute->left()->as<NameNode>().atom(); 1997 markUsedByStencil(key); 1998 1999 // Note: This should be driven by a host hook 2000 // (HostGetSupportedImportAttributes), however the infrastructure of said 2001 // host hook is deeply unclear, and so right now embedders will not have 2002 // the ability to alter or extend the set of supported attributes. 2003 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1840723. 2004 if (key == TaggedParserAtomIndex::WellKnown::type()) { 2005 auto value = attribute->right()->as<NameNode>().atom(); 2006 markUsedByStencil(value); 2007 2008 StencilModuleImportAttribute attributeStencil(key, value); 2009 if (!request.attributes.append(attributeStencil)) { 2010 js::ReportOutOfMemory(fc_); 2011 return false; 2012 } 2013 } else { 2014 if (!request.firstUnsupportedAttributeKey) { 2015 request.firstUnsupportedAttributeKey = key; 2016 } 2017 } 2018 } 2019 2020 return true; 2021 } 2022 2023 bool ModuleBuilder::processImport(frontend::BinaryNode* importNode) { 2024 using namespace js::frontend; 2025 2026 MOZ_ASSERT(importNode->isKind(ParseNodeKind::ImportDecl)); 2027 2028 auto* specList = &importNode->left()->as<ListNode>(); 2029 MOZ_ASSERT(specList->isKind(ParseNodeKind::ImportSpecList)); 2030 2031 auto* moduleRequest = &importNode->right()->as<BinaryNode>(); 2032 MOZ_ASSERT(moduleRequest->isKind(ParseNodeKind::ImportModuleRequest)); 2033 2034 auto* moduleSpec = &moduleRequest->left()->as<NameNode>(); 2035 MOZ_ASSERT(moduleSpec->isKind(ParseNodeKind::StringExpr)); 2036 2037 auto* attributeList = &moduleRequest->right()->as<ListNode>(); 2038 MOZ_ASSERT(attributeList->isKind(ParseNodeKind::ImportAttributeList)); 2039 2040 auto specifier = moduleSpec->atom(); 2041 MaybeModuleRequestIndex moduleRequestIndex = 2042 appendModuleRequest(specifier, attributeList); 2043 if (!moduleRequestIndex.isSome()) { 2044 return false; 2045 } 2046 2047 if (!maybeAppendRequestedModule(moduleRequestIndex, moduleSpec)) { 2048 return false; 2049 } 2050 2051 for (ParseNode* item : specList->contents()) { 2052 uint32_t line; 2053 JS::LimitedColumnNumberOneOrigin column; 2054 eitherParser_.computeLineAndColumn(item->pn_pos.begin, &line, &column); 2055 2056 StencilModuleEntry entry; 2057 TaggedParserAtomIndex localName; 2058 if (item->isKind(ParseNodeKind::ImportSpec)) { 2059 auto* spec = &item->as<BinaryNode>(); 2060 2061 auto* importNameNode = &spec->left()->as<NameNode>(); 2062 auto* localNameNode = &spec->right()->as<NameNode>(); 2063 2064 auto importName = importNameNode->atom(); 2065 localName = localNameNode->atom(); 2066 2067 markUsedByStencil(localName); 2068 markUsedByStencil(importName); 2069 entry = StencilModuleEntry::importEntry( 2070 moduleRequestIndex, localName, importName, line, 2071 JS::ColumnNumberOneOrigin(column)); 2072 } else { 2073 MOZ_ASSERT(item->isKind(ParseNodeKind::ImportNamespaceSpec)); 2074 auto* spec = &item->as<UnaryNode>(); 2075 2076 auto* localNameNode = &spec->kid()->as<NameNode>(); 2077 2078 localName = localNameNode->atom(); 2079 2080 markUsedByStencil(localName); 2081 entry = StencilModuleEntry::importNamespaceEntry( 2082 moduleRequestIndex, localName, line, 2083 JS::ColumnNumberOneOrigin(column)); 2084 } 2085 2086 if (!importEntries_.put(localName, entry)) { 2087 return false; 2088 } 2089 } 2090 2091 return true; 2092 } 2093 2094 bool ModuleBuilder::processExport(frontend::ParseNode* exportNode) { 2095 using namespace js::frontend; 2096 2097 MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportStmt) || 2098 exportNode->isKind(ParseNodeKind::ExportDefaultStmt)); 2099 2100 bool isDefault = exportNode->isKind(ParseNodeKind::ExportDefaultStmt); 2101 ParseNode* kid = isDefault ? exportNode->as<BinaryNode>().left() 2102 : exportNode->as<UnaryNode>().kid(); 2103 2104 if (isDefault && exportNode->as<BinaryNode>().right()) { 2105 // This is an export default containing an expression. 2106 auto localName = TaggedParserAtomIndex::WellKnown::default_(); 2107 auto exportName = TaggedParserAtomIndex::WellKnown::default_(); 2108 return appendExportEntry(exportName, localName); 2109 } 2110 2111 switch (kid->getKind()) { 2112 case ParseNodeKind::ExportSpecList: { 2113 MOZ_ASSERT(!isDefault); 2114 for (ParseNode* item : kid->as<ListNode>().contents()) { 2115 BinaryNode* spec = &item->as<BinaryNode>(); 2116 MOZ_ASSERT(spec->isKind(ParseNodeKind::ExportSpec)); 2117 2118 NameNode* localNameNode = &spec->left()->as<NameNode>(); 2119 NameNode* exportNameNode = &spec->right()->as<NameNode>(); 2120 2121 auto localName = localNameNode->atom(); 2122 auto exportName = exportNameNode->atom(); 2123 2124 if (!appendExportEntry(exportName, localName, spec)) { 2125 return false; 2126 } 2127 } 2128 break; 2129 } 2130 2131 case ParseNodeKind::ClassDecl: { 2132 const ClassNode& cls = kid->as<ClassNode>(); 2133 MOZ_ASSERT(cls.names()); 2134 auto localName = cls.names()->innerBinding()->atom(); 2135 auto exportName = 2136 isDefault ? TaggedParserAtomIndex::WellKnown::default_() : localName; 2137 if (!appendExportEntry(exportName, localName)) { 2138 return false; 2139 } 2140 break; 2141 } 2142 2143 case ParseNodeKind::VarStmt: 2144 case ParseNodeKind::ConstDecl: 2145 case ParseNodeKind::LetDecl: { 2146 for (ParseNode* binding : kid->as<ListNode>().contents()) { 2147 if (binding->isKind(ParseNodeKind::AssignExpr)) { 2148 binding = binding->as<AssignmentNode>().left(); 2149 } else { 2150 MOZ_ASSERT(binding->isKind(ParseNodeKind::Name)); 2151 } 2152 2153 if (binding->isKind(ParseNodeKind::Name)) { 2154 auto localName = binding->as<NameNode>().atom(); 2155 auto exportName = isDefault 2156 ? TaggedParserAtomIndex::WellKnown::default_() 2157 : localName; 2158 if (!appendExportEntry(exportName, localName)) { 2159 return false; 2160 } 2161 } else if (binding->isKind(ParseNodeKind::ArrayExpr)) { 2162 if (!processExportArrayBinding(&binding->as<ListNode>())) { 2163 return false; 2164 } 2165 } else { 2166 MOZ_ASSERT(binding->isKind(ParseNodeKind::ObjectExpr)); 2167 if (!processExportObjectBinding(&binding->as<ListNode>())) { 2168 return false; 2169 } 2170 } 2171 } 2172 break; 2173 } 2174 2175 case ParseNodeKind::Function: { 2176 FunctionBox* box = kid->as<FunctionNode>().funbox(); 2177 MOZ_ASSERT(!box->isArrow()); 2178 auto localName = box->explicitName(); 2179 auto exportName = 2180 isDefault ? TaggedParserAtomIndex::WellKnown::default_() : localName; 2181 if (!appendExportEntry(exportName, localName)) { 2182 return false; 2183 } 2184 break; 2185 } 2186 2187 default: 2188 MOZ_CRASH("Unexpected parse node"); 2189 } 2190 2191 return true; 2192 } 2193 2194 bool ModuleBuilder::processExportBinding(frontend::ParseNode* binding) { 2195 using namespace js::frontend; 2196 2197 if (binding->isKind(ParseNodeKind::Name)) { 2198 auto name = binding->as<NameNode>().atom(); 2199 return appendExportEntry(name, name); 2200 } 2201 2202 if (binding->isKind(ParseNodeKind::ArrayExpr)) { 2203 return processExportArrayBinding(&binding->as<ListNode>()); 2204 } 2205 2206 MOZ_ASSERT(binding->isKind(ParseNodeKind::ObjectExpr)); 2207 return processExportObjectBinding(&binding->as<ListNode>()); 2208 } 2209 2210 bool ModuleBuilder::processExportArrayBinding(frontend::ListNode* array) { 2211 using namespace js::frontend; 2212 2213 MOZ_ASSERT(array->isKind(ParseNodeKind::ArrayExpr)); 2214 2215 for (ParseNode* node : array->contents()) { 2216 if (node->isKind(ParseNodeKind::Elision)) { 2217 continue; 2218 } 2219 2220 if (node->isKind(ParseNodeKind::Spread)) { 2221 node = node->as<UnaryNode>().kid(); 2222 } else if (node->isKind(ParseNodeKind::AssignExpr)) { 2223 node = node->as<AssignmentNode>().left(); 2224 } 2225 2226 if (!processExportBinding(node)) { 2227 return false; 2228 } 2229 } 2230 2231 return true; 2232 } 2233 2234 bool ModuleBuilder::processExportObjectBinding(frontend::ListNode* obj) { 2235 using namespace js::frontend; 2236 2237 MOZ_ASSERT(obj->isKind(ParseNodeKind::ObjectExpr)); 2238 2239 for (ParseNode* node : obj->contents()) { 2240 MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) || 2241 node->isKind(ParseNodeKind::PropertyDefinition) || 2242 node->isKind(ParseNodeKind::Shorthand) || 2243 node->isKind(ParseNodeKind::Spread)); 2244 2245 ParseNode* target; 2246 if (node->isKind(ParseNodeKind::Spread)) { 2247 target = node->as<UnaryNode>().kid(); 2248 } else { 2249 if (node->isKind(ParseNodeKind::MutateProto)) { 2250 target = node->as<UnaryNode>().kid(); 2251 } else { 2252 target = node->as<BinaryNode>().right(); 2253 } 2254 2255 if (target->isKind(ParseNodeKind::AssignExpr)) { 2256 target = target->as<AssignmentNode>().left(); 2257 } 2258 } 2259 2260 if (!processExportBinding(target)) { 2261 return false; 2262 } 2263 } 2264 2265 return true; 2266 } 2267 2268 bool ModuleBuilder::processExportFrom(frontend::BinaryNode* exportNode) { 2269 using namespace js::frontend; 2270 2271 MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportFromStmt)); 2272 2273 auto* specList = &exportNode->left()->as<ListNode>(); 2274 MOZ_ASSERT(specList->isKind(ParseNodeKind::ExportSpecList)); 2275 2276 auto* moduleRequest = &exportNode->right()->as<BinaryNode>(); 2277 MOZ_ASSERT(moduleRequest->isKind(ParseNodeKind::ImportModuleRequest)); 2278 2279 auto* moduleSpec = &moduleRequest->left()->as<NameNode>(); 2280 MOZ_ASSERT(moduleSpec->isKind(ParseNodeKind::StringExpr)); 2281 2282 auto* attributeList = &moduleRequest->right()->as<ListNode>(); 2283 MOZ_ASSERT(attributeList->isKind(ParseNodeKind::ImportAttributeList)); 2284 2285 auto specifier = moduleSpec->atom(); 2286 MaybeModuleRequestIndex moduleRequestIndex = 2287 appendModuleRequest(specifier, attributeList); 2288 if (!moduleRequestIndex.isSome()) { 2289 return false; 2290 } 2291 2292 if (!maybeAppendRequestedModule(moduleRequestIndex, moduleSpec)) { 2293 return false; 2294 } 2295 2296 for (ParseNode* spec : specList->contents()) { 2297 uint32_t line; 2298 JS::LimitedColumnNumberOneOrigin column; 2299 eitherParser_.computeLineAndColumn(spec->pn_pos.begin, &line, &column); 2300 2301 StencilModuleEntry entry; 2302 if (spec->isKind(ParseNodeKind::ExportSpec)) { 2303 auto* importNameNode = &spec->as<BinaryNode>().left()->as<NameNode>(); 2304 auto* exportNameNode = &spec->as<BinaryNode>().right()->as<NameNode>(); 2305 2306 auto importName = importNameNode->atom(); 2307 auto exportName = exportNameNode->atom(); 2308 MOZ_ASSERT(exportNames_.has(exportName)); 2309 2310 markUsedByStencil(importName); 2311 markUsedByStencil(exportName); 2312 entry = StencilModuleEntry::exportFromEntry( 2313 moduleRequestIndex, importName, exportName, line, 2314 JS::ColumnNumberOneOrigin(column)); 2315 } else if (spec->isKind(ParseNodeKind::ExportNamespaceSpec)) { 2316 auto* exportNameNode = &spec->as<UnaryNode>().kid()->as<NameNode>(); 2317 2318 auto exportName = exportNameNode->atom(); 2319 MOZ_ASSERT(exportNames_.has(exportName)); 2320 2321 markUsedByStencil(exportName); 2322 entry = StencilModuleEntry::exportNamespaceFromEntry( 2323 moduleRequestIndex, exportName, line, 2324 JS::ColumnNumberOneOrigin(column)); 2325 } else { 2326 MOZ_ASSERT(spec->isKind(ParseNodeKind::ExportBatchSpecStmt)); 2327 2328 entry = StencilModuleEntry::exportBatchFromEntry( 2329 moduleRequestIndex, line, JS::ColumnNumberOneOrigin(column)); 2330 } 2331 2332 if (!exportEntries_.append(entry)) { 2333 return false; 2334 } 2335 } 2336 2337 return true; 2338 } 2339 2340 frontend::StencilModuleEntry* ModuleBuilder::importEntryFor( 2341 frontend::TaggedParserAtomIndex localName) const { 2342 MOZ_ASSERT(localName); 2343 auto ptr = importEntries_.lookup(localName); 2344 if (!ptr) { 2345 return nullptr; 2346 } 2347 2348 return &ptr->value(); 2349 } 2350 2351 ModuleBuilder::NoteExportedNameResult ModuleBuilder::noteExportedName( 2352 frontend::TaggedParserAtomIndex name) { 2353 MOZ_ASSERT(name); 2354 auto addPtr = exportNames_.lookupForAdd(name); 2355 if (addPtr) { 2356 return NoteExportedNameResult::AlreadyDeclared; 2357 } 2358 if (!exportNames_.add(addPtr, name)) { 2359 return NoteExportedNameResult::OutOfMemory; 2360 } 2361 return NoteExportedNameResult::Success; 2362 } 2363 2364 bool ModuleBuilder::appendExportEntry( 2365 frontend::TaggedParserAtomIndex exportName, 2366 frontend::TaggedParserAtomIndex localName, frontend::ParseNode* node) { 2367 MOZ_ASSERT(exportNames_.has(exportName)); 2368 2369 uint32_t line = 0; 2370 JS::LimitedColumnNumberOneOrigin column; 2371 if (node) { 2372 eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column); 2373 } 2374 2375 markUsedByStencil(localName); 2376 markUsedByStencil(exportName); 2377 auto entry = frontend::StencilModuleEntry::exportAsEntry( 2378 localName, exportName, line, JS::ColumnNumberOneOrigin(column)); 2379 return exportEntries_.append(entry); 2380 } 2381 2382 frontend::MaybeModuleRequestIndex ModuleBuilder::appendModuleRequest( 2383 frontend::TaggedParserAtomIndex specifier, 2384 frontend::ListNode* attributeList) { 2385 markUsedByStencil(specifier); 2386 auto request = frontend::StencilModuleRequest(specifier); 2387 2388 if (!processAttributes(request, attributeList)) { 2389 return MaybeModuleRequestIndex(); 2390 } 2391 2392 if (auto ptr = moduleRequestIndexes_.lookup(request)) { 2393 return MaybeModuleRequestIndex(ptr->value()); 2394 } 2395 2396 uint32_t index = moduleRequests_.length(); 2397 if (!moduleRequests_.append(request) || 2398 !moduleRequestIndexes_.put(request, index)) { 2399 js::ReportOutOfMemory(fc_); 2400 return MaybeModuleRequestIndex(); 2401 } 2402 2403 return MaybeModuleRequestIndex(index); 2404 } 2405 2406 bool ModuleBuilder::maybeAppendRequestedModule( 2407 MaybeModuleRequestIndex moduleRequest, frontend::ParseNode* node) { 2408 uint32_t index = moduleRequest.value(); 2409 if (requestedModuleIndexes_.has(index)) { 2410 return true; 2411 } 2412 2413 uint32_t line; 2414 JS::LimitedColumnNumberOneOrigin column; 2415 eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column); 2416 2417 auto entry = frontend::StencilModuleEntry::requestedModule( 2418 moduleRequest, line, JS::ColumnNumberOneOrigin(column)); 2419 2420 if (!requestedModules_.append(entry)) { 2421 js::ReportOutOfMemory(fc_); 2422 return false; 2423 } 2424 2425 return requestedModuleIndexes_.put(index); 2426 } 2427 2428 void ModuleBuilder::markUsedByStencil(frontend::TaggedParserAtomIndex name) { 2429 // Imported/exported identifiers must be atomized. 2430 eitherParser_.parserAtoms().markUsedByStencil( 2431 name, frontend::ParserAtom::Atomize::Yes); 2432 } 2433 2434 JSObject* js::GetOrCreateModuleMetaObject(JSContext* cx, 2435 HandleObject moduleArg) { 2436 Handle<ModuleObject*> module = moduleArg.as<ModuleObject>(); 2437 if (JSObject* obj = module->metaObject()) { 2438 return obj; 2439 } 2440 2441 RootedObject metaObject(cx, NewPlainObjectWithProto(cx, nullptr)); 2442 if (!metaObject) { 2443 return nullptr; 2444 } 2445 2446 JS::ModuleMetadataHook func = cx->runtime()->moduleMetadataHook; 2447 if (!func) { 2448 JS_ReportErrorASCII(cx, "Module metadata hook not set"); 2449 return nullptr; 2450 } 2451 2452 RootedValue modulePrivate(cx, JS::GetModulePrivate(module)); 2453 if (!func(cx, modulePrivate, metaObject)) { 2454 return nullptr; 2455 } 2456 2457 module->setMetaObject(metaObject); 2458 2459 return metaObject; 2460 } 2461 2462 bool ModuleObject::topLevelCapabilityResolve(JSContext* cx, 2463 Handle<ModuleObject*> module) { 2464 RootedValue rval(cx); 2465 Rooted<PromiseObject*> promise( 2466 cx, &module->topLevelCapability()->as<PromiseObject>()); 2467 return AsyncFunctionReturned(cx, promise, rval); 2468 } 2469 2470 bool ModuleObject::topLevelCapabilityReject(JSContext* cx, 2471 Handle<ModuleObject*> module, 2472 HandleValue error) { 2473 Rooted<PromiseObject*> promise( 2474 cx, &module->topLevelCapability()->as<PromiseObject>()); 2475 return AsyncFunctionThrown(cx, promise, error); 2476 }