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