mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 08:03:29 +00:00
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 <daihuina1@huawei.com> Change-Id: I7e5eab96e7fe252aa96bb38256728234bd2d90d5
This commit is contained in:
parent
8c6170a146
commit
52d373fa63
1
BUILD.gn
1
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",
|
||||
|
@ -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
|
@ -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> 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<JSTaggedValue> 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<SourceTextModule> 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<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
|
||||
EcmaRuntimeCallInfo *info =
|
||||
EcmaInterpreter::NewRuntimeCallInfo(thread,
|
||||
|
@ -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();
|
||||
|
52
ecmascript/module/js_dynamic_import.cpp
Normal file
52
ecmascript/module/js_dynamic_import.cpp
Normal file
@ -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<EcmaString> specifierString,
|
||||
ModuleTypes moduleType, JSHandle<JSPromiseReactionsFunction> resolve, JSHandle<JSPromiseReactionsFunction> reject)
|
||||
{
|
||||
ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager();
|
||||
CString requestPath = ConvertToString(specifierString.GetTaggedValue());
|
||||
CString entryPoint = PathHelper::GetStrippedModuleName(requestPath);
|
||||
JSHandle<JSTaggedValue> nativeModule = moduleManager->ResolveNativeModule(requestPath, moduleType);
|
||||
JSHandle<SourceTextModule> requiredModule = JSHandle<SourceTextModule>::Cast(nativeModule);
|
||||
if (!SourceTextModule::LoadNativeModule(thread, requiredModule,
|
||||
JSHandle<JSTaggedValue>(specifierString), moduleType)) {
|
||||
LOG_FULL(WARN) << "LoadNativeModule " << requestPath << " failed";
|
||||
}
|
||||
JSHandle<JSTaggedValue> nativeExports(thread, requiredModule->GetModuleValue(thread, 0, false));
|
||||
requiredModule->SetStatus(ModuleStatus::EVALUATED);
|
||||
JSHandle<JSTaggedValue> moduleNamespace = SourceTextModule::GetModuleNamespace(thread, requiredModule);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, BuiltinsPromiseJob::CatchException(thread, reject));
|
||||
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
|
||||
EcmaRuntimeCallInfo *info =
|
||||
EcmaInterpreter::NewRuntimeCallInfo(thread,
|
||||
JSHandle<JSTaggedValue>(resolve),
|
||||
undefined, undefined, 1);
|
||||
info->SetCallArg(moduleNamespace.GetTaggedValue());
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return JSFunction::Call(info);
|
||||
}
|
||||
|
||||
} // namespace panda::ecmascript
|
31
ecmascript/module/js_dynamic_import.h
Normal file
31
ecmascript/module/js_dynamic_import.h
Normal file
@ -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<EcmaString> specifierString,
|
||||
ModuleTypes moduleType, JSHandle<JSPromiseReactionsFunction> resolve,
|
||||
JSHandle<JSPromiseReactionsFunction> reject);
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_MODULE_JS_DYNAMIC_IMPORT_H
|
@ -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<SourceTextModule> requiredModuleST = JSHandle<SourceTextModule>::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<SourceTextModule> e
|
||||
return index;
|
||||
}
|
||||
|
||||
std::pair<bool, ModuleTypes> 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<JSValueRef> ModuleManager::GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType)
|
||||
{
|
||||
Local<ObjectRef> 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<StringRef>(funcName));
|
||||
}
|
||||
|
||||
void ModuleManager::MakeAppArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &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<Local<JSValueRef>> &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<SourceTextModule> &requiredModule,
|
||||
const JSHandle<JSTaggedValue> &moduleRequest, ModuleTypes moduleType)
|
||||
{
|
||||
EcmaVM *vm = thread->GetEcmaVM();
|
||||
LocalScope scope(vm);
|
||||
|
||||
CString moduleRequestName = ConvertToString(EcmaString::Cast(moduleRequest->GetTaggedObject()));
|
||||
CString moduleName = GetStrippedModuleName(moduleRequestName);
|
||||
std::vector<Local<JSValueRef>> 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<FunctionRef> 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<JSTaggedValue> ModuleManager::HostResolveImportedModule(const JSPandaFile *jsPandaFile,
|
||||
const CString &filename)
|
||||
{
|
||||
|
@ -79,16 +79,6 @@ public:
|
||||
static CString GetRecordName(JSTaggedValue module);
|
||||
static int GetExportObjectIndex(EcmaVM *vm, JSHandle<SourceTextModule> 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<bool, ModuleTypes> CheckNativeModule(const CString &moduleRequestName);
|
||||
static bool LoadNativeModule(JSThread *thread, JSHandle<SourceTextModule> &requiredModule,
|
||||
const JSHandle<JSTaggedValue> &moduleRequest, ModuleTypes moduleType);
|
||||
private:
|
||||
NO_COPY_SEMANTIC(ModuleManager);
|
||||
NO_MOVE_SEMANTIC(ModuleManager);
|
||||
@ -117,13 +107,6 @@ private:
|
||||
JSHandle<JSTaggedValue> ResolveModuleWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile,
|
||||
const CString &recordName);
|
||||
|
||||
static Local<JSValueRef> 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<Local<JSValueRef>> &arguments, const CString &moduleName);
|
||||
static void MakeInternalArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &arguments,
|
||||
const CString &moduleRequestName);
|
||||
|
||||
static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4;
|
||||
|
||||
EcmaVM *vm_ {nullptr};
|
||||
|
@ -29,6 +29,8 @@
|
||||
|
||||
namespace panda::ecmascript {
|
||||
using PathHelper = base::PathHelper;
|
||||
using StringHelper = base::StringHelper;
|
||||
|
||||
CVector<std::string> SourceTextModule::GetExportedNames(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const JSHandle<TaggedArray> &exportStarSet)
|
||||
{
|
||||
@ -84,7 +86,7 @@ JSHandle<JSTaggedValue> 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<SourceTex
|
||||
InitializeEnvironment(thread, currentModule, cjsModuleName, cjsExports, isBundle);
|
||||
}
|
||||
|
||||
std::pair<bool, ModuleTypes> 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<JSValueRef> SourceTextModule::GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType)
|
||||
{
|
||||
Local<ObjectRef> 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<StringRef>(funcName));
|
||||
}
|
||||
|
||||
void SourceTextModule::MakeAppArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &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<Local<JSValueRef>> &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<SourceTextModule> &requiredModule,
|
||||
const JSHandle<JSTaggedValue> &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<Local<JSValueRef>> 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<FunctionRef> 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<SourceTextModule> ¤tModule,
|
||||
JSHandle<SourceTextModule> &requiredModule, const JSHandle<JSTaggedValue> &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<Mod
|
||||
requiredModule.Update(JSHandle<SourceTextModule>::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 JSHandle<ModuleRe
|
||||
requiredModule.Update(SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required));
|
||||
}
|
||||
ModuleTypes moduleType = requiredModule->GetTypes();
|
||||
if (ModuleManager::IsNativeModule(moduleType)) {
|
||||
if (SourceTextModule::IsNativeModule(moduleType)) {
|
||||
InstantiateNativeModule(thread, module, requiredModule, required, moduleType);
|
||||
requiredModule->SetStatus(ModuleStatus::EVALUATED);
|
||||
continue;
|
||||
@ -1309,7 +1402,7 @@ JSHandle<JSTaggedValue> SourceTextModule::ResolveLocalExport(JSThread *thread,
|
||||
}
|
||||
|
||||
if ((JSTaggedValue::SameValue(ee->GetExportName(), exportName.GetTaggedValue())) ||
|
||||
ModuleManager::IsNativeModule(moduleType)) {
|
||||
IsNativeModule(moduleType)) {
|
||||
// Adapter new module
|
||||
if (module->GetIsNewBcVersion()) {
|
||||
return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module,
|
||||
|
@ -90,6 +90,21 @@ public:
|
||||
const JSHandle<IndirectExportEntry> &exportEntry, size_t idx, uint32_t len);
|
||||
static void AddStarExportEntry(JSThread *thread, const JSHandle<SourceTextModule> &module,
|
||||
const JSHandle<StarExportEntry> &exportEntry, size_t idx, uint32_t len);
|
||||
static std::pair<bool, ModuleTypes> CheckNativeModule(const CString &moduleRequestName);
|
||||
static Local<JSValueRef> GetRequireNativeModuleFunc(EcmaVM *vm, ModuleTypes moduleType);
|
||||
static void MakeAppArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &arguments, const CString &moduleName);
|
||||
static void MakeInternalArgs(const EcmaVM *vm, std::vector<Local<JSValueRef>> &arguments,
|
||||
const CString &moduleRequestName);
|
||||
static bool LoadNativeModule(JSThread *thread, JSHandle<SourceTextModule> &requiredModule,
|
||||
const JSHandle<JSTaggedValue> &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);
|
||||
|
@ -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<bool, ModuleTypes> res1 = ModuleManager::CheckNativeModule(requestName1);
|
||||
std::pair<bool, ModuleTypes> res1 = SourceTextModule::CheckNativeModule(requestName1);
|
||||
EXPECT_EQ(res1.first, false);
|
||||
EXPECT_EQ(res1.second, ModuleTypes::UNKNOWN);
|
||||
|
||||
std::pair<bool, ModuleTypes> res2 = ModuleManager::CheckNativeModule(requestName2);
|
||||
std::pair<bool, ModuleTypes> res2 = SourceTextModule::CheckNativeModule(requestName2);
|
||||
EXPECT_EQ(res2.first, true);
|
||||
EXPECT_EQ(res2.second, ModuleTypes::OHOS_MODULE);
|
||||
|
||||
std::pair<bool, ModuleTypes> res3 = ModuleManager::CheckNativeModule(requestName3);
|
||||
std::pair<bool, ModuleTypes> res3 = SourceTextModule::CheckNativeModule(requestName3);
|
||||
EXPECT_EQ(res3.first, true);
|
||||
EXPECT_EQ(res3.second, ModuleTypes::APP_MODULE);
|
||||
|
||||
std::pair<bool, ModuleTypes> res4 = ModuleManager::CheckNativeModule(requestName4);
|
||||
std::pair<bool, ModuleTypes> res4 = SourceTextModule::CheckNativeModule(requestName4);
|
||||
EXPECT_EQ(res4.first, true);
|
||||
EXPECT_EQ(res4.second, ModuleTypes::NATIVE_MODULE);
|
||||
|
||||
std::pair<bool, ModuleTypes> res5 = ModuleManager::CheckNativeModule(requestName5);
|
||||
std::pair<bool, ModuleTypes> res5 = SourceTextModule::CheckNativeModule(requestName5);
|
||||
EXPECT_EQ(res5.first, true);
|
||||
EXPECT_EQ(res5.second, ModuleTypes::INTERNAL_MODULE);
|
||||
|
||||
std::pair<bool, ModuleTypes> res6 = ModuleManager::CheckNativeModule(requestName6);
|
||||
std::pair<bool, ModuleTypes> res6 = SourceTextModule::CheckNativeModule(requestName6);
|
||||
EXPECT_EQ(res6.first, false);
|
||||
EXPECT_EQ(res6.second, ModuleTypes::UNKNOWN);
|
||||
|
||||
std::pair<bool, ModuleTypes> res7 = ModuleManager::CheckNativeModule(requestName7);
|
||||
std::pair<bool, ModuleTypes> res7 = SourceTextModule::CheckNativeModule(requestName7);
|
||||
EXPECT_EQ(res7.first, false);
|
||||
EXPECT_EQ(res7.second, ModuleTypes::UNKNOWN);
|
||||
}
|
||||
|
@ -142,8 +142,7 @@ GlobalTSTypeRef TSTypeParser::ResolveImportType(const JSPandaFile *jsPandaFile,
|
||||
JSHandle<EcmaString> 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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user