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