[WebAssembly][Modules] Prototype wasm import
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSModuleLoader.cpp
1 /*
2  * Copyright (C) 2015-2017 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "JSModuleLoader.h"
29
30 #include "BuiltinNames.h"
31 #include "CatchScope.h"
32 #include "CodeProfiling.h"
33 #include "Error.h"
34 #include "Exception.h"
35 #include "JSCInlines.h"
36 #include "JSGlobalObjectFunctions.h"
37 #include "JSInternalPromise.h"
38 #include "JSInternalPromiseDeferred.h"
39 #include "JSMap.h"
40 #include "JSModuleEnvironment.h"
41 #include "JSModuleRecord.h"
42 #include "JSSourceCode.h"
43 #include "ModuleAnalyzer.h"
44 #include "ModuleLoaderPrototype.h"
45 #include "Nodes.h"
46 #include "ObjectConstructor.h"
47 #include "Parser.h"
48 #include "ParserError.h"
49
50 namespace JSC {
51
52 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSModuleLoader);
53
54 const ClassInfo JSModuleLoader::s_info = { "ModuleLoader", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSModuleLoader) };
55
56 JSModuleLoader::JSModuleLoader(VM& vm, Structure* structure)
57     : JSNonFinalObject(vm, structure)
58 {
59 }
60
61 void JSModuleLoader::finishCreation(ExecState* exec, VM& vm, JSGlobalObject* globalObject)
62 {
63     auto scope = DECLARE_CATCH_SCOPE(vm);
64
65     Base::finishCreation(vm);
66     ASSERT(inherits(vm, info()));
67     JSMap* map = JSMap::create(exec, vm, globalObject->mapStructure());
68     scope.releaseAssertNoException();
69     putDirect(vm, Identifier::fromString(&vm, "registry"), map);
70 }
71
72 // ------------------------------ Functions --------------------------------
73
74 static String printableModuleKey(ExecState* exec, JSValue key)
75 {
76     VM& vm = exec->vm();
77     if (key.isString() || key.isSymbol())
78         return key.toPropertyKey(exec).impl();
79     return vm.propertyNames->emptyIdentifier.impl();
80 }
81
82 JSValue JSModuleLoader::provideFetch(ExecState* exec, JSValue key, const SourceCode& sourceCode)
83 {
84     VM& vm = exec->vm();
85     auto scope = DECLARE_THROW_SCOPE(vm);
86
87     JSObject* function = jsCast<JSObject*>(get(exec, vm.propertyNames->builtinNames().provideFetchPublicName()));
88     RETURN_IF_EXCEPTION(scope, { });
89     CallData callData;
90     CallType callType = JSC::getCallData(function, callData);
91     ASSERT(callType != CallType::None);
92
93     SourceCode source { sourceCode };
94     MarkedArgumentBuffer arguments;
95     arguments.append(key);
96     arguments.append(JSSourceCode::create(vm, WTFMove(source)));
97     ASSERT(!arguments.hasOverflowed());
98
99     scope.release();
100     return call(exec, function, callType, callData, this, arguments);
101 }
102
103 JSInternalPromise* JSModuleLoader::loadAndEvaluateModule(ExecState* exec, JSValue moduleName, JSValue parameters, JSValue scriptFetcher)
104 {
105     VM& vm = exec->vm();
106     auto scope = DECLARE_THROW_SCOPE(vm);
107
108     JSObject* function = jsCast<JSObject*>(get(exec, vm.propertyNames->builtinNames().loadAndEvaluateModulePublicName()));
109     RETURN_IF_EXCEPTION(scope, nullptr);
110     CallData callData;
111     CallType callType = JSC::getCallData(function, callData);
112     ASSERT(callType != CallType::None);
113
114     MarkedArgumentBuffer arguments;
115     arguments.append(moduleName);
116     arguments.append(parameters);
117     arguments.append(scriptFetcher);
118     ASSERT(!arguments.hasOverflowed());
119
120     scope.release();
121     return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
122 }
123
124 JSInternalPromise* JSModuleLoader::loadModule(ExecState* exec, JSValue moduleName, JSValue parameters, JSValue scriptFetcher)
125 {
126     VM& vm = exec->vm();
127     auto scope = DECLARE_THROW_SCOPE(vm);
128
129     JSObject* function = jsCast<JSObject*>(get(exec, vm.propertyNames->builtinNames().loadModulePublicName()));
130     RETURN_IF_EXCEPTION(scope, nullptr);
131     CallData callData;
132     CallType callType = JSC::getCallData(function, callData);
133     ASSERT(callType != CallType::None);
134
135     MarkedArgumentBuffer arguments;
136     arguments.append(moduleName);
137     arguments.append(parameters);
138     arguments.append(scriptFetcher);
139     ASSERT(!arguments.hasOverflowed());
140
141     scope.release();
142     return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
143 }
144
145 JSValue JSModuleLoader::linkAndEvaluateModule(ExecState* exec, JSValue moduleKey, JSValue scriptFetcher)
146 {
147     VM& vm = exec->vm();
148     auto scope = DECLARE_THROW_SCOPE(vm);
149
150     JSObject* function = jsCast<JSObject*>(get(exec, vm.propertyNames->builtinNames().linkAndEvaluateModulePublicName()));
151     RETURN_IF_EXCEPTION(scope, { });
152     CallData callData;
153     CallType callType = JSC::getCallData(function, callData);
154     ASSERT(callType != CallType::None);
155
156     MarkedArgumentBuffer arguments;
157     arguments.append(moduleKey);
158     arguments.append(scriptFetcher);
159     ASSERT(!arguments.hasOverflowed());
160
161     scope.release();
162     return call(exec, function, callType, callData, this, arguments);
163 }
164
165 JSInternalPromise* JSModuleLoader::requestImportModule(ExecState* exec, const Identifier& moduleKey, JSValue parameters, JSValue scriptFetcher)
166 {
167     VM& vm = exec->vm();
168     auto scope = DECLARE_THROW_SCOPE(vm);
169
170     auto* function = jsCast<JSObject*>(get(exec, vm.propertyNames->builtinNames().requestImportModulePublicName()));
171     RETURN_IF_EXCEPTION(scope, nullptr);
172     CallData callData;
173     auto callType = JSC::getCallData(function, callData);
174     ASSERT(callType != CallType::None);
175
176     MarkedArgumentBuffer arguments;
177     arguments.append(jsString(exec, moduleKey.impl()));
178     arguments.append(parameters);
179     arguments.append(scriptFetcher);
180     ASSERT(!arguments.hasOverflowed());
181
182     scope.release();
183     return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
184 }
185
186 JSInternalPromise* JSModuleLoader::importModule(ExecState* exec, JSString* moduleName, JSValue parameters, const SourceOrigin& referrer)
187 {
188     if (Options::dumpModuleLoadingState())
189         dataLog("Loader [import] ", printableModuleKey(exec, moduleName), "\n");
190
191     auto* globalObject = exec->lexicalGlobalObject();
192     VM& vm = globalObject->vm();
193     auto scope = DECLARE_CATCH_SCOPE(vm);
194
195     if (globalObject->globalObjectMethodTable()->moduleLoaderImportModule)
196         return globalObject->globalObjectMethodTable()->moduleLoaderImportModule(globalObject, exec, this, moduleName, parameters, referrer);
197
198     auto* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
199     auto moduleNameString = moduleName->value(exec);
200     if (UNLIKELY(scope.exception())) {
201         JSValue exception = scope.exception()->value();
202         scope.clearException();
203         deferred->reject(exec, exception);
204         return deferred->promise();
205     }
206     deferred->reject(exec, createError(exec, makeString("Could not import the module '", moduleNameString, "'.")));
207     return deferred->promise();
208 }
209
210 Identifier JSModuleLoader::resolveSync(ExecState* exec, JSValue name, JSValue referrer, JSValue scriptFetcher)
211 {
212     if (Options::dumpModuleLoadingState())
213         dataLog("Loader [resolve] ", printableModuleKey(exec, name), "\n");
214
215     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
216     if (globalObject->globalObjectMethodTable()->moduleLoaderResolve)
217         return globalObject->globalObjectMethodTable()->moduleLoaderResolve(globalObject, exec, this, name, referrer, scriptFetcher);
218     return name.toPropertyKey(exec);
219 }
220
221 JSInternalPromise* JSModuleLoader::resolve(ExecState* exec, JSValue name, JSValue referrer, JSValue scriptFetcher)
222 {
223     VM& vm = exec->vm();
224     auto scope = DECLARE_CATCH_SCOPE(vm);
225
226     JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, exec->lexicalGlobalObject());
227     scope.releaseAssertNoException();
228     const Identifier moduleKey = resolveSync(exec, name, referrer, scriptFetcher);
229     if (UNLIKELY(scope.exception())) {
230         JSValue exception = scope.exception();
231         scope.clearException();
232         return deferred->reject(exec, exception);
233     }
234     auto result = deferred->resolve(exec, identifierToJSValue(vm, moduleKey));
235     scope.releaseAssertNoException();
236     return result;
237 }
238
239 JSInternalPromise* JSModuleLoader::fetch(ExecState* exec, JSValue key, JSValue parameters, JSValue scriptFetcher)
240 {
241     if (Options::dumpModuleLoadingState())
242         dataLog("Loader [fetch] ", printableModuleKey(exec, key), "\n");
243
244     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
245     VM& vm = globalObject->vm();
246     auto scope = DECLARE_CATCH_SCOPE(vm);
247     if (globalObject->globalObjectMethodTable()->moduleLoaderFetch)
248         return globalObject->globalObjectMethodTable()->moduleLoaderFetch(globalObject, exec, this, key, parameters, scriptFetcher);
249     JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
250     String moduleKey = key.toWTFString(exec);
251     if (UNLIKELY(scope.exception())) {
252         JSValue exception = scope.exception()->value();
253         scope.clearException();
254         deferred->reject(exec, exception);
255         return deferred->promise();
256     }
257     deferred->reject(exec, createError(exec, makeString("Could not open the module '", moduleKey, "'.")));
258     return deferred->promise();
259 }
260
261 JSObject* JSModuleLoader::createImportMetaProperties(ExecState* exec, JSValue key, JSModuleRecord* moduleRecord, JSValue scriptFetcher)
262 {
263     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
264     if (globalObject->globalObjectMethodTable()->moduleLoaderCreateImportMetaProperties)
265         return globalObject->globalObjectMethodTable()->moduleLoaderCreateImportMetaProperties(globalObject, exec, this, key, moduleRecord, scriptFetcher);
266     return constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
267 }
268
269 JSValue JSModuleLoader::evaluate(ExecState* exec, JSValue key, JSValue moduleRecordValue, JSValue scriptFetcher)
270 {
271     if (Options::dumpModuleLoadingState())
272         dataLog("Loader [evaluate] ", printableModuleKey(exec, key), "\n");
273
274     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
275     if (globalObject->globalObjectMethodTable()->moduleLoaderEvaluate)
276         return globalObject->globalObjectMethodTable()->moduleLoaderEvaluate(globalObject, exec, this, key, moduleRecordValue, scriptFetcher);
277
278     if (auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(exec->vm(), moduleRecordValue))
279         return moduleRecord->evaluate(exec);
280     return jsUndefined();
281 }
282
283 JSModuleNamespaceObject* JSModuleLoader::getModuleNamespaceObject(ExecState* exec, JSValue moduleRecordValue)
284 {
285     VM& vm = exec->vm();
286     auto scope = DECLARE_THROW_SCOPE(vm);
287
288     auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(vm, moduleRecordValue);
289     if (!moduleRecord) {
290         throwTypeError(exec, scope);
291         return nullptr;
292     }
293
294     scope.release();
295     return moduleRecord->getModuleNamespace(exec);
296 }
297
298 } // namespace JSC