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 #ifndef vm_ModuleBuilder_h
8 #define vm_ModuleBuilder_h
9 
10 #include "mozilla/Attributes.h"  // MOZ_STACK_CLASS
11 
12 #include "jstypes.h"               // JS_PUBLIC_API
13 #include "builtin/ModuleObject.h"  // js::{{Im,Ex}portEntry,Requested{Module,}}Object
14 #include "frontend/EitherParser.h"  // js::frontend::EitherParser
15 #include "frontend/ParserAtom.h"    // js::frontend::TaggedParserAtomIndex
16 #include "frontend/Stencil.h"       // js::frontend::StencilModuleEntry
17 #include "frontend/TaggedParserAtomIndexHasher.h"  // frontend::TaggedParserAtomIndexHasher
18 #include "js/GCHashTable.h"                        // JS::GCHash{Map,Set}
19 #include "js/GCVector.h"                           // JS::GCVector
20 #include "js/RootingAPI.h"                         // JS::{Handle,Rooted}
21 #include "vm/AtomsTable.h"                         // js::AtomSet
22 
23 struct JS_PUBLIC_API JSContext;
24 class JS_PUBLIC_API JSAtom;
25 
26 namespace js {
27 
28 namespace frontend {
29 
30 class BinaryNode;
31 class ListNode;
32 class ParseNode;
33 
34 }  // namespace frontend
35 
36 // Process a module's parse tree to collate the import and export data used when
37 // creating a ModuleObject.
38 class MOZ_STACK_CLASS ModuleBuilder {
39   explicit ModuleBuilder(JSContext* cx,
40                          const frontend::EitherParser& eitherParser);
41 
42  public:
43   template <class Parser>
ModuleBuilder(JSContext * cx,Parser * parser)44   explicit ModuleBuilder(JSContext* cx, Parser* parser)
45       : ModuleBuilder(cx, frontend::EitherParser(parser)) {}
46 
47   bool processImport(frontend::BinaryNode* importNode);
48   bool processExport(frontend::ParseNode* exportNode);
49   bool processExportFrom(frontend::BinaryNode* exportNode);
50 
51   bool hasExportedName(frontend::TaggedParserAtomIndex name) const;
52 
53   bool buildTables(frontend::StencilModuleMetadata& metadata);
54 
55   // During BytecodeEmitter we note top-level functions, and afterwards we must
56   // call finishFunctionDecls on the list.
57   bool noteFunctionDeclaration(JSContext* cx, uint32_t funIndex);
58   void finishFunctionDecls(frontend::StencilModuleMetadata& metadata);
59 
60   void noteAsync(frontend::StencilModuleMetadata& metadata);
61 
62  private:
63   using RequestedModuleVector =
64       Vector<frontend::StencilModuleEntry, 0, js::SystemAllocPolicy>;
65 
66   using AtomSet = HashSet<frontend::TaggedParserAtomIndex,
67                           frontend::TaggedParserAtomIndexHasher>;
68   using ExportEntryVector = Vector<frontend::StencilModuleEntry>;
69   using ImportEntryMap =
70       HashMap<frontend::TaggedParserAtomIndex, frontend::StencilModuleEntry,
71               frontend::TaggedParserAtomIndexHasher>;
72 
73   JSContext* cx_;
74   frontend::EitherParser eitherParser_;
75 
76   // These are populated while parsing.
77   AtomSet requestedModuleSpecifiers_;
78   RequestedModuleVector requestedModules_;
79   ImportEntryMap importEntries_;
80   ExportEntryVector exportEntries_;
81   AtomSet exportNames_;
82 
83   // These are populated while emitting bytecode.
84   frontend::FunctionDeclarationVector functionDecls_;
85 
86   frontend::StencilModuleEntry* importEntryFor(
87       frontend::TaggedParserAtomIndex localName) const;
88 
89   bool processExportBinding(frontend::ParseNode* pn);
90   bool processExportArrayBinding(frontend::ListNode* array);
91   bool processExportObjectBinding(frontend::ListNode* obj);
92 
93   bool appendExportEntry(frontend::TaggedParserAtomIndex exportName,
94                          frontend::TaggedParserAtomIndex localName,
95                          frontend::ParseNode* node = nullptr);
96 
97   bool maybeAppendRequestedModule(frontend::TaggedParserAtomIndex specifier,
98                                   frontend::ParseNode* node);
99 
100   void markUsedByStencil(frontend::TaggedParserAtomIndex name);
101 };
102 
103 template <typename T>
104 ArrayObject* CreateArray(JSContext* cx,
105                          const JS::Rooted<JS::GCVector<T>>& vector);
106 
107 }  // namespace js
108 
109 #endif  // vm_ModuleBuilder_h
110