| // Copyright 2017 the V8 project authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef V8_OBJECTS_MODULE_H_ | |
| #define V8_OBJECTS_MODULE_H_ | |
| #include "src/objects.h" | |
| #include "src/objects/fixed-array.h" | |
| // Has to be the last include (doesn't have include guards): | |
| #include "src/objects/object-macros.h" | |
| namespace v8 { | |
| namespace internal { | |
| template <typename T> | |
| class Handle; | |
| class Isolate; | |
| class JSModuleNamespace; | |
| class ModuleDescriptor; | |
| class ModuleInfo; | |
| class ModuleInfoEntry; | |
| class String; | |
| class Zone; | |
| // The runtime representation of an ECMAScript module. | |
| class Module : public Struct, public NeverReadOnlySpaceObject { | |
| public: | |
| using NeverReadOnlySpaceObject::GetHeap; | |
| using NeverReadOnlySpaceObject::GetIsolate; | |
| DECL_CAST(Module) | |
| DECL_VERIFIER(Module) | |
| DECL_PRINTER(Module) | |
| // The code representing this module, or an abstraction thereof. | |
| // This is either a SharedFunctionInfo, a JSFunction, a JSGeneratorObject, or | |
| // a ModuleInfo, depending on the state (status) the module is in. See | |
| // Module::ModuleVerify() for the precise invariant. | |
| DECL_ACCESSORS(code, Object) | |
| // Arrays of cells corresponding to regular exports and regular imports. | |
| // A cell's position in the array is determined by the cell index of the | |
| // associated module entry (which coincides with the variable index of the | |
| // associated variable). | |
| DECL_ACCESSORS(regular_exports, FixedArray) | |
| DECL_ACCESSORS(regular_imports, FixedArray) | |
| // The complete export table, mapping an export name to its cell. | |
| // TODO(neis): We may want to remove the regular exports from the table. | |
| DECL_ACCESSORS(exports, ObjectHashTable) | |
| // Hash for this object (a random non-zero Smi). | |
| DECL_INT_ACCESSORS(hash) | |
| // Status. | |
| DECL_INT_ACCESSORS(status) | |
| enum Status { | |
| // Order matters! | |
| kUninstantiated, | |
| kPreInstantiating, | |
| kInstantiating, | |
| kInstantiated, | |
| kEvaluating, | |
| kEvaluated, | |
| kErrored | |
| }; | |
| // The exception in the case {status} is kErrored. | |
| Object* GetException(); | |
| // The shared function info in case {status} is not kEvaluating, kEvaluated or | |
| // kErrored. | |
| SharedFunctionInfo* GetSharedFunctionInfo() const; | |
| // The namespace object (or undefined). | |
| DECL_ACCESSORS(module_namespace, HeapObject) | |
| // Modules imported or re-exported by this module. | |
| // Corresponds 1-to-1 to the module specifier strings in | |
| // ModuleInfo::module_requests. | |
| DECL_ACCESSORS(requested_modules, FixedArray) | |
| // [script]: Script from which the module originates. | |
| DECL_ACCESSORS(script, Script) | |
| // The value of import.meta inside of this module. | |
| // Lazily initialized on first access. It's the hole before first access and | |
| // a JSObject afterwards. | |
| DECL_ACCESSORS(import_meta, Object) | |
| // Get the ModuleInfo associated with the code. | |
| inline ModuleInfo* info() const; | |
| // Implementation of spec operation ModuleDeclarationInstantiation. | |
| // Returns false if an exception occurred during instantiation, true | |
| // otherwise. (In the case where the callback throws an exception, that | |
| // exception is propagated.) | |
| static V8_WARN_UNUSED_RESULT bool Instantiate( | |
| Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context, | |
| v8::Module::ResolveCallback callback); | |
| // Implementation of spec operation ModuleEvaluation. | |
| static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate( | |
| Isolate* isolate, Handle<Module> module); | |
| Cell* GetCell(int cell_index); | |
| static Handle<Object> LoadVariable(Isolate* isolate, Handle<Module> module, | |
| int cell_index); | |
| static void StoreVariable(Handle<Module> module, int cell_index, | |
| Handle<Object> value); | |
| // Get the namespace object for [module_request] of [module]. If it doesn't | |
| // exist yet, it is created. | |
| static Handle<JSModuleNamespace> GetModuleNamespace(Isolate* isolate, | |
| Handle<Module> module, | |
| int module_request); | |
| // Get the namespace object for [module]. If it doesn't exist yet, it is | |
| // created. | |
| static Handle<JSModuleNamespace> GetModuleNamespace(Isolate* isolate, | |
| Handle<Module> module); | |
| static const int kCodeOffset = HeapObject::kHeaderSize; | |
| static const int kExportsOffset = kCodeOffset + kPointerSize; | |
| static const int kRegularExportsOffset = kExportsOffset + kPointerSize; | |
| static const int kRegularImportsOffset = kRegularExportsOffset + kPointerSize; | |
| static const int kHashOffset = kRegularImportsOffset + kPointerSize; | |
| static const int kModuleNamespaceOffset = kHashOffset + kPointerSize; | |
| static const int kRequestedModulesOffset = | |
| kModuleNamespaceOffset + kPointerSize; | |
| static const int kStatusOffset = kRequestedModulesOffset + kPointerSize; | |
| static const int kDfsIndexOffset = kStatusOffset + kPointerSize; | |
| static const int kDfsAncestorIndexOffset = kDfsIndexOffset + kPointerSize; | |
| static const int kExceptionOffset = kDfsAncestorIndexOffset + kPointerSize; | |
| static const int kScriptOffset = kExceptionOffset + kPointerSize; | |
| static const int kImportMetaOffset = kScriptOffset + kPointerSize; | |
| static const int kSize = kImportMetaOffset + kPointerSize; | |
| private: | |
| friend class Factory; | |
| DECL_ACCESSORS(exception, Object) | |
| // TODO(neis): Don't store those in the module object? | |
| DECL_INT_ACCESSORS(dfs_index) | |
| DECL_INT_ACCESSORS(dfs_ancestor_index) | |
| // Helpers for Instantiate and Evaluate. | |
| static void CreateExport(Isolate* isolate, Handle<Module> module, | |
| int cell_index, Handle<FixedArray> names); | |
| static void CreateIndirectExport(Isolate* isolate, Handle<Module> module, | |
| Handle<String> name, | |
| Handle<ModuleInfoEntry> entry); | |
| // The [must_resolve] argument indicates whether or not an exception should be | |
| // thrown in case the module does not provide an export named [name] | |
| // (including when a cycle is detected). An exception is always thrown in the | |
| // case of conflicting star exports. | |
| // | |
| // If [must_resolve] is true, a null result indicates an exception. If | |
| // [must_resolve] is false, a null result may or may not indicate an | |
| // exception (so check manually!). | |
| class ResolveSet; | |
| static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExport( | |
| Isolate* isolate, Handle<Module> module, Handle<String> module_specifier, | |
| Handle<String> export_name, MessageLocation loc, bool must_resolve, | |
| ResolveSet* resolve_set); | |
| static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveImport( | |
| Isolate* isolate, Handle<Module> module, Handle<String> name, | |
| int module_request, MessageLocation loc, bool must_resolve, | |
| ResolveSet* resolve_set); | |
| static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExportUsingStarExports( | |
| Isolate* isolate, Handle<Module> module, Handle<String> module_specifier, | |
| Handle<String> export_name, MessageLocation loc, bool must_resolve, | |
| ResolveSet* resolve_set); | |
| static V8_WARN_UNUSED_RESULT bool PrepareInstantiate( | |
| Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context, | |
| v8::Module::ResolveCallback callback); | |
| static V8_WARN_UNUSED_RESULT bool FinishInstantiate( | |
| Isolate* isolate, Handle<Module> module, | |
| ZoneForwardList<Handle<Module>>* stack, unsigned* dfs_index, Zone* zone); | |
| static V8_WARN_UNUSED_RESULT bool RunInitializationCode( | |
| Isolate* isolate, Handle<Module> module); | |
| static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate( | |
| Isolate* isolate, Handle<Module> module, | |
| ZoneForwardList<Handle<Module>>* stack, unsigned* dfs_index); | |
| static V8_WARN_UNUSED_RESULT bool MaybeTransitionComponent( | |
| Isolate* isolate, Handle<Module> module, | |
| ZoneForwardList<Handle<Module>>* stack, Status new_status); | |
| // Set module's status back to kUninstantiated and reset other internal state. | |
| // This is used when instantiation fails. | |
| static void Reset(Isolate* isolate, Handle<Module> module); | |
| static void ResetGraph(Isolate* isolate, Handle<Module> module); | |
| // To set status to kErrored, RecordError should be used. | |
| void SetStatus(Status status); | |
| void RecordError(Isolate* isolate); | |
| #ifdef DEBUG | |
| // For --trace-module-status. | |
| void PrintStatusTransition(Status new_status); | |
| #endif // DEBUG | |
| DISALLOW_IMPLICIT_CONSTRUCTORS(Module); | |
| }; | |
| // When importing a module namespace (import * as foo from "bar"), a | |
| // JSModuleNamespace object (representing module "bar") is created and bound to | |
| // the declared variable (foo). A module can have at most one namespace object. | |
| class JSModuleNamespace : public JSObject { | |
| public: | |
| DECL_CAST(JSModuleNamespace) | |
| DECL_PRINTER(JSModuleNamespace) | |
| DECL_VERIFIER(JSModuleNamespace) | |
| // The actual module whose namespace is being represented. | |
| DECL_ACCESSORS(module, Module) | |
| // Retrieve the value exported by [module] under the given [name]. If there is | |
| // no such export, return Just(undefined). If the export is uninitialized, | |
| // schedule an exception and return Nothing. | |
| V8_WARN_UNUSED_RESULT MaybeHandle<Object> GetExport(Isolate* isolate, | |
| Handle<String> name); | |
| // Return the (constant) property attributes for the referenced property, | |
| // which is assumed to correspond to an export. If the export is | |
| // uninitialized, schedule an exception and return Nothing. | |
| static V8_WARN_UNUSED_RESULT Maybe<PropertyAttributes> GetPropertyAttributes( | |
| LookupIterator* it); | |
| // In-object fields. | |
| enum { | |
| kToStringTagFieldIndex, | |
| kInObjectFieldCount, | |
| }; | |
| static const int kModuleOffset = JSObject::kHeaderSize; | |
| static const int kHeaderSize = kModuleOffset + kPointerSize; | |
| static const int kSize = kHeaderSize + kPointerSize * kInObjectFieldCount; | |
| private: | |
| DISALLOW_IMPLICIT_CONSTRUCTORS(JSModuleNamespace); | |
| }; | |
| // ModuleInfo is to ModuleDescriptor what ScopeInfo is to Scope. | |
| class ModuleInfo : public FixedArray { | |
| public: | |
| DECL_CAST(ModuleInfo) | |
| static Handle<ModuleInfo> New(Isolate* isolate, Zone* zone, | |
| ModuleDescriptor* descr); | |
| inline FixedArray* module_requests() const; | |
| inline FixedArray* special_exports() const; | |
| inline FixedArray* regular_exports() const; | |
| inline FixedArray* regular_imports() const; | |
| inline FixedArray* namespace_imports() const; | |
| inline FixedArray* module_request_positions() const; | |
| // Accessors for [regular_exports]. | |
| int RegularExportCount() const; | |
| String* RegularExportLocalName(int i) const; | |
| int RegularExportCellIndex(int i) const; | |
| FixedArray* RegularExportExportNames(int i) const; | |
| #ifdef DEBUG | |
| inline bool Equals(ModuleInfo* other) const; | |
| #endif | |
| private: | |
| friend class Factory; | |
| friend class ModuleDescriptor; | |
| enum { | |
| kModuleRequestsIndex, | |
| kSpecialExportsIndex, | |
| kRegularExportsIndex, | |
| kNamespaceImportsIndex, | |
| kRegularImportsIndex, | |
| kModuleRequestPositionsIndex, | |
| kLength | |
| }; | |
| enum { | |
| kRegularExportLocalNameOffset, | |
| kRegularExportCellIndexOffset, | |
| kRegularExportExportNamesOffset, | |
| kRegularExportLength | |
| }; | |
| DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleInfo); | |
| }; | |
| class ModuleInfoEntry : public Struct { | |
| public: | |
| DECL_CAST(ModuleInfoEntry) | |
| DECL_PRINTER(ModuleInfoEntry) | |
| DECL_VERIFIER(ModuleInfoEntry) | |
| DECL_ACCESSORS(export_name, Object) | |
| DECL_ACCESSORS(local_name, Object) | |
| DECL_ACCESSORS(import_name, Object) | |
| DECL_INT_ACCESSORS(module_request) | |
| DECL_INT_ACCESSORS(cell_index) | |
| DECL_INT_ACCESSORS(beg_pos) | |
| DECL_INT_ACCESSORS(end_pos) | |
| static Handle<ModuleInfoEntry> New(Isolate* isolate, | |
| Handle<Object> export_name, | |
| Handle<Object> local_name, | |
| Handle<Object> import_name, | |
| int module_request, int cell_index, | |
| int beg_pos, int end_pos); | |
| static const int kExportNameOffset = HeapObject::kHeaderSize; | |
| static const int kLocalNameOffset = kExportNameOffset + kPointerSize; | |
| static const int kImportNameOffset = kLocalNameOffset + kPointerSize; | |
| static const int kModuleRequestOffset = kImportNameOffset + kPointerSize; | |
| static const int kCellIndexOffset = kModuleRequestOffset + kPointerSize; | |
| static const int kBegPosOffset = kCellIndexOffset + kPointerSize; | |
| static const int kEndPosOffset = kBegPosOffset + kPointerSize; | |
| static const int kSize = kEndPosOffset + kPointerSize; | |
| private: | |
| DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleInfoEntry); | |
| }; | |
| } // namespace internal | |
| } // namespace v8 | |
| #include "src/objects/object-macros-undef.h" | |
| #endif // V8_OBJECTS_MODULE_H_ |