From 62c1465d501d61e4473a959c27b375bd7d0f5d3e Mon Sep 17 00:00:00 2001 From: yaochaonan Date: Sat, 12 Jul 2025 14:44:12 +0800 Subject: [PATCH] Fix worker pull sharedModule Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICL9OF?from=project-issue Signed-off-by: yaochaonan Change-Id: I74aba5576b1ca78f4f8763fda61c50ffa86c4c72 --- .../jspandafile/js_pandafile_executor.cpp | 14 +++- ecmascript/module/js_module_source_text.cpp | 18 +++++ ecmascript/module/js_module_source_text.h | 2 + ecmascript/module/tests/BUILD.gn | 3 + ecmascript/module/tests/ecma_module_test.cpp | 76 +++++++++++++++++++ .../tests/module_test/single_instance.js | 22 ++++++ .../tests/module_test/single_instance_test.js | 19 +++++ .../single_instance_test_shared.js | 20 +++++ 8 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 ecmascript/module/tests/module_test/single_instance.js create mode 100644 ecmascript/module/tests/module_test/single_instance_test.js create mode 100644 ecmascript/module/tests/module_test/single_instance_test_shared.js diff --git a/ecmascript/jspandafile/js_pandafile_executor.cpp b/ecmascript/jspandafile/js_pandafile_executor.cpp index a5c31ef300..28ac7561d3 100644 --- a/ecmascript/jspandafile/js_pandafile_executor.cpp +++ b/ecmascript/jspandafile/js_pandafile_executor.cpp @@ -66,7 +66,9 @@ Expected JSPandaFileExecutor::ExecuteFromFile(JSThread *thr SourceTextModule::Instantiate(thread, moduleRecord, executeType); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, Unexpected(false)); JSHandle module = JSHandle::Cast(moduleRecord); - module->SetStatus(ModuleStatus::INSTANTIATED); + if (!SourceTextModule::ResetStatusForNormalModuleToReExecute(thread, module)) { + return JSTaggedValue::Undefined(); + } SourceTextModule::Evaluate(thread, module, nullptr, 0, executeType); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, Unexpected(false)); return JSTaggedValue::Undefined(); @@ -205,7 +207,9 @@ Expected JSPandaFileExecutor::CommonExecuteBuffer(JSThread RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, Unexpected(false)); JSHandle module = JSHandle::Cast(moduleRecord); - module->SetStatus(ModuleStatus::INSTANTIATED); + if (!SourceTextModule::ResetStatusForNormalModuleToReExecute(thread, module)) { + return JSTaggedValue::Undefined(); + } SourceTextModule::Evaluate(thread, module, buffer, size, executeType); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, Unexpected(false)); return JSTaggedValue::Undefined(); @@ -309,7 +313,9 @@ Expected JSPandaFileExecutor::CommonExecuteBuffer(JSThread SourceTextModule::Instantiate(thread, moduleRecord); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, Unexpected(false)); JSHandle module = JSHandle::Cast(moduleRecord); - module->SetStatus(ModuleStatus::INSTANTIATED); + if (!SourceTextModule::ResetStatusForNormalModuleToReExecute(thread, module)) { + return JSTaggedValue::Undefined(); + } //After the module is instantiated, stop preloading so and parallel abc loading thread->GetEcmaVM()->StopPreLoadSoOrAbc(); @@ -499,7 +505,7 @@ int JSPandaFileExecutor::ExecuteAbcFileWithSingletonPatternFlag(JSThread *thread SourceTextModule::Instantiate(thread, moduleRecord); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ROUTE_INTERNAL_ERROR); JSHandle module = JSHandle::Cast(moduleRecord); - if (!isSingletonPattern) { + if (!isSingletonPattern && !SourceTextModule::IsSharedModule(module)) { LOG_ECMA(INFO) << "Route jump to non-singleton page: " << entryPoint; module->SetStatus(ModuleStatus::INSTANTIATED); } else { diff --git a/ecmascript/module/js_module_source_text.cpp b/ecmascript/module/js_module_source_text.cpp index b69265c07c..ff931f8ae4 100644 --- a/ecmascript/module/js_module_source_text.cpp +++ b/ecmascript/module/js_module_source_text.cpp @@ -2332,4 +2332,22 @@ JSHandle SourceTextModule::FindFuncInModuleForHook(JSThread* thre } return functionFound; } + +/* + * normal module: will re-execute once interface is called. + * shared module: only execute once. + */ +bool SourceTextModule::ResetStatusForNormalModuleToReExecute(JSThread* thread, JSHandle module) +{ + if (!SourceTextModule::IsSharedModule(module)) { + module->SetStatus(ModuleStatus::INSTANTIATED); + return true; + } + LOG_ECMA(ERROR) << "Shared Module: " << module->GetEcmaModuleRecordNameString() << " loading is not supported."; + if (module->GetStatus() >= ModuleStatus::EVALUATED) { + return false; + } + // Shared module in evaluating status will still undergo evaluate process to ensure module execution completion. + return true; +} } // namespace panda::ecmascript diff --git a/ecmascript/module/js_module_source_text.h b/ecmascript/module/js_module_source_text.h index 566aed9616..af7e6a8c90 100644 --- a/ecmascript/module/js_module_source_text.h +++ b/ecmascript/module/js_module_source_text.h @@ -440,6 +440,8 @@ public: // Find function in JsModuleSourceText For Hook static JSHandle FindFuncInModuleForHook(JSThread* thread, const std::string &recordName, const std::string &className, const std::string &funcName); + + static bool ResetStatusForNormalModuleToReExecute(JSThread* thread, JSHandle module); private: static JSHandle GetStarResolution(JSThread *thread, diff --git a/ecmascript/module/tests/BUILD.gn b/ecmascript/module/tests/BUILD.gn index 5bd309b271..0b44205eba 100644 --- a/ecmascript/module/tests/BUILD.gn +++ b/ecmascript/module/tests/BUILD.gn @@ -26,6 +26,9 @@ test_js_files = [ "module_unexecute_A", "module_unexecute_B", "module_unexecute_C", + "single_instance_test_shared", + "single_instance_test", + "single_instance" ] foreach(file, test_js_files) { diff --git a/ecmascript/module/tests/ecma_module_test.cpp b/ecmascript/module/tests/ecma_module_test.cpp index 05fe497b11..7458481eb8 100644 --- a/ecmascript/module/tests/ecma_module_test.cpp +++ b/ecmascript/module/tests/ecma_module_test.cpp @@ -37,6 +37,7 @@ #include "ecmascript/module/module_path_helper.h" #include "ecmascript/module/module_resolver.h" #include "ecmascript/module/module_tools.h" +#include "ecmascript/jspandafile/js_pandafile_executor.h" #include "ecmascript/require/js_cjs_module.h" #include "ecmascript/tests/test_helper.h" #include "libpandafile/class_data_accessor-inl.h" @@ -4288,4 +4289,79 @@ HWTEST_F_L0(EcmaModuleTest, UpdateSharedModule) thread, curmodule, resolvedBinding.GetTaggedValue(), false); EXPECT_EQ(res, val.GetTaggedValue()); } + +HWTEST_F_L0(EcmaModuleTest, ResetStatusForNormalModuleToReExecute) +{ + ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory(); + // input is normal module status == instantiaed + JSHandle module1 = objectFactory->NewSourceTextModule(); + module1->SetSharedType(SharedTypes::UNSENDABLE_MODULE); + module1->SetStatus(ModuleStatus::INSTANTIATED); + bool res1 = SourceTextModule::ResetStatusForNormalModuleToReExecute(thread, module1); + EXPECT_TRUE(res1); + // input is normal module status > instantiaed + JSHandle module2 = objectFactory->NewSourceTextModule(); + module2->SetSharedType(SharedTypes::UNSENDABLE_MODULE); + module2->SetStatus(ModuleStatus::EVALUATED); + bool res2 = SourceTextModule::ResetStatusForNormalModuleToReExecute(thread, module2); + EXPECT_TRUE(res2); + // input is shared module status == instantiaed + JSHandle module3 = objectFactory->NewSSourceTextModule(); + module3->SetSharedType(SharedTypes::SHARED_MODULE); + module3->SetStatus(ModuleStatus::INSTANTIATED); + bool res3 = SourceTextModule::ResetStatusForNormalModuleToReExecute(thread, module3); + EXPECT_TRUE(res3); + // input is shared module status == evaluating + JSHandle module4 = objectFactory->NewSSourceTextModule(); + module4->SetSharedType(SharedTypes::SHARED_MODULE); + module4->SetStatus(ModuleStatus::EVALUATING); + bool res4 = SourceTextModule::ResetStatusForNormalModuleToReExecute(thread, module4); + EXPECT_TRUE(res4); + // input is shared module status == evaluated + JSHandle module5 = objectFactory->NewSSourceTextModule(); + module5->SetSharedType(SharedTypes::SHARED_MODULE); + module5->SetStatus(ModuleStatus::EVALUATED); + bool res5 = SourceTextModule::ResetStatusForNormalModuleToReExecute(thread, module5); + EXPECT_TRUE(!res5); +} + +HWTEST_F_L0(EcmaModuleTest, SharedModuleReExecuteTest) +{ + CString baseFileName = MODULE_ABC_PATH "single_instance_test_shared.abc"; + // shared module import first time + Expected result1 = + JSPandaFileExecutor::ExecuteFromFile(thread, baseFileName, "single_instance_test_shared"); + EXPECT_TRUE(result1); + ModuleManager *moduleManager = thread->GetModuleManager(); + JSHandle module = moduleManager->GetImportedModule("single_instance_test_shared"); + JSHandle moduleRecord = JSHandle::Cast(module); + JSTaggedValue val1 = ModuleValueAccessor::GetModuleValueInner(thread, 0, moduleRecord); + EXPECT_EQ(val1, JSTaggedValue(1)); + // shared module import second time + Expected result2 = + JSPandaFileExecutor::ExecuteFromFile(thread, baseFileName, "single_instance_test_shared"); + EXPECT_TRUE(result2); + JSTaggedValue val2 = ModuleValueAccessor::GetModuleValueInner(thread, 0, moduleRecord); + EXPECT_EQ(val2, JSTaggedValue(1)); +} + +HWTEST_F_L0(EcmaModuleTest, NormalModuleReExecuteTest) +{ + CString baseFileName = MODULE_ABC_PATH "single_instance_test.abc"; + // normal module import first time + Expected result1 = + JSPandaFileExecutor::ExecuteFromFile(thread, baseFileName, "single_instance_test"); + EXPECT_TRUE(result1); + ModuleManager *moduleManager = thread->GetModuleManager(); + JSHandle module = moduleManager->GetImportedModule("single_instance_test"); + JSHandle moduleRecord = JSHandle::Cast(module); + JSTaggedValue val1 = ModuleValueAccessor::GetModuleValueInner(thread, 0, moduleRecord); + EXPECT_EQ(val1, JSTaggedValue(1)); + // normal module import second time + Expected result2 = + JSPandaFileExecutor::ExecuteFromFile(thread, baseFileName, "single_instance_test"); + EXPECT_TRUE(result2); + JSTaggedValue val2 = ModuleValueAccessor::GetModuleValueInner(thread, 0, moduleRecord); + EXPECT_EQ(val2, JSTaggedValue(2)); +} } // namespace panda::test diff --git a/ecmascript/module/tests/module_test/single_instance.js b/ecmascript/module/tests/module_test/single_instance.js new file mode 100644 index 0000000000..029ba2ca00 --- /dev/null +++ b/ecmascript/module/tests/module_test/single_instance.js @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 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. + */ + +class A { + static a = 0; + add() { + return A.a++; + } +} +export {A}; \ No newline at end of file diff --git a/ecmascript/module/tests/module_test/single_instance_test.js b/ecmascript/module/tests/module_test/single_instance_test.js new file mode 100644 index 0000000000..cbfb7fb76f --- /dev/null +++ b/ecmascript/module/tests/module_test/single_instance_test.js @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 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. + */ + +import {A} from "./single_instance" +let instanceA = new A(); +instanceA.add(); +export let normalA = A.a; \ No newline at end of file diff --git a/ecmascript/module/tests/module_test/single_instance_test_shared.js b/ecmascript/module/tests/module_test/single_instance_test_shared.js new file mode 100644 index 0000000000..3a6cf2c312 --- /dev/null +++ b/ecmascript/module/tests/module_test/single_instance_test_shared.js @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 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. + */ + +import {A} from "./single_instance" +"use shared" +let instanceA = new A(); +instanceA.add(); +export let normalA = A.a; \ No newline at end of file -- Gitee