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 | |
16 | namespace v8 { |
17 | namespace internal { |
18 | |
19 | template <typename T> |
20 | class Handle; |
21 | class Isolate; |
22 | class JSModuleNamespace; |
23 | class ModuleDescriptor; |
24 | class ModuleInfo; |
25 | class ModuleInfoEntry; |
26 | class String; |
27 | class Zone; |
28 | |
29 | // The runtime representation of an ECMAScript module. |
30 | class 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. |
226 | class 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(, 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. |
270 | class 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 | |
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 | 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 | |