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