From 52d373fa63bdb0e8356ee14f9fb85db91f0a734f Mon Sep 17 00:00:00 2001 From: DaiHN Date: Thu, 1 Jun 2023 19:30:08 +0800 Subject: [PATCH] Support using dynamic-import to load native module issue : https://gitee.com/openharmony/developtools_ace_ets2bundle/issues/I76TBP?from=project-issue Signed-off-by: DaiHN Change-Id: I7e5eab96e7fe252aa96bb38256728234bd2d90d5 --- BUILD.gn | 1 + ecmascript/base/path_helper.h | 33 ++++++ ecmascript/builtins/builtins_promise_job.cpp | 19 ++- .../compiler/bytecode_info_collector.cpp | 3 +- ecmascript/module/js_dynamic_import.cpp | 52 ++++++++ ecmascript/module/js_dynamic_import.h | 31 +++++ ecmascript/module/js_module_manager.cpp | 112 +----------------- ecmascript/module/js_module_manager.h | 17 --- ecmascript/module/js_module_source_text.cpp | 103 +++++++++++++++- ecmascript/module/js_module_source_text.h | 15 +++ ecmascript/module/tests/ecma_module_test.cpp | 14 +-- ecmascript/ts_types/ts_type_parser.cpp | 3 +- 12 files changed, 255 insertions(+), 148 deletions(-) create mode 100644 ecmascript/module/js_dynamic_import.cpp create mode 100644 ecmascript/module/js_dynamic_import.h diff --git a/BUILD.gn b/BUILD.gn index 5ff7e858e9..18de547327 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -726,6 +726,7 @@ ecma_source = [ "ecmascript/mem/verification.cpp", "ecmascript/mem/work_manager.cpp", "ecmascript/module/js_module_manager.cpp", + "ecmascript/module/js_dynamic_import.cpp", "ecmascript/module/js_module_namespace.cpp", "ecmascript/module/js_module_record.cpp", "ecmascript/module/js_module_source_text.cpp", diff --git a/ecmascript/base/path_helper.h b/ecmascript/base/path_helper.h index 777f4dad13..281223e5d9 100644 --- a/ecmascript/base/path_helper.h +++ b/ecmascript/base/path_helper.h @@ -528,6 +528,19 @@ public: return res; } + inline static bool IsNativeModuleRequest(const CString &requestName) + { + if (requestName[0] != '@') { + return false; + } + if (StringHelper::StringStartWith(requestName, PathHelper::REQUIRE_NAPI_OHOS_PREFIX) || + StringHelper::StringStartWith(requestName, PathHelper::REQUIRE_NAPI_APP_PREFIX) || + StringHelper::StringStartWith(requestName, PathHelper::REQUIRE_NAITVE_MODULE_PREFIX)) { + return true; + } + return false; + } + static CString ConcatFileNameWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile, CString &baseFileName, CString recordName, CString requestName) { @@ -552,6 +565,26 @@ public: } return entryPoint; } + + static CString GetStrippedModuleName(const CString &moduleRequestName) + { + // @xxx:**** -> **** + size_t pos = moduleRequestName.find(':'); + if (pos == CString::npos) { + LOG_FULL(FATAL) << "Unknown format " << moduleRequestName; + } + return moduleRequestName.substr(pos + 1); + } + + static CString GetInternalModulePrefix(const CString &moduleRequestName) + { + // @xxx:* -> xxx + size_t pos = moduleRequestName.find(':'); + if (pos == CString::npos) { + LOG_FULL(FATAL) << "Unknown format " << moduleRequestName; + } + return moduleRequestName.substr(1, pos - 1); + } }; } // namespace panda::ecmascript::base #endif // ECMASCRIPT_BASE_PATH_HELPER_H \ No newline at end of file diff --git a/ecmascript/builtins/builtins_promise_job.cpp b/ecmascript/builtins/builtins_promise_job.cpp index c192f4ba3e..318ad7f79f 100644 --- a/ecmascript/builtins/builtins_promise_job.cpp +++ b/ecmascript/builtins/builtins_promise_job.cpp @@ -25,6 +25,7 @@ #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/js_promise.h" #include "ecmascript/js_tagged_value.h" +#include "ecmascript/module/js_dynamic_import.h" #include "ecmascript/module/js_module_manager.h" #include "ecmascript/platform/file.h" #include "ecmascript/require/js_cjs_module.h" @@ -147,6 +148,13 @@ JSTaggedValue BuiltinsPromiseJob::DynamicImportJob(EcmaRuntimeCallInfo *argv) CString entryPoint = JSPandaFile::ENTRY_MAIN_FUNCTION; CString baseFilename = ConvertToString(dirPath.GetTaggedValue()); CString fileNameStr = ""; + CString requestPath = ConvertToString(specifierString.GetTaggedValue()); + + // resolve native module + auto [isNative, moduleType] = SourceTextModule::CheckNativeModule(requestPath); + if (isNative) { + return DynamicImport::ExecuteNativeModule(thread, specifierString, moduleType, resolve, reject); + } if (recordName->IsUndefined()) { moduleName = ResolveFilenameFromNative(thread, dirPath.GetTaggedValue(), specifierString.GetTaggedValue()); @@ -154,7 +162,6 @@ JSTaggedValue BuiltinsPromiseJob::DynamicImportJob(EcmaRuntimeCallInfo *argv) fileNameStr = ConvertToString(moduleName.GetTaggedValue()); } else { CString recordNameStr = ConvertToString(recordName.GetTaggedValue()); - CString requestModule = ConvertToString(specifierString.GetTaggedValue()); std::shared_ptr jsPandaFile = JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, baseFilename, recordNameStr.c_str()); if (jsPandaFile == nullptr) { @@ -164,7 +171,7 @@ JSTaggedValue BuiltinsPromiseJob::DynamicImportJob(EcmaRuntimeCallInfo *argv) } entryPoint = - PathHelper::ConcatFileNameWithMerge(thread, jsPandaFile.get(), baseFilename, recordNameStr, requestModule); + PathHelper::ConcatFileNameWithMerge(thread, jsPandaFile.get(), baseFilename, recordNameStr, requestPath); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, CatchException(thread, reject)); fileNameStr = baseFilename; moduleName = vm->GetFactory()->NewFromUtf8(entryPoint); @@ -177,8 +184,10 @@ JSTaggedValue BuiltinsPromiseJob::DynamicImportJob(EcmaRuntimeCallInfo *argv) THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, CatchException(thread, reject)); } bool isModule = jsPandaFile->IsModule(thread, entryPoint); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, CatchException(thread, reject)); + ModuleManager *moduleManager = vm->GetModuleManager(); JSMutableHandle moduleNamespace(thread, JSTaggedValue::Undefined()); - if (!vm->GetModuleManager()->IsImportedModuleLoaded(moduleName.GetTaggedValue())) { + if (!moduleManager->IsImportedModuleLoaded(moduleName.GetTaggedValue())) { if (!JSPandaFileExecutor::ExecuteFromFile(thread, fileNameStr.c_str(), entryPoint.c_str(), false, true)) { CString msg = "Cannot execute request dynamic-imported module : " + entryPoint; JSTaggedValue error = factory->GetJSError(ErrorType::REFERENCE_ERROR, msg.c_str()).GetTaggedValue(); @@ -192,11 +201,11 @@ JSTaggedValue BuiltinsPromiseJob::DynamicImportJob(EcmaRuntimeCallInfo *argv) } else { // b. Let moduleRecord be ! HostResolveImportedModule(referencingScriptOrModule, specifier). JSHandle moduleRecord = - vm->GetModuleManager()->HostGetImportedModule(moduleName.GetTaggedValue()); + moduleManager->HostGetImportedModule(moduleName.GetTaggedValue()); // d. Let namespace be ? GetModuleNamespace(moduleRecord). moduleNamespace.Update(SourceTextModule::GetModuleNamespace(thread, moduleRecord)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, CatchException(thread, reject)); } - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, CatchException(thread, reject)); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, diff --git a/ecmascript/compiler/bytecode_info_collector.cpp b/ecmascript/compiler/bytecode_info_collector.cpp index 7d11f16434..657d70158f 100644 --- a/ecmascript/compiler/bytecode_info_collector.cpp +++ b/ecmascript/compiler/bytecode_info_collector.cpp @@ -659,8 +659,7 @@ void BytecodeInfoCollector::CollectRecordExportInfo(const CString &recordName) starExportEntry.Update(starEntriesArray->Get(index)); JSTaggedValue moduleRequest = starExportEntry->GetModuleRequest(); CString moduleRequestName = ConvertToString(EcmaString::Cast(moduleRequest.GetTaggedObject())); - auto [isNative, _] = ModuleManager::CheckNativeModule(moduleRequestName); - if (isNative) { + if (base::PathHelper::IsNativeModuleRequest(moduleRequestName)) { return; } CString baseFileName = jsPandaFile_->GetJSPandaFileDesc(); diff --git a/ecmascript/module/js_dynamic_import.cpp b/ecmascript/module/js_dynamic_import.cpp new file mode 100644 index 0000000000..54f6ba0dd1 --- /dev/null +++ b/ecmascript/module/js_dynamic_import.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/module/js_dynamic_import.h" +#include "ecmascript/base/path_helper.h" +#include "ecmascript/builtins/builtins_promise_job.h" +#include "ecmascript/js_function.h" +#include "ecmascript/module/js_module_manager.h" + +namespace panda::ecmascript { +using PathHelper = base::PathHelper; +using BuiltinsPromiseJob = builtins::BuiltinsPromiseJob; + +JSTaggedValue DynamicImport::ExecuteNativeModule(JSThread *thread, JSHandle specifierString, + ModuleTypes moduleType, JSHandle resolve, JSHandle reject) +{ + ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); + CString requestPath = ConvertToString(specifierString.GetTaggedValue()); + CString entryPoint = PathHelper::GetStrippedModuleName(requestPath); + JSHandle nativeModule = moduleManager->ResolveNativeModule(requestPath, moduleType); + JSHandle requiredModule = JSHandle::Cast(nativeModule); + if (!SourceTextModule::LoadNativeModule(thread, requiredModule, + JSHandle(specifierString), moduleType)) { + LOG_FULL(WARN) << "LoadNativeModule " << requestPath << " failed"; + } + JSHandle nativeExports(thread, requiredModule->GetModuleValue(thread, 0, false)); + requiredModule->SetStatus(ModuleStatus::EVALUATED); + JSHandle moduleNamespace = SourceTextModule::GetModuleNamespace(thread, requiredModule); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, BuiltinsPromiseJob::CatchException(thread, reject)); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, + JSHandle(resolve), + undefined, undefined, 1); + info->SetCallArg(moduleNamespace.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return JSFunction::Call(info); +} + +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/module/js_dynamic_import.h b/ecmascript/module/js_dynamic_import.h new file mode 100644 index 0000000000..0c84b4d1d6 --- /dev/null +++ b/ecmascript/module/js_dynamic_import.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_MODULE_JS_DYNAMIC_IMPORT_H +#define ECMASCRIPT_MODULE_JS_DYNAMIC_IMPORT_H + +#include "ecmascript/builtins/builtins_promise_job.h" +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/module/js_module_source_text.h" + +namespace panda::ecmascript { +class DynamicImport { +public: + static JSTaggedValue ExecuteNativeModule(JSThread *thread, JSHandle specifierString, + ModuleTypes moduleType, JSHandle resolve, + JSHandle reject); +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MODULE_JS_DYNAMIC_IMPORT_H \ No newline at end of file diff --git a/ecmascript/module/js_module_manager.cpp b/ecmascript/module/js_module_manager.cpp index e27b181023..bfbb220f5a 100644 --- a/ecmascript/module/js_module_manager.cpp +++ b/ecmascript/module/js_module_manager.cpp @@ -108,7 +108,7 @@ JSTaggedValue ModuleManager::GetModuleValueOutterInternal(int32_t index, JSTagge SourceTextModule *module = SourceTextModule::Cast(resolvedModule.GetTaggedObject()); ModuleTypes moduleType = module->GetTypes(); - if (IsNativeModule(moduleType)) { + if (SourceTextModule::IsNativeModule(moduleType)) { return GetNativeModuleValue(thread, currentModule, resolvedModule, binding); } if (module->GetTypes() == ModuleTypes::CJS_MODULE) { @@ -559,7 +559,7 @@ JSTaggedValue ModuleManager::GetModuleNamespaceInternal(int32_t index, JSTaggedV JSHandle requiredModuleST = JSHandle::Cast(requiredModule); ModuleTypes moduleType = requiredModuleST->GetTypes(); // if requiredModuleST is Native module - if (ModuleManager::IsNativeModule(moduleType)) { + if (SourceTextModule::IsNativeModule(moduleType)) { return SourceTextModule::Cast(requiredModuleST.GetTaggedValue())->GetModuleValue(thread, 0, false); } // if requiredModuleST is CommonJS @@ -647,114 +647,6 @@ int ModuleManager::GetExportObjectIndex(EcmaVM *vm, JSHandle e return index; } -std::pair ModuleManager::CheckNativeModule(const CString &moduleRequestName) -{ - if (moduleRequestName[0] != '@' || - StringHelper::StringStartWith(moduleRequestName, PathHelper::PREFIX_BUNDLE) || - StringHelper::StringStartWith(moduleRequestName, PathHelper::PREFIX_PACKAGE)|| - moduleRequestName.find(':') == CString::npos) { - return {false, ModuleTypes::UNKNOWN}; - } - if (StringHelper::StringStartWith(moduleRequestName, PathHelper::REQUIRE_NAPI_OHOS_PREFIX)) { - return {true, ModuleTypes::OHOS_MODULE}; - } else if (StringHelper::StringStartWith(moduleRequestName, PathHelper::REQUIRE_NAPI_APP_PREFIX)) { - return {true, ModuleTypes::APP_MODULE}; - } else if (StringHelper::StringStartWith(moduleRequestName, PathHelper::REQUIRE_NAITVE_MODULE_PREFIX)) { - return {true, ModuleTypes::NATIVE_MODULE}; - } else { - return {true, ModuleTypes::INTERNAL_MODULE}; - } -} - -CString ModuleManager::GetStrippedModuleName(const CString &moduleRequestName) -{ - size_t pos = moduleRequestName.find(':'); - if (pos == CString::npos) { - LOG_FULL(FATAL) << "Unknown format " << moduleRequestName; - } - return moduleRequestName.substr(pos + 1); -} - -CString ModuleManager::GetInternalModuleDir(const CString &moduleRequestName) -{ - // @xxx:* -> xxx - size_t pos = moduleRequestName.find(':'); - if (pos == CString::npos) { - LOG_FULL(FATAL) << "Unknown format " << moduleRequestName; - } - return moduleRequestName.substr(1, pos - 1); -} - -Local ModuleManager::GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType) -{ - Local globalObject = JSNApi::GetGlobalObject(vm); - auto globalConstants = vm->GetJSThread()->GlobalConstants(); - auto funcName = (moduleType == ModuleTypes::NATIVE_MODULE) ? - globalConstants->GetHandledRequireNativeModuleString() : - globalConstants->GetHandledRequireNapiString(); - return globalObject->Get(vm, JSNApiHelper::ToLocal(funcName)); -} - -void ModuleManager::MakeAppArgs(const EcmaVM *vm, std::vector> &arguments, - const CString &moduleName) -{ - size_t pos = moduleName.find_last_of('/'); - if (pos == CString::npos) { - LOG_FULL(FATAL) << "Invalid native module " << moduleName; - UNREACHABLE(); - } - CString soName = moduleName.substr(pos + 1); - CString path = moduleName.substr(0, pos); - // use module name as so name - arguments[0] = StringRef::NewFromUtf8(vm, soName.c_str()); - arguments.emplace_back(BooleanRef::New(vm, true)); - arguments.emplace_back(StringRef::NewFromUtf8(vm, path.c_str())); -} - -void ModuleManager::MakeInternalArgs(const EcmaVM *vm, std::vector> &arguments, - const CString &moduleRequestName) -{ - arguments.emplace_back(BooleanRef::New(vm, false)); - arguments.emplace_back(StringRef::NewFromUtf8(vm, "")); - CString moduleDir = GetInternalModuleDir(moduleRequestName); - arguments.emplace_back(StringRef::NewFromUtf8(vm, moduleDir.c_str())); -} - -bool ModuleManager::LoadNativeModule(JSThread *thread, JSHandle &requiredModule, - const JSHandle &moduleRequest, ModuleTypes moduleType) -{ - EcmaVM *vm = thread->GetEcmaVM(); - LocalScope scope(vm); - - CString moduleRequestName = ConvertToString(EcmaString::Cast(moduleRequest->GetTaggedObject())); - CString moduleName = GetStrippedModuleName(moduleRequestName); - std::vector> arguments; - LOG_FULL(DEBUG) << "Request module is " << moduleRequestName; - - arguments.emplace_back(StringRef::NewFromUtf8(vm, moduleName.c_str())); - if (moduleType == ModuleTypes::APP_MODULE) { - MakeAppArgs(vm, arguments, moduleName); - } else if (moduleType == ModuleTypes::INTERNAL_MODULE) { - MakeInternalArgs(vm, arguments, moduleRequestName); - } - auto maybeFuncRef = GetRequireNativeModuleFunc(vm, moduleType); - // some function(s) may not registered in global object for non-main thread - if (!maybeFuncRef->IsFunction()) { - LOG_FULL(WARN) << "Not found require func"; - return false; - } - - Local funcRef = maybeFuncRef; - auto exportObject = funcRef->Call(vm, JSValueRef::Undefined(vm), arguments.data(), arguments.size()); - if (UNLIKELY(thread->HasPendingException())) { - thread->ClearException(); - LOG_FULL(ERROR) << "LoadNativeModule has exception"; - return false; - } - requiredModule->StoreModuleValue(thread, 0, JSNApiHelper::ToJSHandle(exportObject)); - return true; -} - JSHandle ModuleManager::HostResolveImportedModule(const JSPandaFile *jsPandaFile, const CString &filename) { diff --git a/ecmascript/module/js_module_manager.h b/ecmascript/module/js_module_manager.h index 4dfdf5f201..38901a44ce 100644 --- a/ecmascript/module/js_module_manager.h +++ b/ecmascript/module/js_module_manager.h @@ -79,16 +79,6 @@ public: static CString GetRecordName(JSTaggedValue module); static int GetExportObjectIndex(EcmaVM *vm, JSHandle ecmaModule, const std::string &key); - inline static bool IsNativeModule(ModuleTypes moduleType) - { - return moduleType == ModuleTypes::OHOS_MODULE || - moduleType == ModuleTypes::APP_MODULE || - moduleType == ModuleTypes::NATIVE_MODULE || - moduleType == ModuleTypes::INTERNAL_MODULE; - } - static std::pair CheckNativeModule(const CString &moduleRequestName); - static bool LoadNativeModule(JSThread *thread, JSHandle &requiredModule, - const JSHandle &moduleRequest, ModuleTypes moduleType); private: NO_COPY_SEMANTIC(ModuleManager); NO_MOVE_SEMANTIC(ModuleManager); @@ -117,13 +107,6 @@ private: JSHandle ResolveModuleWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile, const CString &recordName); - static Local GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType); - static CString GetStrippedModuleName(const CString &moduleRequestName); - static CString GetInternalModuleDir(const CString &moduleRequestName); - static void MakeAppArgs(const EcmaVM *vm, std::vector> &arguments, const CString &moduleName); - static void MakeInternalArgs(const EcmaVM *vm, std::vector> &arguments, - const CString &moduleRequestName); - static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4; EcmaVM *vm_ {nullptr}; diff --git a/ecmascript/module/js_module_source_text.cpp b/ecmascript/module/js_module_source_text.cpp index ff592a4d18..ff8b4884e4 100644 --- a/ecmascript/module/js_module_source_text.cpp +++ b/ecmascript/module/js_module_source_text.cpp @@ -29,6 +29,8 @@ namespace panda::ecmascript { using PathHelper = base::PathHelper; +using StringHelper = base::StringHelper; + CVector SourceTextModule::GetExportedNames(JSThread *thread, const JSHandle &module, const JSHandle &exportStarSet) { @@ -84,7 +86,7 @@ JSHandle SourceTextModule::HostResolveImportedModuleWithMerge( } CString moduleRequestName = ConvertToString(EcmaString::Cast(moduleRequest->GetTaggedObject())); - auto [isNative, moduleType] = ModuleManager::CheckNativeModule(moduleRequestName); + auto [isNative, moduleType] = SourceTextModule::CheckNativeModule(moduleRequestName); if (isNative) { return moduleManager->ResolveNativeModule(moduleRequestName, moduleType); } @@ -265,12 +267,103 @@ void SourceTextModule::InstantiateCJS(JSThread *thread, const JSHandle SourceTextModule::CheckNativeModule(const CString &moduleRequestName) +{ + if (moduleRequestName[0] != '@' || + StringHelper::StringStartWith(moduleRequestName, PathHelper::PREFIX_BUNDLE) || + StringHelper::StringStartWith(moduleRequestName, PathHelper::PREFIX_PACKAGE)|| + moduleRequestName.find(':') == CString::npos) { + return {false, ModuleTypes::UNKNOWN}; + } + + if (StringHelper::StringStartWith(moduleRequestName, PathHelper::REQUIRE_NAPI_OHOS_PREFIX)) { + return {true, ModuleTypes::OHOS_MODULE}; + } + if (StringHelper::StringStartWith(moduleRequestName, PathHelper::REQUIRE_NAPI_APP_PREFIX)) { + return {true, ModuleTypes::APP_MODULE}; + } + if (StringHelper::StringStartWith(moduleRequestName, PathHelper::REQUIRE_NAITVE_MODULE_PREFIX)) { + return {true, ModuleTypes::NATIVE_MODULE}; + } + return {true, ModuleTypes::INTERNAL_MODULE}; +} + +Local SourceTextModule::GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType) +{ + Local globalObject = JSNApi::GetGlobalObject(vm); + auto globalConstants = vm->GetJSThread()->GlobalConstants(); + auto funcName = (moduleType == ModuleTypes::NATIVE_MODULE) ? + globalConstants->GetHandledRequireNativeModuleString() : + globalConstants->GetHandledRequireNapiString(); + return globalObject->Get(vm, JSNApiHelper::ToLocal(funcName)); +} + +void SourceTextModule::MakeAppArgs(const EcmaVM *vm, std::vector> &arguments, + const CString &moduleName) +{ + size_t pos = moduleName.find_last_of('/'); + if (pos == CString::npos) { + LOG_FULL(FATAL) << "Invalid native module " << moduleName; + UNREACHABLE(); + } + CString soName = moduleName.substr(pos + 1); + CString path = moduleName.substr(0, pos); + // use module name as so name + arguments[0] = StringRef::NewFromUtf8(vm, soName.c_str()); + arguments.emplace_back(BooleanRef::New(vm, true)); + arguments.emplace_back(StringRef::NewFromUtf8(vm, path.c_str())); +} + +void SourceTextModule::MakeInternalArgs(const EcmaVM *vm, std::vector> &arguments, + const CString &moduleRequestName) +{ + arguments.emplace_back(BooleanRef::New(vm, false)); + arguments.emplace_back(StringRef::NewFromUtf8(vm, "")); + CString moduleDir = PathHelper::GetInternalModulePrefix(moduleRequestName); + arguments.emplace_back(StringRef::NewFromUtf8(vm, moduleDir.c_str())); +} + +bool SourceTextModule::LoadNativeModule(JSThread *thread, JSHandle &requiredModule, + const JSHandle &moduleRequest, ModuleTypes moduleType) +{ + EcmaVM *vm = thread->GetEcmaVM(); + [[maybe_unused]] LocalScope scope(vm); + + CString moduleRequestName = ConvertToString(EcmaString::Cast(moduleRequest->GetTaggedObject())); + CString moduleName = PathHelper::GetStrippedModuleName(moduleRequestName); + std::vector> arguments; + LOG_FULL(DEBUG) << "Request module is " << moduleRequestName; + + arguments.emplace_back(StringRef::NewFromUtf8(vm, moduleName.c_str())); + if (moduleType == ModuleTypes::APP_MODULE) { + MakeAppArgs(vm, arguments, moduleName); + } else if (moduleType == ModuleTypes::INTERNAL_MODULE) { + MakeInternalArgs(vm, arguments, moduleRequestName); + } + auto maybeFuncRef = GetRequireNativeModuleFunc(vm, moduleType); + // some function(s) may not registered in global object for non-main thread + if (!maybeFuncRef->IsFunction()) { + LOG_FULL(WARN) << "Not found require func"; + return false; + } + + Local funcRef = maybeFuncRef; + auto exportObject = funcRef->Call(vm, JSValueRef::Undefined(vm), arguments.data(), arguments.size()); + if (UNLIKELY(thread->HasPendingException())) { + thread->ClearException(); + LOG_FULL(ERROR) << "LoadNativeModule has exception"; + return false; + } + requiredModule->StoreModuleValue(thread, 0, JSNApiHelper::ToJSHandle(exportObject)); + return true; +} + void SourceTextModule::InstantiateNativeModule(JSThread *thread, JSHandle ¤tModule, JSHandle &requiredModule, const JSHandle &moduleRequest, ModuleTypes moduleType) { if (requiredModule->GetStatus() != ModuleStatus::EVALUATED) { - if (!ModuleManager::LoadNativeModule(thread, requiredModule, moduleRequest, moduleType)) { + if (!SourceTextModule::LoadNativeModule(thread, requiredModule, moduleRequest, moduleType)) { LOG_FULL(WARN) << "LoadNativeModule " << ConvertToString( EcmaString::Cast(moduleRequest->GetTaggedObject())) << " failed"; return; @@ -845,7 +938,7 @@ int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle::Cast(requiredVal)); } ModuleTypes moduleType = requiredModule->GetTypes(); - if (ModuleManager::IsNativeModule(moduleType)) { + if (SourceTextModule::IsNativeModule(moduleType)) { InstantiateNativeModule(thread, module, requiredModule, required, moduleType); requiredModule->SetStatus(ModuleStatus::EVALUATED); continue; @@ -930,7 +1023,7 @@ int SourceTextModule::ModuleEvaluation(JSThread *thread, const JSHandleGetTypes(); - if (ModuleManager::IsNativeModule(moduleType)) { + if (SourceTextModule::IsNativeModule(moduleType)) { InstantiateNativeModule(thread, module, requiredModule, required, moduleType); requiredModule->SetStatus(ModuleStatus::EVALUATED); continue; @@ -1309,7 +1402,7 @@ JSHandle SourceTextModule::ResolveLocalExport(JSThread *thread, } if ((JSTaggedValue::SameValue(ee->GetExportName(), exportName.GetTaggedValue())) || - ModuleManager::IsNativeModule(moduleType)) { + IsNativeModule(moduleType)) { // Adapter new module if (module->GetIsNewBcVersion()) { return JSHandle::Cast(factory->NewResolvedIndexBindingRecord(module, diff --git a/ecmascript/module/js_module_source_text.h b/ecmascript/module/js_module_source_text.h index 61426db171..d8c4625141 100644 --- a/ecmascript/module/js_module_source_text.h +++ b/ecmascript/module/js_module_source_text.h @@ -90,6 +90,21 @@ public: const JSHandle &exportEntry, size_t idx, uint32_t len); static void AddStarExportEntry(JSThread *thread, const JSHandle &module, const JSHandle &exportEntry, size_t idx, uint32_t len); + static std::pair CheckNativeModule(const CString &moduleRequestName); + static Local GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType); + static void MakeAppArgs(const EcmaVM *vm, std::vector> &arguments, const CString &moduleName); + static void MakeInternalArgs(const EcmaVM *vm, std::vector> &arguments, + const CString &moduleRequestName); + static bool LoadNativeModule(JSThread *thread, JSHandle &requiredModule, + const JSHandle &moduleRequest, ModuleTypes moduleType); + inline static bool IsNativeModule(ModuleTypes moduleType) + { + return moduleType == ModuleTypes::OHOS_MODULE || + moduleType == ModuleTypes::APP_MODULE || + moduleType == ModuleTypes::NATIVE_MODULE || + moduleType == ModuleTypes::INTERNAL_MODULE; + } + static constexpr size_t SOURCE_TEXT_MODULE_OFFSET = ModuleRecord::SIZE; ACCESSORS(Environment, SOURCE_TEXT_MODULE_OFFSET, NAMESPACE_OFFSET); ACCESSORS(Namespace, NAMESPACE_OFFSET, ECMA_MODULE_FILENAME); diff --git a/ecmascript/module/tests/ecma_module_test.cpp b/ecmascript/module/tests/ecma_module_test.cpp index 5767ba337b..b7b7773775 100644 --- a/ecmascript/module/tests/ecma_module_test.cpp +++ b/ecmascript/module/tests/ecma_module_test.cpp @@ -511,31 +511,31 @@ HWTEST_F_L0(EcmaModuleTest, CheckNativeModule) CString requestName6 = "@package:pkg_modules/.ohpm/json5@2.2.3/pkg_modules/json5/dist/index"; CString requestName7 = "@ohos/common"; - std::pair res1 = ModuleManager::CheckNativeModule(requestName1); + std::pair res1 = SourceTextModule::CheckNativeModule(requestName1); EXPECT_EQ(res1.first, false); EXPECT_EQ(res1.second, ModuleTypes::UNKNOWN); - std::pair res2 = ModuleManager::CheckNativeModule(requestName2); + std::pair res2 = SourceTextModule::CheckNativeModule(requestName2); EXPECT_EQ(res2.first, true); EXPECT_EQ(res2.second, ModuleTypes::OHOS_MODULE); - std::pair res3 = ModuleManager::CheckNativeModule(requestName3); + std::pair res3 = SourceTextModule::CheckNativeModule(requestName3); EXPECT_EQ(res3.first, true); EXPECT_EQ(res3.second, ModuleTypes::APP_MODULE); - std::pair res4 = ModuleManager::CheckNativeModule(requestName4); + std::pair res4 = SourceTextModule::CheckNativeModule(requestName4); EXPECT_EQ(res4.first, true); EXPECT_EQ(res4.second, ModuleTypes::NATIVE_MODULE); - std::pair res5 = ModuleManager::CheckNativeModule(requestName5); + std::pair res5 = SourceTextModule::CheckNativeModule(requestName5); EXPECT_EQ(res5.first, true); EXPECT_EQ(res5.second, ModuleTypes::INTERNAL_MODULE); - std::pair res6 = ModuleManager::CheckNativeModule(requestName6); + std::pair res6 = SourceTextModule::CheckNativeModule(requestName6); EXPECT_EQ(res6.first, false); EXPECT_EQ(res6.second, ModuleTypes::UNKNOWN); - std::pair res7 = ModuleManager::CheckNativeModule(requestName7); + std::pair res7 = SourceTextModule::CheckNativeModule(requestName7); EXPECT_EQ(res7.first, false); EXPECT_EQ(res7.second, ModuleTypes::UNKNOWN); } diff --git a/ecmascript/ts_types/ts_type_parser.cpp b/ecmascript/ts_types/ts_type_parser.cpp index f9dd244e01..fb508a598f 100644 --- a/ecmascript/ts_types/ts_type_parser.cpp +++ b/ecmascript/ts_types/ts_type_parser.cpp @@ -142,8 +142,7 @@ GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile, JSHandle relativePath = GenerateImportRelativePath(importVarNamePath); CString cstringRelativePath = ConvertToString(*relativePath); // skip @ohos:|@app:|@native: prefixed imports - auto [isNative, _] = ModuleManager::CheckNativeModule(cstringRelativePath); - if (isNative) { + if (base::PathHelper::IsNativeModuleRequest(cstringRelativePath)) { return GetAndStoreGT(jsPandaFile, typeId, recordName); }