Coverage Report

Created: 2018-09-25 14:53

/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 */