b3f00c5153a634ad94d0478eae829eca832a516c
[WebKit-https.git] / Source / JavaScriptCore / runtime / ModuleLoaderPrototype.cpp
1 /*
2  * Copyright (C) 2015-2016 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 #include "config.h"
27 #include "ModuleLoaderPrototype.h"
28
29 #include "BuiltinNames.h"
30 #include "CatchScope.h"
31 #include "CodeProfiling.h"
32 #include "Error.h"
33 #include "Exception.h"
34 #include "JSCInlines.h"
35 #include "JSGlobalObjectFunctions.h"
36 #include "JSInternalPromise.h"
37 #include "JSInternalPromiseDeferred.h"
38 #include "JSMap.h"
39 #include "JSModuleEnvironment.h"
40 #include "JSModuleLoader.h"
41 #include "JSModuleNamespaceObject.h"
42 #include "JSModuleRecord.h"
43 #include "JSSourceCode.h"
44 #include "ModuleAnalyzer.h"
45 #include "Nodes.h"
46 #include "Parser.h"
47 #include "ParserError.h"
48
49 namespace JSC {
50
51 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeParseModule(ExecState*);
52 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeRequestedModules(ExecState*);
53 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeEvaluate(ExecState*);
54 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeModuleDeclarationInstantiation(ExecState*);
55 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeResolve(ExecState*);
56 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeResolveSync(ExecState*);
57 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeFetch(ExecState*);
58 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeGetModuleNamespaceObject(ExecState*);
59 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeNotifyCompleted(ExecState*);
60 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeNotifyFailed(ExecState*);
61
62 }
63
64 #include "ModuleLoaderPrototype.lut.h"
65
66 namespace JSC {
67
68 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ModuleLoaderPrototype);
69
70 const ClassInfo ModuleLoaderPrototype::s_info = { "ModuleLoader", &Base::s_info, &moduleLoaderPrototypeTable, nullptr, CREATE_METHOD_TABLE(ModuleLoaderPrototype) };
71
72 /* Source for ModuleLoaderPrototype.lut.h
73 @begin moduleLoaderPrototypeTable
74     ensureRegistered               JSBuiltin                                           DontEnum|Function 1
75     forceFulfillPromise            JSBuiltin                                           DontEnum|Function 2
76     fulfillFetch                   JSBuiltin                                           DontEnum|Function 2
77     requestFetch                   JSBuiltin                                           DontEnum|Function 3
78     requestInstantiate             JSBuiltin                                           DontEnum|Function 3
79     requestSatisfy                 JSBuiltin                                           DontEnum|Function 3
80     link                           JSBuiltin                                           DontEnum|Function 2
81     moduleDeclarationInstantiation moduleLoaderPrototypeModuleDeclarationInstantiation DontEnum|Function 3
82     moduleEvaluation               JSBuiltin                                           DontEnum|Function 2
83     evaluate                       moduleLoaderPrototypeEvaluate                       DontEnum|Function 3
84     provideFetch                   JSBuiltin                                           DontEnum|Function 2
85     loadAndEvaluateModule          JSBuiltin                                           DontEnum|Function 3
86     loadModule                     JSBuiltin                                           DontEnum|Function 3
87     linkAndEvaluateModule          JSBuiltin                                           DontEnum|Function 2
88     requestImportModule            JSBuiltin                                           DontEnum|Function 3
89     getModuleNamespaceObject       moduleLoaderPrototypeGetModuleNamespaceObject       DontEnum|Function 1
90     parseModule                    moduleLoaderPrototypeParseModule                    DontEnum|Function 2
91     requestedModules               moduleLoaderPrototypeRequestedModules               DontEnum|Function 1
92     resolve                        moduleLoaderPrototypeResolve                        DontEnum|Function 2
93     resolveSync                    moduleLoaderPrototypeResolveSync                    DontEnum|Function 2
94     fetch                          moduleLoaderPrototypeFetch                          DontEnum|Function 3
95     notifyCompleted                moduleLoaderPrototypeNotifyCompleted                DontEnum|Function 2
96     notifyFailed                   moduleLoaderPrototypeNotifyFailed                   DontEnum|Function 2
97 @end
98 */
99
100 ModuleLoaderPrototype::ModuleLoaderPrototype(VM& vm, Structure* structure)
101     : JSNonFinalObject(vm, structure)
102 {
103 }
104
105 // ------------------------------ Functions --------------------------------
106
107 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeParseModule(ExecState* exec)
108 {
109     VM& vm = exec->vm();
110     auto scope = DECLARE_THROW_SCOPE(vm);
111
112     const Identifier moduleKey = exec->argument(0).toPropertyKey(exec);
113     RETURN_IF_EXCEPTION(scope, encodedJSValue());
114
115     auto* jsSourceCode = jsDynamicCast<JSSourceCode*>(vm, exec->argument(1));
116     if (!jsSourceCode)
117         return throwVMTypeError(exec, scope);
118     SourceCode sourceCode = jsSourceCode->sourceCode();
119
120     CodeProfiling profile(sourceCode);
121
122     ParserError error;
123     std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
124         &vm, sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin,
125         JSParserStrictMode::Strict, JSParserScriptMode::Module, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
126
127     if (error.isValid()) {
128         throwVMError(exec, scope, error.toErrorObject(exec->lexicalGlobalObject(), sourceCode));
129         return JSValue::encode(jsUndefined());
130     }
131     ASSERT(moduleProgramNode);
132
133     ModuleAnalyzer moduleAnalyzer(exec, moduleKey, sourceCode, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
134     RETURN_IF_EXCEPTION(scope, encodedJSValue());
135     JSModuleRecord* moduleRecord = moduleAnalyzer.analyze(*moduleProgramNode);
136
137     return JSValue::encode(moduleRecord);
138 }
139
140 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeRequestedModules(ExecState* exec)
141 {
142     VM& vm = exec->vm();
143     auto scope = DECLARE_THROW_SCOPE(vm);
144     JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(vm, exec->argument(0));
145     if (!moduleRecord) {
146         scope.release();
147         return JSValue::encode(constructEmptyArray(exec, nullptr));
148     }
149
150     JSArray* result = constructEmptyArray(exec, nullptr, moduleRecord->requestedModules().size());
151     RETURN_IF_EXCEPTION(scope, encodedJSValue());
152     size_t i = 0;
153     for (auto& key : moduleRecord->requestedModules()) {
154         result->putDirectIndex(exec, i++, jsString(exec, key.get()));
155         RETURN_IF_EXCEPTION(scope, encodedJSValue());
156     }
157     return JSValue::encode(result);
158 }
159
160 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeModuleDeclarationInstantiation(ExecState* exec)
161 {
162     VM& vm = exec->vm();
163     auto scope = DECLARE_THROW_SCOPE(vm);
164     JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(vm, exec->argument(0));
165     if (!moduleRecord)
166         return JSValue::encode(jsUndefined());
167
168     if (Options::dumpModuleLoadingState())
169         dataLog("Loader [link] ", moduleRecord->moduleKey(), "\n");
170
171     moduleRecord->link(exec, exec->argument(1), exec->argument(2));
172     RETURN_IF_EXCEPTION(scope, encodedJSValue());
173
174     return JSValue::encode(jsUndefined());
175 }
176
177 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeNotifyCompleted(ExecState* exec)
178 {
179     VM& vm = exec->vm();
180     JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, exec->thisValue());
181     if (!loader)
182         return JSValue::encode(jsUndefined());
183     return JSValue::encode(loader->notifyCompleted(exec, exec->argument(0), exec->argument(1)));
184 }
185
186 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeNotifyFailed(ExecState* exec)
187 {
188     VM& vm = exec->vm();
189     JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, exec->thisValue());
190     if (!loader)
191         return JSValue::encode(jsUndefined());
192     return JSValue::encode(loader->notifyFailed(exec, exec->argument(0), exec->argument(1)));
193 }
194
195 // ------------------------------ Hook Functions ---------------------------
196
197 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeResolve(ExecState* exec)
198 {
199     VM& vm = exec->vm();
200     // Hook point, Loader.resolve.
201     // https://whatwg.github.io/loader/#browser-resolve
202     // Take the name and resolve it to the unique identifier for the resource location.
203     // For example, take the "jquery" and return the URL for the resource.
204     JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, exec->thisValue());
205     if (!loader)
206         return JSValue::encode(jsUndefined());
207     return JSValue::encode(loader->resolve(exec, exec->argument(0), exec->argument(1), exec->argument(2)));
208 }
209
210 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeResolveSync(ExecState* exec)
211 {
212     VM& vm = exec->vm();
213     auto scope = DECLARE_CATCH_SCOPE(vm);
214
215     JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, exec->thisValue());
216     if (!loader)
217         return JSValue::encode(jsUndefined());
218     auto result = loader->resolveSync(exec, exec->argument(0), exec->argument(1), exec->argument(2));
219     RETURN_IF_EXCEPTION(scope, encodedJSValue());
220     return JSValue::encode(identifierToJSValue(vm, result));
221 }
222
223 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeFetch(ExecState* exec)
224 {
225     VM& vm = exec->vm();
226     // Hook point, Loader.fetch
227     // https://whatwg.github.io/loader/#browser-fetch
228     // Take the key and fetch the resource actually.
229     // For example, JavaScriptCore shell can provide the hook fetching the resource
230     // from the local file system.
231     JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, exec->thisValue());
232     if (!loader)
233         return JSValue::encode(jsUndefined());
234     return JSValue::encode(loader->fetch(exec, exec->argument(0), exec->argument(1), exec->argument(2)));
235 }
236
237 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeGetModuleNamespaceObject(ExecState* exec)
238 {
239     VM& vm = exec->vm();
240     auto scope = DECLARE_THROW_SCOPE(vm);
241
242     auto* loader = jsDynamicCast<JSModuleLoader*>(vm, exec->thisValue());
243     if (!loader)
244         return JSValue::encode(jsUndefined());
245     auto* moduleNamespaceObject = loader->getModuleNamespaceObject(exec, exec->argument(0));
246     RETURN_IF_EXCEPTION(scope, encodedJSValue());
247     return JSValue::encode(moduleNamespaceObject);
248 }
249
250 // ------------------- Additional Hook Functions ---------------------------
251
252 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeEvaluate(ExecState* exec)
253 {
254     // To instrument and retrieve the errors raised from the module execution,
255     // we inserted the hook point here.
256
257     VM& vm = exec->vm();
258     JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, exec->thisValue());
259     if (!loader)
260         return JSValue::encode(jsUndefined());
261     return JSValue::encode(loader->evaluate(exec, exec->argument(0), exec->argument(1), exec->argument(2)));
262 }
263
264 } // namespace JSC