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/EnumSet.h"
11 #include "mozilla/ScopeExit.h"
12 
13 #include "builtin/Promise.h"
14 #include "builtin/SelfHostingDefines.h"
15 #include "frontend/ParseNode.h"
16 #include "frontend/SharedContext.h"
17 #include "gc/FreeOp.h"
18 #include "gc/Policy.h"
19 #include "gc/Tracer.h"
20 #include "js/friend/ErrorMessages.h"  // JSMSG_*
21 #include "js/Modules.h"  // JS::GetModulePrivate, JS::ModuleDynamicImportHook
22 #include "js/PropertySpec.h"
23 #include "vm/AsyncFunction.h"
24 #include "vm/AsyncIteration.h"
25 #include "vm/EqualityOperations.h"  // js::SameValue
26 #include "vm/ModuleBuilder.h"       // js::ModuleBuilder
27 #include "vm/PlainObject.h"         // js::PlainObject
28 #include "vm/PromiseObject.h"       // js::PromiseObject
29 #include "vm/SelfHosting.h"
30 #include "vm/SharedStencil.h"  // js::GCThingIndex
31 
32 #include "builtin/HandlerFunction-inl.h"  // js::ExtraValueFromHandler, js::NewHandler{,WithExtraValue}, js::TargetFromHandler
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 static_assert(MODULE_STATUS_UNLINKED < MODULE_STATUS_LINKING &&
41                   MODULE_STATUS_LINKING < MODULE_STATUS_LINKED &&
42                   MODULE_STATUS_LINKED < MODULE_STATUS_EVALUATED &&
43                   MODULE_STATUS_EVALUATED < MODULE_STATUS_EVALUATED_ERROR,
44               "Module statuses are ordered incorrectly");
45 
46 template <typename T, Value ValueGetter(const T* obj)>
ModuleValueGetterImpl(JSContext * cx,const CallArgs & args)47 static bool ModuleValueGetterImpl(JSContext* cx, const CallArgs& args) {
48   args.rval().set(ValueGetter(&args.thisv().toObject().as<T>()));
49   return true;
50 }
51 
52 template <typename T, Value ValueGetter(const T* obj)>
ModuleValueGetter(JSContext * cx,unsigned argc,Value * vp)53 static bool ModuleValueGetter(JSContext* cx, unsigned argc, Value* vp) {
54   CallArgs args = CallArgsFromVp(argc, vp);
55   return CallNonGenericMethod<T::isInstance,
56                               ModuleValueGetterImpl<T, ValueGetter>>(cx, args);
57 }
58 
59 #define DEFINE_GETTER_FUNCTIONS(cls, name, slot)                              \
60   static Value cls##_##name##Value(const cls* obj) {                          \
61     return obj->getReservedSlot(cls::slot);                                   \
62   }                                                                           \
63                                                                               \
64   static bool cls##_##name##Getter(JSContext* cx, unsigned argc, Value* vp) { \
65     return ModuleValueGetter<cls, cls##_##name##Value>(cx, argc, vp);         \
66   }
67 
68 #define DEFINE_ATOM_ACCESSOR_METHOD(cls, name) \
69   JSAtom* cls::name() const {                  \
70     Value value = cls##_##name##Value(this);   \
71     return &value.toString()->asAtom();        \
72   }
73 
74 #define DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(cls, name) \
75   JSAtom* cls::name() const {                          \
76     Value value = cls##_##name##Value(this);           \
77     if (value.isNull()) return nullptr;                \
78     return &value.toString()->asAtom();                \
79   }
80 
81 #define DEFINE_UINT32_ACCESSOR_METHOD(cls, name) \
82   uint32_t cls::name() const {                   \
83     Value value = cls##_##name##Value(this);     \
84     MOZ_ASSERT(value.toNumber() >= 0);           \
85     if (value.isInt32()) return value.toInt32(); \
86     return JS::ToUint32(value.toDouble());       \
87   }
88 
StringOrNullValue(JSString * maybeString)89 static Value StringOrNullValue(JSString* maybeString) {
90   return maybeString ? StringValue(maybeString) : NullValue();
91 }
92 
93 ///////////////////////////////////////////////////////////////////////////
94 // ImportEntryObject
95 
96 /* static */ const JSClass ImportEntryObject::class_ = {
97     "ImportEntry", JSCLASS_HAS_RESERVED_SLOTS(ImportEntryObject::SlotCount)};
98 
DEFINE_GETTER_FUNCTIONS(ImportEntryObject,moduleRequest,ModuleRequestSlot)99 DEFINE_GETTER_FUNCTIONS(ImportEntryObject, moduleRequest, ModuleRequestSlot)
100 DEFINE_GETTER_FUNCTIONS(ImportEntryObject, importName, ImportNameSlot)
101 DEFINE_GETTER_FUNCTIONS(ImportEntryObject, localName, LocalNameSlot)
102 DEFINE_GETTER_FUNCTIONS(ImportEntryObject, lineNumber, LineNumberSlot)
103 DEFINE_GETTER_FUNCTIONS(ImportEntryObject, columnNumber, ColumnNumberSlot)
104 
105 DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ImportEntryObject, importName)
106 DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, localName)
107 DEFINE_UINT32_ACCESSOR_METHOD(ImportEntryObject, lineNumber)
108 DEFINE_UINT32_ACCESSOR_METHOD(ImportEntryObject, columnNumber)
109 
110 ModuleRequestObject* ImportEntryObject::moduleRequest() const {
111   Value value = getReservedSlot(ModuleRequestSlot);
112   return &value.toObject().as<ModuleRequestObject>();
113 }
114 
115 /* static */
isInstance(HandleValue value)116 bool ImportEntryObject::isInstance(HandleValue value) {
117   return value.isObject() && value.toObject().is<ImportEntryObject>();
118 }
119 
120 /* static */
initImportEntryProto(JSContext * cx,Handle<GlobalObject * > global)121 bool GlobalObject::initImportEntryProto(JSContext* cx,
122                                         Handle<GlobalObject*> global) {
123   static const JSPropertySpec protoAccessors[] = {
124       JS_PSG("moduleRequest", ImportEntryObject_moduleRequestGetter, 0),
125       JS_PSG("importName", ImportEntryObject_importNameGetter, 0),
126       JS_PSG("localName", ImportEntryObject_localNameGetter, 0),
127       JS_PSG("lineNumber", ImportEntryObject_lineNumberGetter, 0),
128       JS_PSG("columnNumber", ImportEntryObject_columnNumberGetter, 0),
129       JS_PS_END};
130 
131   RootedObject proto(
132       cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
133   if (!proto) {
134     return false;
135   }
136 
137   if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors, nullptr)) {
138     return false;
139   }
140 
141   global->initReservedSlot(IMPORT_ENTRY_PROTO, ObjectValue(*proto));
142   return true;
143 }
144 
145 /* static */
create(JSContext * cx,HandleObject moduleRequest,HandleAtom maybeImportName,HandleAtom localName,uint32_t lineNumber,uint32_t columnNumber)146 ImportEntryObject* ImportEntryObject::create(
147     JSContext* cx, HandleObject moduleRequest, HandleAtom maybeImportName,
148     HandleAtom localName, uint32_t lineNumber, uint32_t columnNumber) {
149   RootedObject proto(
150       cx, GlobalObject::getOrCreateImportEntryPrototype(cx, cx->global()));
151   if (!proto) {
152     return nullptr;
153   }
154 
155   ImportEntryObject* self =
156       NewObjectWithGivenProto<ImportEntryObject>(cx, proto);
157   if (!self) {
158     return nullptr;
159   }
160 
161   self->initReservedSlot(ModuleRequestSlot, ObjectValue(*moduleRequest));
162   self->initReservedSlot(ImportNameSlot, StringOrNullValue(maybeImportName));
163   self->initReservedSlot(LocalNameSlot, StringValue(localName));
164   self->initReservedSlot(LineNumberSlot, NumberValue(lineNumber));
165   self->initReservedSlot(ColumnNumberSlot, NumberValue(columnNumber));
166   return self;
167 }
168 
169 ///////////////////////////////////////////////////////////////////////////
170 // ExportEntryObject
171 
172 /* static */ const JSClass ExportEntryObject::class_ = {
173     "ExportEntry", JSCLASS_HAS_RESERVED_SLOTS(ExportEntryObject::SlotCount)};
174 
DEFINE_GETTER_FUNCTIONS(ExportEntryObject,exportName,ExportNameSlot)175 DEFINE_GETTER_FUNCTIONS(ExportEntryObject, exportName, ExportNameSlot)
176 DEFINE_GETTER_FUNCTIONS(ExportEntryObject, moduleRequest, ModuleRequestSlot)
177 DEFINE_GETTER_FUNCTIONS(ExportEntryObject, importName, ImportNameSlot)
178 DEFINE_GETTER_FUNCTIONS(ExportEntryObject, localName, LocalNameSlot)
179 DEFINE_GETTER_FUNCTIONS(ExportEntryObject, lineNumber, LineNumberSlot)
180 DEFINE_GETTER_FUNCTIONS(ExportEntryObject, columnNumber, ColumnNumberSlot)
181 
182 DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, exportName)
183 DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, importName)
184 DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, localName)
185 DEFINE_UINT32_ACCESSOR_METHOD(ExportEntryObject, lineNumber)
186 DEFINE_UINT32_ACCESSOR_METHOD(ExportEntryObject, columnNumber)
187 
188 ModuleRequestObject* ExportEntryObject::moduleRequest() const {
189   Value value = getReservedSlot(ModuleRequestSlot);
190   return &value.toObject().as<ModuleRequestObject>();
191 }
192 
193 /* static */
isInstance(HandleValue value)194 bool ExportEntryObject::isInstance(HandleValue value) {
195   return value.isObject() && value.toObject().is<ExportEntryObject>();
196 }
197 
198 /* static */
initExportEntryProto(JSContext * cx,Handle<GlobalObject * > global)199 bool GlobalObject::initExportEntryProto(JSContext* cx,
200                                         Handle<GlobalObject*> global) {
201   static const JSPropertySpec protoAccessors[] = {
202       JS_PSG("exportName", ExportEntryObject_exportNameGetter, 0),
203       JS_PSG("moduleRequest", ExportEntryObject_moduleRequestGetter, 0),
204       JS_PSG("importName", ExportEntryObject_importNameGetter, 0),
205       JS_PSG("localName", ExportEntryObject_localNameGetter, 0),
206       JS_PSG("lineNumber", ExportEntryObject_lineNumberGetter, 0),
207       JS_PSG("columnNumber", ExportEntryObject_columnNumberGetter, 0),
208       JS_PS_END};
209 
210   RootedObject proto(
211       cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
212   if (!proto) {
213     return false;
214   }
215 
216   if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors, nullptr)) {
217     return false;
218   }
219 
220   global->initReservedSlot(EXPORT_ENTRY_PROTO, ObjectValue(*proto));
221   return true;
222 }
223 
224 /* static */
create(JSContext * cx,HandleAtom maybeExportName,HandleObject moduleRequest,HandleAtom maybeImportName,HandleAtom maybeLocalName,uint32_t lineNumber,uint32_t columnNumber)225 ExportEntryObject* ExportEntryObject::create(
226     JSContext* cx, HandleAtom maybeExportName, HandleObject moduleRequest,
227     HandleAtom maybeImportName, HandleAtom maybeLocalName, uint32_t lineNumber,
228     uint32_t columnNumber) {
229   // Line and column numbers are optional for export entries since direct
230   // entries are checked at parse time.
231 
232   RootedObject proto(
233       cx, GlobalObject::getOrCreateExportEntryPrototype(cx, cx->global()));
234   if (!proto) {
235     return nullptr;
236   }
237 
238   ExportEntryObject* self =
239       NewObjectWithGivenProto<ExportEntryObject>(cx, proto);
240   if (!self) {
241     return nullptr;
242   }
243 
244   self->initReservedSlot(ExportNameSlot, StringOrNullValue(maybeExportName));
245   self->initReservedSlot(ModuleRequestSlot, ObjectValue(*moduleRequest));
246   self->initReservedSlot(ImportNameSlot, StringOrNullValue(maybeImportName));
247   self->initReservedSlot(LocalNameSlot, StringOrNullValue(maybeLocalName));
248   self->initReservedSlot(LineNumberSlot, NumberValue(lineNumber));
249   self->initReservedSlot(ColumnNumberSlot, NumberValue(columnNumber));
250   return self;
251 }
252 
253 ///////////////////////////////////////////////////////////////////////////
254 // RequestedModuleObject
255 
256 /* static */ const JSClass RequestedModuleObject::class_ = {
257     "RequestedModule",
258     JSCLASS_HAS_RESERVED_SLOTS(RequestedModuleObject::SlotCount)};
259 
DEFINE_GETTER_FUNCTIONS(RequestedModuleObject,moduleRequest,ModuleRequestSlot)260 DEFINE_GETTER_FUNCTIONS(RequestedModuleObject, moduleRequest, ModuleRequestSlot)
261 DEFINE_GETTER_FUNCTIONS(RequestedModuleObject, lineNumber, LineNumberSlot)
262 DEFINE_GETTER_FUNCTIONS(RequestedModuleObject, columnNumber, ColumnNumberSlot)
263 
264 DEFINE_UINT32_ACCESSOR_METHOD(RequestedModuleObject, lineNumber)
265 DEFINE_UINT32_ACCESSOR_METHOD(RequestedModuleObject, columnNumber)
266 
267 ModuleRequestObject* RequestedModuleObject::moduleRequest() const {
268   Value value = getReservedSlot(ModuleRequestSlot);
269   return &value.toObject().as<ModuleRequestObject>();
270 }
271 
272 /* static */
isInstance(HandleValue value)273 bool RequestedModuleObject::isInstance(HandleValue value) {
274   return value.isObject() && value.toObject().is<RequestedModuleObject>();
275 }
276 
277 /* static */
initRequestedModuleProto(JSContext * cx,Handle<GlobalObject * > global)278 bool GlobalObject::initRequestedModuleProto(JSContext* cx,
279                                             Handle<GlobalObject*> global) {
280   static const JSPropertySpec protoAccessors[] = {
281       JS_PSG("moduleRequest", RequestedModuleObject_moduleRequestGetter, 0),
282       JS_PSG("lineNumber", RequestedModuleObject_lineNumberGetter, 0),
283       JS_PSG("columnNumber", RequestedModuleObject_columnNumberGetter, 0),
284       JS_PS_END};
285 
286   RootedObject proto(
287       cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
288   if (!proto) {
289     return false;
290   }
291 
292   if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors, nullptr)) {
293     return false;
294   }
295 
296   global->initReservedSlot(REQUESTED_MODULE_PROTO, ObjectValue(*proto));
297   return true;
298 }
299 
300 /* static */
create(JSContext * cx,HandleObject moduleRequest,uint32_t lineNumber,uint32_t columnNumber)301 RequestedModuleObject* RequestedModuleObject::create(JSContext* cx,
302                                                      HandleObject moduleRequest,
303                                                      uint32_t lineNumber,
304                                                      uint32_t columnNumber) {
305   RootedObject proto(
306       cx, GlobalObject::getOrCreateRequestedModulePrototype(cx, cx->global()));
307   if (!proto) {
308     return nullptr;
309   }
310 
311   RequestedModuleObject* self =
312       NewObjectWithGivenProto<RequestedModuleObject>(cx, proto);
313   if (!self) {
314     return nullptr;
315   }
316 
317   self->initReservedSlot(ModuleRequestSlot, ObjectValue(*moduleRequest));
318   self->initReservedSlot(LineNumberSlot, NumberValue(lineNumber));
319   self->initReservedSlot(ColumnNumberSlot, NumberValue(columnNumber));
320   return self;
321 }
322 
323 ///////////////////////////////////////////////////////////////////////////
324 // ModuleRequestObject
325 /* static */ const JSClass ModuleRequestObject::class_ = {
326     "ModuleRequest",
327     JSCLASS_HAS_RESERVED_SLOTS(ModuleRequestObject::SlotCount)};
328 
DEFINE_GETTER_FUNCTIONS(ModuleRequestObject,specifier,SpecifierSlot)329 DEFINE_GETTER_FUNCTIONS(ModuleRequestObject, specifier, SpecifierSlot)
330 
331 DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ModuleRequestObject, specifier)
332 
333 /* static */
334 bool ModuleRequestObject::isInstance(HandleValue value) {
335   return value.isObject() && value.toObject().is<ModuleRequestObject>();
336 }
337 
338 /* static */
initModuleRequestProto(JSContext * cx,Handle<GlobalObject * > global)339 bool GlobalObject::initModuleRequestProto(JSContext* cx,
340                                           Handle<GlobalObject*> global) {
341   static const JSPropertySpec protoAccessors[] = {
342       JS_PSG("specifier", ModuleRequestObject_specifierGetter, 0), JS_PS_END};
343 
344   RootedObject proto(
345       cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
346   if (!proto) {
347     return false;
348   }
349 
350   if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors, nullptr)) {
351     return false;
352   }
353 
354   global->initReservedSlot(MODULE_REQUEST_PROTO, ObjectValue(*proto));
355   return true;
356 }
357 
358 /* static */
create(JSContext * cx,HandleAtom specifier)359 ModuleRequestObject* ModuleRequestObject::create(JSContext* cx,
360                                                  HandleAtom specifier) {
361   RootedObject proto(
362       cx, GlobalObject::getOrCreateModuleRequestPrototype(cx, cx->global()));
363   if (!proto) {
364     return nullptr;
365   }
366 
367   ModuleRequestObject* self =
368       NewObjectWithGivenProto<ModuleRequestObject>(cx, proto);
369   if (!self) {
370     return nullptr;
371   }
372 
373   self->initReservedSlot(SpecifierSlot, StringOrNullValue(specifier));
374   return self;
375 }
376 
377 ///////////////////////////////////////////////////////////////////////////
378 // IndirectBindingMap
379 
Binding(ModuleEnvironmentObject * environment,jsid targetName,PropertyInfo prop)380 IndirectBindingMap::Binding::Binding(ModuleEnvironmentObject* environment,
381                                      jsid targetName, PropertyInfo prop)
382     : environment(environment),
383 #ifdef DEBUG
384       targetName(targetName),
385 #endif
386       prop(prop) {
387 }
388 
trace(JSTracer * trc)389 void IndirectBindingMap::trace(JSTracer* trc) {
390   if (!map_) {
391     return;
392   }
393 
394   for (Map::Enum e(*map_); !e.empty(); e.popFront()) {
395     Binding& b = e.front().value();
396     TraceEdge(trc, &b.environment, "module bindings environment");
397 #ifdef DEBUG
398     TraceEdge(trc, &b.targetName, "module bindings target name");
399 #endif
400     mozilla::DebugOnly<jsid> prev(e.front().key());
401     TraceEdge(trc, &e.front().mutableKey(), "module bindings binding name");
402     MOZ_ASSERT(e.front().key() == prev);
403   }
404 }
405 
put(JSContext * cx,HandleId name,HandleModuleEnvironmentObject environment,HandleId targetName)406 bool IndirectBindingMap::put(JSContext* cx, HandleId name,
407                              HandleModuleEnvironmentObject environment,
408                              HandleId targetName) {
409   // This object might have been allocated on the background parsing thread in
410   // different zone to the final module. Lazily allocate the map so we don't
411   // have to switch its zone when merging realms.
412   if (!map_) {
413     MOZ_ASSERT(!cx->zone()->createdForHelperThread());
414     map_.emplace(cx->zone());
415   }
416 
417   mozilla::Maybe<PropertyInfo> prop = environment->lookup(cx, targetName);
418   MOZ_ASSERT(prop.isSome());
419   if (!map_->put(name, Binding(environment, targetName, *prop))) {
420     ReportOutOfMemory(cx);
421     return false;
422   }
423 
424   return true;
425 }
426 
lookup(jsid name,ModuleEnvironmentObject ** envOut,mozilla::Maybe<PropertyInfo> * propOut) const427 bool IndirectBindingMap::lookup(jsid name, ModuleEnvironmentObject** envOut,
428                                 mozilla::Maybe<PropertyInfo>* propOut) const {
429   if (!map_) {
430     return false;
431   }
432 
433   auto ptr = map_->lookup(name);
434   if (!ptr) {
435     return false;
436   }
437 
438   const Binding& binding = ptr->value();
439   MOZ_ASSERT(binding.environment);
440   MOZ_ASSERT(
441       binding.environment->containsPure(binding.targetName, binding.prop));
442   *envOut = binding.environment;
443   *propOut = mozilla::Some(binding.prop);
444   return true;
445 }
446 
447 ///////////////////////////////////////////////////////////////////////////
448 // ModuleNamespaceObject
449 
450 /* static */
451 const ModuleNamespaceObject::ProxyHandler ModuleNamespaceObject::proxyHandler;
452 
453 /* static */
isInstance(HandleValue value)454 bool ModuleNamespaceObject::isInstance(HandleValue value) {
455   return value.isObject() && value.toObject().is<ModuleNamespaceObject>();
456 }
457 
458 /* static */
create(JSContext * cx,HandleModuleObject module,HandleArrayObject exports,UniquePtr<IndirectBindingMap> bindings)459 ModuleNamespaceObject* ModuleNamespaceObject::create(
460     JSContext* cx, HandleModuleObject module, HandleArrayObject exports,
461     UniquePtr<IndirectBindingMap> bindings) {
462   RootedValue priv(cx, ObjectValue(*module));
463   ProxyOptions options;
464   options.setLazyProto(true);
465   Rooted<UniquePtr<IndirectBindingMap>> rootedBindings(cx, std::move(bindings));
466   RootedObject object(
467       cx, NewProxyObject(cx, &proxyHandler, priv, nullptr, options));
468   if (!object) {
469     return nullptr;
470   }
471 
472   SetProxyReservedSlot(object, ExportsSlot, ObjectValue(*exports));
473   SetProxyReservedSlot(object, BindingsSlot,
474                        PrivateValue(rootedBindings.release()));
475   AddCellMemory(object, sizeof(IndirectBindingMap),
476                 MemoryUse::ModuleBindingMap);
477 
478   return &object->as<ModuleNamespaceObject>();
479 }
480 
module()481 ModuleObject& ModuleNamespaceObject::module() {
482   return GetProxyPrivate(this).toObject().as<ModuleObject>();
483 }
484 
exports()485 ArrayObject& ModuleNamespaceObject::exports() {
486   return GetProxyReservedSlot(this, ExportsSlot).toObject().as<ArrayObject>();
487 }
488 
bindings()489 IndirectBindingMap& ModuleNamespaceObject::bindings() {
490   Value value = GetProxyReservedSlot(this, BindingsSlot);
491   auto bindings = static_cast<IndirectBindingMap*>(value.toPrivate());
492   MOZ_ASSERT(bindings);
493   return *bindings;
494 }
495 
hasBindings() const496 bool ModuleNamespaceObject::hasBindings() const {
497   // Import bindings may not be present if we hit OOM in initialization.
498   return !GetProxyReservedSlot(this, BindingsSlot).isUndefined();
499 }
500 
addBinding(JSContext * cx,HandleAtom exportedName,HandleModuleObject targetModule,HandleAtom targetName)501 bool ModuleNamespaceObject::addBinding(JSContext* cx, HandleAtom exportedName,
502                                        HandleModuleObject targetModule,
503                                        HandleAtom targetName) {
504   RootedModuleEnvironmentObject environment(
505       cx, &targetModule->initialEnvironment());
506   RootedId exportedNameId(cx, AtomToId(exportedName));
507   RootedId targetNameId(cx, AtomToId(targetName));
508   return bindings().put(cx, exportedNameId, environment, targetNameId);
509 }
510 
511 const char ModuleNamespaceObject::ProxyHandler::family = 0;
512 
ProxyHandler()513 ModuleNamespaceObject::ProxyHandler::ProxyHandler()
514     : BaseProxyHandler(&family, false) {}
515 
getPrototype(JSContext * cx,HandleObject proxy,MutableHandleObject protop) const516 bool ModuleNamespaceObject::ProxyHandler::getPrototype(
517     JSContext* cx, HandleObject proxy, MutableHandleObject protop) const {
518   protop.set(nullptr);
519   return true;
520 }
521 
setPrototype(JSContext * cx,HandleObject proxy,HandleObject proto,ObjectOpResult & result) const522 bool ModuleNamespaceObject::ProxyHandler::setPrototype(
523     JSContext* cx, HandleObject proxy, HandleObject proto,
524     ObjectOpResult& result) const {
525   if (!proto) {
526     return result.succeed();
527   }
528   return result.failCantSetProto();
529 }
530 
getPrototypeIfOrdinary(JSContext * cx,HandleObject proxy,bool * isOrdinary,MutableHandleObject protop) const531 bool ModuleNamespaceObject::ProxyHandler::getPrototypeIfOrdinary(
532     JSContext* cx, HandleObject proxy, bool* isOrdinary,
533     MutableHandleObject protop) const {
534   *isOrdinary = false;
535   return true;
536 }
537 
setImmutablePrototype(JSContext * cx,HandleObject proxy,bool * succeeded) const538 bool ModuleNamespaceObject::ProxyHandler::setImmutablePrototype(
539     JSContext* cx, HandleObject proxy, bool* succeeded) const {
540   *succeeded = true;
541   return true;
542 }
543 
isExtensible(JSContext * cx,HandleObject proxy,bool * extensible) const544 bool ModuleNamespaceObject::ProxyHandler::isExtensible(JSContext* cx,
545                                                        HandleObject proxy,
546                                                        bool* extensible) const {
547   *extensible = false;
548   return true;
549 }
550 
preventExtensions(JSContext * cx,HandleObject proxy,ObjectOpResult & result) const551 bool ModuleNamespaceObject::ProxyHandler::preventExtensions(
552     JSContext* cx, HandleObject proxy, ObjectOpResult& result) const {
553   result.succeed();
554   return true;
555 }
556 
getOwnPropertyDescriptor(JSContext * cx,HandleObject proxy,HandleId id,MutableHandle<mozilla::Maybe<PropertyDescriptor>> desc) const557 bool ModuleNamespaceObject::ProxyHandler::getOwnPropertyDescriptor(
558     JSContext* cx, HandleObject proxy, HandleId id,
559     MutableHandle<mozilla::Maybe<PropertyDescriptor>> desc) const {
560   Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
561   if (id.isSymbol()) {
562     if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
563       desc.set(mozilla::Some(
564           PropertyDescriptor::Data(StringValue(cx->names().Module))));
565       return true;
566     }
567 
568     desc.reset();
569     return true;
570   }
571 
572   const IndirectBindingMap& bindings = ns->bindings();
573   ModuleEnvironmentObject* env;
574   mozilla::Maybe<PropertyInfo> prop;
575   if (!bindings.lookup(id, &env, &prop)) {
576     // Not found.
577     desc.reset();
578     return true;
579   }
580 
581   RootedValue value(cx, env->getSlot(prop->slot()));
582   if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) {
583     ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id);
584     return false;
585   }
586 
587   desc.set(mozilla::Some(PropertyDescriptor::Data(
588       value,
589       {JS::PropertyAttribute::Enumerable, JS::PropertyAttribute::Writable})));
590   return true;
591 }
592 
ValidatePropertyDescriptor(JSContext * cx,Handle<PropertyDescriptor> desc,bool expectedWritable,bool expectedEnumerable,bool expectedConfigurable,HandleValue expectedValue,ObjectOpResult & result)593 static bool ValidatePropertyDescriptor(
594     JSContext* cx, Handle<PropertyDescriptor> desc, bool expectedWritable,
595     bool expectedEnumerable, bool expectedConfigurable,
596     HandleValue expectedValue, ObjectOpResult& result) {
597   if (desc.isAccessorDescriptor()) {
598     return result.fail(JSMSG_CANT_REDEFINE_PROP);
599   }
600 
601   if (desc.hasWritable() && desc.writable() != expectedWritable) {
602     return result.fail(JSMSG_CANT_REDEFINE_PROP);
603   }
604 
605   if (desc.hasEnumerable() && desc.enumerable() != expectedEnumerable) {
606     return result.fail(JSMSG_CANT_REDEFINE_PROP);
607   }
608 
609   if (desc.hasConfigurable() && desc.configurable() != expectedConfigurable) {
610     return result.fail(JSMSG_CANT_REDEFINE_PROP);
611   }
612 
613   if (desc.hasValue()) {
614     bool same;
615     if (!SameValue(cx, desc.value(), expectedValue, &same)) {
616       return false;
617     }
618     if (!same) {
619       return result.fail(JSMSG_CANT_REDEFINE_PROP);
620     }
621   }
622 
623   return result.succeed();
624 }
625 
defineProperty(JSContext * cx,HandleObject proxy,HandleId id,Handle<PropertyDescriptor> desc,ObjectOpResult & result) const626 bool ModuleNamespaceObject::ProxyHandler::defineProperty(
627     JSContext* cx, HandleObject proxy, HandleId id,
628     Handle<PropertyDescriptor> desc, ObjectOpResult& result) const {
629   if (id.isSymbol()) {
630     if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
631       RootedValue value(cx, StringValue(cx->names().Module));
632       return ValidatePropertyDescriptor(cx, desc, false, false, false, value,
633                                         result);
634     }
635     return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE);
636   }
637 
638   const IndirectBindingMap& bindings =
639       proxy->as<ModuleNamespaceObject>().bindings();
640   ModuleEnvironmentObject* env;
641   mozilla::Maybe<PropertyInfo> prop;
642   if (!bindings.lookup(id, &env, &prop)) {
643     return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE);
644   }
645 
646   RootedValue value(cx, env->getSlot(prop->slot()));
647   if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) {
648     ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id);
649     return false;
650   }
651 
652   return ValidatePropertyDescriptor(cx, desc, true, true, false, value, result);
653 }
654 
has(JSContext * cx,HandleObject proxy,HandleId id,bool * bp) const655 bool ModuleNamespaceObject::ProxyHandler::has(JSContext* cx, HandleObject proxy,
656                                               HandleId id, bool* bp) const {
657   Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
658   if (id.isSymbol()) {
659     *bp = id.isWellKnownSymbol(JS::SymbolCode::toStringTag);
660     return true;
661   }
662 
663   *bp = ns->bindings().has(id);
664   return true;
665 }
666 
get(JSContext * cx,HandleObject proxy,HandleValue receiver,HandleId id,MutableHandleValue vp) const667 bool ModuleNamespaceObject::ProxyHandler::get(JSContext* cx, HandleObject proxy,
668                                               HandleValue receiver, HandleId id,
669                                               MutableHandleValue vp) const {
670   Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
671   if (id.isSymbol()) {
672     if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
673       vp.setString(cx->names().Module);
674       return true;
675     }
676 
677     vp.setUndefined();
678     return true;
679   }
680 
681   ModuleEnvironmentObject* env;
682   mozilla::Maybe<PropertyInfo> prop;
683   if (!ns->bindings().lookup(id, &env, &prop)) {
684     vp.setUndefined();
685     return true;
686   }
687 
688   RootedValue value(cx, env->getSlot(prop->slot()));
689   if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) {
690     ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id);
691     return false;
692   }
693 
694   vp.set(value);
695   return true;
696 }
697 
set(JSContext * cx,HandleObject proxy,HandleId id,HandleValue v,HandleValue receiver,ObjectOpResult & result) const698 bool ModuleNamespaceObject::ProxyHandler::set(JSContext* cx, HandleObject proxy,
699                                               HandleId id, HandleValue v,
700                                               HandleValue receiver,
701                                               ObjectOpResult& result) const {
702   return result.failReadOnly();
703 }
704 
delete_(JSContext * cx,HandleObject proxy,HandleId id,ObjectOpResult & result) const705 bool ModuleNamespaceObject::ProxyHandler::delete_(
706     JSContext* cx, HandleObject proxy, HandleId id,
707     ObjectOpResult& result) const {
708   Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
709   if (id.isSymbol()) {
710     if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
711       return result.failCantDelete();
712     }
713 
714     return result.succeed();
715   }
716 
717   if (ns->bindings().has(id)) {
718     return result.failCantDelete();
719   }
720 
721   return result.succeed();
722 }
723 
ownPropertyKeys(JSContext * cx,HandleObject proxy,MutableHandleIdVector props) const724 bool ModuleNamespaceObject::ProxyHandler::ownPropertyKeys(
725     JSContext* cx, HandleObject proxy, MutableHandleIdVector props) const {
726   Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
727   Rooted<ArrayObject*> exports(cx, &ns->exports());
728   uint32_t count = exports->length();
729   if (!props.reserve(props.length() + count + 1)) {
730     return false;
731   }
732 
733   Rooted<ValueVector> names(cx, ValueVector(cx));
734   if (!names.resize(count) || !GetElements(cx, exports, count, names.begin())) {
735     return false;
736   }
737 
738   for (uint32_t i = 0; i < count; i++) {
739     props.infallibleAppend(AtomToId(&names[i].toString()->asAtom()));
740   }
741 
742   props.infallibleAppend(SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
743 
744   return true;
745 }
746 
trace(JSTracer * trc,JSObject * proxy) const747 void ModuleNamespaceObject::ProxyHandler::trace(JSTracer* trc,
748                                                 JSObject* proxy) const {
749   auto& self = proxy->as<ModuleNamespaceObject>();
750 
751   if (self.hasBindings()) {
752     self.bindings().trace(trc);
753   }
754 }
755 
finalize(JSFreeOp * fop,JSObject * proxy) const756 void ModuleNamespaceObject::ProxyHandler::finalize(JSFreeOp* fop,
757                                                    JSObject* proxy) const {
758   auto& self = proxy->as<ModuleNamespaceObject>();
759 
760   if (self.hasBindings()) {
761     fop->delete_(proxy, &self.bindings(), MemoryUse::ModuleBindingMap);
762   }
763 }
764 
765 ///////////////////////////////////////////////////////////////////////////
766 // ModuleObject
767 
768 /* static */ const JSClassOps ModuleObject::classOps_ = {
769     nullptr,                 // addProperty
770     nullptr,                 // delProperty
771     nullptr,                 // enumerate
772     nullptr,                 // newEnumerate
773     nullptr,                 // resolve
774     nullptr,                 // mayResolve
775     ModuleObject::finalize,  // finalize
776     nullptr,                 // call
777     nullptr,                 // hasInstance
778     nullptr,                 // construct
779     ModuleObject::trace,     // trace
780 };
781 
782 /* static */ const JSClass ModuleObject::class_ = {
783     "Module",
784     JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) |
785         JSCLASS_BACKGROUND_FINALIZE,
786     &ModuleObject::classOps_};
787 
788 #define DEFINE_ARRAY_SLOT_ACCESSOR(cls, name, slot)                 \
789   ArrayObject& cls::name() const {                                  \
790     return getReservedSlot(cls::slot).toObject().as<ArrayObject>(); \
791   }
792 
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject,requestedModules,RequestedModulesSlot)793 DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, requestedModules, RequestedModulesSlot)
794 DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, importEntries, ImportEntriesSlot)
795 DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, localExportEntries,
796                            LocalExportEntriesSlot)
797 DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, indirectExportEntries,
798                            IndirectExportEntriesSlot)
799 DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, starExportEntries,
800                            StarExportEntriesSlot)
801 
802 /* static */
803 bool ModuleObject::isInstance(HandleValue value) {
804   return value.isObject() && value.toObject().is<ModuleObject>();
805 }
806 
807 // Declared as static function instead of ModuleObject method in order to
808 // avoid recursive #include dependency between frontend and VM.
GetFunctionDeclarations(ModuleObject * module)809 static frontend::FunctionDeclarationVector* GetFunctionDeclarations(
810     ModuleObject* module) {
811   Value value = module->getReservedSlot(ModuleObject::FunctionDeclarationsSlot);
812   if (value.isUndefined()) {
813     return nullptr;
814   }
815 
816   return static_cast<frontend::FunctionDeclarationVector*>(value.toPrivate());
817 }
818 
InitFunctionDeclarations(ModuleObject * module,frontend::FunctionDeclarationVector && decls)819 static void InitFunctionDeclarations(
820     ModuleObject* module, frontend::FunctionDeclarationVector&& decls) {
821   *GetFunctionDeclarations(module) = std::move(decls);
822 }
823 
824 /* static */
create(JSContext * cx)825 ModuleObject* ModuleObject::create(JSContext* cx) {
826   RootedObject proto(
827       cx, GlobalObject::getOrCreateModulePrototype(cx, cx->global()));
828   if (!proto) {
829     return nullptr;
830   }
831 
832   RootedModuleObject self(cx, NewObjectWithGivenProto<ModuleObject>(cx, proto));
833   if (!self) {
834     return nullptr;
835   }
836 
837   IndirectBindingMap* bindings = cx->new_<IndirectBindingMap>();
838   if (!bindings) {
839     return nullptr;
840   }
841 
842   InitReservedSlot(self, ImportBindingsSlot, bindings,
843                    MemoryUse::ModuleBindingMap);
844 
845   frontend::FunctionDeclarationVector* funDecls =
846       cx->new_<frontend::FunctionDeclarationVector>();
847   if (!funDecls) {
848     return nullptr;
849   }
850 
851   self->initReservedSlot(FunctionDeclarationsSlot, PrivateValue(funDecls));
852   return self;
853 }
854 
855 /* static */
finalize(JSFreeOp * fop,JSObject * obj)856 void ModuleObject::finalize(JSFreeOp* fop, JSObject* obj) {
857   MOZ_ASSERT(fop->maybeOnHelperThread());
858   ModuleObject* self = &obj->as<ModuleObject>();
859   if (self->hasImportBindings()) {
860     fop->delete_(obj, &self->importBindings(), MemoryUse::ModuleBindingMap);
861   }
862   if (frontend::FunctionDeclarationVector* funDecls =
863           GetFunctionDeclarations(self)) {
864     // Not tracked as these may move between zones on merge.
865     fop->deleteUntracked(funDecls);
866   }
867 }
868 
initialEnvironment() const869 ModuleEnvironmentObject& ModuleObject::initialEnvironment() const {
870   Value value = getReservedSlot(EnvironmentSlot);
871   return value.toObject().as<ModuleEnvironmentObject>();
872 }
873 
environment() const874 ModuleEnvironmentObject* ModuleObject::environment() const {
875   // Note that this it's valid to call this even if there was an error
876   // evaluating the module.
877 
878   // According to the spec the environment record is created during
879   // instantiation, but we create it earlier than that.
880   if (status() < MODULE_STATUS_LINKED) {
881     return nullptr;
882   }
883 
884   return &initialEnvironment();
885 }
886 
hasImportBindings() const887 bool ModuleObject::hasImportBindings() const {
888   // Import bindings may not be present if we hit OOM in initialization.
889   return !getReservedSlot(ImportBindingsSlot).isUndefined();
890 }
891 
importBindings()892 IndirectBindingMap& ModuleObject::importBindings() {
893   return *static_cast<IndirectBindingMap*>(
894       getReservedSlot(ImportBindingsSlot).toPrivate());
895 }
896 
namespace_()897 ModuleNamespaceObject* ModuleObject::namespace_() {
898   Value value = getReservedSlot(NamespaceSlot);
899   if (value.isUndefined()) {
900     return nullptr;
901   }
902   return &value.toObject().as<ModuleNamespaceObject>();
903 }
904 
scriptSourceObject() const905 ScriptSourceObject* ModuleObject::scriptSourceObject() const {
906   return &getReservedSlot(ScriptSourceObjectSlot)
907               .toObject()
908               .as<ScriptSourceObject>();
909 }
910 
initAsyncSlots(JSContext * cx,bool isAsync,HandleObject asyncParentModulesList)911 bool ModuleObject::initAsyncSlots(JSContext* cx, bool isAsync,
912                                   HandleObject asyncParentModulesList) {
913   initReservedSlot(AsyncSlot, BooleanValue(isAsync));
914   initReservedSlot(AsyncParentModulesSlot,
915                    ObjectValue(*asyncParentModulesList));
916   return true;
917 }
918 
919 constexpr uint32_t ASYNC_EVALUATING_POST_ORDER_FALSE = 0;
920 constexpr uint32_t ASYNC_EVALUATING_POST_ORDER_INIT = 1;
921 uint32_t AsyncPostOrder = ASYNC_EVALUATING_POST_ORDER_INIT;
922 
nextPostOrder()923 uint32_t nextPostOrder() {
924   uint32_t ordinal = AsyncPostOrder;
925   MOZ_ASSERT(AsyncPostOrder < MAX_UINT32);
926   AsyncPostOrder++;
927   return ordinal;
928 }
929 
initAsyncEvaluatingSlot()930 bool ModuleObject::initAsyncEvaluatingSlot() {
931   initReservedSlot(AsyncEvaluatingPostOrderSlot,
932                    PrivateUint32Value(nextPostOrder()));
933   return true;
934 }
935 
initScriptSlots(HandleScript script)936 void ModuleObject::initScriptSlots(HandleScript script) {
937   MOZ_ASSERT(script);
938   initReservedSlot(ScriptSlot, PrivateGCThingValue(script));
939   initReservedSlot(ScriptSourceObjectSlot,
940                    ObjectValue(*script->sourceObject()));
941 }
942 
setInitialEnvironment(HandleModuleEnvironmentObject initialEnvironment)943 void ModuleObject::setInitialEnvironment(
944     HandleModuleEnvironmentObject initialEnvironment) {
945   initReservedSlot(EnvironmentSlot, ObjectValue(*initialEnvironment));
946 }
947 
initStatusSlot()948 void ModuleObject::initStatusSlot() {
949   initReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_UNLINKED));
950 }
951 
initImportExportData(HandleArrayObject requestedModules,HandleArrayObject importEntries,HandleArrayObject localExportEntries,HandleArrayObject indirectExportEntries,HandleArrayObject starExportEntries)952 void ModuleObject::initImportExportData(HandleArrayObject requestedModules,
953                                         HandleArrayObject importEntries,
954                                         HandleArrayObject localExportEntries,
955                                         HandleArrayObject indirectExportEntries,
956                                         HandleArrayObject starExportEntries) {
957   initReservedSlot(RequestedModulesSlot, ObjectValue(*requestedModules));
958   initReservedSlot(ImportEntriesSlot, ObjectValue(*importEntries));
959   initReservedSlot(LocalExportEntriesSlot, ObjectValue(*localExportEntries));
960   initReservedSlot(IndirectExportEntriesSlot,
961                    ObjectValue(*indirectExportEntries));
962   initReservedSlot(StarExportEntriesSlot, ObjectValue(*starExportEntries));
963 }
964 
FreezeObjectProperty(JSContext * cx,HandleNativeObject obj,uint32_t slot)965 static bool FreezeObjectProperty(JSContext* cx, HandleNativeObject obj,
966                                  uint32_t slot) {
967   RootedObject property(cx, &obj->getSlot(slot).toObject());
968   return FreezeObject(cx, property);
969 }
970 
971 /* static */
Freeze(JSContext * cx,HandleModuleObject self)972 bool ModuleObject::Freeze(JSContext* cx, HandleModuleObject self) {
973   return FreezeObjectProperty(cx, self, RequestedModulesSlot) &&
974          FreezeObjectProperty(cx, self, ImportEntriesSlot) &&
975          FreezeObjectProperty(cx, self, LocalExportEntriesSlot) &&
976          FreezeObjectProperty(cx, self, IndirectExportEntriesSlot) &&
977          FreezeObjectProperty(cx, self, StarExportEntriesSlot) &&
978          FreezeObject(cx, self);
979 }
980 
981 #ifdef DEBUG
982 
CheckObjectFrozen(JSContext * cx,HandleObject obj,bool * result)983 static inline bool CheckObjectFrozen(JSContext* cx, HandleObject obj,
984                                      bool* result) {
985   return TestIntegrityLevel(cx, obj, IntegrityLevel::Frozen, result);
986 }
987 
CheckObjectPropertyFrozen(JSContext * cx,HandleNativeObject obj,uint32_t slot,bool * result)988 static inline bool CheckObjectPropertyFrozen(JSContext* cx,
989                                              HandleNativeObject obj,
990                                              uint32_t slot, bool* result) {
991   RootedObject property(cx, &obj->getSlot(slot).toObject());
992   return CheckObjectFrozen(cx, property, result);
993 }
994 
AssertFrozen(JSContext * cx,HandleModuleObject self)995 /* static */ inline bool ModuleObject::AssertFrozen(JSContext* cx,
996                                                     HandleModuleObject self) {
997   static const mozilla::EnumSet<ModuleSlot> slotsToCheck = {
998       RequestedModulesSlot, ImportEntriesSlot, LocalExportEntriesSlot,
999       IndirectExportEntriesSlot, StarExportEntriesSlot};
1000 
1001   bool frozen = false;
1002   for (auto slot : slotsToCheck) {
1003     if (!CheckObjectPropertyFrozen(cx, self, slot, &frozen)) {
1004       return false;
1005     }
1006     MOZ_ASSERT(frozen);
1007   }
1008 
1009   if (!CheckObjectFrozen(cx, self, &frozen)) {
1010     return false;
1011   }
1012   MOZ_ASSERT(frozen);
1013 
1014   return true;
1015 }
1016 
1017 #endif
1018 
AssertModuleScopesMatch(ModuleObject * module)1019 inline static void AssertModuleScopesMatch(ModuleObject* module) {
1020   MOZ_ASSERT(module->enclosingScope()->is<GlobalScope>());
1021   MOZ_ASSERT(IsGlobalLexicalEnvironment(
1022       &module->initialEnvironment().enclosingEnvironment()));
1023 }
1024 
fixEnvironmentsAfterRealmMerge()1025 void ModuleObject::fixEnvironmentsAfterRealmMerge() {
1026   AssertModuleScopesMatch(this);
1027   initialEnvironment().fixEnclosingEnvironmentAfterRealmMerge(
1028       script()->global());
1029   AssertModuleScopesMatch(this);
1030 }
1031 
maybeScript() const1032 JSScript* ModuleObject::maybeScript() const {
1033   Value value = getReservedSlot(ScriptSlot);
1034   if (value.isUndefined()) {
1035     return nullptr;
1036   }
1037   BaseScript* script = value.toGCThing()->as<BaseScript>();
1038   MOZ_ASSERT(script->hasBytecode(),
1039              "Module scripts should always have bytecode");
1040   return script->asJSScript();
1041 }
1042 
script() const1043 JSScript* ModuleObject::script() const {
1044   JSScript* ptr = maybeScript();
1045   MOZ_RELEASE_ASSERT(ptr);
1046   return ptr;
1047 }
1048 
AssertValidModuleStatus(ModuleStatus status)1049 static inline void AssertValidModuleStatus(ModuleStatus status) {
1050   MOZ_ASSERT(status >= MODULE_STATUS_UNLINKED &&
1051              status <= MODULE_STATUS_EVALUATED_ERROR);
1052 }
1053 
status() const1054 ModuleStatus ModuleObject::status() const {
1055   ModuleStatus status = getReservedSlot(StatusSlot).toInt32();
1056   AssertValidModuleStatus(status);
1057   return status;
1058 }
1059 
isAsync() const1060 bool ModuleObject::isAsync() const {
1061   return getReservedSlot(AsyncSlot).toBoolean();
1062 }
1063 
isAsyncEvaluating() const1064 bool ModuleObject::isAsyncEvaluating() const {
1065   if (getReservedSlot(AsyncEvaluatingPostOrderSlot).isUndefined()) {
1066     return false;
1067   }
1068   return getReservedSlot(AsyncEvaluatingPostOrderSlot).toPrivateUint32() !=
1069          ASYNC_EVALUATING_POST_ORDER_FALSE;
1070 }
1071 
setAsyncEvaluatingFalse()1072 void ModuleObject::setAsyncEvaluatingFalse() {
1073   if (AsyncPostOrder == getAsyncEvaluatingPostOrder()) {
1074     // If this condition is true, we can reset postOrder.
1075     // Graph is not re-entrant and any future modules will be independent from
1076     // this one.
1077     AsyncPostOrder = ASYNC_EVALUATING_POST_ORDER_INIT;
1078   }
1079   return setReservedSlot(AsyncEvaluatingPostOrderSlot,
1080                          PrivateUint32Value(ASYNC_EVALUATING_POST_ORDER_FALSE));
1081 }
1082 
dfsIndex() const1083 uint32_t ModuleObject::dfsIndex() const {
1084   return getReservedSlot(DFSIndexSlot).toInt32();
1085 }
1086 
dfsAncestorIndex() const1087 uint32_t ModuleObject::dfsAncestorIndex() const {
1088   return getReservedSlot(DFSAncestorIndexSlot).toInt32();
1089 }
1090 
topLevelCapability() const1091 JSObject* ModuleObject::topLevelCapability() const {
1092   Value capability = getReservedSlot(TopLevelCapabilitySlot);
1093   MOZ_RELEASE_ASSERT(capability.isObject());
1094   return &capability.toObject();
1095 }
1096 
createTopLevelCapability(JSContext * cx,HandleModuleObject module)1097 PromiseObject* ModuleObject::createTopLevelCapability(
1098     JSContext* cx, HandleModuleObject module) {
1099   MOZ_ASSERT(module->getReservedSlot(TopLevelCapabilitySlot).isUndefined());
1100   Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectForAsync(cx));
1101   if (!resultPromise) {
1102     return nullptr;
1103   }
1104   module->setInitialTopLevelCapability(resultPromise);
1105   return resultPromise;
1106 }
1107 
setInitialTopLevelCapability(HandleObject promiseObj)1108 void ModuleObject::setInitialTopLevelCapability(HandleObject promiseObj) {
1109   initReservedSlot(TopLevelCapabilitySlot, ObjectValue(*promiseObj));
1110 }
1111 
asyncParentModules() const1112 inline ListObject* ModuleObject::asyncParentModules() const {
1113   return &getReservedSlot(AsyncParentModulesSlot).toObject().as<ListObject>();
1114 }
1115 
appendAsyncParentModule(JSContext * cx,HandleModuleObject self,HandleModuleObject parent)1116 bool ModuleObject::appendAsyncParentModule(JSContext* cx,
1117                                            HandleModuleObject self,
1118                                            HandleModuleObject parent) {
1119   Rooted<Value> parentValue(cx, ObjectValue(*parent));
1120   return self->asyncParentModules()->append(cx, parentValue);
1121 }
1122 
pendingAsyncDependencies() const1123 uint32_t ModuleObject::pendingAsyncDependencies() const {
1124   return getReservedSlot(PendingAsyncDependenciesSlot).toInt32();
1125 }
1126 
getAsyncEvaluatingPostOrder() const1127 uint32_t ModuleObject::getAsyncEvaluatingPostOrder() const {
1128   MOZ_ASSERT(isAsyncEvaluating());
1129   return getReservedSlot(AsyncEvaluatingPostOrderSlot).toPrivateUint32();
1130 }
1131 
setPendingAsyncDependencies(uint32_t newValue)1132 void ModuleObject::setPendingAsyncDependencies(uint32_t newValue) {
1133   return setReservedSlot(PendingAsyncDependenciesSlot, NumberValue(newValue));
1134 }
1135 
setCycleRoot(ModuleObject * cycleRoot)1136 void ModuleObject::setCycleRoot(ModuleObject* cycleRoot) {
1137   return setReservedSlot(CycleRootSlot, ObjectValue(*cycleRoot));
1138 }
1139 
getCycleRoot() const1140 ModuleObject* ModuleObject::getCycleRoot() const {
1141   Value cycleRoot = getReservedSlot(CycleRootSlot);
1142   MOZ_RELEASE_ASSERT(cycleRoot.isObject());
1143   return &cycleRoot.toObject().as<ModuleObject>();
1144 }
1145 
hasTopLevelCapability() const1146 bool ModuleObject::hasTopLevelCapability() const {
1147   return !getReservedSlot(TopLevelCapabilitySlot).isUndefined();
1148 }
1149 
hadEvaluationError() const1150 bool ModuleObject::hadEvaluationError() const {
1151   return status() == MODULE_STATUS_EVALUATED_ERROR;
1152 }
1153 
setEvaluationError(HandleValue newValue)1154 void ModuleObject::setEvaluationError(HandleValue newValue) {
1155   setReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_EVALUATED_ERROR));
1156   return setReservedSlot(EvaluationErrorSlot, newValue);
1157 }
1158 
evaluationError() const1159 Value ModuleObject::evaluationError() const {
1160   MOZ_ASSERT(hadEvaluationError());
1161   return getReservedSlot(EvaluationErrorSlot);
1162 }
1163 
metaObject() const1164 JSObject* ModuleObject::metaObject() const {
1165   Value value = getReservedSlot(MetaObjectSlot);
1166   if (value.isObject()) {
1167     return &value.toObject();
1168   }
1169 
1170   MOZ_ASSERT(value.isUndefined());
1171   return nullptr;
1172 }
1173 
setMetaObject(JSObject * obj)1174 void ModuleObject::setMetaObject(JSObject* obj) {
1175   MOZ_ASSERT(obj);
1176   MOZ_ASSERT(!metaObject());
1177   setReservedSlot(MetaObjectSlot, ObjectValue(*obj));
1178 }
1179 
enclosingScope() const1180 Scope* ModuleObject::enclosingScope() const {
1181   return script()->enclosingScope();
1182 }
1183 
1184 /* static */
trace(JSTracer * trc,JSObject * obj)1185 void ModuleObject::trace(JSTracer* trc, JSObject* obj) {
1186   ModuleObject& module = obj->as<ModuleObject>();
1187 
1188   if (module.hasImportBindings()) {
1189     module.importBindings().trace(trc);
1190   }
1191 }
1192 
1193 /* static */
instantiateFunctionDeclarations(JSContext * cx,HandleModuleObject self)1194 bool ModuleObject::instantiateFunctionDeclarations(JSContext* cx,
1195                                                    HandleModuleObject self) {
1196 #ifdef DEBUG
1197   MOZ_ASSERT(self->status() == MODULE_STATUS_LINKING);
1198   if (!AssertFrozen(cx, self)) {
1199     return false;
1200   }
1201 #endif
1202   // |self| initially manages this vector.
1203   frontend::FunctionDeclarationVector* funDecls =
1204       GetFunctionDeclarations(self.get());
1205   if (!funDecls) {
1206     JS_ReportErrorASCII(
1207         cx, "Module function declarations have already been instantiated");
1208     return false;
1209   }
1210 
1211   RootedModuleEnvironmentObject env(cx, &self->initialEnvironment());
1212   RootedObject obj(cx);
1213   RootedValue value(cx);
1214   RootedFunction fun(cx);
1215   RootedPropertyName name(cx);
1216 
1217   for (GCThingIndex funIndex : *funDecls) {
1218     fun.set(self->script()->getFunction(funIndex));
1219     obj = Lambda(cx, fun, env);
1220     if (!obj) {
1221       return false;
1222     }
1223 
1224     name = fun->explicitName()->asPropertyName();
1225     value = ObjectValue(*obj);
1226     if (!SetProperty(cx, env, name, value)) {
1227       return false;
1228     }
1229   }
1230 
1231   // Transfer ownership of the vector from |self|, then free the vector, once
1232   // its contents are no longer needed.
1233   self->setReservedSlot(FunctionDeclarationsSlot, UndefinedValue());
1234   js_delete(funDecls);
1235   return true;
1236 }
1237 
1238 /* static */
execute(JSContext * cx,HandleModuleObject self,MutableHandleValue rval)1239 bool ModuleObject::execute(JSContext* cx, HandleModuleObject self,
1240                            MutableHandleValue rval) {
1241 #ifdef DEBUG
1242   MOZ_ASSERT(self->status() == MODULE_STATUS_EVALUATING ||
1243              self->status() == MODULE_STATUS_EVALUATED);
1244   if (!AssertFrozen(cx, self)) {
1245     return false;
1246   }
1247 #endif
1248 
1249   RootedScript script(cx, self->script());
1250 
1251   // The top-level script if a module is only ever executed once. Clear the
1252   // reference at exit to prevent us keeping this alive unnecessarily. This is
1253   // kept while executing so it is available to the debugger.
1254   auto guardA = mozilla::MakeScopeExit(
1255       [&] { self->setReservedSlot(ScriptSlot, UndefinedValue()); });
1256 
1257   RootedModuleEnvironmentObject env(cx, self->environment());
1258   if (!env) {
1259     JS_ReportErrorASCII(cx,
1260                         "Module declarations have not yet been instantiated");
1261     return false;
1262   }
1263 
1264   return Execute(cx, script, env, rval);
1265 }
1266 
1267 /* static */
createNamespace(JSContext * cx,HandleModuleObject self,HandleObject exports)1268 ModuleNamespaceObject* ModuleObject::createNamespace(JSContext* cx,
1269                                                      HandleModuleObject self,
1270                                                      HandleObject exports) {
1271   MOZ_ASSERT(!self->namespace_());
1272   MOZ_ASSERT(exports->is<ArrayObject>());
1273 
1274   auto bindings = cx->make_unique<IndirectBindingMap>();
1275   if (!bindings) {
1276     return nullptr;
1277   }
1278 
1279   auto ns = ModuleNamespaceObject::create(cx, self, exports.as<ArrayObject>(),
1280                                           std::move(bindings));
1281   if (!ns) {
1282     return nullptr;
1283   }
1284 
1285   self->initReservedSlot(NamespaceSlot, ObjectValue(*ns));
1286   return ns;
1287 }
1288 
1289 /* static */
createEnvironment(JSContext * cx,HandleModuleObject self)1290 bool ModuleObject::createEnvironment(JSContext* cx, HandleModuleObject self) {
1291   RootedModuleEnvironmentObject env(cx,
1292                                     ModuleEnvironmentObject::create(cx, self));
1293   if (!env) {
1294     return false;
1295   }
1296 
1297   self->setInitialEnvironment(env);
1298   return true;
1299 }
1300 
InvokeSelfHostedMethod(JSContext * cx,HandleModuleObject self,HandlePropertyName name,MutableHandleValue rval)1301 static bool InvokeSelfHostedMethod(JSContext* cx, HandleModuleObject self,
1302                                    HandlePropertyName name,
1303                                    MutableHandleValue rval) {
1304   RootedValue thisv(cx, ObjectValue(*self));
1305   FixedInvokeArgs<0> args(cx);
1306 
1307   return CallSelfHostedFunction(cx, name, thisv, args, rval);
1308 }
1309 
1310 /* static */
Instantiate(JSContext * cx,HandleModuleObject self)1311 bool ModuleObject::Instantiate(JSContext* cx, HandleModuleObject self) {
1312   RootedValue ignored(cx);
1313   return InvokeSelfHostedMethod(cx, self, cx->names().ModuleInstantiate,
1314                                 &ignored);
1315 }
1316 
1317 /* static */
Evaluate(JSContext * cx,HandleModuleObject self,MutableHandleValue rval)1318 bool ModuleObject::Evaluate(JSContext* cx, HandleModuleObject self,
1319                             MutableHandleValue rval) {
1320   return InvokeSelfHostedMethod(cx, self, cx->names().ModuleEvaluate, rval);
1321 }
1322 
1323 /* static */
GetOrCreateModuleNamespace(JSContext * cx,HandleModuleObject self)1324 ModuleNamespaceObject* ModuleObject::GetOrCreateModuleNamespace(
1325     JSContext* cx, HandleModuleObject self) {
1326   FixedInvokeArgs<1> args(cx);
1327   args[0].setObject(*self);
1328 
1329   RootedValue result(cx);
1330   if (!CallSelfHostedFunction(cx, cx->names().GetModuleNamespace,
1331                               UndefinedHandleValue, args, &result)) {
1332     return nullptr;
1333   }
1334 
1335   return &result.toObject().as<ModuleNamespaceObject>();
1336 }
1337 
DEFINE_GETTER_FUNCTIONS(ModuleObject,namespace_,NamespaceSlot)1338 DEFINE_GETTER_FUNCTIONS(ModuleObject, namespace_, NamespaceSlot)
1339 DEFINE_GETTER_FUNCTIONS(ModuleObject, status, StatusSlot)
1340 DEFINE_GETTER_FUNCTIONS(ModuleObject, evaluationError, EvaluationErrorSlot)
1341 DEFINE_GETTER_FUNCTIONS(ModuleObject, requestedModules, RequestedModulesSlot)
1342 DEFINE_GETTER_FUNCTIONS(ModuleObject, importEntries, ImportEntriesSlot)
1343 DEFINE_GETTER_FUNCTIONS(ModuleObject, localExportEntries,
1344                         LocalExportEntriesSlot)
1345 DEFINE_GETTER_FUNCTIONS(ModuleObject, indirectExportEntries,
1346                         IndirectExportEntriesSlot)
1347 DEFINE_GETTER_FUNCTIONS(ModuleObject, starExportEntries, StarExportEntriesSlot)
1348 DEFINE_GETTER_FUNCTIONS(ModuleObject, dfsIndex, DFSIndexSlot)
1349 DEFINE_GETTER_FUNCTIONS(ModuleObject, dfsAncestorIndex, DFSAncestorIndexSlot)
1350 DEFINE_GETTER_FUNCTIONS(ModuleObject, async, AsyncSlot)
1351 DEFINE_GETTER_FUNCTIONS(ModuleObject, topLevelCapability,
1352                         TopLevelCapabilitySlot)
1353 DEFINE_GETTER_FUNCTIONS(ModuleObject, asyncEvaluatingPostOrder,
1354                         AsyncEvaluatingPostOrderSlot)
1355 DEFINE_GETTER_FUNCTIONS(ModuleObject, asyncParentModules,
1356                         AsyncParentModulesSlot)
1357 DEFINE_GETTER_FUNCTIONS(ModuleObject, pendingAsyncDependencies,
1358                         PendingAsyncDependenciesSlot)
1359 
1360 /* static */
1361 bool GlobalObject::initModuleProto(JSContext* cx,
1362                                    Handle<GlobalObject*> global) {
1363   static const JSPropertySpec protoAccessors[] = {
1364       JS_PSG("namespace", ModuleObject_namespace_Getter, 0),
1365       JS_PSG("status", ModuleObject_statusGetter, 0),
1366       JS_PSG("evaluationError", ModuleObject_evaluationErrorGetter, 0),
1367       JS_PSG("requestedModules", ModuleObject_requestedModulesGetter, 0),
1368       JS_PSG("importEntries", ModuleObject_importEntriesGetter, 0),
1369       JS_PSG("localExportEntries", ModuleObject_localExportEntriesGetter, 0),
1370       JS_PSG("indirectExportEntries", ModuleObject_indirectExportEntriesGetter,
1371              0),
1372       JS_PSG("starExportEntries", ModuleObject_starExportEntriesGetter, 0),
1373       JS_PSG("dfsIndex", ModuleObject_dfsIndexGetter, 0),
1374       JS_PSG("dfsAncestorIndex", ModuleObject_dfsAncestorIndexGetter, 0),
1375       JS_PSG("async", ModuleObject_asyncGetter, 0),
1376       JS_PSG("topLevelCapability", ModuleObject_topLevelCapabilityGetter, 0),
1377       JS_PSG("asyncEvaluatingPostOrder",
1378              ModuleObject_asyncEvaluatingPostOrderGetter, 0),
1379       JS_PSG("asyncParentModules", ModuleObject_asyncParentModulesGetter, 0),
1380       JS_PSG("pendingAsyncDependencies",
1381              ModuleObject_pendingAsyncDependenciesGetter, 0),
1382       JS_PS_END};
1383 
1384   static const JSFunctionSpec protoFunctions[] = {
1385       JS_SELF_HOSTED_FN("getExportedNames", "ModuleGetExportedNames", 1, 0),
1386       JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 2, 0),
1387       JS_SELF_HOSTED_FN("declarationInstantiation", "ModuleInstantiate", 0, 0),
1388       JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluate", 0, 0),
1389       JS_SELF_HOSTED_FN("gatherAsyncParentCompletions",
1390                         "GatherAsyncParentCompletions", 2, 0),
1391       JS_FS_END};
1392 
1393   RootedObject proto(
1394       cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
1395   if (!proto) {
1396     return false;
1397   }
1398 
1399   if (!DefinePropertiesAndFunctions(cx, proto, protoAccessors,
1400                                     protoFunctions)) {
1401     return false;
1402   }
1403 
1404   global->setReservedSlot(MODULE_PROTO, ObjectValue(*proto));
1405   return true;
1406 }
1407 
1408 #undef DEFINE_GETTER_FUNCTIONS
1409 #undef DEFINE_STRING_ACCESSOR_METHOD
1410 #undef DEFINE_ARRAY_SLOT_ACCESSOR
1411 
1412 ///////////////////////////////////////////////////////////////////////////
1413 // ModuleBuilder
1414 
ModuleBuilder(JSContext * cx,const frontend::EitherParser & eitherParser)1415 ModuleBuilder::ModuleBuilder(JSContext* cx,
1416                              const frontend::EitherParser& eitherParser)
1417     : cx_(cx),
1418       eitherParser_(eitherParser),
1419       requestedModuleSpecifiers_(cx),
1420       importEntries_(cx),
1421       exportEntries_(cx),
1422       exportNames_(cx) {}
1423 
noteFunctionDeclaration(JSContext * cx,uint32_t funIndex)1424 bool ModuleBuilder::noteFunctionDeclaration(JSContext* cx, uint32_t funIndex) {
1425   if (!functionDecls_.emplaceBack(funIndex)) {
1426     js::ReportOutOfMemory(cx);
1427     return false;
1428   }
1429   return true;
1430 }
1431 
noteAsync(frontend::StencilModuleMetadata & metadata)1432 void ModuleBuilder::noteAsync(frontend::StencilModuleMetadata& metadata) {
1433   metadata.isAsync = true;
1434 }
1435 
buildTables(frontend::StencilModuleMetadata & metadata)1436 bool ModuleBuilder::buildTables(frontend::StencilModuleMetadata& metadata) {
1437   // https://tc39.es/ecma262/#sec-parsemodule
1438   // 15.2.1.17.1 ParseModule, Steps 4-11.
1439 
1440   // Step 4.
1441   metadata.requestedModules = std::move(requestedModules_);
1442 
1443   // Step 5.
1444   if (!metadata.importEntries.reserve(importEntries_.count())) {
1445     js::ReportOutOfMemory(cx_);
1446     return false;
1447   }
1448   for (auto r = importEntries_.all(); !r.empty(); r.popFront()) {
1449     frontend::StencilModuleEntry& entry = r.front().value();
1450     metadata.importEntries.infallibleAppend(entry);
1451   }
1452 
1453   // Steps 6-11.
1454   for (const frontend::StencilModuleEntry& exp : exportEntries_) {
1455     if (!exp.specifier) {
1456       frontend::StencilModuleEntry* importEntry = importEntryFor(exp.localName);
1457       if (!importEntry) {
1458         if (!metadata.localExportEntries.append(exp)) {
1459           js::ReportOutOfMemory(cx_);
1460           return false;
1461         }
1462       } else {
1463         if (!importEntry->importName) {
1464           if (!metadata.localExportEntries.append(exp)) {
1465             js::ReportOutOfMemory(cx_);
1466             return false;
1467           }
1468         } else {
1469           // All names should have already been marked as used-by-stencil.
1470           auto entry = frontend::StencilModuleEntry::exportFromEntry(
1471               importEntry->specifier, importEntry->importName, exp.exportName,
1472               exp.lineno, exp.column);
1473           if (!metadata.indirectExportEntries.append(entry)) {
1474             js::ReportOutOfMemory(cx_);
1475             return false;
1476           }
1477         }
1478       }
1479     } else if (!exp.importName && !exp.exportName) {
1480       if (!metadata.starExportEntries.append(exp)) {
1481         js::ReportOutOfMemory(cx_);
1482         return false;
1483       }
1484     } else {
1485       if (!metadata.indirectExportEntries.append(exp)) {
1486         js::ReportOutOfMemory(cx_);
1487         return false;
1488       }
1489     }
1490   }
1491 
1492   return true;
1493 }
1494 
finishFunctionDecls(frontend::StencilModuleMetadata & metadata)1495 void ModuleBuilder::finishFunctionDecls(
1496     frontend::StencilModuleMetadata& metadata) {
1497   metadata.functionDecls = std::move(functionDecls_);
1498 }
1499 
1500 enum class ModuleArrayType {
1501   ImportEntryObject,
1502   ExportEntryObject,
1503   RequestedModuleObject,
1504 };
1505 
ModuleBuilderInitArray(JSContext * cx,frontend::CompilationAtomCache & atomCache,ModuleArrayType arrayType,const frontend::StencilModuleMetadata::EntryVector & vector)1506 static ArrayObject* ModuleBuilderInitArray(
1507     JSContext* cx, frontend::CompilationAtomCache& atomCache,
1508     ModuleArrayType arrayType,
1509     const frontend::StencilModuleMetadata::EntryVector& vector) {
1510   RootedArrayObject resultArray(
1511       cx, NewDenseFullyAllocatedArray(cx, vector.length()));
1512   if (!resultArray) {
1513     return nullptr;
1514   }
1515 
1516   resultArray->ensureDenseInitializedLength(0, vector.length());
1517 
1518   RootedAtom specifier(cx);
1519   RootedAtom localName(cx);
1520   RootedAtom importName(cx);
1521   RootedAtom exportName(cx);
1522   RootedObject req(cx);
1523   RootedObject moduleRequest(cx);
1524 
1525   for (uint32_t i = 0; i < vector.length(); ++i) {
1526     const frontend::StencilModuleEntry& entry = vector[i];
1527 
1528     if (entry.specifier) {
1529       specifier = atomCache.getExistingAtomAt(cx, entry.specifier);
1530       MOZ_ASSERT(specifier);
1531     } else {
1532       MOZ_ASSERT(!specifier);
1533     }
1534 
1535     if (entry.localName) {
1536       localName = atomCache.getExistingAtomAt(cx, entry.localName);
1537       MOZ_ASSERT(localName);
1538     } else {
1539       MOZ_ASSERT(!localName);
1540     }
1541 
1542     if (entry.importName) {
1543       importName = atomCache.getExistingAtomAt(cx, entry.importName);
1544       MOZ_ASSERT(importName);
1545     } else {
1546       importName = nullptr;
1547     }
1548 
1549     if (entry.exportName) {
1550       exportName = atomCache.getExistingAtomAt(cx, entry.exportName);
1551       MOZ_ASSERT(exportName);
1552     } else {
1553       MOZ_ASSERT(!exportName);
1554     }
1555 
1556     moduleRequest = ModuleRequestObject::create(cx, specifier);
1557     if (!moduleRequest) {
1558       return nullptr;
1559     }
1560 
1561     switch (arrayType) {
1562       case ModuleArrayType::ImportEntryObject:
1563         MOZ_ASSERT(localName);
1564         req = ImportEntryObject::create(cx, moduleRequest, importName,
1565                                         localName, entry.lineno, entry.column);
1566         break;
1567       case ModuleArrayType::ExportEntryObject:
1568         req =
1569             ExportEntryObject::create(cx, exportName, moduleRequest, importName,
1570                                       localName, entry.lineno, entry.column);
1571         break;
1572       case ModuleArrayType::RequestedModuleObject:
1573         req = RequestedModuleObject::create(cx, moduleRequest, entry.lineno,
1574                                             entry.column);
1575         // TODO: Make this consistent with other object types.
1576         if (req && !FreezeObject(cx, req)) {
1577           return nullptr;
1578         }
1579         break;
1580     }
1581     if (!req) {
1582       return nullptr;
1583     }
1584     resultArray->initDenseElement(i, ObjectValue(*req));
1585   }
1586 
1587   return resultArray;
1588 }
1589 
1590 // Use StencilModuleMetadata data to fill in ModuleObject
initModule(JSContext * cx,frontend::CompilationAtomCache & atomCache,JS::Handle<ModuleObject * > module) const1591 bool frontend::StencilModuleMetadata::initModule(
1592     JSContext* cx, frontend::CompilationAtomCache& atomCache,
1593     JS::Handle<ModuleObject*> module) const {
1594   RootedArrayObject requestedModulesObject(
1595       cx, ModuleBuilderInitArray(cx, atomCache,
1596                                  ModuleArrayType::RequestedModuleObject,
1597                                  requestedModules));
1598   if (!requestedModulesObject) {
1599     return false;
1600   }
1601 
1602   RootedArrayObject importEntriesObject(
1603       cx,
1604       ModuleBuilderInitArray(cx, atomCache, ModuleArrayType::ImportEntryObject,
1605                              importEntries));
1606   if (!importEntriesObject) {
1607     return false;
1608   }
1609 
1610   RootedArrayObject localExportEntriesObject(
1611       cx,
1612       ModuleBuilderInitArray(cx, atomCache, ModuleArrayType::ExportEntryObject,
1613                              localExportEntries));
1614   if (!localExportEntriesObject) {
1615     return false;
1616   }
1617 
1618   RootedArrayObject indirectExportEntriesObject(
1619       cx,
1620       ModuleBuilderInitArray(cx, atomCache, ModuleArrayType::ExportEntryObject,
1621                              indirectExportEntries));
1622   if (!indirectExportEntriesObject) {
1623     return false;
1624   }
1625 
1626   RootedArrayObject starExportEntriesObject(
1627       cx,
1628       ModuleBuilderInitArray(cx, atomCache, ModuleArrayType::ExportEntryObject,
1629                              starExportEntries));
1630   if (!starExportEntriesObject) {
1631     return false;
1632   }
1633 
1634   // Copy the vector of declarations to the ModuleObject.
1635   FunctionDeclarationVector functionDeclsCopy;
1636   if (!functionDeclsCopy.appendAll(functionDecls)) {
1637     js::ReportOutOfMemory(cx);
1638     return false;
1639   }
1640   InitFunctionDeclarations(module.get(), std::move(functionDeclsCopy));
1641 
1642   Rooted<ListObject*> asyncParentModulesList(cx, ListObject::create(cx));
1643   if (!asyncParentModulesList) {
1644     return false;
1645   }
1646 
1647   if (!module->initAsyncSlots(cx, isAsync, asyncParentModulesList)) {
1648     return false;
1649   }
1650 
1651   module->initImportExportData(
1652       requestedModulesObject, importEntriesObject, localExportEntriesObject,
1653       indirectExportEntriesObject, starExportEntriesObject);
1654 
1655   return true;
1656 }
1657 
processImport(frontend::BinaryNode * importNode)1658 bool ModuleBuilder::processImport(frontend::BinaryNode* importNode) {
1659   using namespace js::frontend;
1660 
1661   MOZ_ASSERT(importNode->isKind(ParseNodeKind::ImportDecl));
1662 
1663   auto* specList = &importNode->left()->as<ListNode>();
1664   MOZ_ASSERT(specList->isKind(ParseNodeKind::ImportSpecList));
1665 
1666   auto* moduleSpec = &importNode->right()->as<NameNode>();
1667   MOZ_ASSERT(moduleSpec->isKind(ParseNodeKind::StringExpr));
1668 
1669   auto module = moduleSpec->atom();
1670   if (!maybeAppendRequestedModule(module, moduleSpec)) {
1671     return false;
1672   }
1673 
1674   for (ParseNode* item : specList->contents()) {
1675     uint32_t line;
1676     uint32_t column;
1677     eitherParser_.computeLineAndColumn(item->pn_pos.begin, &line, &column);
1678 
1679     StencilModuleEntry entry;
1680     TaggedParserAtomIndex localName;
1681     if (item->isKind(ParseNodeKind::ImportSpec)) {
1682       auto* spec = &item->as<BinaryNode>();
1683 
1684       auto* importNameNode = &spec->left()->as<NameNode>();
1685       auto* localNameNode = &spec->right()->as<NameNode>();
1686 
1687       auto importName = importNameNode->atom();
1688       localName = localNameNode->atom();
1689 
1690       markUsedByStencil(module);
1691       markUsedByStencil(localName);
1692       markUsedByStencil(importName);
1693       entry = StencilModuleEntry::importEntry(module, localName, importName,
1694                                               line, column);
1695     } else {
1696       MOZ_ASSERT(item->isKind(ParseNodeKind::ImportNamespaceSpec));
1697       auto* spec = &item->as<UnaryNode>();
1698 
1699       auto* localNameNode = &spec->kid()->as<NameNode>();
1700 
1701       localName = localNameNode->atom();
1702 
1703       markUsedByStencil(module);
1704       markUsedByStencil(localName);
1705       entry = StencilModuleEntry::importNamespaceEntry(module, localName, line,
1706                                                        column);
1707     }
1708     if (!importEntries_.put(localName, entry)) {
1709       return false;
1710     }
1711   }
1712 
1713   return true;
1714 }
1715 
processExport(frontend::ParseNode * exportNode)1716 bool ModuleBuilder::processExport(frontend::ParseNode* exportNode) {
1717   using namespace js::frontend;
1718 
1719   MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportStmt) ||
1720              exportNode->isKind(ParseNodeKind::ExportDefaultStmt));
1721 
1722   bool isDefault = exportNode->isKind(ParseNodeKind::ExportDefaultStmt);
1723   ParseNode* kid = isDefault ? exportNode->as<BinaryNode>().left()
1724                              : exportNode->as<UnaryNode>().kid();
1725 
1726   if (isDefault && exportNode->as<BinaryNode>().right()) {
1727     // This is an export default containing an expression.
1728     auto localName = TaggedParserAtomIndex::WellKnown::default_();
1729     auto exportName = TaggedParserAtomIndex::WellKnown::default_();
1730     return appendExportEntry(exportName, localName);
1731   }
1732 
1733   switch (kid->getKind()) {
1734     case ParseNodeKind::ExportSpecList: {
1735       MOZ_ASSERT(!isDefault);
1736       for (ParseNode* item : kid->as<ListNode>().contents()) {
1737         BinaryNode* spec = &item->as<BinaryNode>();
1738         MOZ_ASSERT(spec->isKind(ParseNodeKind::ExportSpec));
1739 
1740         NameNode* localNameNode = &spec->left()->as<NameNode>();
1741         NameNode* exportNameNode = &spec->right()->as<NameNode>();
1742 
1743         auto localName = localNameNode->atom();
1744         auto exportName = exportNameNode->atom();
1745 
1746         if (!appendExportEntry(exportName, localName, spec)) {
1747           return false;
1748         }
1749       }
1750       break;
1751     }
1752 
1753     case ParseNodeKind::ClassDecl: {
1754       const ClassNode& cls = kid->as<ClassNode>();
1755       MOZ_ASSERT(cls.names());
1756       auto localName = cls.names()->innerBinding()->atom();
1757       auto exportName =
1758           isDefault ? TaggedParserAtomIndex::WellKnown::default_() : localName;
1759       if (!appendExportEntry(exportName, localName)) {
1760         return false;
1761       }
1762       break;
1763     }
1764 
1765     case ParseNodeKind::VarStmt:
1766     case ParseNodeKind::ConstDecl:
1767     case ParseNodeKind::LetDecl: {
1768       for (ParseNode* binding : kid->as<ListNode>().contents()) {
1769         if (binding->isKind(ParseNodeKind::AssignExpr)) {
1770           binding = binding->as<AssignmentNode>().left();
1771         } else {
1772           MOZ_ASSERT(binding->isKind(ParseNodeKind::Name));
1773         }
1774 
1775         if (binding->isKind(ParseNodeKind::Name)) {
1776           auto localName = binding->as<NameNode>().atom();
1777           auto exportName = isDefault
1778                                 ? TaggedParserAtomIndex::WellKnown::default_()
1779                                 : localName;
1780           if (!appendExportEntry(exportName, localName)) {
1781             return false;
1782           }
1783         } else if (binding->isKind(ParseNodeKind::ArrayExpr)) {
1784           if (!processExportArrayBinding(&binding->as<ListNode>())) {
1785             return false;
1786           }
1787         } else {
1788           MOZ_ASSERT(binding->isKind(ParseNodeKind::ObjectExpr));
1789           if (!processExportObjectBinding(&binding->as<ListNode>())) {
1790             return false;
1791           }
1792         }
1793       }
1794       break;
1795     }
1796 
1797     case ParseNodeKind::Function: {
1798       FunctionBox* box = kid->as<FunctionNode>().funbox();
1799       MOZ_ASSERT(!box->isArrow());
1800       auto localName = box->explicitName();
1801       auto exportName =
1802           isDefault ? TaggedParserAtomIndex::WellKnown::default_() : localName;
1803       if (!appendExportEntry(exportName, localName)) {
1804         return false;
1805       }
1806       break;
1807     }
1808 
1809     default:
1810       MOZ_CRASH("Unexpected parse node");
1811   }
1812 
1813   return true;
1814 }
1815 
processExportBinding(frontend::ParseNode * binding)1816 bool ModuleBuilder::processExportBinding(frontend::ParseNode* binding) {
1817   using namespace js::frontend;
1818 
1819   if (binding->isKind(ParseNodeKind::Name)) {
1820     auto name = binding->as<NameNode>().atom();
1821     return appendExportEntry(name, name);
1822   }
1823 
1824   if (binding->isKind(ParseNodeKind::ArrayExpr)) {
1825     return processExportArrayBinding(&binding->as<ListNode>());
1826   }
1827 
1828   MOZ_ASSERT(binding->isKind(ParseNodeKind::ObjectExpr));
1829   return processExportObjectBinding(&binding->as<ListNode>());
1830 }
1831 
processExportArrayBinding(frontend::ListNode * array)1832 bool ModuleBuilder::processExportArrayBinding(frontend::ListNode* array) {
1833   using namespace js::frontend;
1834 
1835   MOZ_ASSERT(array->isKind(ParseNodeKind::ArrayExpr));
1836 
1837   for (ParseNode* node : array->contents()) {
1838     if (node->isKind(ParseNodeKind::Elision)) {
1839       continue;
1840     }
1841 
1842     if (node->isKind(ParseNodeKind::Spread)) {
1843       node = node->as<UnaryNode>().kid();
1844     } else if (node->isKind(ParseNodeKind::AssignExpr)) {
1845       node = node->as<AssignmentNode>().left();
1846     }
1847 
1848     if (!processExportBinding(node)) {
1849       return false;
1850     }
1851   }
1852 
1853   return true;
1854 }
1855 
processExportObjectBinding(frontend::ListNode * obj)1856 bool ModuleBuilder::processExportObjectBinding(frontend::ListNode* obj) {
1857   using namespace js::frontend;
1858 
1859   MOZ_ASSERT(obj->isKind(ParseNodeKind::ObjectExpr));
1860 
1861   for (ParseNode* node : obj->contents()) {
1862     MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
1863                node->isKind(ParseNodeKind::PropertyDefinition) ||
1864                node->isKind(ParseNodeKind::Shorthand) ||
1865                node->isKind(ParseNodeKind::Spread));
1866 
1867     ParseNode* target;
1868     if (node->isKind(ParseNodeKind::Spread)) {
1869       target = node->as<UnaryNode>().kid();
1870     } else {
1871       if (node->isKind(ParseNodeKind::MutateProto)) {
1872         target = node->as<UnaryNode>().kid();
1873       } else {
1874         target = node->as<BinaryNode>().right();
1875       }
1876 
1877       if (target->isKind(ParseNodeKind::AssignExpr)) {
1878         target = target->as<AssignmentNode>().left();
1879       }
1880     }
1881 
1882     if (!processExportBinding(target)) {
1883       return false;
1884     }
1885   }
1886 
1887   return true;
1888 }
1889 
processExportFrom(frontend::BinaryNode * exportNode)1890 bool ModuleBuilder::processExportFrom(frontend::BinaryNode* exportNode) {
1891   using namespace js::frontend;
1892 
1893   MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportFromStmt));
1894 
1895   auto* specList = &exportNode->left()->as<ListNode>();
1896   MOZ_ASSERT(specList->isKind(ParseNodeKind::ExportSpecList));
1897 
1898   auto* moduleSpec = &exportNode->right()->as<NameNode>();
1899   MOZ_ASSERT(moduleSpec->isKind(ParseNodeKind::StringExpr));
1900 
1901   auto module = moduleSpec->atom();
1902 
1903   if (!maybeAppendRequestedModule(module, moduleSpec)) {
1904     return false;
1905   }
1906 
1907   for (ParseNode* spec : specList->contents()) {
1908     uint32_t line;
1909     uint32_t column;
1910     eitherParser_.computeLineAndColumn(spec->pn_pos.begin, &line, &column);
1911 
1912     StencilModuleEntry entry;
1913     TaggedParserAtomIndex exportName;
1914     if (spec->isKind(ParseNodeKind::ExportSpec)) {
1915       auto* importNameNode = &spec->as<BinaryNode>().left()->as<NameNode>();
1916       auto* exportNameNode = &spec->as<BinaryNode>().right()->as<NameNode>();
1917 
1918       auto importName = importNameNode->atom();
1919       exportName = exportNameNode->atom();
1920 
1921       markUsedByStencil(module);
1922       markUsedByStencil(importName);
1923       markUsedByStencil(exportName);
1924       entry = StencilModuleEntry::exportFromEntry(module, importName,
1925                                                   exportName, line, column);
1926     } else if (spec->isKind(ParseNodeKind::ExportNamespaceSpec)) {
1927       auto* exportNameNode = &spec->as<UnaryNode>().kid()->as<NameNode>();
1928 
1929       exportName = exportNameNode->atom();
1930 
1931       markUsedByStencil(module);
1932       markUsedByStencil(exportName);
1933       entry = StencilModuleEntry::exportNamespaceFromEntry(module, exportName,
1934                                                            line, column);
1935     } else {
1936       MOZ_ASSERT(spec->isKind(ParseNodeKind::ExportBatchSpecStmt));
1937 
1938       markUsedByStencil(module);
1939       entry = StencilModuleEntry::exportBatchFromEntry(module, line, column);
1940     }
1941 
1942     if (!exportEntries_.append(entry)) {
1943       return false;
1944     }
1945     if (exportName && !exportNames_.put(exportName)) {
1946       return false;
1947     }
1948   }
1949 
1950   return true;
1951 }
1952 
importEntryFor(frontend::TaggedParserAtomIndex localName) const1953 frontend::StencilModuleEntry* ModuleBuilder::importEntryFor(
1954     frontend::TaggedParserAtomIndex localName) const {
1955   MOZ_ASSERT(localName);
1956   auto ptr = importEntries_.lookup(localName);
1957   if (!ptr) {
1958     return nullptr;
1959   }
1960 
1961   return &ptr->value();
1962 }
1963 
hasExportedName(frontend::TaggedParserAtomIndex name) const1964 bool ModuleBuilder::hasExportedName(
1965     frontend::TaggedParserAtomIndex name) const {
1966   MOZ_ASSERT(name);
1967   return exportNames_.has(name);
1968 }
1969 
appendExportEntry(frontend::TaggedParserAtomIndex exportName,frontend::TaggedParserAtomIndex localName,frontend::ParseNode * node)1970 bool ModuleBuilder::appendExportEntry(
1971     frontend::TaggedParserAtomIndex exportName,
1972     frontend::TaggedParserAtomIndex localName, frontend::ParseNode* node) {
1973   uint32_t line = 0;
1974   uint32_t column = 0;
1975   if (node) {
1976     eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
1977   }
1978 
1979   markUsedByStencil(localName);
1980   markUsedByStencil(exportName);
1981   auto entry = frontend::StencilModuleEntry::exportAsEntry(
1982       localName, exportName, line, column);
1983   if (!exportEntries_.append(entry)) {
1984     return false;
1985   }
1986 
1987   if (!exportNames_.put(exportName)) {
1988     return false;
1989   }
1990 
1991   return true;
1992 }
1993 
maybeAppendRequestedModule(frontend::TaggedParserAtomIndex specifier,frontend::ParseNode * node)1994 bool ModuleBuilder::maybeAppendRequestedModule(
1995     frontend::TaggedParserAtomIndex specifier, frontend::ParseNode* node) {
1996   if (requestedModuleSpecifiers_.has(specifier)) {
1997     return true;
1998   }
1999 
2000   uint32_t line;
2001   uint32_t column;
2002   eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
2003 
2004   markUsedByStencil(specifier);
2005   auto entry =
2006       frontend::StencilModuleEntry::moduleRequest(specifier, line, column);
2007   if (!requestedModules_.append(entry)) {
2008     js::ReportOutOfMemory(cx_);
2009     return false;
2010   }
2011 
2012   return requestedModuleSpecifiers_.put(specifier);
2013 }
2014 
markUsedByStencil(frontend::TaggedParserAtomIndex name)2015 void ModuleBuilder::markUsedByStencil(frontend::TaggedParserAtomIndex name) {
2016   eitherParser_.parserAtoms().markUsedByStencil(name);
2017 }
2018 
2019 template <typename T>
CreateArray(JSContext * cx,const JS::Rooted<GCVector<T>> & vector)2020 ArrayObject* js::CreateArray(JSContext* cx,
2021                              const JS::Rooted<GCVector<T>>& vector) {
2022   uint32_t length = vector.length();
2023   RootedArrayObject array(cx, NewDenseFullyAllocatedArray(cx, length));
2024   if (!array) {
2025     return nullptr;
2026   }
2027 
2028   array->setDenseInitializedLength(length);
2029   for (uint32_t i = 0; i < length; i++) {
2030     array->initDenseElement(i, ObjectValue(*vector[i]));
2031   }
2032 
2033   return array;
2034 }
2035 
GetOrCreateModuleMetaObject(JSContext * cx,HandleObject moduleArg)2036 JSObject* js::GetOrCreateModuleMetaObject(JSContext* cx,
2037                                           HandleObject moduleArg) {
2038   HandleModuleObject module = moduleArg.as<ModuleObject>();
2039   if (JSObject* obj = module->metaObject()) {
2040     return obj;
2041   }
2042 
2043   RootedObject metaObject(cx,
2044                           NewObjectWithGivenProto<PlainObject>(cx, nullptr));
2045   if (!metaObject) {
2046     return nullptr;
2047   }
2048 
2049   JS::ModuleMetadataHook func = cx->runtime()->moduleMetadataHook;
2050   if (!func) {
2051     JS_ReportErrorASCII(cx, "Module metadata hook not set");
2052     return nullptr;
2053   }
2054 
2055   RootedValue modulePrivate(cx, JS::GetModulePrivate(module));
2056   if (!func(cx, modulePrivate, metaObject)) {
2057     return nullptr;
2058   }
2059 
2060   module->setMetaObject(metaObject);
2061 
2062   return metaObject;
2063 }
2064 
CallModuleResolveHook(JSContext * cx,HandleValue referencingPrivate,HandleObject moduleRequest)2065 JSObject* js::CallModuleResolveHook(JSContext* cx,
2066                                     HandleValue referencingPrivate,
2067                                     HandleObject moduleRequest) {
2068   JS::ModuleResolveHook moduleResolveHook = cx->runtime()->moduleResolveHook;
2069   if (!moduleResolveHook) {
2070     JS_ReportErrorASCII(cx, "Module resolve hook not set");
2071     return nullptr;
2072   }
2073 
2074   RootedObject result(cx,
2075                       moduleResolveHook(cx, referencingPrivate, moduleRequest));
2076   if (!result) {
2077     return nullptr;
2078   }
2079 
2080   if (!result->is<ModuleObject>()) {
2081     JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
2082     return nullptr;
2083   }
2084 
2085   return result;
2086 }
2087 
AsyncModuleExecutionFulfilledHandler(JSContext * cx,unsigned argc,Value * vp)2088 bool js::AsyncModuleExecutionFulfilledHandler(JSContext* cx, unsigned argc,
2089                                               Value* vp) {
2090   CallArgs args = CallArgsFromVp(argc, vp);
2091   JSFunction& func = args.callee().as<JSFunction>();
2092 
2093   Rooted<ModuleObject*> module(
2094       cx, &func.getExtendedSlot(FunctionExtended::MODULE_SLOT)
2095                .toObject()
2096                .as<ModuleObject>());
2097   AsyncModuleExecutionFulfilled(cx, module);
2098   args.rval().setUndefined();
2099   return true;
2100 }
2101 
AsyncModuleExecutionRejectedHandler(JSContext * cx,unsigned argc,Value * vp)2102 bool js::AsyncModuleExecutionRejectedHandler(JSContext* cx, unsigned argc,
2103                                              Value* vp) {
2104   CallArgs args = CallArgsFromVp(argc, vp);
2105   JSFunction& func = args.callee().as<JSFunction>();
2106   Rooted<ModuleObject*> module(
2107       cx, &func.getExtendedSlot(FunctionExtended::MODULE_SLOT)
2108                .toObject()
2109                .as<ModuleObject>());
2110   AsyncModuleExecutionRejected(cx, module, args.get(0));
2111   args.rval().setUndefined();
2112   return true;
2113 }
2114 
2115 // Top Level Await
2116 // https://tc39.es/proposal-top-level-await/#sec-gather-async-parent-completions
GatherAsyncParentCompletions(JSContext * cx,HandleModuleObject module,MutableHandleArrayObject execList)2117 bool ModuleObject::GatherAsyncParentCompletions(
2118     JSContext* cx, HandleModuleObject module,
2119     MutableHandleArrayObject execList) {
2120   FixedInvokeArgs<1> args(cx);
2121   args[0].setObject(*module);
2122 
2123   RootedValue rval(cx);
2124   if (!CallSelfHostedFunction(cx, cx->names().GatherAsyncParentCompletions,
2125                               UndefinedHandleValue, args, &rval)) {
2126     // This will happen if we OOM, we don't have a good way of handling this in
2127     // this specific situationn (promise resolution is in progress) so we will
2128     // reject the promise.
2129     return false;
2130   }
2131   execList.set(&rval.toObject().as<ArrayObject>());
2132   return true;
2133 }
2134 
2135 // Top Level Await
2136 // https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionfulfilled
AsyncModuleExecutionFulfilled(JSContext * cx,HandleModuleObject module)2137 void js::AsyncModuleExecutionFulfilled(JSContext* cx,
2138                                        HandleModuleObject module) {
2139   // Step 1.
2140   MOZ_ASSERT(module->status() == MODULE_STATUS_EVALUATED);
2141 
2142   // Step 2.
2143   MOZ_ASSERT(module->isAsyncEvaluating());
2144 
2145   if (module->hasTopLevelCapability()) {
2146     MOZ_ASSERT(module->getCycleRoot() == module);
2147     ModuleObject::topLevelCapabilityResolve(cx, module);
2148   }
2149 
2150   RootedArrayObject sortedList(cx);
2151   if (!ModuleObject::GatherAsyncParentCompletions(cx, module, &sortedList)) {
2152     // We have OOM'd -- all bets are off, reject the promise. Not much more we
2153     // can do.
2154     MOZ_ASSERT(cx->isExceptionPending());
2155     RootedValue exception(cx);
2156     if (!cx->getPendingException(&exception)) {
2157       return;
2158     }
2159     cx->clearPendingException();
2160     AsyncModuleExecutionRejected(cx, module, exception);
2161   }
2162 
2163   // this is out of step with the spec in order to be able to OOM
2164   module->setAsyncEvaluatingFalse();
2165 
2166   RootedValue ignored(cx);
2167   Rooted<ModuleObject*> m(cx);
2168 
2169   uint32_t length = sortedList->length();
2170   for (uint32_t i = 0; i < length; i++) {
2171     m = &sortedList->getDenseElement(i).toObject().as<ModuleObject>();
2172     // Step 2.
2173     if (!m->isAsyncEvaluating()) {
2174       MOZ_ASSERT(m->hadEvaluationError());
2175       return;
2176     }
2177 
2178     if (m->isAsync()) {
2179       // Steps for ExecuteAsyncModule
2180       MOZ_ASSERT(m->status() == MODULE_STATUS_EVALUATING ||
2181                  m->status() == MODULE_STATUS_EVALUATED);
2182       MOZ_ASSERT(m->isAsync());
2183       MOZ_ASSERT(m->isAsyncEvaluating());
2184       ModuleObject::execute(cx, m, &ignored);
2185     } else {
2186       if (!ModuleObject::execute(cx, m, &ignored)) {
2187         MOZ_ASSERT(cx->isExceptionPending());
2188         RootedValue exception(cx);
2189         if (!cx->getPendingException(&exception)) {
2190           return;
2191         }
2192         cx->clearPendingException();
2193         AsyncModuleExecutionRejected(cx, m, exception);
2194       } else {
2195         m->setAsyncEvaluatingFalse();
2196         if (m->hasTopLevelCapability()) {
2197           MOZ_ASSERT(m->getCycleRoot() == m);
2198           ModuleObject::topLevelCapabilityResolve(cx, m);
2199         }
2200       }
2201     }
2202   }
2203 
2204   // Step 6.
2205   // Return undefined.
2206 }
2207 
2208 // https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionrejected
AsyncModuleExecutionRejected(JSContext * cx,HandleModuleObject module,HandleValue error)2209 void js::AsyncModuleExecutionRejected(JSContext* cx, HandleModuleObject module,
2210                                       HandleValue error) {
2211   // Step 1.
2212   MOZ_ASSERT(module->status() == MODULE_STATUS_EVALUATED ||
2213              module->status() == MODULE_STATUS_EVALUATED_ERROR);
2214 
2215   // Step 2.
2216   if (!module->isAsyncEvaluating()) {
2217     MOZ_ASSERT(module->hadEvaluationError());
2218     return;
2219   }
2220 
2221   // Step 3.
2222   MOZ_ASSERT(!module->hadEvaluationError());
2223 
2224   // Step 4.
2225   module->setEvaluationError(error);
2226 
2227   // Step 5.
2228   module->setAsyncEvaluatingFalse();
2229 
2230   // Step 6.
2231   uint32_t length = module->asyncParentModules()->length();
2232   Rooted<ModuleObject*> parent(cx);
2233   for (uint32_t i = 0; i < length; i++) {
2234     parent =
2235         &module->asyncParentModules()->get(i).toObject().as<ModuleObject>();
2236     AsyncModuleExecutionRejected(cx, parent, error);
2237   }
2238 
2239   // Step 7.
2240   if (module->hasTopLevelCapability()) {
2241     MOZ_ASSERT(module->getCycleRoot() == module);
2242     ModuleObject::topLevelCapabilityReject(cx, module, error);
2243   }
2244 
2245   // Return undefined.
2246 }
2247 
topLevelCapabilityResolve(JSContext * cx,HandleModuleObject module)2248 bool ModuleObject::topLevelCapabilityResolve(JSContext* cx,
2249                                              HandleModuleObject module) {
2250   RootedValue rval(cx);
2251   Rooted<PromiseObject*> promise(
2252       cx, &module->topLevelCapability()->as<PromiseObject>());
2253   return AsyncFunctionReturned(cx, promise, rval);
2254 }
2255 
topLevelCapabilityReject(JSContext * cx,HandleModuleObject module,HandleValue error)2256 bool ModuleObject::topLevelCapabilityReject(JSContext* cx,
2257                                             HandleModuleObject module,
2258                                             HandleValue error) {
2259   Rooted<PromiseObject*> promise(
2260       cx, &module->topLevelCapability()->as<PromiseObject>());
2261   return AsyncFunctionThrown(cx, promise, error);
2262 }
2263 
StartDynamicModuleImport(JSContext * cx,HandleScript script,HandleValue specifierArg)2264 JSObject* js::StartDynamicModuleImport(JSContext* cx, HandleScript script,
2265                                        HandleValue specifierArg) {
2266   RootedObject promiseConstructor(cx, JS::GetPromiseConstructor(cx));
2267   if (!promiseConstructor) {
2268     return nullptr;
2269   }
2270 
2271   RootedObject promiseObject(cx, JS::NewPromiseObject(cx, nullptr));
2272   if (!promiseObject) {
2273     return nullptr;
2274   }
2275 
2276   Handle<PromiseObject*> promise = promiseObject.as<PromiseObject>();
2277 
2278   JS::ModuleDynamicImportHook importHook =
2279       cx->runtime()->moduleDynamicImportHook;
2280 
2281   if (!importHook) {
2282     // Dynamic import can be disabled by a pref and is not supported in all
2283     // contexts (e.g. web workers).
2284     JS_ReportErrorASCII(
2285         cx,
2286         "Dynamic module import is disabled or not supported in this context");
2287     if (!RejectPromiseWithPendingError(cx, promise)) {
2288       return nullptr;
2289     }
2290     return promise;
2291   }
2292 
2293   RootedString specifier(cx, ToString(cx, specifierArg));
2294   if (!specifier) {
2295     if (!RejectPromiseWithPendingError(cx, promise)) {
2296       return nullptr;
2297     }
2298     return promise;
2299   }
2300 
2301   RootedValue referencingPrivate(cx,
2302                                  script->sourceObject()->canonicalPrivate());
2303   cx->runtime()->addRefScriptPrivate(referencingPrivate);
2304 
2305   RootedAtom specifierAtom(cx, AtomizeString(cx, specifier));
2306   if (!specifierAtom) {
2307     if (!RejectPromiseWithPendingError(cx, promise)) {
2308       return nullptr;
2309     }
2310     return promise;
2311   }
2312 
2313   RootedObject moduleRequest(cx,
2314                              ModuleRequestObject::create(cx, specifierAtom));
2315   if (!moduleRequest) {
2316     if (!RejectPromiseWithPendingError(cx, promise)) {
2317       return nullptr;
2318     }
2319     return promise;
2320   }
2321 
2322   if (!importHook(cx, referencingPrivate, moduleRequest, promise)) {
2323     cx->runtime()->releaseScriptPrivate(referencingPrivate);
2324 
2325     // If there's no exception pending then the script is terminating
2326     // anyway, so just return nullptr.
2327     if (!cx->isExceptionPending() ||
2328         !RejectPromiseWithPendingError(cx, promise)) {
2329       return nullptr;
2330     }
2331     return promise;
2332   }
2333 
2334   return promise;
2335 }
2336 
OnRootModuleRejected(JSContext * cx,unsigned argc,Value * vp)2337 static bool OnRootModuleRejected(JSContext* cx, unsigned argc, Value* vp) {
2338   CallArgs args = CallArgsFromVp(argc, vp);
2339   HandleValue error = args.get(0);
2340 
2341   js::ReportExceptionClosure reportExn(error);
2342   PrepareScriptEnvironmentAndInvoke(cx, cx->global(), reportExn);
2343 
2344   args.rval().setUndefined();
2345   return true;
2346 };
2347 
OnModuleEvaluationFailure(JSContext * cx,HandleObject evaluationPromise)2348 bool js::OnModuleEvaluationFailure(JSContext* cx,
2349                                    HandleObject evaluationPromise) {
2350   if (evaluationPromise == nullptr) {
2351     return false;
2352   }
2353 
2354   RootedFunction onRejected(
2355       cx, NewHandler(cx, OnRootModuleRejected, evaluationPromise));
2356   if (!onRejected) {
2357     return false;
2358   }
2359 
2360   return JS::AddPromiseReactions(cx, evaluationPromise, nullptr, onRejected);
2361 }
2362 
2363 // Adjustment for Top-level await;
2364 // See: https://github.com/tc39/proposal-dynamic-import/pull/71/files
OnResolvedDynamicModule(JSContext * cx,unsigned argc,Value * vp)2365 static bool OnResolvedDynamicModule(JSContext* cx, unsigned argc, Value* vp) {
2366   CallArgs args = CallArgsFromVp(argc, vp);
2367   MOZ_ASSERT(args.get(0).isUndefined());
2368 
2369   // This is a hack to allow us to have the 2 extra variables needed
2370   // for FinishDynamicModuleImport in the resolve callback.
2371   Rooted<ListObject*> resolvedModuleParams(cx,
2372                                            ExtraFromHandler<ListObject>(args));
2373   MOZ_ASSERT(resolvedModuleParams->length() == 2);
2374   RootedValue referencingPrivate(cx, resolvedModuleParams->get(0));
2375 
2376   RootedAtom specifier(
2377       cx, AtomizeString(cx, resolvedModuleParams->get(1).toString()));
2378   if (!specifier) {
2379     return false;
2380   }
2381 
2382   Rooted<PromiseObject*> promise(cx, TargetFromHandler<PromiseObject>(args));
2383 
2384   auto releasePrivate = mozilla::MakeScopeExit(
2385       [&] { cx->runtime()->releaseScriptPrivate(referencingPrivate); });
2386 
2387   RootedObject moduleRequest(cx, ModuleRequestObject::create(cx, specifier));
2388   if (!moduleRequest) {
2389     return RejectPromiseWithPendingError(cx, promise);
2390   }
2391 
2392   RootedObject result(
2393       cx, CallModuleResolveHook(cx, referencingPrivate, moduleRequest));
2394 
2395   if (!result) {
2396     return RejectPromiseWithPendingError(cx, promise);
2397   }
2398 
2399   RootedModuleObject module(cx, &result->as<ModuleObject>());
2400   if (module->status() != MODULE_STATUS_EVALUATED) {
2401     JS_ReportErrorASCII(
2402         cx, "Unevaluated or errored module returned by module resolve hook");
2403     return RejectPromiseWithPendingError(cx, promise);
2404   }
2405 
2406   MOZ_ASSERT(module->getCycleRoot()
2407                  ->topLevelCapability()
2408                  ->as<PromiseObject>()
2409                  .state() == JS::PromiseState::Fulfilled);
2410 
2411   RootedObject ns(cx, ModuleObject::GetOrCreateModuleNamespace(cx, module));
2412   if (!ns) {
2413     return RejectPromiseWithPendingError(cx, promise);
2414   }
2415 
2416   args.rval().setUndefined();
2417   RootedValue value(cx, ObjectValue(*ns));
2418   return PromiseObject::resolve(cx, promise, value);
2419 };
2420 
OnRejectedDynamicModule(JSContext * cx,unsigned argc,Value * vp)2421 static bool OnRejectedDynamicModule(JSContext* cx, unsigned argc, Value* vp) {
2422   CallArgs args = CallArgsFromVp(argc, vp);
2423   HandleValue error = args.get(0);
2424 
2425   RootedValue referencingPrivate(cx, ExtraValueFromHandler(args));
2426   Rooted<PromiseObject*> promise(cx, TargetFromHandler<PromiseObject>(args));
2427 
2428   auto releasePrivate = mozilla::MakeScopeExit(
2429       [&] { cx->runtime()->releaseScriptPrivate(referencingPrivate); });
2430 
2431   args.rval().setUndefined();
2432   return PromiseObject::reject(cx, promise, error);
2433 };
2434 
FinishDynamicModuleImport_impl(JSContext * cx,HandleObject evaluationPromise,HandleValue referencingPrivate,HandleObject moduleRequest,HandleObject promiseArg)2435 bool FinishDynamicModuleImport_impl(JSContext* cx,
2436                                     HandleObject evaluationPromise,
2437                                     HandleValue referencingPrivate,
2438                                     HandleObject moduleRequest,
2439                                     HandleObject promiseArg) {
2440   Rooted<ListObject*> resolutionArgs(cx, ListObject::create(cx));
2441   if (!resolutionArgs->append(cx, referencingPrivate)) {
2442     return false;
2443   }
2444   Rooted<Value> stringValue(
2445       cx, StringValue(moduleRequest->as<ModuleRequestObject>().specifier()));
2446   if (!resolutionArgs->append(cx, stringValue)) {
2447     return false;
2448   }
2449 
2450   Rooted<Value> resolutionArgsValue(cx, ObjectValue(*resolutionArgs));
2451 
2452   RootedFunction onResolved(
2453       cx, NewHandlerWithExtraValue(cx, OnResolvedDynamicModule, promiseArg,
2454                                    resolutionArgsValue));
2455   if (!onResolved) {
2456     return false;
2457   }
2458 
2459   RootedFunction onRejected(
2460       cx, NewHandlerWithExtraValue(cx, OnRejectedDynamicModule, promiseArg,
2461                                    referencingPrivate));
2462   if (!onRejected) {
2463     return false;
2464   }
2465 
2466   return JS::AddPromiseReactionsIgnoringUnhandledRejection(
2467       cx, evaluationPromise, onResolved, onRejected);
2468 }
2469 
FinishDynamicModuleImport(JSContext * cx,HandleObject evaluationPromise,HandleValue referencingPrivate,HandleObject moduleRequest,HandleObject promiseArg)2470 bool js::FinishDynamicModuleImport(JSContext* cx,
2471                                    HandleObject evaluationPromise,
2472                                    HandleValue referencingPrivate,
2473                                    HandleObject moduleRequest,
2474                                    HandleObject promiseArg) {
2475   // If we do not have an evaluation promise for the module, we can assume that
2476   // evaluation has failed or been interrupted -- we can reject the dynamic
2477   // module.
2478   auto releasePrivate = mozilla::MakeScopeExit(
2479       [&] { cx->runtime()->releaseScriptPrivate(referencingPrivate); });
2480 
2481   if (!evaluationPromise) {
2482     Handle<PromiseObject*> promise = promiseArg.as<PromiseObject>();
2483     return RejectPromiseWithPendingError(cx, promise);
2484   }
2485 
2486   if (!FinishDynamicModuleImport_impl(cx, evaluationPromise, referencingPrivate,
2487                                       moduleRequest, promiseArg)) {
2488     return false;
2489   }
2490 
2491   releasePrivate.release();
2492   return true;
2493 }
2494 
FinishDynamicModuleImport_NoTLA(JSContext * cx,JS::DynamicImportStatus status,HandleValue referencingPrivate,HandleObject moduleRequest,HandleObject promiseArg)2495 bool js::FinishDynamicModuleImport_NoTLA(JSContext* cx,
2496                                          JS::DynamicImportStatus status,
2497                                          HandleValue referencingPrivate,
2498                                          HandleObject moduleRequest,
2499                                          HandleObject promiseArg) {
2500   MOZ_ASSERT_IF(cx->isExceptionPending(),
2501                 status == JS::DynamicImportStatus::Failed);
2502 
2503   Handle<PromiseObject*> promise = promiseArg.as<PromiseObject>();
2504 
2505   auto releasePrivate = mozilla::MakeScopeExit(
2506       [&] { cx->runtime()->releaseScriptPrivate(referencingPrivate); });
2507 
2508   if (status == JS::DynamicImportStatus::Failed) {
2509     return RejectPromiseWithPendingError(cx, promise);
2510   }
2511 
2512   RootedObject result(
2513       cx, CallModuleResolveHook(cx, referencingPrivate, moduleRequest));
2514   if (!result) {
2515     return RejectPromiseWithPendingError(cx, promise);
2516   }
2517 
2518   RootedModuleObject module(cx, &result->as<ModuleObject>());
2519   if (module->status() != MODULE_STATUS_EVALUATED) {
2520     JS_ReportErrorASCII(
2521         cx, "Unevaluated or errored module returned by module resolve hook");
2522     return RejectPromiseWithPendingError(cx, promise);
2523   }
2524 
2525   RootedObject ns(cx, ModuleObject::GetOrCreateModuleNamespace(cx, module));
2526   if (!ns) {
2527     return RejectPromiseWithPendingError(cx, promise);
2528   }
2529 
2530   RootedValue value(cx, ObjectValue(*ns));
2531   return PromiseObject::resolve(cx, promise, value);
2532 }
2533 
2534 template <XDRMode mode>
XDRExportEntries(XDRState<mode> * xdr,MutableHandleArrayObject vec)2535 XDRResult js::XDRExportEntries(XDRState<mode>* xdr,
2536                                MutableHandleArrayObject vec) {
2537   JSContext* cx = xdr->cx();
2538   Rooted<GCVector<ExportEntryObject*>> expVec(cx);
2539   RootedExportEntryObject expObj(cx);
2540   RootedAtom exportName(cx);
2541   RootedModuleRequestObject moduleRequest(cx);
2542   RootedAtom importName(cx);
2543   RootedAtom localName(cx);
2544 
2545   uint32_t length = 0;
2546   uint32_t lineNumber = 0;
2547   uint32_t columnNumber = 0;
2548 
2549   if (mode == XDR_ENCODE) {
2550     length = vec->length();
2551   }
2552   MOZ_TRY(xdr->codeUint32(&length));
2553   for (uint32_t i = 0; i < length; i++) {
2554     if (mode == XDR_ENCODE) {
2555       expObj = &vec->getDenseElement(i).toObject().as<ExportEntryObject>();
2556 
2557       exportName = expObj->exportName();
2558       moduleRequest = expObj->moduleRequest();
2559       importName = expObj->importName();
2560       localName = expObj->localName();
2561       lineNumber = expObj->lineNumber();
2562       columnNumber = expObj->columnNumber();
2563     }
2564 
2565     MOZ_TRY(XDRAtomOrNull(xdr, &exportName));
2566     MOZ_TRY(XDRModuleRequestObject(xdr, &moduleRequest, true));
2567     MOZ_TRY(XDRAtomOrNull(xdr, &importName));
2568     MOZ_TRY(XDRAtomOrNull(xdr, &localName));
2569 
2570     MOZ_TRY(xdr->codeUint32(&lineNumber));
2571     MOZ_TRY(xdr->codeUint32(&columnNumber));
2572 
2573     if (mode == XDR_DECODE) {
2574       expObj.set(ExportEntryObject::create(cx, exportName, moduleRequest,
2575                                            importName, localName, lineNumber,
2576                                            columnNumber));
2577       if (!expObj) {
2578         return xdr->fail(JS::TranscodeResult::Throw);
2579       }
2580       if (!expVec.append(expObj)) {
2581         return xdr->fail(JS::TranscodeResult::Throw);
2582       }
2583     }
2584   }
2585 
2586   if (mode == XDR_DECODE) {
2587     RootedArrayObject expArr(cx, js::CreateArray(cx, expVec));
2588     if (!expArr) {
2589       return xdr->fail(JS::TranscodeResult::Throw);
2590     }
2591     vec.set(expArr);
2592   }
2593 
2594   return Ok();
2595 }
2596 
2597 template <XDRMode mode>
XDRRequestedModuleObject(XDRState<mode> * xdr,MutableHandleRequestedModuleObject reqObj)2598 XDRResult js::XDRRequestedModuleObject(
2599     XDRState<mode>* xdr, MutableHandleRequestedModuleObject reqObj) {
2600   JSContext* cx = xdr->cx();
2601   RootedModuleRequestObject moduleRequest(cx);
2602   uint32_t lineNumber = 0;
2603   uint32_t columnNumber = 0;
2604   if (mode == XDR_ENCODE) {
2605     moduleRequest = reqObj->moduleRequest();
2606     lineNumber = reqObj->lineNumber();
2607     columnNumber = reqObj->columnNumber();
2608   }
2609 
2610   MOZ_TRY(XDRModuleRequestObject(xdr, &moduleRequest, false));
2611   MOZ_TRY(xdr->codeUint32(&lineNumber));
2612   MOZ_TRY(xdr->codeUint32(&columnNumber));
2613 
2614   if (mode == XDR_DECODE) {
2615     reqObj.set(RequestedModuleObject::create(cx, moduleRequest, lineNumber,
2616                                              columnNumber));
2617     if (!reqObj) {
2618       return xdr->fail(JS::TranscodeResult::Throw);
2619     }
2620   }
2621 
2622   return Ok();
2623 }
2624 
2625 template <XDRMode mode>
XDRModuleRequestObject(XDRState<mode> * xdr,MutableHandleModuleRequestObject moduleRequestObj,bool allowNullSpecifier)2626 XDRResult js::XDRModuleRequestObject(
2627     XDRState<mode>* xdr, MutableHandleModuleRequestObject moduleRequestObj,
2628     bool allowNullSpecifier) {
2629   JSContext* cx = xdr->cx();
2630   RootedAtom specifier(cx);
2631   if (mode == XDR_ENCODE) {
2632     specifier = moduleRequestObj->specifier();
2633   }
2634 
2635   MOZ_TRY(XDRAtomOrNull(xdr, &specifier));
2636 
2637   if (mode == XDR_DECODE) {
2638     if (!allowNullSpecifier && !specifier) {
2639       return xdr->fail(JS::TranscodeResult::Throw);
2640     }
2641     moduleRequestObj.set(ModuleRequestObject::create(cx, specifier));
2642     if (!moduleRequestObj) {
2643       return xdr->fail(JS::TranscodeResult::Throw);
2644     }
2645   }
2646 
2647   return Ok();
2648 }
2649 
2650 template <XDRMode mode>
XDRImportEntryObject(XDRState<mode> * xdr,MutableHandleImportEntryObject impObj)2651 XDRResult js::XDRImportEntryObject(XDRState<mode>* xdr,
2652                                    MutableHandleImportEntryObject impObj) {
2653   JSContext* cx = xdr->cx();
2654   RootedModuleRequestObject moduleRequest(cx);
2655   RootedAtom importName(cx);
2656   RootedAtom localName(cx);
2657   uint32_t lineNumber = 0;
2658   uint32_t columnNumber = 0;
2659   if (mode == XDR_ENCODE) {
2660     moduleRequest = impObj->moduleRequest();
2661     importName = impObj->importName();
2662     localName = impObj->localName();
2663     lineNumber = impObj->lineNumber();
2664     columnNumber = impObj->columnNumber();
2665   }
2666 
2667   MOZ_TRY(XDRModuleRequestObject(xdr, &moduleRequest, true));
2668   MOZ_TRY(XDRAtomOrNull(xdr, &importName));
2669   MOZ_TRY(XDRAtomOrNull(xdr, &localName));
2670   MOZ_TRY(xdr->codeUint32(&lineNumber));
2671   MOZ_TRY(xdr->codeUint32(&columnNumber));
2672 
2673   if (mode == XDR_DECODE) {
2674     impObj.set(ImportEntryObject::create(cx, moduleRequest, importName,
2675                                          localName, lineNumber, columnNumber));
2676     if (!impObj) {
2677       return xdr->fail(JS::TranscodeResult::Throw);
2678     }
2679   }
2680 
2681   return Ok();
2682 }
2683 
2684 template <XDRMode mode>
XDRModuleObject(XDRState<mode> * xdr,MutableHandleModuleObject modp)2685 XDRResult js::XDRModuleObject(XDRState<mode>* xdr,
2686                               MutableHandleModuleObject modp) {
2687   JSContext* cx = xdr->cx();
2688   RootedModuleObject module(cx, modp);
2689 
2690   RootedScope enclosingScope(cx);
2691   RootedScript script(cx);
2692 
2693   RootedArrayObject requestedModules(cx);
2694   RootedArrayObject importEntries(cx);
2695   RootedArrayObject localExportEntries(cx);
2696   RootedArrayObject indirectExportEntries(cx);
2697   RootedArrayObject starExportEntries(cx);
2698   // funcDecls points to data traced by the ModuleObject,
2699   // but is itself heap-allocated so we don't need to
2700   // worry about rooting it again here.
2701   frontend::FunctionDeclarationVector* funcDecls;
2702 
2703   uint32_t requestedModulesLength = 0;
2704   uint32_t importEntriesLength = 0;
2705   uint32_t funcDeclLength = 0;
2706 
2707   if (mode == XDR_ENCODE) {
2708     module = modp.get();
2709 
2710     script.set(module->script());
2711     enclosingScope.set(module->enclosingScope());
2712     MOZ_ASSERT(!enclosingScope->as<GlobalScope>().hasBindings());
2713 
2714     requestedModules = &module->requestedModules();
2715     importEntries = &module->importEntries();
2716     localExportEntries = &module->localExportEntries();
2717     indirectExportEntries = &module->indirectExportEntries();
2718     starExportEntries = &module->starExportEntries();
2719     funcDecls = GetFunctionDeclarations(module.get());
2720 
2721     requestedModulesLength = requestedModules->length();
2722     importEntriesLength = importEntries->length();
2723     funcDeclLength = funcDecls->length();
2724   }
2725 
2726   /* ScriptSourceObject slot - ScriptSourceObject is created in XDRScript and is
2727    * set when init is called. */
2728   if (mode == XDR_DECODE) {
2729     enclosingScope.set(&cx->global()->emptyGlobalScope());
2730     module.set(ModuleObject::create(cx));
2731     if (!module) {
2732       return xdr->fail(JS::TranscodeResult::Throw);
2733     }
2734   }
2735 
2736   /* Script slot */
2737   MOZ_TRY(XDRScript(xdr, enclosingScope, nullptr, module, &script));
2738 
2739   if (mode == XDR_DECODE) {
2740     module->initScriptSlots(script);
2741     module->initStatusSlot();
2742   }
2743 
2744   /* Environment Slot */
2745   if (mode == XDR_DECODE) {
2746     if (!ModuleObject::createEnvironment(cx, module)) {
2747       return xdr->fail(JS::TranscodeResult::Throw);
2748     }
2749   }
2750 
2751   /* Namespace Slot, Status Slot, EvaluationErrorSlot, MetaObject - Initialized
2752    * at instantiation */
2753 
2754   /* RequestedModules slot */
2755   RootedRequestedModuleVector reqVec(cx, GCVector<RequestedModuleObject*>(cx));
2756   RootedRequestedModuleObject reqObj(cx);
2757   MOZ_TRY(xdr->codeUint32(&requestedModulesLength));
2758   for (uint32_t i = 0; i < requestedModulesLength; i++) {
2759     if (mode == XDR_ENCODE) {
2760       reqObj = &module->requestedModules()
2761                     .getDenseElement(i)
2762                     .toObject()
2763                     .as<RequestedModuleObject>();
2764     }
2765     MOZ_TRY(XDRRequestedModuleObject(xdr, &reqObj));
2766     if (mode == XDR_DECODE) {
2767       if (!reqVec.append(reqObj)) {
2768         return xdr->fail(JS::TranscodeResult::Throw);
2769       }
2770     }
2771   }
2772   if (mode == XDR_DECODE) {
2773     RootedArrayObject reqArr(cx, js::CreateArray(cx, reqVec));
2774     if (!reqArr) {
2775       return xdr->fail(JS::TranscodeResult::Throw);
2776     }
2777     requestedModules.set(reqArr);
2778   }
2779 
2780   /* ImportEntries slot */
2781   RootedImportEntryVector impVec(cx, GCVector<ImportEntryObject*>(cx));
2782   RootedImportEntryObject impObj(cx);
2783   MOZ_TRY(xdr->codeUint32(&importEntriesLength));
2784   for (uint32_t i = 0; i < importEntriesLength; i++) {
2785     if (mode == XDR_ENCODE) {
2786       impObj = &module->importEntries()
2787                     .getDenseElement(i)
2788                     .toObject()
2789                     .as<ImportEntryObject>();
2790     }
2791     MOZ_TRY(XDRImportEntryObject(xdr, &impObj));
2792     if (mode == XDR_DECODE) {
2793       if (!impVec.append(impObj)) {
2794         return xdr->fail(JS::TranscodeResult::Throw);
2795       }
2796     }
2797   }
2798 
2799   if (mode == XDR_DECODE) {
2800     RootedArrayObject impArr(cx, js::CreateArray(cx, impVec));
2801     if (!impArr) {
2802       return xdr->fail(JS::TranscodeResult::Throw);
2803     }
2804     importEntries.set(impArr);
2805   }
2806 
2807   /* LocalExportEntries slot */
2808   MOZ_TRY(XDRExportEntries(xdr, &localExportEntries));
2809   /* IndirectExportEntries slot */
2810   MOZ_TRY(XDRExportEntries(xdr, &indirectExportEntries));
2811   /* StarExportEntries slot */
2812   MOZ_TRY(XDRExportEntries(xdr, &starExportEntries));
2813 
2814   /* FunctionDeclarations slot */
2815   uint32_t funIndex = 0;
2816   MOZ_TRY(xdr->codeUint32(&funcDeclLength));
2817   for (uint32_t i = 0; i < funcDeclLength; i++) {
2818     if (mode == XDR_ENCODE) {
2819       funIndex = (*funcDecls)[i];
2820     }
2821 
2822     MOZ_TRY(xdr->codeUint32(&funIndex));
2823 
2824     if (mode == XDR_DECODE) {
2825       if (!GetFunctionDeclarations(module.get())->append(funIndex)) {
2826         ReportOutOfMemory(cx);
2827         return xdr->fail(JS::TranscodeResult::Throw);
2828       }
2829     }
2830   }
2831 
2832   /* ImportBindings slot, DFSIndex slot, DFSAncestorIndex slot -
2833    * Initialized at instantiation */
2834   if (mode == XDR_DECODE) {
2835     module->initImportExportData(requestedModules, importEntries,
2836                                  localExportEntries, indirectExportEntries,
2837                                  starExportEntries);
2838   }
2839 
2840   /* isAsync Slot */
2841   uint8_t isAsyncModule = 0;
2842   if (mode == XDR_ENCODE) {
2843     isAsyncModule = module->isAsync() ? 1 : 0;
2844   }
2845 
2846   MOZ_TRY(xdr->codeUint8(&isAsyncModule));
2847 
2848   if (mode == XDR_DECODE) {
2849     Rooted<ListObject*> asyncParentModulesList(cx, ListObject::create(cx));
2850     if (!asyncParentModulesList) {
2851       return xdr->fail(JS::TranscodeResult::Throw);
2852     }
2853 
2854     module->initAsyncSlots(cx, isAsyncModule == 1, asyncParentModulesList);
2855   }
2856 
2857   modp.set(module);
2858   return Ok();
2859 }
2860 
2861 template XDRResult js::XDRModuleObject(XDRState<XDR_ENCODE>* xdr,
2862                                        MutableHandleModuleObject scriptp);
2863 
2864 template XDRResult js::XDRModuleObject(XDRState<XDR_DECODE>* xdr,
2865                                        MutableHandleModuleObject scriptp);
2866