|  | /* | 
|  | * Copyright (C) 2015-2021 Apple Inc. All Rights Reserved. | 
|  | * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | * 1. Redistributions of source code must retain the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer. | 
|  | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer in the | 
|  | *    documentation and/or other materials provided with the distribution. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
|  | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|  | * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
|  | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
|  | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
|  | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
|  | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
|  | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "JSModuleLoader.h" | 
|  |  | 
|  | #include "BuiltinNames.h" | 
|  | #include "CatchScope.h" | 
|  | #include "GlobalObjectMethodTable.h" | 
|  | #include "JSCInlines.h" | 
|  | #include "JSInternalPromise.h" | 
|  | #include "JSMap.h" | 
|  | #include "JSModuleNamespaceObject.h" | 
|  | #include "JSModuleRecord.h" | 
|  | #include "JSScriptFetchParameters.h" | 
|  | #include "JSSourceCode.h" | 
|  | #include "JSWebAssembly.h" | 
|  | #include "ModuleAnalyzer.h" | 
|  | #include "Nodes.h" | 
|  | #include "ObjectConstructor.h" | 
|  | #include "Parser.h" | 
|  | #include "ParserError.h" | 
|  | #include "SyntheticModuleRecord.h" | 
|  | #include "VMTrapsInlines.h" | 
|  | #include <wtf/text/MakeString.h> | 
|  |  | 
|  | namespace JSC { | 
|  |  | 
|  | static JSC_DECLARE_HOST_FUNCTION(moduleLoaderParseModule); | 
|  | static JSC_DECLARE_HOST_FUNCTION(moduleLoaderRequestedModules); | 
|  | static JSC_DECLARE_HOST_FUNCTION(moduleLoaderRequestedModuleParameters); | 
|  | static JSC_DECLARE_HOST_FUNCTION(moduleLoaderEvaluate); | 
|  | static JSC_DECLARE_HOST_FUNCTION(moduleLoaderModuleDeclarationInstantiation); | 
|  | static JSC_DECLARE_HOST_FUNCTION(moduleLoaderResolve); | 
|  | static JSC_DECLARE_HOST_FUNCTION(moduleLoaderFetch); | 
|  | static JSC_DECLARE_HOST_FUNCTION(moduleLoaderGetModuleNamespaceObject); | 
|  |  | 
|  | } | 
|  |  | 
|  | namespace JSC { | 
|  |  | 
|  | STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSModuleLoader); | 
|  |  | 
|  | const ClassInfo JSModuleLoader::s_info = { "ModuleLoader"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSModuleLoader) }; | 
|  |  | 
|  | JSModuleLoader::JSModuleLoader(VM& vm, Structure* structure) | 
|  | : JSNonFinalObject(vm, structure) | 
|  | { | 
|  | } | 
|  |  | 
|  | void JSModuleLoader::finishCreation(JSGlobalObject* globalObject, VM& vm) | 
|  | { | 
|  | Base::finishCreation(vm); | 
|  | ASSERT(inherits(info())); | 
|  | JSMap* map = JSMap::create(vm, globalObject->mapStructure()); | 
|  | putDirect(vm, Identifier::fromString(vm, "registry"_s), map); | 
|  |  | 
|  | JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("getModuleNamespaceObject"_s, moduleLoaderGetModuleNamespaceObject, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private); | 
|  | JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("parseModule"_s, moduleLoaderParseModule, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, ImplementationVisibility::Private); | 
|  | JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("requestedModules"_s, moduleLoaderRequestedModules, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private); | 
|  | JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("requestedModuleParameters"_s, moduleLoaderRequestedModuleParameters, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, ImplementationVisibility::Private); | 
|  | JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("resolve"_s, moduleLoaderResolve, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, ImplementationVisibility::Private); | 
|  | JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("fetch"_s, moduleLoaderFetch, static_cast<unsigned>(PropertyAttribute::DontEnum), 3, ImplementationVisibility::Private); | 
|  | JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("moduleDeclarationInstantiation"_s, moduleLoaderModuleDeclarationInstantiation, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, ImplementationVisibility::Private); | 
|  | JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("evaluate"_s, moduleLoaderEvaluate, static_cast<unsigned>(PropertyAttribute::DontEnum), 3, ImplementationVisibility::Private); | 
|  |  | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().ensureRegisteredPublicName(), moduleLoaderEnsureRegisteredCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().requestFetchPublicName(), moduleLoaderRequestFetchCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().requestInstantiatePublicName(), moduleLoaderRequestInstantiateCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().requestSatisfyPublicName(), moduleLoaderRequestSatisfyCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().requestSatisfyUtilPublicName(), moduleLoaderRequestSatisfyUtilCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().linkPublicName(), moduleLoaderLinkCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().moduleEvaluationPublicName(), moduleLoaderModuleEvaluationCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().asyncModuleEvaluationPublicName(), moduleLoaderAsyncModuleEvaluationCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().provideFetchPublicName(), moduleLoaderProvideFetchCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().loadAndEvaluateModulePublicName(), moduleLoaderLoadAndEvaluateModuleCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().loadModulePublicName(), moduleLoaderLoadModuleCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().linkAndEvaluateModulePublicName(), moduleLoaderLinkAndEvaluateModuleCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().requestImportModulePublicName(), moduleLoaderRequestImportModuleCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().dependencyKeysIfEvaluatedPublicName(), moduleLoaderDependencyKeysIfEvaluatedCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum)); | 
|  | } | 
|  |  | 
|  | // ------------------------------ Functions -------------------------------- | 
|  |  | 
|  | static String printableModuleKey(JSGlobalObject* globalObject, JSValue key) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_CATCH_SCOPE(vm); | 
|  | if (key.isString() || key.isSymbol()) { | 
|  | auto propertyName = key.toPropertyKey(globalObject); | 
|  | scope.assertNoExceptionExceptTermination(); // This is OK since this function is just for debugging purpose. | 
|  | return propertyName.impl(); | 
|  | } | 
|  | return vm.propertyNames->emptyIdentifier.impl(); | 
|  | } | 
|  |  | 
|  | JSArray* JSModuleLoader::dependencyKeysIfEvaluated(JSGlobalObject* globalObject, JSValue key) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | JSObject* function = getAs<JSObject*>(globalObject, vm.propertyNames->builtinNames().dependencyKeysIfEvaluatedPublicName()); | 
|  | RETURN_IF_EXCEPTION(scope, nullptr); | 
|  | auto callData = JSC::getCallData(function); | 
|  | ASSERT(callData.type != CallData::Type::None); | 
|  |  | 
|  | MarkedArgumentBuffer arguments; | 
|  | arguments.append(key); | 
|  | ASSERT(!arguments.hasOverflowed()); | 
|  |  | 
|  | JSValue result = call(globalObject, function, callData, this, arguments); | 
|  | RETURN_IF_EXCEPTION(scope, nullptr); | 
|  |  | 
|  | return jsDynamicCast<JSArray*>(result); | 
|  | } | 
|  |  | 
|  | JSValue JSModuleLoader::provideFetch(JSGlobalObject* globalObject, JSValue key, const SourceCode& sourceCode) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | JSObject* function = getAs<JSObject*>(globalObject, vm.propertyNames->builtinNames().provideFetchPublicName()); | 
|  | RETURN_IF_EXCEPTION(scope, { }); | 
|  | auto callData = JSC::getCallData(function); | 
|  | ASSERT(callData.type != CallData::Type::None); | 
|  |  | 
|  | SourceCode source { sourceCode }; | 
|  | MarkedArgumentBuffer arguments; | 
|  | arguments.append(key); | 
|  | arguments.append(JSSourceCode::create(vm, WTFMove(source))); | 
|  | ASSERT(!arguments.hasOverflowed()); | 
|  |  | 
|  | RELEASE_AND_RETURN(scope, call(globalObject, function, callData, this, arguments)); | 
|  | } | 
|  |  | 
|  | JSInternalPromise* JSModuleLoader::loadAndEvaluateModule(JSGlobalObject* globalObject, JSValue moduleName, JSValue parameters, JSValue scriptFetcher) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | JSObject* function = getAs<JSObject*>(globalObject, vm.propertyNames->builtinNames().loadAndEvaluateModulePublicName()); | 
|  | RETURN_IF_EXCEPTION(scope, nullptr); | 
|  | auto callData = JSC::getCallData(function); | 
|  | ASSERT(callData.type != CallData::Type::None); | 
|  |  | 
|  | MarkedArgumentBuffer arguments; | 
|  | arguments.append(moduleName); | 
|  | arguments.append(parameters); | 
|  | arguments.append(scriptFetcher); | 
|  | ASSERT(!arguments.hasOverflowed()); | 
|  |  | 
|  | JSValue promise = call(globalObject, function, callData, this, arguments); | 
|  | RETURN_IF_EXCEPTION(scope, nullptr); | 
|  | return jsCast<JSInternalPromise*>(promise); | 
|  | } | 
|  |  | 
|  | JSInternalPromise* JSModuleLoader::loadModule(JSGlobalObject* globalObject, JSValue moduleKey, JSValue parameters, JSValue scriptFetcher) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | JSObject* function = getAs<JSObject*>(globalObject, vm.propertyNames->builtinNames().loadModulePublicName()); | 
|  | RETURN_IF_EXCEPTION(scope, nullptr); | 
|  | auto callData = JSC::getCallData(function); | 
|  | ASSERT(callData.type != CallData::Type::None); | 
|  |  | 
|  | MarkedArgumentBuffer arguments; | 
|  | arguments.append(moduleKey); | 
|  | arguments.append(parameters); | 
|  | arguments.append(scriptFetcher); | 
|  | ASSERT(!arguments.hasOverflowed()); | 
|  |  | 
|  | JSValue promise = call(globalObject, function, callData, this, arguments); | 
|  | RETURN_IF_EXCEPTION(scope, nullptr); | 
|  | return jsCast<JSInternalPromise*>(promise); | 
|  | } | 
|  |  | 
|  | JSValue JSModuleLoader::linkAndEvaluateModule(JSGlobalObject* globalObject, JSValue moduleKey, JSValue scriptFetcher) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | JSObject* function = getAs<JSObject*>(globalObject, vm.propertyNames->builtinNames().linkAndEvaluateModulePublicName()); | 
|  | RETURN_IF_EXCEPTION(scope, { }); | 
|  | auto callData = JSC::getCallData(function); | 
|  | ASSERT(callData.type != CallData::Type::None); | 
|  |  | 
|  | MarkedArgumentBuffer arguments; | 
|  | arguments.append(moduleKey); | 
|  | arguments.append(scriptFetcher); | 
|  | ASSERT(!arguments.hasOverflowed()); | 
|  |  | 
|  | RELEASE_AND_RETURN(scope, call(globalObject, function, callData, this, arguments)); | 
|  | } | 
|  |  | 
|  | JSInternalPromise* JSModuleLoader::requestImportModule(JSGlobalObject* globalObject, const Identifier& moduleName, JSValue referrer, JSValue parameters, JSValue scriptFetcher) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | auto* function = getAs<JSObject*>(globalObject, vm.propertyNames->builtinNames().requestImportModulePublicName()); | 
|  | RETURN_IF_EXCEPTION(scope, nullptr); | 
|  | auto callData = JSC::getCallData(function); | 
|  | ASSERT(callData.type != CallData::Type::None); | 
|  |  | 
|  | MarkedArgumentBuffer arguments; | 
|  | arguments.append(jsString(vm, moduleName.string())); | 
|  | arguments.append(referrer); | 
|  | arguments.append(parameters); | 
|  | arguments.append(scriptFetcher); | 
|  | ASSERT(!arguments.hasOverflowed()); | 
|  |  | 
|  | JSValue promise = call(globalObject, function, callData, this, arguments); | 
|  | RETURN_IF_EXCEPTION(scope, nullptr); | 
|  | return jsCast<JSInternalPromise*>(promise); | 
|  | } | 
|  |  | 
|  | JSInternalPromise* JSModuleLoader::importModule(JSGlobalObject* globalObject, JSString* moduleName, JSValue parameters, const SourceOrigin& referrer) | 
|  | { | 
|  | dataLogLnIf(Options::dumpModuleLoadingState(), "Loader [import] ", printableModuleKey(globalObject, moduleName)); | 
|  |  | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | if (globalObject->globalObjectMethodTable()->moduleLoaderImportModule) | 
|  | RELEASE_AND_RETURN(scope, globalObject->globalObjectMethodTable()->moduleLoaderImportModule(globalObject, this, moduleName, parameters, referrer)); | 
|  |  | 
|  | auto* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); | 
|  | auto moduleNameString = moduleName->value(globalObject); | 
|  | RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); | 
|  |  | 
|  | scope.release(); | 
|  | promise->reject(globalObject, createError(globalObject, makeString("Could not import the module '"_s, moduleNameString.data, "'."_s))); | 
|  | return promise; | 
|  | } | 
|  |  | 
|  | Identifier JSModuleLoader::resolve(JSGlobalObject* globalObject, JSValue name, JSValue referrer, JSValue scriptFetcher) | 
|  | { | 
|  | dataLogLnIf(Options::dumpModuleLoadingState(), "Loader [resolve] ", printableModuleKey(globalObject, name)); | 
|  |  | 
|  | if (globalObject->globalObjectMethodTable()->moduleLoaderResolve) | 
|  | return globalObject->globalObjectMethodTable()->moduleLoaderResolve(globalObject, this, name, referrer, scriptFetcher); | 
|  | return name.toPropertyKey(globalObject); | 
|  | } | 
|  |  | 
|  | JSInternalPromise* JSModuleLoader::fetch(JSGlobalObject* globalObject, JSValue key, JSValue parameters, JSValue scriptFetcher) | 
|  | { | 
|  | dataLogLnIf(Options::dumpModuleLoadingState(), "Loader [fetch] ", printableModuleKey(globalObject, key)); | 
|  |  | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | if (globalObject->globalObjectMethodTable()->moduleLoaderFetch) | 
|  | RELEASE_AND_RETURN(scope, globalObject->globalObjectMethodTable()->moduleLoaderFetch(globalObject, this, key, parameters, scriptFetcher)); | 
|  |  | 
|  | auto* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); | 
|  | String moduleKey = key.toWTFString(globalObject); | 
|  | RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); | 
|  |  | 
|  | scope.release(); | 
|  | promise->reject(globalObject, createError(globalObject, makeString("Could not open the module '"_s, moduleKey, "'."_s))); | 
|  | return promise; | 
|  | } | 
|  |  | 
|  | JSObject* JSModuleLoader::createImportMetaProperties(JSGlobalObject* globalObject, JSValue key, JSModuleRecord* moduleRecord, JSValue scriptFetcher) | 
|  | { | 
|  | if (globalObject->globalObjectMethodTable()->moduleLoaderCreateImportMetaProperties) | 
|  | return globalObject->globalObjectMethodTable()->moduleLoaderCreateImportMetaProperties(globalObject, this, key, moduleRecord, scriptFetcher); | 
|  | return constructEmptyObject(globalObject->vm(), globalObject->nullPrototypeObjectStructure()); | 
|  | } | 
|  |  | 
|  | JSValue JSModuleLoader::evaluate(JSGlobalObject* globalObject, JSValue key, JSValue moduleRecordValue, JSValue scriptFetcher, JSValue sentValue, JSValue resumeMode) | 
|  | { | 
|  | dataLogLnIf(Options::dumpModuleLoadingState(), "Loader [evaluate] ", printableModuleKey(globalObject, key)); | 
|  |  | 
|  | if (globalObject->globalObjectMethodTable()->moduleLoaderEvaluate) | 
|  | return globalObject->globalObjectMethodTable()->moduleLoaderEvaluate(globalObject, this, key, moduleRecordValue, scriptFetcher, sentValue, resumeMode); | 
|  |  | 
|  | return evaluateNonVirtual(globalObject, key, moduleRecordValue, scriptFetcher, sentValue, resumeMode); | 
|  | } | 
|  |  | 
|  | JSValue JSModuleLoader::evaluateNonVirtual(JSGlobalObject* globalObject, JSValue, JSValue moduleRecordValue, JSValue, JSValue sentValue, JSValue resumeMode) | 
|  | { | 
|  | if (auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(moduleRecordValue)) | 
|  | return moduleRecord->evaluate(globalObject, sentValue, resumeMode); | 
|  | return jsUndefined(); | 
|  | } | 
|  |  | 
|  | JSModuleNamespaceObject* JSModuleLoader::getModuleNamespaceObject(JSGlobalObject* globalObject, JSValue moduleRecordValue) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(moduleRecordValue); | 
|  | if (!moduleRecord) { | 
|  | throwTypeError(globalObject, scope); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | RELEASE_AND_RETURN(scope, moduleRecord->getModuleNamespace(globalObject)); | 
|  | } | 
|  |  | 
|  | // ------------------------------ Functions -------------------------------- | 
|  |  | 
|  | JSC_DEFINE_HOST_FUNCTION(moduleLoaderParseModule, (JSGlobalObject* globalObject, CallFrame* callFrame)) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  |  | 
|  | auto* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); | 
|  |  | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | auto rejectWithError = [&](JSValue error) { | 
|  | promise->reject(globalObject, error); | 
|  | return promise; | 
|  | }; | 
|  |  | 
|  | const Identifier moduleKey = callFrame->argument(0).toPropertyKey(globalObject); | 
|  | RETURN_IF_EXCEPTION(scope, JSValue::encode(promise->rejectWithCaughtException(globalObject, scope))); | 
|  |  | 
|  | dataLogLnIf(Options::dumpModuleLoadingState(), "loader [parsing] ", moduleKey); | 
|  |  | 
|  | JSValue source = callFrame->argument(1); | 
|  | auto* jsSourceCode = jsCast<JSSourceCode*>(source); | 
|  | SourceCode sourceCode = jsSourceCode->sourceCode(); | 
|  |  | 
|  | #if ENABLE(WEBASSEMBLY) | 
|  | if (sourceCode.provider()->sourceType() == SourceProviderSourceType::WebAssembly) | 
|  | RELEASE_AND_RETURN(scope, JSValue::encode(JSWebAssembly::instantiate(globalObject, promise, moduleKey, jsSourceCode))); | 
|  | #endif | 
|  |  | 
|  | // https://tc39.es/proposal-json-modules/#sec-parse-json-module | 
|  | if (sourceCode.provider()->sourceType() == SourceProviderSourceType::JSON) { | 
|  | auto* moduleRecord = SyntheticModuleRecord::parseJSONModule(globalObject, moduleKey, WTFMove(sourceCode)); | 
|  | RETURN_IF_EXCEPTION(scope, JSValue::encode(promise->rejectWithCaughtException(globalObject, scope))); | 
|  | scope.release(); | 
|  | promise->resolve(globalObject, moduleRecord); | 
|  | return JSValue::encode(promise); | 
|  | } | 
|  |  | 
|  | ParserError error; | 
|  | std::unique_ptr<ModuleProgramNode> moduleProgramNode = parseRootNode<ModuleProgramNode>( | 
|  | vm, sourceCode, ImplementationVisibility::Public, JSParserBuiltinMode::NotBuiltin, | 
|  | StrictModeLexicallyScopedFeature, JSParserScriptMode::Module, SourceParseMode::ModuleAnalyzeMode, error); | 
|  | if (error.isValid()) | 
|  | RELEASE_AND_RETURN(scope, JSValue::encode(rejectWithError(error.toErrorObject(globalObject, sourceCode)))); | 
|  | ASSERT(moduleProgramNode); | 
|  |  | 
|  | ModuleAnalyzer moduleAnalyzer(globalObject, moduleKey, sourceCode, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables(), moduleProgramNode->features()); | 
|  | RETURN_IF_EXCEPTION(scope, JSValue::encode(promise->rejectWithCaughtException(globalObject, scope))); | 
|  |  | 
|  | auto result = moduleAnalyzer.analyze(*moduleProgramNode); | 
|  | if (!result) { | 
|  | auto [ errorType, message ] = WTFMove(result.error()); | 
|  | RELEASE_AND_RETURN(scope, JSValue::encode(rejectWithError(createError(globalObject, errorType, message)))); | 
|  | } | 
|  |  | 
|  | scope.release(); | 
|  | promise->resolve(globalObject, result.value()); | 
|  | return JSValue::encode(promise); | 
|  | } | 
|  |  | 
|  | JSC_DEFINE_HOST_FUNCTION(moduleLoaderRequestedModules, (JSGlobalObject* globalObject, CallFrame* callFrame)) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  | auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(callFrame->argument(0)); | 
|  | if (!moduleRecord) | 
|  | RELEASE_AND_RETURN(scope, JSValue::encode(constructEmptyArray(globalObject, nullptr))); | 
|  |  | 
|  | JSArray* result = constructEmptyArray(globalObject, nullptr, moduleRecord->requestedModules().size()); | 
|  | RETURN_IF_EXCEPTION(scope, encodedJSValue()); | 
|  | size_t i = 0; | 
|  | for (auto& request : moduleRecord->requestedModules()) { | 
|  | result->putDirectIndex(globalObject, i++, jsString(vm, String { request.m_specifier.get() })); | 
|  | RETURN_IF_EXCEPTION(scope, encodedJSValue()); | 
|  | } | 
|  | return JSValue::encode(result); | 
|  | } | 
|  |  | 
|  | JSC_DEFINE_HOST_FUNCTION(moduleLoaderRequestedModuleParameters, (JSGlobalObject* globalObject, CallFrame* callFrame)) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  | auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(callFrame->argument(0)); | 
|  | if (!moduleRecord) | 
|  | RELEASE_AND_RETURN(scope, JSValue::encode(constructEmptyArray(globalObject, nullptr))); | 
|  |  | 
|  | JSArray* result = constructEmptyArray(globalObject, nullptr, moduleRecord->requestedModules().size()); | 
|  | RETURN_IF_EXCEPTION(scope, encodedJSValue()); | 
|  | size_t i = 0; | 
|  | for (auto& request : moduleRecord->requestedModules()) { | 
|  | if (request.m_attributes) | 
|  | result->putDirectIndex(globalObject, i++, JSScriptFetchParameters::create(vm, vm.scriptFetchParametersStructure.get(), *request.m_attributes)); | 
|  | else | 
|  | result->putDirectIndex(globalObject, i++, jsUndefined()); | 
|  | RETURN_IF_EXCEPTION(scope, encodedJSValue()); | 
|  | } | 
|  | return JSValue::encode(result); | 
|  | } | 
|  |  | 
|  | JSC_DEFINE_HOST_FUNCTION(moduleLoaderModuleDeclarationInstantiation, (JSGlobalObject* globalObject, CallFrame* callFrame)) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  | auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(callFrame->argument(0)); | 
|  | if (!moduleRecord) | 
|  | return JSValue::encode(jsUndefined()); | 
|  |  | 
|  | dataLogLnIf(Options::dumpModuleLoadingState(), "Loader [link] ", moduleRecord->moduleKey()); | 
|  |  | 
|  | auto sync = moduleRecord->link(globalObject, callFrame->argument(1)); | 
|  | RETURN_IF_EXCEPTION(scope, encodedJSValue()); | 
|  |  | 
|  | return JSValue::encode(jsBoolean(sync == Synchronousness::Async)); | 
|  | } | 
|  |  | 
|  | // ------------------------------ Hook Functions --------------------------- | 
|  |  | 
|  | JSC_DEFINE_HOST_FUNCTION(moduleLoaderResolve, (JSGlobalObject* globalObject, CallFrame* callFrame)) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(callFrame->thisValue()); | 
|  | if (!loader) | 
|  | return JSValue::encode(jsUndefined()); | 
|  | auto result = loader->resolve(globalObject, callFrame->argument(0), callFrame->argument(1), callFrame->argument(2)); | 
|  | RETURN_IF_EXCEPTION(scope, encodedJSValue()); | 
|  | return JSValue::encode(identifierToJSValue(vm, result)); | 
|  | } | 
|  |  | 
|  | JSC_DEFINE_HOST_FUNCTION(moduleLoaderFetch, (JSGlobalObject* globalObject, CallFrame* callFrame)) | 
|  | { | 
|  | // Hook point, Loader.fetch | 
|  | // https://whatwg.github.io/loader/#browser-fetch | 
|  | // Take the key and fetch the resource actually. | 
|  | // For example, JavaScriptCore shell can provide the hook fetching the resource | 
|  | // from the local file system. | 
|  | JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(callFrame->thisValue()); | 
|  | if (!loader) | 
|  | return JSValue::encode(jsUndefined()); | 
|  | return JSValue::encode(loader->fetch(globalObject, callFrame->argument(0), callFrame->argument(1), callFrame->argument(2))); | 
|  | } | 
|  |  | 
|  | JSC_DEFINE_HOST_FUNCTION(moduleLoaderGetModuleNamespaceObject, (JSGlobalObject* globalObject, CallFrame* callFrame)) | 
|  | { | 
|  | VM& vm = globalObject->vm(); | 
|  | auto scope = DECLARE_THROW_SCOPE(vm); | 
|  |  | 
|  | auto* loader = jsDynamicCast<JSModuleLoader*>(callFrame->thisValue()); | 
|  | if (!loader) | 
|  | return JSValue::encode(jsUndefined()); | 
|  | auto* moduleNamespaceObject = loader->getModuleNamespaceObject(globalObject, callFrame->argument(0)); | 
|  | RETURN_IF_EXCEPTION(scope, encodedJSValue()); | 
|  | return JSValue::encode(moduleNamespaceObject); | 
|  | } | 
|  |  | 
|  | // ------------------- Additional Hook Functions --------------------------- | 
|  |  | 
|  | JSC_DEFINE_HOST_FUNCTION(moduleLoaderEvaluate, (JSGlobalObject* globalObject, CallFrame* callFrame)) | 
|  | { | 
|  | // To instrument and retrieve the errors raised from the module execution, | 
|  | // we inserted the hook point here. | 
|  |  | 
|  | JSModuleLoader* loader = jsDynamicCast<JSModuleLoader*>(callFrame->thisValue()); | 
|  | if (!loader) | 
|  | return JSValue::encode(jsUndefined()); | 
|  | return JSValue::encode(loader->evaluate(globalObject, callFrame->argument(0), callFrame->argument(1), callFrame->argument(2), callFrame->argument(3), callFrame->argument(4))); | 
|  | } | 
|  |  | 
|  | } // namespace JSC |