1/*
2 * Copyright (C) 2015-2019 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 "JSMap.h"
39#include "JSModuleEnvironment.h"
40#include "JSModuleNamespaceObject.h"
41#include "JSModuleRecord.h"
42#include "JSSourceCode.h"
43#include "JSWebAssembly.h"
44#include "ModuleAnalyzer.h"
45#include "Nodes.h"
46#include "ObjectConstructor.h"
47#include "Parser.h"
48#include "ParserError.h"
49
50namespace JSC {
51
52static EncodedJSValue JSC_HOST_CALL moduleLoaderParseModule(JSGlobalObject*, CallFrame*);
53static EncodedJSValue JSC_HOST_CALL moduleLoaderRequestedModules(JSGlobalObject*, CallFrame*);
54static EncodedJSValue JSC_HOST_CALL moduleLoaderEvaluate(JSGlobalObject*, CallFrame*);
55static EncodedJSValue JSC_HOST_CALL moduleLoaderModuleDeclarationInstantiation(JSGlobalObject*, CallFrame*);
56static EncodedJSValue JSC_HOST_CALL moduleLoaderResolve(JSGlobalObject*, CallFrame*);
57static EncodedJSValue JSC_HOST_CALL moduleLoaderResolveSync(JSGlobalObject*, CallFrame*);
58static EncodedJSValue JSC_HOST_CALL moduleLoaderFetch(JSGlobalObject*, CallFrame*);
59static EncodedJSValue JSC_HOST_CALL moduleLoaderGetModuleNamespaceObject(JSGlobalObject*, CallFrame*);
60
61}
62
63#include "JSModuleLoader.lut.h"
64
65namespace JSC {
66
67STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSModuleLoader);
68
69const ClassInfo JSModuleLoader::s_info = { "ModuleLoader", &Base::s_info, &moduleLoaderTable, nullptr, CREATE_METHOD_TABLE(JSModuleLoader) };
70
71/* Source for JSModuleLoader.lut.h
72@begin moduleLoaderTable
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 moduleLoaderModuleDeclarationInstantiation DontEnum|Function 2
81 moduleEvaluation JSBuiltin DontEnum|Function 2
82 evaluate moduleLoaderEvaluate 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 dependencyKeysIfEvaluated JSBuiltin DontEnum|Function 1
89 getModuleNamespaceObject moduleLoaderGetModuleNamespaceObject DontEnum|Function 1
90 parseModule moduleLoaderParseModule DontEnum|Function 2
91 requestedModules moduleLoaderRequestedModules DontEnum|Function 1
92 resolve moduleLoaderResolve DontEnum|Function 2
93 resolveSync moduleLoaderResolveSync DontEnum|Function 2
94 fetch moduleLoaderFetch DontEnum|Function 3
95@end
96*/
97
98JSModuleLoader::JSModuleLoader(VM& vm, Structure* structure)
99 : JSNonFinalObject(vm, structure)
100{
101}
102
103void JSModuleLoader::finishCreation(JSGlobalObject* globalObject, VM& vm)
104{
105 auto scope = DECLARE_CATCH_SCOPE(vm);
106
107 Base::finishCreation(vm);
108 ASSERT(inherits(vm, info()));
109 JSMap* map = JSMap::create(globalObject, vm, globalObject->mapStructure());
110 scope.releaseAssertNoException();
111 putDirect(vm, Identifier::fromString(vm, "registry"), map);
112}
113
114// ------------------------------ Functions --------------------------------
115
116static String printableModuleKey(JSGlobalObject* globalObject, JSValue key)
117{
118 VM& vm = globalObject->vm();
119 auto scope = DECLARE_THROW_SCOPE(vm);
120 if (key.isString() || key.isSymbol()) {
121 auto propertyName = key.toPropertyKey(globalObject);
122 scope.assertNoException(); // This is OK since this function is just for debugging purpose.
123 return propertyName.impl();
124 }
125 return vm.propertyNames->emptyIdentifier.impl();
126}
127
128JSArray* JSModuleLoader::dependencyKeysIfEvaluated(JSGlobalObject* globalObject, JSValue key)
129{
130 VM& vm = globalObject->vm();
131 auto scope = DECLARE_THROW_SCOPE(vm);
132
133 JSObject* function = jsCast<JSObject*>(get(globalObject, vm.propertyNames->builtinNames().dependencyKeysIfEvaluatedPublicName()));
134 RETURN_IF_EXCEPTION(scope, nullptr);
135 CallData callData;
136 CallType callType = JSC::getCallData(vm, function, callData);
137 ASSERT(callType != CallType::None);
138
139 MarkedArgumentBuffer arguments;
140 arguments.append(key);
141
142 JSValue result = call(globalObject, function, callType, callData, this, arguments);
143 RETURN_IF_EXCEPTION(scope, nullptr);
144
145 return jsDynamicCast<JSArray*>(vm, result);
146}
147
148JSValue JSModuleLoader::provideFetch(JSGlobalObject* globalObject, JSValue key, const SourceCode& sourceCode)
149{
150 VM& vm = globalObject->vm();
151 auto scope = DECLARE_THROW_SCOPE(vm);
152
153 JSObject* function = jsCast<JSObject*>(get(globalObject, vm.propertyNames->builtinNames().provideFetchPublicName()));
154 RETURN_IF_EXCEPTION(scope, { });
155 CallData callData;
156 CallType callType = JSC::getCallData(vm, function, callData);
157 ASSERT(callType != CallType::None);
158
159 SourceCode source { sourceCode };
160 MarkedArgumentBuffer arguments;
161 arguments.append(key);
162 arguments.append(JSSourceCode::create(vm, WTFMove(source)));
163 ASSERT(!arguments.hasOverflowed());
164
165 RELEASE_AND_RETURN(scope, call(globalObject, function, callType, callData, this, arguments));
166}
167
168JSInternalPromise* JSModuleLoader::loadAndEvaluateModule(JSGlobalObject* globalObject, JSValue moduleName, JSValue parameters, JSValue scriptFetcher)
169{
170 VM& vm = globalObject->vm();
171 auto scope = DECLARE_THROW_SCOPE(vm);
172
173 JSObject* function = jsCast<JSObject*>(get(globalObject, vm.propertyNames->builtinNames().loadAndEvaluateModulePublicName()));
174 RETURN_IF_EXCEPTION(scope, nullptr);
175 CallData callData;
176 CallType callType = JSC::getCallData(vm, function, callData);
177 ASSERT(callType != CallType::None);
178
179 MarkedArgumentBuffer arguments;
180 arguments.append(moduleName);
181 arguments.append(parameters);
182 arguments.append(scriptFetcher);
183 ASSERT(!arguments.hasOverflowed());
184
185 JSValue promise = call(globalObject, function, callType, callData, this, arguments);
186 RETURN_IF_EXCEPTION(scope, nullptr);
187 return jsCast<JSInternalPromise*>(promise);
188}
189
190JSInternalPromise* JSModuleLoader::loadModule(JSGlobalObject* globalObject, JSValue moduleName, JSValue parameters, JSValue scriptFetcher)
191{
192 VM& vm = globalObject->vm();
193 auto scope = DECLARE_THROW_SCOPE(vm);
194
195 JSObject* function = jsCast<JSObject*>(get(globalObject, vm.propertyNames->builtinNames().loadModulePublicName()));
196 RETURN_IF_EXCEPTION(scope, nullptr);
197 CallData callData;
198 CallType callType = JSC::getCallData(vm, function, callData);
199 ASSERT(callType != CallType::None);
200
201 MarkedArgumentBuffer arguments;
202 arguments.append(moduleName);
203 arguments.append(parameters);
204 arguments.append(scriptFetcher);
205 ASSERT(!arguments.hasOverflowed());
206
207 JSValue promise = call(globalObject, function, callType, callData, this, arguments);
208 RETURN_IF_EXCEPTION(scope, nullptr);
209 return jsCast<JSInternalPromise*>(promise);
210}
211
212JSValue JSModuleLoader::linkAndEvaluateModule(JSGlobalObject* globalObject, JSValue moduleKey, JSValue scriptFetcher)
213{
214 VM& vm = globalObject->vm();
215 auto scope = DECLARE_THROW_SCOPE(vm);
216
217 JSObject* function = jsCast<JSObject*>(get(globalObject, vm.propertyNames->builtinNames().linkAndEvaluateModulePublicName()));
218 RETURN_IF_EXCEPTION(scope, { });
219 CallData callData;
220 CallType callType = JSC::getCallData(vm, function, callData);
221 ASSERT(callType != CallType::None);
222
223 MarkedArgumentBuffer arguments;
224 arguments.append(moduleKey);
225 arguments.append(scriptFetcher);
226 ASSERT(!arguments.hasOverflowed());
227
228 RELEASE_AND_RETURN(scope, call(globalObject, function, callType, callData, this, arguments));
229}
230
231JSInternalPromise* JSModuleLoader::requestImportModule(JSGlobalObject* globalObject, const Identifier& moduleKey, JSValue parameters, JSValue scriptFetcher)
232{
233 VM& vm = globalObject->vm();
234 auto scope = DECLARE_THROW_SCOPE(vm);
235
236 auto* function = jsCast<JSObject*>(get(globalObject, vm.propertyNames->builtinNames().requestImportModulePublicName()));
237 RETURN_IF_EXCEPTION(scope, nullptr);
238 CallData callData;
239 auto callType = JSC::getCallData(vm, function, callData);
240 ASSERT(callType != CallType::None);
241
242 MarkedArgumentBuffer arguments;
243 arguments.append(jsString(vm, moduleKey.impl()));
244 arguments.append(parameters);
245 arguments.append(scriptFetcher);
246 ASSERT(!arguments.hasOverflowed());
247
248 JSValue promise = call(globalObject, function, callType, callData, this, arguments);
249 RETURN_IF_EXCEPTION(scope, nullptr);
250 return jsCast<JSInternalPromise*>(promise);
251}
252
253JSInternalPromise* JSModuleLoader::importModule(JSGlobalObject* globalObject, JSString* moduleName, JSValue parameters, const SourceOrigin& referrer)
254{
255 if (Options::dumpModuleLoadingState())
256 dataLog("Loader [import] ", printableModuleKey(globalObject, moduleName), "\n");
257
258 VM& vm = globalObject->vm();
259 auto throwScope = DECLARE_THROW_SCOPE(vm);
260
261 if (globalObject->globalObjectMethodTable()->moduleLoaderImportModule)
262 RELEASE_AND_RETURN(throwScope, globalObject->globalObjectMethodTable()->moduleLoaderImportModule(globalObject, this, moduleName, parameters, referrer));
263
264 auto* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure());
265
266 auto catchScope = DECLARE_CATCH_SCOPE(vm);
267 auto moduleNameString = moduleName->value(globalObject);
268 if (UNLIKELY(catchScope.exception())) {
269 JSValue exception = catchScope.exception()->value();
270 catchScope.clearException();
271 promise->reject(globalObject, exception);
272 catchScope.clearException();
273 return promise;
274 }
275 promise->reject(globalObject, createError(globalObject, makeString("Could not import the module '", moduleNameString, "'.")));
276 catchScope.clearException();
277 return promise;
278}
279
280Identifier JSModuleLoader::resolveSync(JSGlobalObject* globalObject, JSValue name, JSValue referrer, JSValue scriptFetcher)
281{
282 if (Options::dumpModuleLoadingState())
283 dataLog("Loader [resolve] ", printableModuleKey(globalObject, name), "\n");
284
285 if (globalObject->globalObjectMethodTable()->moduleLoaderResolve)
286 return globalObject->globalObjectMethodTable()->moduleLoaderResolve(globalObject, this, name, referrer, scriptFetcher);
287 return name.toPropertyKey(globalObject);
288}
289
290JSInternalPromise* JSModuleLoader::resolve(JSGlobalObject* globalObject, JSValue name, JSValue referrer, JSValue scriptFetcher)
291{
292 VM& vm = globalObject->vm();
293
294 auto* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure());
295
296 auto catchScope = DECLARE_CATCH_SCOPE(vm);
297
298 const Identifier moduleKey = resolveSync(globalObject, name, referrer, scriptFetcher);
299 if (UNLIKELY(catchScope.exception())) {
300 JSValue exception = catchScope.exception();
301 catchScope.clearException();
302 promise->reject(globalObject, exception);
303 catchScope.clearException();
304 return promise;
305 }
306 promise->resolve(globalObject, identifierToJSValue(vm, moduleKey));
307 catchScope.clearException();
308 return promise;
309}
310
311JSInternalPromise* JSModuleLoader::fetch(JSGlobalObject* globalObject, JSValue key, JSValue parameters, JSValue scriptFetcher)
312{
313 if (Options::dumpModuleLoadingState())
314 dataLog("Loader [fetch] ", printableModuleKey(globalObject, key), "\n");
315
316 VM& vm = globalObject->vm();
317 auto throwScope = DECLARE_THROW_SCOPE(vm);
318
319 if (globalObject->globalObjectMethodTable()->moduleLoaderFetch)
320 RELEASE_AND_RETURN(throwScope, globalObject->globalObjectMethodTable()->moduleLoaderFetch(globalObject, this, key, parameters, scriptFetcher));
321
322 auto* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure());
323
324 auto catchScope = DECLARE_CATCH_SCOPE(vm);
325
326 String moduleKey = key.toWTFString(globalObject);
327 if (UNLIKELY(catchScope.exception())) {
328 JSValue exception = catchScope.exception()->value();
329 catchScope.clearException();
330 promise->reject(globalObject, exception);
331 catchScope.clearException();
332 return promise;
333 }
334 promise->reject(globalObject, createError(globalObject, makeString("Could not open the module '", moduleKey, "'.")));
335 catchScope.clearException();
336 return promise;
337}
338
339JSObject* JSModuleLoader::createImportMetaProperties(JSGlobalObject* globalObject, JSValue key, JSModuleRecord* moduleRecord, JSValue scriptFetcher)
340{
341 if (globalObject->globalObjectMethodTable()->moduleLoaderCreateImportMetaProperties)
342 return globalObject->globalObjectMethodTable()->moduleLoaderCreateImportMetaProperties(globalObject, this, key, moduleRecord, scriptFetcher);
343 return constructEmptyObject(globalObject->vm(), globalObject->nullPrototypeObjectStructure());
344}
345
346JSValue JSModuleLoader::evaluate(JSGlobalObject* globalObject, JSValue key, JSValue moduleRecordValue, JSValue scriptFetcher)
347{
348 if (Options::dumpModuleLoadingState())
349 dataLog("Loader [evaluate] ", printableModuleKey(globalObject, key), "\n");
350
351 if (globalObject->globalObjectMethodTable()->moduleLoaderEvaluate)
352 return globalObject->globalObjectMethodTable()->moduleLoaderEvaluate(globalObject, this, key, moduleRecordValue, scriptFetcher);
353
354 return evaluateNonVirtual(globalObject, key, moduleRecordValue, scriptFetcher);
355}
356
357JSValue JSModuleLoader::evaluateNonVirtual(JSGlobalObject* globalObject, JSValue, JSValue moduleRecordValue, JSValue)
358{
359 if (auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(globalObject->vm(), moduleRecordValue))
360 return moduleRecord->evaluate(globalObject);
361 return jsUndefined();
362}
363
364JSModuleNamespaceObject* JSModuleLoader::getModuleNamespaceObject(JSGlobalObject* globalObject, JSValue moduleRecordValue)
365{
366 VM& vm = globalObject->vm();
367 auto scope = DECLARE_THROW_SCOPE(vm);
368
369 auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(vm, moduleRecordValue);
370 if (!moduleRecord) {
371 throwTypeError(globalObject, scope);
372 return nullptr;
373 }
374
375 RELEASE_AND_RETURN(scope, moduleRecord->getModuleNamespace(globalObject));
376}
377
378// ------------------------------ Functions --------------------------------
379
380EncodedJSValue JSC_HOST_CALL moduleLoaderParseModule(JSGlobalObject* globalObject, CallFrame* callFrame)
381{
382 VM& vm = globalObject->vm();
383
384 auto* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure());
385
386 auto catchScope = DECLARE_CATCH_SCOPE(vm);
387 auto reject = [&] (JSValue rejectionReason) {
388 catchScope.clearException();
389 promise->reject(globalObject, rejectionReason);
390 catchScope.clearException();
391 return JSValue::encode(promise);
392 };
393
394 const Identifier moduleKey = callFrame->argument(0).toPropertyKey(globalObject);
395 if (UNLIKELY(catchScope.exception()))
396 return reject(catchScope.exception());
397
398 JSValue source = callFrame->argument(1);
399 auto* jsSourceCode = jsCast<JSSourceCode*>(source);
400 SourceCode sourceCode = jsSourceCode->sourceCode();
401
402#if ENABLE(WEBASSEMBLY)
403 if (sourceCode.provider()->sourceType() == SourceProviderSourceType::WebAssembly)
404 return JSValue::encode(JSWebAssembly::instantiate(globalObject, promise, moduleKey, jsSourceCode));
405#endif
406
407 CodeProfiling profile(sourceCode);
408
409 ParserError error;
410 std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
411 vm, sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin,
412 JSParserStrictMode::Strict, JSParserScriptMode::Module, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
413 if (error.isValid())
414 return reject(error.toErrorObject(globalObject, sourceCode));
415 ASSERT(moduleProgramNode);
416
417 ModuleAnalyzer moduleAnalyzer(globalObject, moduleKey, sourceCode, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
418 if (UNLIKELY(catchScope.exception()))
419 return reject(catchScope.exception());
420
421 promise->resolve(globalObject, moduleAnalyzer.analyze(*moduleProgramNode));
422 catchScope.clearException();
423 return JSValue::encode(promise);
424}
425
426EncodedJSValue JSC_HOST_CALL moduleLoaderRequestedModules(JSGlobalObject* globalObject, CallFrame* callFrame)
427{
428 VM& vm = globalObject->vm();
429 auto scope = DECLARE_THROW_SCOPE(vm);
430 auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(vm, callFrame->argument(0));
431 if (!moduleRecord)
432 RELEASE_AND_RETURN(scope, JSValue::encode(constructEmptyArray(globalObject, nullptr)));
433
434 JSArray* result = constructEmptyArray(globalObject, nullptr, moduleRecord->requestedModules().size());
435 RETURN_IF_EXCEPTION(scope, encodedJSValue());
436 size_t i = 0;
437 for (auto& key : moduleRecord->requestedModules()) {
438 result->putDirectIndex(globalObject, i++, jsString(vm, key.get()));
439 RETURN_IF_EXCEPTION(scope, encodedJSValue());
440 }
441 return JSValue::encode(result);
442}
443
444EncodedJSValue JSC_HOST_CALL moduleLoaderModuleDeclarationInstantiation(JSGlobalObject* globalObject, CallFrame* callFrame)
445{
446 VM& vm = globalObject->vm();
447 auto scope = DECLARE_THROW_SCOPE(vm);
448 auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(vm, callFrame->argument(0));
449 if (!moduleRecord)
450 return JSValue::encode(jsUndefined());
451
452 if (Options::dumpModuleLoadingState())
453 dataLog("Loader [link] ", moduleRecord->moduleKey(), "\n");
454
455 moduleRecord->link(globalObject, callFrame->argument(1));
456 RETURN_IF_EXCEPTION(scope, encodedJSValue());
457
458 return JSValue::encode(jsUndefined());
459}
460
461// ------------------------------ Hook Functions ---------------------------
462
463EncodedJSValue JSC_HOST_CALL moduleLoaderResolve(JSGlobalObject* globalObject, CallFrame* callFrame)
464{
465 VM& vm = globalObject->vm();
466 // Hook point, Loader.resolve.
467 // https://whatwg.github.io/loader/#browser-resolve
468 // Take the name and resolve it to the unique identifier for the resource location.
469 // For example, take the "jquery" and return the URL for the resource.
470 JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, callFrame->thisValue());
471 if (!loader)
472 return JSValue::encode(jsUndefined());
473 return JSValue::encode(loader->resolve(globalObject, callFrame->argument(0), callFrame->argument(1), callFrame->argument(2)));
474}
475
476EncodedJSValue JSC_HOST_CALL moduleLoaderResolveSync(JSGlobalObject* globalObject, CallFrame* callFrame)
477{
478 VM& vm = globalObject->vm();
479 auto scope = DECLARE_THROW_SCOPE(vm);
480
481 JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, callFrame->thisValue());
482 if (!loader)
483 return JSValue::encode(jsUndefined());
484 auto result = loader->resolveSync(globalObject, callFrame->argument(0), callFrame->argument(1), callFrame->argument(2));
485 RETURN_IF_EXCEPTION(scope, encodedJSValue());
486 return JSValue::encode(identifierToJSValue(vm, result));
487}
488
489EncodedJSValue JSC_HOST_CALL moduleLoaderFetch(JSGlobalObject* globalObject, CallFrame* callFrame)
490{
491 VM& vm = globalObject->vm();
492 // Hook point, Loader.fetch
493 // https://whatwg.github.io/loader/#browser-fetch
494 // Take the key and fetch the resource actually.
495 // For example, JavaScriptCore shell can provide the hook fetching the resource
496 // from the local file system.
497 JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, callFrame->thisValue());
498 if (!loader)
499 return JSValue::encode(jsUndefined());
500 return JSValue::encode(loader->fetch(globalObject, callFrame->argument(0), callFrame->argument(1), callFrame->argument(2)));
501}
502
503EncodedJSValue JSC_HOST_CALL moduleLoaderGetModuleNamespaceObject(JSGlobalObject* globalObject, CallFrame* callFrame)
504{
505 VM& vm = globalObject->vm();
506 auto scope = DECLARE_THROW_SCOPE(vm);
507
508 auto* loader = jsDynamicCast<JSModuleLoader*>(vm, callFrame->thisValue());
509 if (!loader)
510 return JSValue::encode(jsUndefined());
511 auto* moduleNamespaceObject = loader->getModuleNamespaceObject(globalObject, callFrame->argument(0));
512 RETURN_IF_EXCEPTION(scope, encodedJSValue());
513 return JSValue::encode(moduleNamespaceObject);
514}
515
516// ------------------- Additional Hook Functions ---------------------------
517
518EncodedJSValue JSC_HOST_CALL moduleLoaderEvaluate(JSGlobalObject* globalObject, CallFrame* callFrame)
519{
520 // To instrument and retrieve the errors raised from the module execution,
521 // we inserted the hook point here.
522
523 VM& vm = globalObject->vm();
524 JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(vm, callFrame->thisValue());
525 if (!loader)
526 return JSValue::encode(jsUndefined());
527 return JSValue::encode(loader->evaluate(globalObject, callFrame->argument(0), callFrame->argument(1), callFrame->argument(2)));
528}
529
530} // namespace JSC
531