blob: 21dd84ad7220e5529889a6e6da16c52ba7897a4a [file] [log] [blame]
// 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"
#include "src/objects/js-objects.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:
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_ACCESSORS2(regular_exports, FixedArray)
DECL_ACCESSORS2(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_ACCESSORS2(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_ACCESSORS2(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);
static int ImportIndex(int cell_index);
static int ExportIndex(int cell_index);
// 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);
// Layout description.
#define MODULE_FIELDS(V) \
V(kCodeOffset, kTaggedSize) \
V(kExportsOffset, kTaggedSize) \
V(kRegularExportsOffset, kTaggedSize) \
V(kRegularImportsOffset, kTaggedSize) \
V(kHashOffset, kTaggedSize) \
V(kModuleNamespaceOffset, kTaggedSize) \
V(kRequestedModulesOffset, kTaggedSize) \
V(kStatusOffset, kTaggedSize) \
V(kDfsIndexOffset, kTaggedSize) \
V(kDfsAncestorIndexOffset, kTaggedSize) \
V(kExceptionOffset, kTaggedSize) \
V(kScriptOffset, kTaggedSize) \
V(kImportMetaOffset, kTaggedSize) \
/* Total size. */ \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, MODULE_FIELDS)
#undef MODULE_FIELDS
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_CAST2(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,
};
// Layout description.
#define JS_MODULE_NAMESPACE_FIELDS(V) \
V(kModuleOffset, kTaggedSize) \
/* Header size. */ \
V(kHeaderSize, 0) \
V(kInObjectFieldsOffset, kTaggedSize* kInObjectFieldCount) \
/* Total size. */ \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
JS_MODULE_NAMESPACE_FIELDS)
#undef JS_MODULE_NAMESPACE_FIELDS
OBJECT_CONSTRUCTORS(JSModuleNamespace, JSObject);
};
// ModuleInfo is to ModuleDescriptor what ScopeInfo is to Scope.
class ModuleInfo : public FixedArray {
public:
DECL_CAST2(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
};
OBJECT_CONSTRUCTORS(ModuleInfo, FixedArray);
};
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);
// Layout description.
#define MODULE_INFO_FIELDS(V) \
V(kExportNameOffset, kTaggedSize) \
V(kLocalNameOffset, kTaggedSize) \
V(kImportNameOffset, kTaggedSize) \
V(kModuleRequestOffset, kTaggedSize) \
V(kCellIndexOffset, kTaggedSize) \
V(kBegPosOffset, kTaggedSize) \
V(kEndPosOffset, kTaggedSize) \
/* Total size. */ \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, MODULE_INFO_FIELDS)
#undef MODULE_INFO_FIELDS
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleInfoEntry);
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_MODULE_H_