/src/mozilla-central/js/src/builtin/ModuleObject.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: set ts=8 sts=4 et sw=4 tw=99: |
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 | | #ifndef builtin_ModuleObject_h |
8 | | #define builtin_ModuleObject_h |
9 | | |
10 | | #include "mozilla/Maybe.h" |
11 | | |
12 | | #include "jsapi.h" |
13 | | |
14 | | #include "builtin/SelfHostingDefines.h" |
15 | | #include "gc/Zone.h" |
16 | | #include "js/GCVector.h" |
17 | | #include "js/Id.h" |
18 | | #include "js/UniquePtr.h" |
19 | | #include "vm/JSAtom.h" |
20 | | #include "vm/NativeObject.h" |
21 | | #include "vm/ProxyObject.h" |
22 | | |
23 | | namespace js { |
24 | | |
25 | | class ModuleEnvironmentObject; |
26 | | class ModuleObject; |
27 | | |
28 | | namespace frontend { |
29 | | class BinaryNode; |
30 | | class ListNode; |
31 | | class ParseNode; |
32 | | class TokenStreamAnyChars; |
33 | | } /* namespace frontend */ |
34 | | |
35 | | typedef Rooted<ModuleObject*> RootedModuleObject; |
36 | | typedef Handle<ModuleObject*> HandleModuleObject; |
37 | | typedef Rooted<ModuleEnvironmentObject*> RootedModuleEnvironmentObject; |
38 | | typedef Handle<ModuleEnvironmentObject*> HandleModuleEnvironmentObject; |
39 | | |
40 | | class ImportEntryObject : public NativeObject |
41 | | { |
42 | | public: |
43 | | enum |
44 | | { |
45 | | ModuleRequestSlot = 0, |
46 | | ImportNameSlot, |
47 | | LocalNameSlot, |
48 | | LineNumberSlot, |
49 | | ColumnNumberSlot, |
50 | | SlotCount |
51 | | }; |
52 | | |
53 | | static const Class class_; |
54 | | static bool isInstance(HandleValue value); |
55 | | static ImportEntryObject* create(JSContext* cx, |
56 | | HandleAtom moduleRequest, |
57 | | HandleAtom importName, |
58 | | HandleAtom localName, |
59 | | uint32_t lineNumber, |
60 | | uint32_t columnNumber); |
61 | | JSAtom* moduleRequest() const; |
62 | | JSAtom* importName() const; |
63 | | JSAtom* localName() const; |
64 | | uint32_t lineNumber() const; |
65 | | uint32_t columnNumber() const; |
66 | | }; |
67 | | |
68 | | typedef Rooted<ImportEntryObject*> RootedImportEntryObject; |
69 | | typedef Handle<ImportEntryObject*> HandleImportEntryObject; |
70 | | |
71 | | class ExportEntryObject : public NativeObject |
72 | | { |
73 | | public: |
74 | | enum |
75 | | { |
76 | | ExportNameSlot = 0, |
77 | | ModuleRequestSlot, |
78 | | ImportNameSlot, |
79 | | LocalNameSlot, |
80 | | LineNumberSlot, |
81 | | ColumnNumberSlot, |
82 | | SlotCount |
83 | | }; |
84 | | |
85 | | static const Class class_; |
86 | | static bool isInstance(HandleValue value); |
87 | | static ExportEntryObject* create(JSContext* cx, |
88 | | HandleAtom maybeExportName, |
89 | | HandleAtom maybeModuleRequest, |
90 | | HandleAtom maybeImportName, |
91 | | HandleAtom maybeLocalName, |
92 | | uint32_t lineNumber, |
93 | | uint32_t columnNumber); |
94 | | JSAtom* exportName() const; |
95 | | JSAtom* moduleRequest() const; |
96 | | JSAtom* importName() const; |
97 | | JSAtom* localName() const; |
98 | | uint32_t lineNumber() const; |
99 | | uint32_t columnNumber() const; |
100 | | }; |
101 | | |
102 | | typedef Rooted<ExportEntryObject*> RootedExportEntryObject; |
103 | | typedef Handle<ExportEntryObject*> HandleExportEntryObject; |
104 | | |
105 | | class RequestedModuleObject : public NativeObject |
106 | | { |
107 | | public: |
108 | | enum |
109 | | { |
110 | | ModuleSpecifierSlot = 0, |
111 | | LineNumberSlot, |
112 | | ColumnNumberSlot, |
113 | | SlotCount |
114 | | }; |
115 | | |
116 | | static const Class class_; |
117 | | static bool isInstance(HandleValue value); |
118 | | static RequestedModuleObject* create(JSContext* cx, |
119 | | HandleAtom moduleSpecifier, |
120 | | uint32_t lineNumber, |
121 | | uint32_t columnNumber); |
122 | | JSAtom* moduleSpecifier() const; |
123 | | uint32_t lineNumber() const; |
124 | | uint32_t columnNumber() const; |
125 | | }; |
126 | | |
127 | | typedef Rooted<RequestedModuleObject*> RootedRequestedModuleObject; |
128 | | typedef Handle<RequestedModuleObject*> HandleRequestedModuleObject; |
129 | | |
130 | | class IndirectBindingMap |
131 | | { |
132 | | public: |
133 | | void trace(JSTracer* trc); |
134 | | |
135 | | bool put(JSContext* cx, HandleId name, |
136 | | HandleModuleEnvironmentObject environment, HandleId localName); |
137 | | |
138 | 0 | size_t count() const { |
139 | 0 | return map_ ? map_->count() : 0; |
140 | 0 | } |
141 | | |
142 | 0 | bool has(jsid name) const { |
143 | 0 | return map_ ? map_->has(name) : false; |
144 | 0 | } |
145 | | |
146 | | bool lookup(jsid name, ModuleEnvironmentObject** envOut, Shape** shapeOut) const; |
147 | | |
148 | | template <typename Func> |
149 | 0 | void forEachExportedName(Func func) const { |
150 | 0 | if (!map_) { |
151 | 0 | return; |
152 | 0 | } |
153 | 0 | |
154 | 0 | for (auto r = map_->all(); !r.empty(); r.popFront()) { |
155 | 0 | func(r.front().key()); |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | private: |
160 | | struct Binding |
161 | | { |
162 | | Binding(ModuleEnvironmentObject* environment, Shape* shape); |
163 | | HeapPtr<ModuleEnvironmentObject*> environment; |
164 | | HeapPtr<Shape*> shape; |
165 | | }; |
166 | | |
167 | | typedef HashMap<jsid, Binding, DefaultHasher<jsid>, ZoneAllocPolicy> Map; |
168 | | |
169 | | mozilla::Maybe<Map> map_; |
170 | | }; |
171 | | |
172 | | class ModuleNamespaceObject : public ProxyObject |
173 | | { |
174 | | public: |
175 | | enum ModuleNamespaceSlot |
176 | | { |
177 | | ExportsSlot = 0, |
178 | | BindingsSlot |
179 | | }; |
180 | | |
181 | | static bool isInstance(HandleValue value); |
182 | | static ModuleNamespaceObject* create(JSContext* cx, HandleModuleObject module, |
183 | | HandleObject exports, |
184 | | UniquePtr<IndirectBindingMap> bindings); |
185 | | |
186 | | ModuleObject& module(); |
187 | | JSObject& exports(); |
188 | | IndirectBindingMap& bindings(); |
189 | | |
190 | | bool addBinding(JSContext* cx, HandleAtom exportedName, HandleModuleObject targetModule, |
191 | | HandleAtom localName); |
192 | | |
193 | | private: |
194 | | struct ProxyHandler : public BaseProxyHandler |
195 | | { |
196 | | ProxyHandler(); |
197 | | |
198 | | bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, |
199 | | MutableHandle<PropertyDescriptor> desc) const override; |
200 | | bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, |
201 | | Handle<PropertyDescriptor> desc, |
202 | | ObjectOpResult& result) const override; |
203 | | bool ownPropertyKeys(JSContext* cx, HandleObject proxy, |
204 | | AutoIdVector& props) const override; |
205 | | bool delete_(JSContext* cx, HandleObject proxy, HandleId id, |
206 | | ObjectOpResult& result) const override; |
207 | | bool getPrototype(JSContext* cx, HandleObject proxy, |
208 | | MutableHandleObject protop) const override; |
209 | | bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, |
210 | | ObjectOpResult& result) const override; |
211 | | bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, |
212 | | MutableHandleObject protop) const override; |
213 | | bool setImmutablePrototype(JSContext* cx, HandleObject proxy, |
214 | | bool* succeeded) const override; |
215 | | |
216 | | bool preventExtensions(JSContext* cx, HandleObject proxy, |
217 | | ObjectOpResult& result) const override; |
218 | | bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override; |
219 | | bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override; |
220 | | bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, |
221 | | HandleId id, MutableHandleValue vp) const override; |
222 | | bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, |
223 | | HandleValue receiver, ObjectOpResult& result) const override; |
224 | | |
225 | | void trace(JSTracer* trc, JSObject* proxy) const override; |
226 | | void finalize(JSFreeOp* fop, JSObject* proxy) const override; |
227 | | |
228 | | static const char family; |
229 | | }; |
230 | | |
231 | | public: |
232 | | static const ProxyHandler proxyHandler; |
233 | | }; |
234 | | |
235 | | typedef Rooted<ModuleNamespaceObject*> RootedModuleNamespaceObject; |
236 | | typedef Handle<ModuleNamespaceObject*> HandleModuleNamespaceObject; |
237 | | |
238 | | struct FunctionDeclaration |
239 | | { |
240 | | FunctionDeclaration(HandleAtom name, HandleFunction fun); |
241 | | void trace(JSTracer* trc); |
242 | | |
243 | | HeapPtr<JSAtom*> name; |
244 | | HeapPtr<JSFunction*> fun; |
245 | | }; |
246 | | |
247 | | using FunctionDeclarationVector = GCVector<FunctionDeclaration, 0, ZoneAllocPolicy>; |
248 | | |
249 | | // Possible values for ModuleStatus are defined in SelfHostingDefines.h. |
250 | | using ModuleStatus = int32_t; |
251 | | |
252 | | class ModuleObject : public NativeObject |
253 | | { |
254 | | public: |
255 | | enum ModuleSlot |
256 | | { |
257 | | ScriptSlot = 0, |
258 | | EnvironmentSlot, |
259 | | NamespaceSlot, |
260 | | StatusSlot, |
261 | | EvaluationErrorSlot, |
262 | | MetaObjectSlot, |
263 | | RequestedModulesSlot, |
264 | | ImportEntriesSlot, |
265 | | LocalExportEntriesSlot, |
266 | | IndirectExportEntriesSlot, |
267 | | StarExportEntriesSlot, |
268 | | ImportBindingsSlot, |
269 | | FunctionDeclarationsSlot, |
270 | | DFSIndexSlot, |
271 | | DFSAncestorIndexSlot, |
272 | | SlotCount |
273 | | }; |
274 | | |
275 | | static_assert(EnvironmentSlot == MODULE_OBJECT_ENVIRONMENT_SLOT, |
276 | | "EnvironmentSlot must match self-hosting define"); |
277 | | static_assert(StatusSlot == MODULE_OBJECT_STATUS_SLOT, |
278 | | "StatusSlot must match self-hosting define"); |
279 | | static_assert(EvaluationErrorSlot == MODULE_OBJECT_EVALUATION_ERROR_SLOT, |
280 | | "EvaluationErrorSlot must match self-hosting define"); |
281 | | static_assert(DFSIndexSlot == MODULE_OBJECT_DFS_INDEX_SLOT, |
282 | | "DFSIndexSlot must match self-hosting define"); |
283 | | static_assert(DFSAncestorIndexSlot == MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, |
284 | | "DFSAncestorIndexSlot must match self-hosting define"); |
285 | | |
286 | | static const Class class_; |
287 | | |
288 | | static bool isInstance(HandleValue value); |
289 | | |
290 | | static ModuleObject* create(JSContext* cx); |
291 | | void init(HandleScript script); |
292 | | void setInitialEnvironment(Handle<ModuleEnvironmentObject*> initialEnvironment); |
293 | | void initImportExportData(HandleArrayObject requestedModules, |
294 | | HandleArrayObject importEntries, |
295 | | HandleArrayObject localExportEntries, |
296 | | HandleArrayObject indiretExportEntries, |
297 | | HandleArrayObject starExportEntries); |
298 | | static bool Freeze(JSContext* cx, HandleModuleObject self); |
299 | | #ifdef DEBUG |
300 | | static bool AssertFrozen(JSContext* cx, HandleModuleObject self); |
301 | | #endif |
302 | | void fixEnvironmentsAfterCompartmentMerge(); |
303 | | |
304 | | JSScript* script() const; |
305 | | Scope* enclosingScope() const; |
306 | | ModuleEnvironmentObject& initialEnvironment() const; |
307 | | ModuleEnvironmentObject* environment() const; |
308 | | ModuleNamespaceObject* namespace_(); |
309 | | ModuleStatus status() const; |
310 | | bool hadEvaluationError() const; |
311 | | Value evaluationError() const; |
312 | | JSObject* metaObject() const; |
313 | | ArrayObject& requestedModules() const; |
314 | | ArrayObject& importEntries() const; |
315 | | ArrayObject& localExportEntries() const; |
316 | | ArrayObject& indirectExportEntries() const; |
317 | | ArrayObject& starExportEntries() const; |
318 | | IndirectBindingMap& importBindings(); |
319 | | |
320 | | static bool Instantiate(JSContext* cx, HandleModuleObject self); |
321 | | static bool Evaluate(JSContext* cx, HandleModuleObject self); |
322 | | |
323 | | static ModuleNamespaceObject* GetOrCreateModuleNamespace(JSContext* cx, |
324 | | HandleModuleObject self); |
325 | | |
326 | | void setMetaObject(JSObject* obj); |
327 | | |
328 | | // For BytecodeEmitter. |
329 | | bool noteFunctionDeclaration(JSContext* cx, HandleAtom name, HandleFunction fun); |
330 | | |
331 | | // For intrinsic_InstantiateModuleFunctionDeclarations. |
332 | | static bool instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self); |
333 | | |
334 | | // For intrinsic_ExecuteModule. |
335 | | static bool execute(JSContext* cx, HandleModuleObject self, MutableHandleValue rval); |
336 | | |
337 | | // For intrinsic_NewModuleNamespace. |
338 | | static ModuleNamespaceObject* createNamespace(JSContext* cx, HandleModuleObject self, |
339 | | HandleObject exports); |
340 | | |
341 | | private: |
342 | | static const ClassOps classOps_; |
343 | | |
344 | | static void trace(JSTracer* trc, JSObject* obj); |
345 | | static void finalize(js::FreeOp* fop, JSObject* obj); |
346 | | |
347 | | bool hasScript() const; |
348 | | bool hasImportBindings() const; |
349 | | FunctionDeclarationVector* functionDeclarations(); |
350 | | }; |
351 | | |
352 | | // Process a module's parse tree to collate the import and export data used when |
353 | | // creating a ModuleObject. |
354 | | class MOZ_STACK_CLASS ModuleBuilder |
355 | | { |
356 | | public: |
357 | | explicit ModuleBuilder(JSContext* cx, HandleModuleObject module, |
358 | | const frontend::TokenStreamAnyChars& tokenStream); |
359 | | |
360 | | bool processImport(frontend::BinaryNode* importNode); |
361 | | bool processExport(frontend::ParseNode* exportNode); |
362 | | bool processExportFrom(frontend::BinaryNode* exportNode); |
363 | | |
364 | | bool hasExportedName(JSAtom* name) const; |
365 | | |
366 | | using ExportEntryVector = GCVector<ExportEntryObject*>; |
367 | 0 | const ExportEntryVector& localExportEntries() const { |
368 | 0 | return localExportEntries_; |
369 | 0 | } |
370 | | |
371 | | bool buildTables(); |
372 | | bool initModule(); |
373 | | |
374 | | private: |
375 | | using RequestedModuleVector = GCVector<RequestedModuleObject*>; |
376 | | using AtomSet = JS::GCHashSet<JSAtom*>; |
377 | | using ImportEntryMap = GCHashMap<JSAtom*, ImportEntryObject*>; |
378 | | using RootedExportEntryVector = JS::Rooted<ExportEntryVector>; |
379 | | using RootedRequestedModuleVector = JS::Rooted<RequestedModuleVector>; |
380 | | using RootedAtomSet = JS::Rooted<AtomSet>; |
381 | | using RootedImportEntryMap = JS::Rooted<ImportEntryMap>; |
382 | | |
383 | | JSContext* cx_; |
384 | | RootedModuleObject module_; |
385 | | const frontend::TokenStreamAnyChars& tokenStream_; |
386 | | RootedAtomSet requestedModuleSpecifiers_; |
387 | | RootedRequestedModuleVector requestedModules_; |
388 | | RootedImportEntryMap importEntries_; |
389 | | RootedExportEntryVector exportEntries_; |
390 | | RootedAtomSet exportNames_; |
391 | | RootedExportEntryVector localExportEntries_; |
392 | | RootedExportEntryVector indirectExportEntries_; |
393 | | RootedExportEntryVector starExportEntries_; |
394 | | |
395 | | ImportEntryObject* importEntryFor(JSAtom* localName) const; |
396 | | |
397 | | bool processExportBinding(frontend::ParseNode* pn); |
398 | | bool processExportArrayBinding(frontend::ListNode* array); |
399 | | bool processExportObjectBinding(frontend::ListNode* obj); |
400 | | |
401 | | bool appendImportEntryObject(HandleImportEntryObject importEntry); |
402 | | |
403 | | bool appendExportEntry(HandleAtom exportName, HandleAtom localName, |
404 | | frontend::ParseNode* node = nullptr); |
405 | | bool appendExportFromEntry(HandleAtom exportName, HandleAtom moduleRequest, |
406 | | HandleAtom importName, frontend::ParseNode* node); |
407 | | bool appendExportEntryObject(HandleExportEntryObject exportEntry); |
408 | | |
409 | | bool maybeAppendRequestedModule(HandleAtom specifier, frontend::ParseNode* node); |
410 | | |
411 | | template <typename T> |
412 | | ArrayObject* createArray(const JS::Rooted<GCVector<T>>& vector); |
413 | | template <typename K, typename V> |
414 | | ArrayObject* createArray(const JS::Rooted<GCHashMap<K, V>>& map); |
415 | | }; |
416 | | |
417 | | JSObject* |
418 | | GetOrCreateModuleMetaObject(JSContext* cx, HandleScript script); |
419 | | |
420 | | } // namespace js |
421 | | |
422 | | template<> |
423 | | inline bool |
424 | | JSObject::is<js::ModuleNamespaceObject>() const |
425 | 490 | { |
426 | 490 | return js::IsDerivedProxyObject(this, &js::ModuleNamespaceObject::proxyHandler); |
427 | 490 | } |
428 | | |
429 | | #endif /* builtin_ModuleObject_h */ |