1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_OBJECTS_MODULE_H_
6 #define V8_OBJECTS_MODULE_H_
7 
8 #include "src/objects.h"
9 #include "src/objects/fixed-array.h"
10 
11 // Has to be the last include (doesn't have include guards):
12 #include "src/objects/object-macros.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 template <typename T>
18 class Handle;
19 class Isolate;
20 class JSModuleNamespace;
21 class ModuleDescriptor;
22 class ModuleInfo;
23 class ModuleInfoEntry;
24 class String;
25 class Zone;
26 
27 // The runtime representation of an ECMAScript module.
28 class Module : public Struct, public NeverReadOnlySpaceObject {
29  public:
30   using NeverReadOnlySpaceObject::GetHeap;
31   using NeverReadOnlySpaceObject::GetIsolate;
32 
33   DECL_CAST(Module)
34   DECL_VERIFIER(Module)
35   DECL_PRINTER(Module)
36 
37   // The code representing this module, or an abstraction thereof.
38   // This is either a SharedFunctionInfo, a JSFunction, a JSGeneratorObject, or
39   // a ModuleInfo, depending on the state (status) the module is in. See
40   // Module::ModuleVerify() for the precise invariant.
41   DECL_ACCESSORS(code, Object)
42 
43   // Arrays of cells corresponding to regular exports and regular imports.
44   // A cell's position in the array is determined by the cell index of the
45   // associated module entry (which coincides with the variable index of the
46   // associated variable).
47   DECL_ACCESSORS(regular_exports, FixedArray)
48   DECL_ACCESSORS(regular_imports, FixedArray)
49 
50   // The complete export table, mapping an export name to its cell.
51   // TODO(neis): We may want to remove the regular exports from the table.
52   DECL_ACCESSORS(exports, ObjectHashTable)
53 
54   // Hash for this object (a random non-zero Smi).
55   DECL_INT_ACCESSORS(hash)
56 
57   // Status.
58   DECL_INT_ACCESSORS(status)
59   enum Status {
60     // Order matters!
61     kUninstantiated,
62     kPreInstantiating,
63     kInstantiating,
64     kInstantiated,
65     kEvaluating,
66     kEvaluated,
67     kErrored
68   };
69 
70   // The exception in the case {status} is kErrored.
71   Object* GetException();
72 
73   // The shared function info in case {status} is not kEvaluating, kEvaluated or
74   // kErrored.
75   SharedFunctionInfo* GetSharedFunctionInfo() const;
76 
77   // The namespace object (or undefined).
78   DECL_ACCESSORS(module_namespace, HeapObject)
79 
80   // Modules imported or re-exported by this module.
81   // Corresponds 1-to-1 to the module specifier strings in
82   // ModuleInfo::module_requests.
83   DECL_ACCESSORS(requested_modules, FixedArray)
84 
85   // [script]: Script from which the module originates.
86   DECL_ACCESSORS(script, Script)
87 
88   // The value of import.meta inside of this module.
89   // Lazily initialized on first access. It's the hole before first access and
90   // a JSObject afterwards.
91   DECL_ACCESSORS(import_meta, Object)
92 
93   // Get the ModuleInfo associated with the code.
94   inline ModuleInfo* info() const;
95 
96   // Implementation of spec operation ModuleDeclarationInstantiation.
97   // Returns false if an exception occurred during instantiation, true
98   // otherwise. (In the case where the callback throws an exception, that
99   // exception is propagated.)
100   static V8_WARN_UNUSED_RESULT bool Instantiate(
101       Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context,
102       v8::Module::ResolveCallback callback);
103 
104   // Implementation of spec operation ModuleEvaluation.
105   static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate(
106       Isolate* isolate, Handle<Module> module);
107 
108   Cell* GetCell(int cell_index);
109   static Handle<Object> LoadVariable(Isolate* isolate, Handle<Module> module,
110                                      int cell_index);
111   static void StoreVariable(Handle<Module> module, int cell_index,
112                             Handle<Object> value);
113 
114   // Get the namespace object for [module_request] of [module].  If it doesn't
115   // exist yet, it is created.
116   static Handle<JSModuleNamespace> GetModuleNamespace(Isolate* isolate,
117                                                       Handle<Module> module,
118                                                       int module_request);
119 
120   // Get the namespace object for [module].  If it doesn't exist yet, it is
121   // created.
122   static Handle<JSModuleNamespace> GetModuleNamespace(Isolate* isolate,
123                                                       Handle<Module> module);
124 
125   static const int kCodeOffset = HeapObject::kHeaderSize;
126   static const int kExportsOffset = kCodeOffset + kPointerSize;
127   static const int kRegularExportsOffset = kExportsOffset + kPointerSize;
128   static const int kRegularImportsOffset = kRegularExportsOffset + kPointerSize;
129   static const int kHashOffset = kRegularImportsOffset + kPointerSize;
130   static const int kModuleNamespaceOffset = kHashOffset + kPointerSize;
131   static const int kRequestedModulesOffset =
132       kModuleNamespaceOffset + kPointerSize;
133   static const int kStatusOffset = kRequestedModulesOffset + kPointerSize;
134   static const int kDfsIndexOffset = kStatusOffset + kPointerSize;
135   static const int kDfsAncestorIndexOffset = kDfsIndexOffset + kPointerSize;
136   static const int kExceptionOffset = kDfsAncestorIndexOffset + kPointerSize;
137   static const int kScriptOffset = kExceptionOffset + kPointerSize;
138   static const int kImportMetaOffset = kScriptOffset + kPointerSize;
139   static const int kSize = kImportMetaOffset + kPointerSize;
140 
141  private:
142   friend class Factory;
143 
144   DECL_ACCESSORS(exception, Object)
145 
146   // TODO(neis): Don't store those in the module object?
147   DECL_INT_ACCESSORS(dfs_index)
148   DECL_INT_ACCESSORS(dfs_ancestor_index)
149 
150   // Helpers for Instantiate and Evaluate.
151 
152   static void CreateExport(Isolate* isolate, Handle<Module> module,
153                            int cell_index, Handle<FixedArray> names);
154   static void CreateIndirectExport(Isolate* isolate, Handle<Module> module,
155                                    Handle<String> name,
156                                    Handle<ModuleInfoEntry> entry);
157 
158   // The [must_resolve] argument indicates whether or not an exception should be
159   // thrown in case the module does not provide an export named [name]
160   // (including when a cycle is detected).  An exception is always thrown in the
161   // case of conflicting star exports.
162   //
163   // If [must_resolve] is true, a null result indicates an exception. If
164   // [must_resolve] is false, a null result may or may not indicate an
165   // exception (so check manually!).
166   class ResolveSet;
167   static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExport(
168       Isolate* isolate, Handle<Module> module, Handle<String> module_specifier,
169       Handle<String> export_name, MessageLocation loc, bool must_resolve,
170       ResolveSet* resolve_set);
171   static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveImport(
172       Isolate* isolate, Handle<Module> module, Handle<String> name,
173       int module_request, MessageLocation loc, bool must_resolve,
174       ResolveSet* resolve_set);
175 
176   static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExportUsingStarExports(
177       Isolate* isolate, Handle<Module> module, Handle<String> module_specifier,
178       Handle<String> export_name, MessageLocation loc, bool must_resolve,
179       ResolveSet* resolve_set);
180 
181   static V8_WARN_UNUSED_RESULT bool PrepareInstantiate(
182       Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context,
183       v8::Module::ResolveCallback callback);
184   static V8_WARN_UNUSED_RESULT bool FinishInstantiate(
185       Isolate* isolate, Handle<Module> module,
186       ZoneForwardList<Handle<Module>>* stack, unsigned* dfs_index, Zone* zone);
187   static V8_WARN_UNUSED_RESULT bool RunInitializationCode(
188       Isolate* isolate, Handle<Module> module);
189 
190   static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate(
191       Isolate* isolate, Handle<Module> module,
192       ZoneForwardList<Handle<Module>>* stack, unsigned* dfs_index);
193 
194   static V8_WARN_UNUSED_RESULT bool MaybeTransitionComponent(
195       Isolate* isolate, Handle<Module> module,
196       ZoneForwardList<Handle<Module>>* stack, Status new_status);
197 
198   // Set module's status back to kUninstantiated and reset other internal state.
199   // This is used when instantiation fails.
200   static void Reset(Isolate* isolate, Handle<Module> module);
201   static void ResetGraph(Isolate* isolate, Handle<Module> module);
202 
203   // To set status to kErrored, RecordError should be used.
204   void SetStatus(Status status);
205   void RecordError(Isolate* isolate);
206 
207 #ifdef DEBUG
208   // For --trace-module-status.
209   void PrintStatusTransition(Status new_status);
210 #endif  // DEBUG
211 
212   DISALLOW_IMPLICIT_CONSTRUCTORS(Module);
213 };
214 
215 // When importing a module namespace (import * as foo from "bar"), a
216 // JSModuleNamespace object (representing module "bar") is created and bound to
217 // the declared variable (foo).  A module can have at most one namespace object.
218 class JSModuleNamespace : public JSObject {
219  public:
220   DECL_CAST(JSModuleNamespace)
221   DECL_PRINTER(JSModuleNamespace)
222   DECL_VERIFIER(JSModuleNamespace)
223 
224   // The actual module whose namespace is being represented.
225   DECL_ACCESSORS(module, Module)
226 
227   // Retrieve the value exported by [module] under the given [name]. If there is
228   // no such export, return Just(undefined). If the export is uninitialized,
229   // schedule an exception and return Nothing.
230   V8_WARN_UNUSED_RESULT MaybeHandle<Object> GetExport(Isolate* isolate,
231                                                       Handle<String> name);
232 
233   // Return the (constant) property attributes for the referenced property,
234   // which is assumed to correspond to an export. If the export is
235   // uninitialized, schedule an exception and return Nothing.
236   static V8_WARN_UNUSED_RESULT Maybe<PropertyAttributes> GetPropertyAttributes(
237       LookupIterator* it);
238 
239   // In-object fields.
240   enum {
241     kToStringTagFieldIndex,
242     kInObjectFieldCount,
243   };
244 
245   static const int kModuleOffset = JSObject::kHeaderSize;
246   static const int kHeaderSize = kModuleOffset + kPointerSize;
247 
248   static const int kSize = kHeaderSize + kPointerSize * kInObjectFieldCount;
249 
250  private:
251   DISALLOW_IMPLICIT_CONSTRUCTORS(JSModuleNamespace);
252 };
253 
254 // ModuleInfo is to ModuleDescriptor what ScopeInfo is to Scope.
255 class ModuleInfo : public FixedArray {
256  public:
257   DECL_CAST(ModuleInfo)
258 
259   static Handle<ModuleInfo> New(Isolate* isolate, Zone* zone,
260                                 ModuleDescriptor* descr);
261 
262   inline FixedArray* module_requests() const;
263   inline FixedArray* special_exports() const;
264   inline FixedArray* regular_exports() const;
265   inline FixedArray* regular_imports() const;
266   inline FixedArray* namespace_imports() const;
267   inline FixedArray* module_request_positions() const;
268 
269   // Accessors for [regular_exports].
270   int RegularExportCount() const;
271   String* RegularExportLocalName(int i) const;
272   int RegularExportCellIndex(int i) const;
273   FixedArray* RegularExportExportNames(int i) const;
274 
275 #ifdef DEBUG
276   inline bool Equals(ModuleInfo* other) const;
277 #endif
278 
279  private:
280   friend class Factory;
281   friend class ModuleDescriptor;
282   enum {
283     kModuleRequestsIndex,
284     kSpecialExportsIndex,
285     kRegularExportsIndex,
286     kNamespaceImportsIndex,
287     kRegularImportsIndex,
288     kModuleRequestPositionsIndex,
289     kLength
290   };
291   enum {
292     kRegularExportLocalNameOffset,
293     kRegularExportCellIndexOffset,
294     kRegularExportExportNamesOffset,
295     kRegularExportLength
296   };
297   DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleInfo);
298 };
299 
300 class ModuleInfoEntry : public Struct {
301  public:
302   DECL_CAST(ModuleInfoEntry)
303   DECL_PRINTER(ModuleInfoEntry)
304   DECL_VERIFIER(ModuleInfoEntry)
305 
306   DECL_ACCESSORS(export_name, Object)
307   DECL_ACCESSORS(local_name, Object)
308   DECL_ACCESSORS(import_name, Object)
309   DECL_INT_ACCESSORS(module_request)
310   DECL_INT_ACCESSORS(cell_index)
311   DECL_INT_ACCESSORS(beg_pos)
312   DECL_INT_ACCESSORS(end_pos)
313 
314   static Handle<ModuleInfoEntry> New(Isolate* isolate,
315                                      Handle<Object> export_name,
316                                      Handle<Object> local_name,
317                                      Handle<Object> import_name,
318                                      int module_request, int cell_index,
319                                      int beg_pos, int end_pos);
320 
321   static const int kExportNameOffset = HeapObject::kHeaderSize;
322   static const int kLocalNameOffset = kExportNameOffset + kPointerSize;
323   static const int kImportNameOffset = kLocalNameOffset + kPointerSize;
324   static const int kModuleRequestOffset = kImportNameOffset + kPointerSize;
325   static const int kCellIndexOffset = kModuleRequestOffset + kPointerSize;
326   static const int kBegPosOffset = kCellIndexOffset + kPointerSize;
327   static const int kEndPosOffset = kBegPosOffset + kPointerSize;
328   static const int kSize = kEndPosOffset + kPointerSize;
329 
330  private:
331   DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleInfoEntry);
332 };
333 
334 }  // namespace internal
335 }  // namespace v8
336 
337 #include "src/objects/object-macros-undef.h"
338 
339 #endif  // V8_OBJECTS_MODULE_H_
340