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