summaryrefslogtreecommitdiffstats
path: root/js/src/vm/ModuleBuilder.h
blob: 065ef1e63d6f9c0f7782725f0c210ac1ec5fb5fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef vm_ModuleBuilder_h
#define vm_ModuleBuilder_h

#include "mozilla/Attributes.h"  // MOZ_STACK_CLASS

#include "jstypes.h"               // JS_PUBLIC_API
#include "builtin/ModuleObject.h"  // js::{{Im,Ex}portEntry,Requested{Module,}}Object
#include "frontend/EitherParser.h"  // js::frontend::EitherParser
#include "frontend/ParserAtom.h"  // js::frontend::{ParserAtom, TaggedParserAtomIndex}
#include "frontend/Stencil.h"  // js::frontend::StencilModuleEntry
#include "js/GCHashTable.h"    // JS::GCHash{Map,Set}
#include "js/GCVector.h"       // JS::GCVector
#include "js/RootingAPI.h"     // JS::{Handle,Rooted}
#include "vm/AtomsTable.h"     // js::AtomSet

struct JS_PUBLIC_API JSContext;
class JS_PUBLIC_API JSAtom;

namespace js {

namespace frontend {

class BinaryNode;
class ListNode;
class ParseNode;

}  // namespace frontend

class TaggedParserAtomIndexHasher {
 public:
  using Lookup = frontend::TaggedParserAtomIndex;

  static inline HashNumber hash(const Lookup& l) {
    return HashNumber(
        *const_cast<frontend::TaggedParserAtomIndex&>(l).rawData());
  }
  static inline bool match(frontend::TaggedParserAtomIndex entry,
                           const Lookup& l) {
    return l == entry;
  }
};

// Process a module's parse tree to collate the import and export data used when
// creating a ModuleObject.
class MOZ_STACK_CLASS ModuleBuilder {
  explicit ModuleBuilder(JSContext* cx,
                         const frontend::EitherParser& eitherParser);

 public:
  template <class Parser>
  explicit ModuleBuilder(JSContext* cx, Parser* parser)
      : ModuleBuilder(cx, frontend::EitherParser(parser)) {}

  bool processImport(frontend::BinaryNode* importNode);
  bool processExport(frontend::ParseNode* exportNode);
  bool processExportFrom(frontend::BinaryNode* exportNode);

  bool hasExportedName(const frontend::ParserAtom* name) const;

  bool buildTables(frontend::StencilModuleMetadata& metadata);

  // During BytecodeEmitter we note top-level functions, and afterwards we must
  // call finishFunctionDecls on the list.
  bool noteFunctionDeclaration(JSContext* cx, uint32_t funIndex);
  void finishFunctionDecls(frontend::StencilModuleMetadata& metadata);

  void noteAsync(frontend::StencilModuleMetadata& metadata);

 private:
  using RequestedModuleVector =
      Vector<frontend::StencilModuleEntry, 0, js::SystemAllocPolicy>;
  using AtomSet = HashSet<const frontend::ParserAtom*>;
  using ExportEntryVector = Vector<frontend::StencilModuleEntry>;
  using ImportEntryMap =
      HashMap<frontend::TaggedParserAtomIndex, frontend::StencilModuleEntry,
              TaggedParserAtomIndexHasher>;

  JSContext* cx_;
  frontend::EitherParser eitherParser_;

  // These are populated while parsing.
  AtomSet requestedModuleSpecifiers_;
  RequestedModuleVector requestedModules_;
  ImportEntryMap importEntries_;
  ExportEntryVector exportEntries_;
  AtomSet exportNames_;

  // These are populated while emitting bytecode.
  frontend::FunctionDeclarationVector functionDecls_;

  frontend::StencilModuleEntry* importEntryFor(
      frontend::TaggedParserAtomIndex localName) const;

  bool processExportBinding(frontend::ParseNode* pn);
  bool processExportArrayBinding(frontend::ListNode* array);
  bool processExportObjectBinding(frontend::ListNode* obj);

  bool appendExportEntry(const frontend::ParserAtom* exportName,
                         const frontend::ParserAtom* localName,
                         frontend::ParseNode* node = nullptr);

  bool appendExportFromEntry(const frontend::ParserAtom* exportName,
                             const frontend::ParserAtom* moduleRequest,
                             const frontend::ParserAtom* importName,
                             frontend::ParseNode* node);

  bool maybeAppendRequestedModule(const frontend::ParserAtom* specifier,
                                  frontend::ParseNode* node);
};

template <typename T>
ArrayObject* CreateArray(JSContext* cx,
                         const JS::Rooted<JS::GCVector<T>>& vector);

}  // namespace js

#endif  // vm_ModuleBuilder_h