Bug 1874684 - Part 21: Rename SecondsAndNanoseconds::toTotalNanoseconds. r=dminor
[gecko.git] / js / src / builtin / ModuleObject.h
blobcb74d67c40f357869ccbf6e53ee92c4de79e5cf5
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/. */
7 #ifndef builtin_ModuleObject_h
8 #define builtin_ModuleObject_h
10 #include "mozilla/HashTable.h" // mozilla::{HashMap, DefaultHasher}
11 #include "mozilla/Maybe.h" // mozilla::Maybe
12 #include "mozilla/Span.h"
14 #include <stddef.h> // size_t
15 #include <stdint.h> // int32_t, uint32_t
17 #include "gc/Barrier.h" // HeapPtr
18 #include "gc/ZoneAllocator.h" // CellAllocPolicy
19 #include "js/Class.h" // JSClass, ObjectOpResult
20 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
21 #include "js/GCVector.h"
22 #include "js/Id.h" // jsid
23 #include "js/Modules.h"
24 #include "js/Proxy.h" // BaseProxyHandler
25 #include "js/RootingAPI.h" // Rooted, Handle, MutableHandle
26 #include "js/TypeDecls.h" // HandleValue, HandleId, HandleObject, HandleScript, MutableHandleValue, MutableHandleIdVector, MutableHandleObject
27 #include "js/UniquePtr.h" // UniquePtr
28 #include "vm/JSObject.h" // JSObject
29 #include "vm/NativeObject.h" // NativeObject
30 #include "vm/ProxyObject.h" // ProxyObject
31 #include "vm/SharedStencil.h" // FunctionDeclarationVector
33 class JSAtom;
34 class JSScript;
35 class JSTracer;
37 namespace JS {
38 class PropertyDescriptor;
39 class Value;
40 } // namespace JS
42 namespace js {
44 class ArrayObject;
45 class CyclicModuleFields;
46 class SyntheticModuleFields;
47 class ListObject;
48 class ModuleEnvironmentObject;
49 class ModuleObject;
50 class PromiseObject;
51 class ScriptSourceObject;
53 class ModuleRequestObject : public NativeObject {
54 public:
55 enum { SpecifierSlot = 0, AttributesSlot, SlotCount };
57 static const JSClass class_;
58 static bool isInstance(HandleValue value);
59 [[nodiscard]] static ModuleRequestObject* create(
60 JSContext* cx, Handle<JSAtom*> specifier,
61 Handle<ArrayObject*> maybeAttributes);
63 JSAtom* specifier() const;
64 ArrayObject* attributes() const;
65 bool hasAttributes() const;
66 static bool getModuleType(JSContext* cx,
67 const Handle<ModuleRequestObject*> moduleRequest,
68 JS::ModuleType& moduleType);
71 using ModuleRequestVector =
72 GCVector<HeapPtr<ModuleRequestObject*>, 0, SystemAllocPolicy>;
74 class ImportEntry {
75 const HeapPtr<ModuleRequestObject*> moduleRequest_;
76 const HeapPtr<JSAtom*> importName_;
77 const HeapPtr<JSAtom*> localName_;
79 // Line number (1-origin).
80 const uint32_t lineNumber_;
82 // Column number in UTF-16 code units.
83 const JS::ColumnNumberOneOrigin columnNumber_;
85 public:
86 ImportEntry(Handle<ModuleRequestObject*> moduleRequest,
87 Handle<JSAtom*> maybeImportName, Handle<JSAtom*> localName,
88 uint32_t lineNumber, JS::ColumnNumberOneOrigin columnNumber);
90 ModuleRequestObject* moduleRequest() const { return moduleRequest_; }
91 JSAtom* importName() const { return importName_; }
92 JSAtom* localName() const { return localName_; }
93 uint32_t lineNumber() const { return lineNumber_; }
94 JS::ColumnNumberOneOrigin columnNumber() const { return columnNumber_; }
96 void trace(JSTracer* trc);
99 using ImportEntryVector = GCVector<ImportEntry, 0, SystemAllocPolicy>;
101 class ExportEntry {
102 const HeapPtr<JSAtom*> exportName_;
103 const HeapPtr<ModuleRequestObject*> moduleRequest_;
104 const HeapPtr<JSAtom*> importName_;
105 const HeapPtr<JSAtom*> localName_;
107 // Line number (1-origin).
108 const uint32_t lineNumber_;
110 // Column number in UTF-16 code units.
111 const JS::ColumnNumberOneOrigin columnNumber_;
113 public:
114 ExportEntry(Handle<JSAtom*> maybeExportName,
115 Handle<ModuleRequestObject*> maybeModuleRequest,
116 Handle<JSAtom*> maybeImportName, Handle<JSAtom*> maybeLocalName,
117 uint32_t lineNumber, JS::ColumnNumberOneOrigin columnNumber);
118 JSAtom* exportName() const { return exportName_; }
119 ModuleRequestObject* moduleRequest() const { return moduleRequest_; }
120 JSAtom* importName() const { return importName_; }
121 JSAtom* localName() const { return localName_; }
122 uint32_t lineNumber() const { return lineNumber_; }
123 JS::ColumnNumberOneOrigin columnNumber() const { return columnNumber_; }
125 void trace(JSTracer* trc);
128 using ExportEntryVector = GCVector<ExportEntry, 0, SystemAllocPolicy>;
130 class RequestedModule {
131 const HeapPtr<ModuleRequestObject*> moduleRequest_;
133 // Line number (1-origin).
134 const uint32_t lineNumber_;
136 // Column number in UTF-16 code units.
137 const JS::ColumnNumberOneOrigin columnNumber_;
139 public:
140 RequestedModule(Handle<ModuleRequestObject*> moduleRequest,
141 uint32_t lineNumber, JS::ColumnNumberOneOrigin columnNumber);
142 ModuleRequestObject* moduleRequest() const { return moduleRequest_; }
143 uint32_t lineNumber() const { return lineNumber_; }
144 JS::ColumnNumberOneOrigin columnNumber() const { return columnNumber_; }
146 void trace(JSTracer* trc);
149 using RequestedModuleVector = GCVector<RequestedModule, 0, SystemAllocPolicy>;
151 class ResolvedBindingObject : public NativeObject {
152 public:
153 enum { ModuleSlot = 0, BindingNameSlot, SlotCount };
155 static const JSClass class_;
156 static bool isInstance(HandleValue value);
157 static ResolvedBindingObject* create(JSContext* cx,
158 Handle<ModuleObject*> module,
159 Handle<JSAtom*> bindingName);
160 ModuleObject* module() const;
161 JSAtom* bindingName() const;
164 class IndirectBindingMap {
165 public:
166 void trace(JSTracer* trc);
168 bool put(JSContext* cx, HandleId name,
169 Handle<ModuleEnvironmentObject*> environment, HandleId targetName);
171 size_t count() const { return map_ ? map_->count() : 0; }
173 bool has(jsid name) const { return map_ ? map_->has(name) : false; }
175 bool lookup(jsid name, ModuleEnvironmentObject** envOut,
176 mozilla::Maybe<PropertyInfo>* propOut) const;
178 template <typename Func>
179 void forEachExportedName(Func func) const {
180 if (!map_) {
181 return;
184 for (auto r = map_->all(); !r.empty(); r.popFront()) {
185 func(r.front().key());
189 private:
190 struct Binding {
191 Binding(ModuleEnvironmentObject* environment, jsid targetName,
192 PropertyInfo prop);
193 HeapPtr<ModuleEnvironmentObject*> environment;
194 #ifdef DEBUG
195 HeapPtr<jsid> targetName;
196 #endif
197 PropertyInfo prop;
200 using Map = mozilla::HashMap<PreBarriered<jsid>, Binding,
201 mozilla::DefaultHasher<PreBarriered<jsid>>,
202 CellAllocPolicy>;
204 mozilla::Maybe<Map> map_;
207 // Vector of atoms representing the names exported from a module namespace.
209 // This is used both on the stack and in the heap.
210 using ExportNameVector = GCVector<HeapPtr<JSAtom*>, 0, SystemAllocPolicy>;
212 class ModuleNamespaceObject : public ProxyObject {
213 public:
214 enum ModuleNamespaceSlot { ExportsSlot = 0, BindingsSlot };
216 static bool isInstance(HandleValue value);
217 static ModuleNamespaceObject* create(
218 JSContext* cx, Handle<ModuleObject*> module,
219 MutableHandle<UniquePtr<ExportNameVector>> exports,
220 MutableHandle<UniquePtr<IndirectBindingMap>> bindings);
222 ModuleObject& module();
223 const ExportNameVector& exports() const;
224 IndirectBindingMap& bindings();
226 bool addBinding(JSContext* cx, Handle<JSAtom*> exportedName,
227 Handle<ModuleObject*> targetModule,
228 Handle<JSAtom*> targetName);
230 private:
231 struct ProxyHandler : public BaseProxyHandler {
232 ProxyHandler();
234 bool getOwnPropertyDescriptor(
235 JSContext* cx, HandleObject proxy, HandleId id,
236 MutableHandle<mozilla::Maybe<PropertyDescriptor>> desc) const override;
237 bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
238 Handle<PropertyDescriptor> desc,
239 ObjectOpResult& result) const override;
240 bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
241 MutableHandleIdVector props) const override;
242 bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
243 ObjectOpResult& result) const override;
244 bool getPrototype(JSContext* cx, HandleObject proxy,
245 MutableHandleObject protop) const override;
246 bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
247 ObjectOpResult& result) const override;
248 bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy,
249 bool* isOrdinary,
250 MutableHandleObject protop) const override;
251 bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
252 bool* succeeded) const override;
254 bool preventExtensions(JSContext* cx, HandleObject proxy,
255 ObjectOpResult& result) const override;
256 bool isExtensible(JSContext* cx, HandleObject proxy,
257 bool* extensible) const override;
258 bool has(JSContext* cx, HandleObject proxy, HandleId id,
259 bool* bp) const override;
260 bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
261 HandleId id, MutableHandleValue vp) const override;
262 bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
263 HandleValue receiver, ObjectOpResult& result) const override;
265 void trace(JSTracer* trc, JSObject* proxy) const override;
266 void finalize(JS::GCContext* gcx, JSObject* proxy) const override;
268 static const char family;
271 bool hasBindings() const;
272 bool hasExports() const;
274 ExportNameVector& mutableExports();
276 public:
277 static const ProxyHandler proxyHandler;
280 // Value types of [[Status]] in a Cyclic Module Record
281 // https://tc39.es/ecma262/#table-cyclic-module-fields
282 enum class ModuleStatus : int8_t {
283 Unlinked,
284 Linking,
285 Linked,
286 Evaluating,
287 EvaluatingAsync,
288 Evaluated,
290 // Sub-state of Evaluated with error value set.
292 // This is not returned from ModuleObject::status(); use hadEvaluationError()
293 // to check this.
294 Evaluated_Error
297 // Special values for CyclicModuleFields' asyncEvaluatingPostOrderSlot field,
298 // which is used as part of the implementation of the AsyncEvaluation field of
299 // cyclic module records.
301 // The spec requires us to be able to tell the order in which the field was set
302 // to true for async evaluating modules.
304 // This is arranged by using an integer to record the order. After evaluation is
305 // complete the value is set to ASYNC_EVALUATING_POST_ORDER_CLEARED.
307 // See https://tc39.es/ecma262/#sec-cyclic-module-records for field defintion.
308 // See https://tc39.es/ecma262/#sec-async-module-execution-fulfilled for sort
309 // requirement.
311 // Initial value for the runtime's counter used to generate these values.
312 constexpr uint32_t ASYNC_EVALUATING_POST_ORDER_INIT = 1;
314 // Value that the field is set to after being cleared.
315 constexpr uint32_t ASYNC_EVALUATING_POST_ORDER_CLEARED = 0;
317 // Currently, the ModuleObject class is used to represent both the Source Text
318 // Module Record and the Synthetic Module Record. Ideally, this is something
319 // that should be refactored to follow the same hierarchy as in the spec.
320 // TODO: See Bug 1880519.
321 class ModuleObject : public NativeObject {
322 public:
323 // Module fields including those for AbstractModuleRecords described by:
324 // https://tc39.es/ecma262/#sec-abstract-module-records
325 enum ModuleSlot {
326 ScriptSlot = 0,
327 EnvironmentSlot,
328 NamespaceSlot,
329 CyclicModuleFieldsSlot,
330 // `SyntheticModuleFields` if a synthetic module. Otherwise `undefined`.
331 SyntheticModuleFieldsSlot,
332 SlotCount
335 static const JSClass class_;
337 static bool isInstance(HandleValue value);
339 static ModuleObject* create(JSContext* cx);
341 static ModuleObject* createSynthetic(
342 JSContext* cx, MutableHandle<ExportNameVector> exportNames);
344 // Initialize the slots on this object that are dependent on the script.
345 void initScriptSlots(HandleScript script);
347 void setInitialEnvironment(
348 Handle<ModuleEnvironmentObject*> initialEnvironment);
350 void initFunctionDeclarations(UniquePtr<FunctionDeclarationVector> decls);
351 void initImportExportData(
352 MutableHandle<RequestedModuleVector> requestedModules,
353 MutableHandle<ImportEntryVector> importEntries,
354 MutableHandle<ExportEntryVector> exportEntries, uint32_t localExportCount,
355 uint32_t indirectExportCount, uint32_t starExportCount);
356 static bool Freeze(JSContext* cx, Handle<ModuleObject*> self);
357 #ifdef DEBUG
358 static bool AssertFrozen(JSContext* cx, Handle<ModuleObject*> self);
359 #endif
361 JSScript* maybeScript() const;
362 JSScript* script() const;
363 const char* filename() const;
364 ModuleEnvironmentObject& initialEnvironment() const;
365 ModuleEnvironmentObject* environment() const;
366 ModuleNamespaceObject* namespace_();
367 ModuleStatus status() const;
368 mozilla::Maybe<uint32_t> maybeDfsIndex() const;
369 uint32_t dfsIndex() const;
370 mozilla::Maybe<uint32_t> maybeDfsAncestorIndex() const;
371 uint32_t dfsAncestorIndex() const;
372 bool hadEvaluationError() const;
373 Value maybeEvaluationError() const;
374 Value evaluationError() const;
375 JSObject* metaObject() const;
376 ScriptSourceObject* scriptSourceObject() const;
377 mozilla::Span<const RequestedModule> requestedModules() const;
378 mozilla::Span<const ImportEntry> importEntries() const;
379 mozilla::Span<const ExportEntry> localExportEntries() const;
380 mozilla::Span<const ExportEntry> indirectExportEntries() const;
381 mozilla::Span<const ExportEntry> starExportEntries() const;
382 const ExportNameVector& syntheticExportNames() const;
384 IndirectBindingMap& importBindings();
386 void setStatus(ModuleStatus newStatus);
387 void setDfsIndex(uint32_t index);
388 void setDfsAncestorIndex(uint32_t index);
389 void clearDfsIndexes();
391 static PromiseObject* createTopLevelCapability(JSContext* cx,
392 Handle<ModuleObject*> module);
393 bool hasTopLevelAwait() const;
394 bool isAsyncEvaluating() const;
395 void setAsyncEvaluating();
396 void setEvaluationError(HandleValue newValue);
397 void setPendingAsyncDependencies(uint32_t newValue);
398 void setInitialTopLevelCapability(Handle<PromiseObject*> capability);
399 bool hasTopLevelCapability() const;
400 PromiseObject* maybeTopLevelCapability() const;
401 PromiseObject* topLevelCapability() const;
402 ListObject* asyncParentModules() const;
403 mozilla::Maybe<uint32_t> maybePendingAsyncDependencies() const;
404 uint32_t pendingAsyncDependencies() const;
405 mozilla::Maybe<uint32_t> maybeAsyncEvaluatingPostOrder() const;
406 uint32_t getAsyncEvaluatingPostOrder() const;
407 void clearAsyncEvaluatingPostOrder();
408 void setCycleRoot(ModuleObject* cycleRoot);
409 ModuleObject* getCycleRoot() const;
410 bool hasCyclicModuleFields() const;
411 bool hasSyntheticModuleFields() const;
413 static void onTopLevelEvaluationFinished(ModuleObject* module);
415 static bool appendAsyncParentModule(JSContext* cx, Handle<ModuleObject*> self,
416 Handle<ModuleObject*> parent);
418 [[nodiscard]] static bool topLevelCapabilityResolve(
419 JSContext* cx, Handle<ModuleObject*> module);
420 [[nodiscard]] static bool topLevelCapabilityReject(
421 JSContext* cx, Handle<ModuleObject*> module, HandleValue error);
423 void setMetaObject(JSObject* obj);
425 static bool instantiateFunctionDeclarations(JSContext* cx,
426 Handle<ModuleObject*> self);
428 static bool execute(JSContext* cx, Handle<ModuleObject*> self);
430 static ModuleNamespaceObject* createNamespace(
431 JSContext* cx, Handle<ModuleObject*> self,
432 MutableHandle<UniquePtr<ExportNameVector>> exports);
434 static bool createEnvironment(JSContext* cx, Handle<ModuleObject*> self);
435 static bool createSyntheticEnvironment(JSContext* cx,
436 Handle<ModuleObject*> self,
437 Handle<GCVector<Value>> values);
439 void initAsyncSlots(JSContext* cx, bool hasTopLevelAwait,
440 Handle<ListObject*> asyncParentModules);
442 private:
443 static const JSClassOps classOps_;
445 static void trace(JSTracer* trc, JSObject* obj);
446 static void finalize(JS::GCContext* gcx, JSObject* obj);
448 CyclicModuleFields* cyclicModuleFields();
449 const CyclicModuleFields* cyclicModuleFields() const;
451 SyntheticModuleFields* syntheticModuleFields();
452 const SyntheticModuleFields* syntheticModuleFields() const;
455 JSObject* GetOrCreateModuleMetaObject(JSContext* cx, HandleObject module);
457 ModuleObject* CallModuleResolveHook(JSContext* cx,
458 HandleValue referencingPrivate,
459 HandleObject moduleRequest);
461 JSObject* StartDynamicModuleImport(JSContext* cx, HandleScript script,
462 HandleValue specifier, HandleValue options);
464 bool OnModuleEvaluationFailure(JSContext* cx, HandleObject evaluationPromise,
465 JS::ModuleErrorBehaviour errorBehaviour);
467 bool FinishDynamicModuleImport(JSContext* cx, HandleObject evaluationPromise,
468 HandleValue referencingPrivate,
469 HandleObject moduleRequest,
470 HandleObject promise);
472 } // namespace js
474 template <>
475 inline bool JSObject::is<js::ModuleNamespaceObject>() const {
476 return js::IsDerivedProxyObject(this,
477 &js::ModuleNamespaceObject::proxyHandler);
480 #endif /* builtin_ModuleObject_h */