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#include "src/objects/js-objects.h"
11#include "src/objects/struct.h"
12
13// Has to be the last include (doesn't have include guards):
14#include "src/objects/object-macros.h"
15
16namespace v8 {
17namespace internal {
18
19template <typename T>
20class Handle;
21class Isolate;
22class JSModuleNamespace;
23class ModuleDescriptor;
24class ModuleInfo;
25class ModuleInfoEntry;
26class String;
27class Zone;
28
29// The runtime representation of an ECMAScript module.
30class Module : public Struct {
31 public:
32 NEVER_READ_ONLY_SPACE
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 static int ImportIndex(int cell_index);
115 static int ExportIndex(int cell_index);
116
117 // Get the namespace object for [module_request] of [module]. If it doesn't
118 // exist yet, it is created.
119 static Handle<JSModuleNamespace> GetModuleNamespace(Isolate* isolate,
120 Handle<Module> module,
121 int module_request);
122
123 // Get the namespace object for [module]. If it doesn't exist yet, it is
124 // created.
125 static Handle<JSModuleNamespace> GetModuleNamespace(Isolate* isolate,
126 Handle<Module> module);
127
128// Layout description.
129#define MODULE_FIELDS(V) \
130 V(kCodeOffset, kTaggedSize) \
131 V(kExportsOffset, kTaggedSize) \
132 V(kRegularExportsOffset, kTaggedSize) \
133 V(kRegularImportsOffset, kTaggedSize) \
134 V(kHashOffset, kTaggedSize) \
135 V(kModuleNamespaceOffset, kTaggedSize) \
136 V(kRequestedModulesOffset, kTaggedSize) \
137 V(kStatusOffset, kTaggedSize) \
138 V(kDfsIndexOffset, kTaggedSize) \
139 V(kDfsAncestorIndexOffset, kTaggedSize) \
140 V(kExceptionOffset, kTaggedSize) \
141 V(kScriptOffset, kTaggedSize) \
142 V(kImportMetaOffset, kTaggedSize) \
143 /* Total size. */ \
144 V(kSize, 0)
145
146 DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, MODULE_FIELDS)
147#undef MODULE_FIELDS
148
149 private:
150 friend class Factory;
151
152 DECL_ACCESSORS(exception, Object)
153
154 // TODO(neis): Don't store those in the module object?
155 DECL_INT_ACCESSORS(dfs_index)
156 DECL_INT_ACCESSORS(dfs_ancestor_index)
157
158 // Helpers for Instantiate and Evaluate.
159
160 static void CreateExport(Isolate* isolate, Handle<Module> module,
161 int cell_index, Handle<FixedArray> names);
162 static void CreateIndirectExport(Isolate* isolate, Handle<Module> module,
163 Handle<String> name,
164 Handle<ModuleInfoEntry> entry);
165
166 // The [must_resolve] argument indicates whether or not an exception should be
167 // thrown in case the module does not provide an export named [name]
168 // (including when a cycle is detected). An exception is always thrown in the
169 // case of conflicting star exports.
170 //
171 // If [must_resolve] is true, a null result indicates an exception. If
172 // [must_resolve] is false, a null result may or may not indicate an
173 // exception (so check manually!).
174 class ResolveSet;
175 static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExport(
176 Isolate* isolate, Handle<Module> module, Handle<String> module_specifier,
177 Handle<String> export_name, MessageLocation loc, bool must_resolve,
178 ResolveSet* resolve_set);
179 static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveImport(
180 Isolate* isolate, Handle<Module> module, Handle<String> name,
181 int module_request, MessageLocation loc, bool must_resolve,
182 ResolveSet* resolve_set);
183
184 static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExportUsingStarExports(
185 Isolate* isolate, Handle<Module> module, Handle<String> module_specifier,
186 Handle<String> export_name, MessageLocation loc, bool must_resolve,
187 ResolveSet* resolve_set);
188
189 static V8_WARN_UNUSED_RESULT bool PrepareInstantiate(
190 Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context,
191 v8::Module::ResolveCallback callback);
192 static V8_WARN_UNUSED_RESULT bool FinishInstantiate(
193 Isolate* isolate, Handle<Module> module,
194 ZoneForwardList<Handle<Module>>* stack, unsigned* dfs_index, Zone* zone);
195 static V8_WARN_UNUSED_RESULT bool RunInitializationCode(
196 Isolate* isolate, Handle<Module> module);
197
198 static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate(
199 Isolate* isolate, Handle<Module> module,
200 ZoneForwardList<Handle<Module>>* stack, unsigned* dfs_index);
201
202 static V8_WARN_UNUSED_RESULT bool MaybeTransitionComponent(
203 Isolate* isolate, Handle<Module> module,
204 ZoneForwardList<Handle<Module>>* stack, Status new_status);
205
206 // Set module's status back to kUninstantiated and reset other internal state.
207 // This is used when instantiation fails.
208 static void Reset(Isolate* isolate, Handle<Module> module);
209 static void ResetGraph(Isolate* isolate, Handle<Module> module);
210
211 // To set status to kErrored, RecordError should be used.
212 void SetStatus(Status status);
213 void RecordError(Isolate* isolate);
214
215#ifdef DEBUG
216 // For --trace-module-status.
217 void PrintStatusTransition(Status new_status);
218#endif // DEBUG
219
220 OBJECT_CONSTRUCTORS(Module, Struct);
221};
222
223// When importing a module namespace (import * as foo from "bar"), a
224// JSModuleNamespace object (representing module "bar") is created and bound to
225// the declared variable (foo). A module can have at most one namespace object.
226class JSModuleNamespace : public JSObject {
227 public:
228 DECL_CAST(JSModuleNamespace)
229 DECL_PRINTER(JSModuleNamespace)
230 DECL_VERIFIER(JSModuleNamespace)
231
232 // The actual module whose namespace is being represented.
233 DECL_ACCESSORS(module, Module)
234
235 // Retrieve the value exported by [module] under the given [name]. If there is
236 // no such export, return Just(undefined). If the export is uninitialized,
237 // schedule an exception and return Nothing.
238 V8_WARN_UNUSED_RESULT MaybeHandle<Object> GetExport(Isolate* isolate,
239 Handle<String> name);
240
241 // Return the (constant) property attributes for the referenced property,
242 // which is assumed to correspond to an export. If the export is
243 // uninitialized, schedule an exception and return Nothing.
244 static V8_WARN_UNUSED_RESULT Maybe<PropertyAttributes> GetPropertyAttributes(
245 LookupIterator* it);
246
247 // In-object fields.
248 enum {
249 kToStringTagFieldIndex,
250 kInObjectFieldCount,
251 };
252
253// Layout description.
254#define JS_MODULE_NAMESPACE_FIELDS(V) \
255 V(kModuleOffset, kTaggedSize) \
256 /* Header size. */ \
257 V(kHeaderSize, 0) \
258 V(kInObjectFieldsOffset, kTaggedSize* kInObjectFieldCount) \
259 /* Total size. */ \
260 V(kSize, 0)
261
262 DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
263 JS_MODULE_NAMESPACE_FIELDS)
264#undef JS_MODULE_NAMESPACE_FIELDS
265
266 OBJECT_CONSTRUCTORS(JSModuleNamespace, JSObject);
267};
268
269// ModuleInfo is to ModuleDescriptor what ScopeInfo is to Scope.
270class ModuleInfo : public FixedArray {
271 public:
272 DECL_CAST(ModuleInfo)
273
274 static Handle<ModuleInfo> New(Isolate* isolate, Zone* zone,
275 ModuleDescriptor* descr);
276
277 inline FixedArray module_requests() const;
278 inline FixedArray special_exports() const;
279 inline FixedArray regular_exports() const;
280 inline FixedArray regular_imports() const;
281 inline FixedArray namespace_imports() const;
282 inline FixedArray module_request_positions() const;
283
284 // Accessors for [regular_exports].
285 int RegularExportCount() const;
286 String RegularExportLocalName(int i) const;
287 int RegularExportCellIndex(int i) const;
288 FixedArray RegularExportExportNames(int i) const;
289
290#ifdef DEBUG
291 inline bool Equals(ModuleInfo other) const;
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 OBJECT_CONSTRUCTORS(ModuleInfo, FixedArray);
313};
314
315class 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 DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize,
337 TORQUE_GENERATED_MODULE_INFO_ENTRY_FIELDS)
338
339 OBJECT_CONSTRUCTORS(ModuleInfoEntry, Struct);
340};
341
342} // namespace internal
343} // namespace v8
344
345#include "src/objects/object-macros-undef.h"
346
347#endif // V8_OBJECTS_MODULE_H_
348