diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSModuleRecord.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSModuleRecord.h | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/JSModuleRecord.h b/Source/JavaScriptCore/runtime/JSModuleRecord.h new file mode 100644 index 000000000..b82a9e1d5 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSModuleRecord.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSModuleRecord_h +#define JSModuleRecord_h + +#include "Identifier.h" +#include "JSDestructibleObject.h" +#include "SourceCode.h" +#include "VariableEnvironment.h" +#include <wtf/HashMap.h> +#include <wtf/ListHashSet.h> +#include <wtf/Optional.h> + +namespace JSC { + +class JSModuleNamespaceObject; +class JSModuleEnvironment; +class JSMap; +class ModuleProgramExecutable; + +// Based on the Source Text Module Record +// http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records +class JSModuleRecord : public JSDestructibleObject { + friend class LLIntOffsetsExtractor; +public: + typedef JSDestructibleObject Base; + + struct ExportEntry { + enum class Type { + Local, + Namespace, + Indirect + }; + + static ExportEntry createLocal(const Identifier& exportName, const Identifier& localName, const VariableEnvironmentEntry&); + static ExportEntry createNamespace(const Identifier& exportName, const Identifier& moduleName); + static ExportEntry createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName); + + Type type; + Identifier exportName; + Identifier moduleName; + Identifier importName; + Identifier localName; + VariableEnvironmentEntry variable; + }; + + struct ImportEntry { + Identifier moduleRequest; + Identifier importName; + Identifier localName; + + bool isNamespace(VM& vm) const + { + return importName == vm.propertyNames->timesIdentifier; + } + }; + + typedef WTF::ListHashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> OrderedIdentifierSet; + typedef HashMap<RefPtr<UniquedStringImpl>, ImportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ImportEntries; + typedef HashMap<RefPtr<UniquedStringImpl>, ExportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ExportEntries; + + DECLARE_EXPORT_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + static JSModuleRecord* create(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables) + { + JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm.heap)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables); + instance->finishCreation(vm); + return instance; + } + + void appendRequestedModule(const Identifier&); + void addStarExportEntry(const Identifier&); + void addImportEntry(const ImportEntry&); + void addExportEntry(const ExportEntry&); + + Optional<ImportEntry> tryGetImportEntry(UniquedStringImpl* localName); + Optional<ExportEntry> tryGetExportEntry(UniquedStringImpl* exportName); + + const SourceCode& sourceCode() const { return m_sourceCode; } + const Identifier& moduleKey() const { return m_moduleKey; } + const OrderedIdentifierSet& requestedModules() const { return m_requestedModules; } + const ExportEntries& exportEntries() const { return m_exportEntries; } + const ImportEntries& importEntries() const { return m_importEntries; } + const OrderedIdentifierSet& starExportEntries() const { return m_starExportEntries; } + + const VariableEnvironment& declaredVariables() const { return m_declaredVariables; } + const VariableEnvironment& lexicalVariables() const { return m_lexicalVariables; } + + void dump(); + + JSModuleEnvironment* moduleEnvironment() + { + ASSERT(m_moduleEnvironment); + return m_moduleEnvironment.get(); + } + + void link(ExecState*); + JS_EXPORT_PRIVATE JSValue evaluate(ExecState*); + + ModuleProgramExecutable* moduleProgramExecutable() const { return m_moduleProgramExecutable.get(); } + + struct Resolution { + enum class Type { Resolved, NotFound, Ambiguous, Error }; + + static Resolution notFound(); + static Resolution error(); + static Resolution ambiguous(); + + Type type; + JSModuleRecord* moduleRecord; + Identifier localName; + }; + + Resolution resolveExport(ExecState*, const Identifier& exportName); + Resolution resolveImport(ExecState*, const Identifier& localName); + + JSModuleRecord* hostResolveImportedModule(ExecState*, const Identifier& moduleName); + +private: + JSModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables) + : Base(vm, structure) + , m_moduleKey(moduleKey) + , m_sourceCode(sourceCode) + , m_declaredVariables(declaredVariables) + , m_lexicalVariables(lexicalVariables) + { + } + + void finishCreation(VM&); + + JSModuleNamespaceObject* getModuleNamespace(ExecState*); + + static void visitChildren(JSCell*, SlotVisitor&); + static void destroy(JSCell*); + + void instantiateDeclarations(ExecState*, ModuleProgramExecutable*); + + struct ResolveQuery; + static Resolution resolveExportImpl(ExecState*, const ResolveQuery&); + Optional<Resolution> tryGetCachedResolution(UniquedStringImpl* exportName); + void cacheResolution(UniquedStringImpl* exportName, const Resolution&); + + // The loader resolves the given module name to the module key. The module key is the unique value to represent this module. + Identifier m_moduleKey; + + SourceCode m_sourceCode; + + VariableEnvironment m_declaredVariables; + VariableEnvironment m_lexicalVariables; + + // Currently, we don't keep the occurrence order of the import / export entries. + // So, we does not guarantee the order of the errors. + // e.g. The import declaration that occurr later than the another import declaration may + // throw the error even if the former import declaration also has the invalid content. + // + // import ... // (1) this has some invalid content. + // import ... // (2) this also has some invalid content. + // + // In the above case, (2) may throw the error earlier than (1) + // + // But, in all the cases, we will throw the syntax error. So except for the content of the syntax error, + // there are no difference. + + // Map localName -> ImportEntry. + ImportEntries m_importEntries; + + // Map exportName -> ExportEntry. + ExportEntries m_exportEntries; + + // Save the occurrence order since resolveExport requires it. + OrderedIdentifierSet m_starExportEntries; + + // Save the occurrence order since the module loader loads and runs the modules in this order. + // http://www.ecma-international.org/ecma-262/6.0/#sec-moduleevaluation + OrderedIdentifierSet m_requestedModules; + + WriteBarrier<JSMap> m_dependenciesMap; + + WriteBarrier<ModuleProgramExecutable> m_moduleProgramExecutable; + WriteBarrier<JSModuleEnvironment> m_moduleEnvironment; + WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject; + + // We assume that all the JSModuleRecord are retained by ModuleLoaderObject's registry. + // So here, we don't visit each object for GC. The resolution cache map caches the once + // looked up correctly resolved resolution, since (1) we rarely looked up the non-resolved one, + // and (2) if we cache all the attempts the size of the map becomes infinitely large. + typedef HashMap<RefPtr<UniquedStringImpl>, Resolution, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> Resolutions; + Resolutions m_resolutionCache; +}; + +} // namespace JSC + +#endif // JSModuleRecord_h |