1/*
2 * Copyright (C) 2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "Identifier.h"
29#include "JSDestructibleObject.h"
30#include <wtf/ListHashSet.h>
31
32namespace JSC {
33
34class JSModuleEnvironment;
35class JSModuleNamespaceObject;
36class JSMap;
37
38// Based on the Source Text Module Record
39// http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
40class AbstractModuleRecord : public JSDestructibleObject {
41 friend class LLIntOffsetsExtractor;
42public:
43 typedef JSDestructibleObject Base;
44
45 // https://tc39.github.io/ecma262/#sec-source-text-module-records
46 struct ExportEntry {
47 enum class Type {
48 Local,
49 Indirect
50 };
51
52 static ExportEntry createLocal(const Identifier& exportName, const Identifier& localName);
53 static ExportEntry createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName);
54
55 Type type;
56 Identifier exportName;
57 Identifier moduleName;
58 Identifier importName;
59 Identifier localName;
60 };
61
62 enum class ImportEntryType { Single, Namespace };
63 struct ImportEntry {
64 ImportEntryType type;
65 Identifier moduleRequest;
66 Identifier importName;
67 Identifier localName;
68 };
69
70 typedef WTF::ListHashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> OrderedIdentifierSet;
71 typedef HashMap<RefPtr<UniquedStringImpl>, ImportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ImportEntries;
72 typedef HashMap<RefPtr<UniquedStringImpl>, ExportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ExportEntries;
73
74 DECLARE_EXPORT_INFO;
75
76 void appendRequestedModule(const Identifier&);
77 void addStarExportEntry(const Identifier&);
78 void addImportEntry(const ImportEntry&);
79 void addExportEntry(const ExportEntry&);
80
81 Optional<ImportEntry> tryGetImportEntry(UniquedStringImpl* localName);
82 Optional<ExportEntry> tryGetExportEntry(UniquedStringImpl* exportName);
83
84 const Identifier& moduleKey() const { return m_moduleKey; }
85 const OrderedIdentifierSet& requestedModules() const { return m_requestedModules; }
86 const ExportEntries& exportEntries() const { return m_exportEntries; }
87 const ImportEntries& importEntries() const { return m_importEntries; }
88 const OrderedIdentifierSet& starExportEntries() const { return m_starExportEntries; }
89
90 void dump();
91
92 struct Resolution {
93 enum class Type { Resolved, NotFound, Ambiguous, Error };
94
95 static Resolution notFound();
96 static Resolution error();
97 static Resolution ambiguous();
98
99 Type type;
100 AbstractModuleRecord* moduleRecord;
101 Identifier localName;
102 };
103
104 Resolution resolveExport(JSGlobalObject*, const Identifier& exportName);
105 Resolution resolveImport(JSGlobalObject*, const Identifier& localName);
106
107 AbstractModuleRecord* hostResolveImportedModule(JSGlobalObject*, const Identifier& moduleName);
108
109 JSModuleNamespaceObject* getModuleNamespace(JSGlobalObject*);
110
111 JSModuleEnvironment* moduleEnvironment()
112 {
113 ASSERT(m_moduleEnvironment);
114 return m_moduleEnvironment.get();
115 }
116
117 JSModuleEnvironment* moduleEnvironmentMayBeNull()
118 {
119 return m_moduleEnvironment.get();
120 }
121
122 void link(JSGlobalObject*, JSValue scriptFetcher);
123 JS_EXPORT_PRIVATE JSValue evaluate(JSGlobalObject*);
124
125protected:
126 AbstractModuleRecord(VM&, Structure*, const Identifier&);
127 void finishCreation(JSGlobalObject*, VM&);
128
129 static void visitChildren(JSCell*, SlotVisitor&);
130 static void destroy(JSCell*);
131
132 WriteBarrier<JSModuleEnvironment> m_moduleEnvironment;
133
134private:
135 struct ResolveQuery;
136 static Resolution resolveExportImpl(JSGlobalObject*, const ResolveQuery&);
137 Optional<Resolution> tryGetCachedResolution(UniquedStringImpl* exportName);
138 void cacheResolution(UniquedStringImpl* exportName, const Resolution&);
139
140 // The loader resolves the given module name to the module key. The module key is the unique value to represent this module.
141 Identifier m_moduleKey;
142
143 // Currently, we don't keep the occurrence order of the import / export entries.
144 // So, we does not guarantee the order of the errors.
145 // e.g. The import declaration that occurr later than the another import declaration may
146 // throw the error even if the former import declaration also has the invalid content.
147 //
148 // import ... // (1) this has some invalid content.
149 // import ... // (2) this also has some invalid content.
150 //
151 // In the above case, (2) may throw the error earlier than (1)
152 //
153 // But, in all the cases, we will throw the syntax error. So except for the content of the syntax error,
154 // there are no difference.
155
156 // Map localName -> ImportEntry.
157 ImportEntries m_importEntries;
158
159 // Map exportName -> ExportEntry.
160 ExportEntries m_exportEntries;
161
162 // Save the occurrence order since resolveExport requires it.
163 OrderedIdentifierSet m_starExportEntries;
164
165 // Save the occurrence order since the module loader loads and runs the modules in this order.
166 // http://www.ecma-international.org/ecma-262/6.0/#sec-moduleevaluation
167 OrderedIdentifierSet m_requestedModules;
168
169 WriteBarrier<JSMap> m_dependenciesMap;
170
171 WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
172
173 // We assume that all the AbstractModuleRecord are retained by JSModuleLoader's registry.
174 // So here, we don't visit each object for GC. The resolution cache map caches the once
175 // looked up correctly resolved resolution, since (1) we rarely looked up the non-resolved one,
176 // and (2) if we cache all the attempts the size of the map becomes infinitely large.
177 typedef HashMap<RefPtr<UniquedStringImpl>, Resolution, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> Resolutions;
178 Resolutions m_resolutionCache;
179};
180
181} // namespace JSC
182