From ec287f23509b21ba43faa734d33b6aa66724194f Mon Sep 17 00:00:00 2001 From: yp9522 Date: Wed, 23 Jul 2025 19:59:01 +0800 Subject: [PATCH] Fix recursive dependencymark Issue: https://gitee.com/openharmony/arkcompiler_runtime_core/issues/ICODKZ Signed-off-by: yp9522 --- static_core/libpandafile/file_items.cpp | 12 +- static_core/libpandafile/file_items.h | 19 +- .../static_linker/tests/CMakeLists.txt | 1 - .../tests/data/ets/annotation/field.ets | 5 +- .../tests/data/ets/singlefile/lambda_test.ets | 21 -- .../data/ets/singlefile/lambda_test.gold | 13 - .../static_linker/tests/linker_test.cpp | 300 ++++++++++++++++++ 7 files changed, 330 insertions(+), 41 deletions(-) delete mode 100755 static_core/static_linker/tests/data/ets/singlefile/lambda_test.ets delete mode 100755 static_core/static_linker/tests/data/ets/singlefile/lambda_test.gold diff --git a/static_core/libpandafile/file_items.cpp b/static_core/libpandafile/file_items.cpp index f58695e303..d913bbba26 100644 --- a/static_core/libpandafile/file_items.cpp +++ b/static_core/libpandafile/file_items.cpp @@ -599,7 +599,9 @@ void BaseMethodItem::SetDependencyMark() } auto deps = GetIndexDependencies(); for (auto dep : deps) { - dep->SetDependencyMark(); + if (!dep->GetDependencyMark()) { + dep->SetDependencyMark(); + } } } @@ -1147,6 +1149,14 @@ size_t ArrayValueItem::GetComponentSize() const } } +void ArrayValueItem::SetDependencyMark() +{ + for (auto &it : items_) { + it.SetDependencyMark(); + } + BaseItem::SetDependencyMark(); +} + size_t LiteralItem::CalculateSize() const { size_t size = 0; diff --git a/static_core/libpandafile/file_items.h b/static_core/libpandafile/file_items.h index ef4954b8c7..b3937712f2 100644 --- a/static_core/libpandafile/file_items.h +++ b/static_core/libpandafile/file_items.h @@ -1769,6 +1769,17 @@ public: bool WriteAsUleb128(Writer *writer); + void SetDependencyMark() override + { + if (GetType() == Type::ID) { + if (!GetIdItem()->GetDependencyMark()) { + GetIdItem()->SetDependencyMark(); + } + } else { + ValueItem::SetDependencyMark(); + } + } + private: std::variant value_; }; @@ -1806,6 +1817,8 @@ public: return &items_; } + void SetDependencyMark() override; + private: size_t GetComponentSize() const; @@ -1959,7 +1972,11 @@ public: name_->SetDependencyMark(); } if (value_ != nullptr) { - value_->SetDependencyMark(); + if (value_->IsArray()) { + value_->GetAsArray()->SetDependencyMark(); + } else { + value_->SetDependencyMark(); + } } } diff --git a/static_core/static_linker/tests/CMakeLists.txt b/static_core/static_linker/tests/CMakeLists.txt index ff60d6f2b3..0d1d5bcba6 100644 --- a/static_core/static_linker/tests/CMakeLists.txt +++ b/static_core/static_linker/tests/CMakeLists.txt @@ -138,7 +138,6 @@ if (TARGET es2panda AND TARGET etsstdlib AND PANDA_WITH_ETS AND NOT CMAKE_CROSSC mix/2.ets singlefile/classExtension.ets singlefile/interImpl.ets - singlefile/lambda_test.ets singlefile/ObjectLiteral.ets singlefile/teserror.ets sys/1.ets diff --git a/static_core/static_linker/tests/data/ets/annotation/field.ets b/static_core/static_linker/tests/data/ets/annotation/field.ets index 4d4e4006d1..09f81904c0 100755 --- a/static_core/static_linker/tests/data/ets/annotation/field.ets +++ b/static_core/static_linker/tests/data/ets/annotation/field.ets @@ -44,10 +44,7 @@ } } -@interface MethodAuthor { - authorName: string -} -@MethodAuthor({authorName: "Alice"}) +@PropertyAuthor({authName: "Alice"}) export function main(){ console.log("Starting the application"); } \ No newline at end of file diff --git a/static_core/static_linker/tests/data/ets/singlefile/lambda_test.ets b/static_core/static_linker/tests/data/ets/singlefile/lambda_test.ets deleted file mode 100755 index 84a5583e13..0000000000 --- a/static_core/static_linker/tests/data/ets/singlefile/lambda_test.ets +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -const add = (a: number, b: number) => a + b; - -export function main() { - let res = add(1, 2) - console.log(res) -} diff --git a/static_core/static_linker/tests/data/ets/singlefile/lambda_test.gold b/static_core/static_linker/tests/data/ets/singlefile/lambda_test.gold deleted file mode 100755 index 49bca8ba64..0000000000 --- a/static_core/static_linker/tests/data/ets/singlefile/lambda_test.gold +++ /dev/null @@ -1,13 +0,0 @@ -# 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. -3 diff --git a/static_core/static_linker/tests/linker_test.cpp b/static_core/static_linker/tests/linker_test.cpp index 58881681e5..22753a73ff 100644 --- a/static_core/static_linker/tests/linker_test.cpp +++ b/static_core/static_linker/tests/linker_test.cpp @@ -325,6 +325,38 @@ std::string BuildLinkerCommand(const std::string &path, const std::vector &allowedClasses, + const std::unordered_set ¬AllowedClasses = {}) +{ + auto file = ark::panda_file::File::Open(abcFilePath.c_str(), ark::panda_file::File::READ_ONLY); + ASSERT_TRUE(file != nullptr); + const auto &classIdx = file->GetClasses(); + std::unordered_map allowedFound; + + for (const auto &cls : allowedClasses) { + allowedFound[cls] = false; + } + for (uint32_t idx : classIdx) { + auto entityId = ark::panda_file::File::EntityId(idx); + auto strData = file->GetStringData(entityId); + if (strData.data == nullptr) { + continue; + } + std::string className(reinterpret_cast(strData.data)); + + if (!notAllowedClasses.empty()) { + EXPECT_TRUE(notAllowedClasses.find(className) == notAllowedClasses.end()); + } + + if (allowedClasses.find(className) != allowedClasses.end()) { + allowedFound[className] = true; + } + } + for (const auto &cls : allowedClasses) { + EXPECT_TRUE(allowedFound[cls]); + } +} + void TestSts(const std::string &path, const std::vector &files, bool isGood = true, const StripOptions &deleteOptions = {}, const TestStsConfig &config = {}) { @@ -572,6 +604,28 @@ TEST(linkertests, ClassCallDeleteDependency) TestStsConfig config; config.entryPoint = "dependency/ETSGLOBAL::main"; TestSts("classcall_doublefile", {"dependency.ets.abc", "bedependent.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = { + "Ldependency/ETSGLOBAL;", "Lbedependent/ETSGLOBAL;", "Ldependency/AnotherClass;", "Ldependency/User;", + "Lbedependent/DependencyClass;", "Lbedependent/UnusedClass1;", "Lbedependent/UnusedClass2;"}; + const std::string abcFilePathPrefix = "data/output/classcall_doublefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses); +#endif +} + +TEST(linkertests, ClassCallDeleteDependencyFromEntry) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"dependency/ETSGLOBAL\""; + TestStsConfig config; + config.entryPoint = "dependency/ETSGLOBAL::main"; + TestSts("classcall_doublefile", {"dependency.ets.abc", "bedependent.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Ldependency/ETSGLOBAL;", "Ldependency/User;"}; + std::unordered_set notAllowedClasses = {"Lbedependent/ETSGLOBAL;", "Lbedependent/UnusedClass1;", + "Lbedependent/UnusedClass2;"}; + const std::string abcFilePathPrefix = "data/output/classcall_doublefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); #endif } @@ -585,6 +639,40 @@ TEST(linkertests, ClassCallDeleteDependencyFromEntryInputError) #endif } +TEST(linkertests, ClassCallDeleteDependencyFromConfig) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "@data/ets/classcall_doublefile/configfile.txt"; + TestStsConfig config; + config.entryPoint = "dependency/ETSGLOBAL::main"; + TestSts("classcall_doublefile", {"dependency.ets.abc", "bedependent.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Ldependency/ETSGLOBAL;", "Ldependency/User;"}; + std::unordered_set notAllowedClasses = {"Lbedependent/ETSGLOBAL;", "bedependent/UnusedClass1;", + "Lbedependent/UnusedClass2;"}; + const std::string abcFilePathPrefix = "data/output/classcall_doublefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); +#endif +} + +TEST(linkertests, MethodCallDeleteDependencyFromEntry) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"dependency/ETSGLOBAL/main\""; + TestStsConfig config; + config.entryPoint = "dependency/ETSGLOBAL::main"; + TestSts("classcall_doublefile", {"dependency.ets.abc", "bedependent.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Ldependency/ETSGLOBAL;", "Ldependency/User;"}; + std::unordered_set notAllowedClasses = {"Lbedependent/ETSGLOBAL;", "Lbedependent/UnusedClass1;", + "Lbedependent/UnusedClass2;"}; + const std::string abcFilePathPrefix = "data/output/classcall_doublefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); +#endif +} + TEST(linkertests, MethodCallDeleteDependencyFromEntryInputError) { #ifdef TEST_STATIC_LINKER_WITH_STS @@ -595,6 +683,23 @@ TEST(linkertests, MethodCallDeleteDependencyFromEntryInputError) #endif } +TEST(linkertests, MethodCallDeleteDependencyFromConfig) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "@data/ets/classcall_doublefile/methodconfig.txt"; + TestStsConfig config; + config.entryPoint = "dependency/ETSGLOBAL::main"; + TestSts("classcall_doublefile", {"dependency.ets.abc", "bedependent.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Ldependency/ETSGLOBAL;", "Ldependency/User;"}; + std::unordered_set notAllowedClasses = {"Lbedependent/ETSGLOBAL;", "Lbedependent/UnusedClass1;", + "Lbedependent/UnusedClass2;"}; + const std::string abcFilePathPrefix = "data/output/classcall_doublefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); +#endif +} + TEST(linkertests, CallDeleteDependencyFromConfigFileNotExist) { #ifdef TEST_STATIC_LINKER_WITH_STS @@ -605,6 +710,24 @@ TEST(linkertests, CallDeleteDependencyFromConfigFileNotExist) #endif } +TEST(linkertests, CallDeleteDependencyFromEntryFile) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"dependency.ets\""; + TestStsConfig config; + config.entryPoint = "dependency/ETSGLOBAL::main"; + TestSts("classcall_doublefile", {"dependency.ets.abc", "bedependent.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Ldependency/ETSGLOBAL;", "Ldependency/AnotherClass;", + "Lbedependent/DependencyClass;", "Ldependency/User;"}; + std::unordered_set notAllowedClasses = {"Lbedependent/ETSGLOBAL;", "Lbedependent/UnusedClass1;", + "Lbedependent/UnusedClass2;"}; + const std::string abcFilePathPrefix = "data/output/classcall_doublefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); +#endif +} + TEST(linkertests, CallDeleteDependencyFromEntryFileNotExist) { #ifdef TEST_STATIC_LINKER_WITH_STS @@ -615,6 +738,123 @@ TEST(linkertests, CallDeleteDependencyFromEntryFileNotExist) #endif } +TEST(linkertests, MethodAnnotationDeleteDependency) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"method/ETSGLOBAL/main\""; + TestStsConfig config; + config.entryPoint = "method/ETSGLOBAL::main"; + TestSts("annotation", {"method.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Lmethod/ETSGLOBAL;", "Lmethod/ClassAuthor;"}; + std::unordered_set notAllowedClasses = {"Lmethod/C3;", "Lmethod/ClassPreamble;"}; + const std::string abcFilePathPrefix = "data/output/annotation/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); +#endif +} + +TEST(linkertests, FieldAnnotationDeleteDependency) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"field/ETSGLOBAL/main\""; + TestStsConfig config; + config.entryPoint = "field/ETSGLOBAL::main"; + TestSts("annotation", {"field.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Lfield/ETSGLOBAL;", "Lfield/PropertyAuthor;"}; + std::unordered_set notAllowedClasses = {"Lfield/C3;", "Lfield/ClassPreamble;", + "Lfield/DeprecatedProperty;"}; + const std::string abcFilePathPrefix = "data/output/annotation/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); +#endif +} + +TEST(linkertests, ClassExtensionDeleteDependency) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"classExtension/ETSGLOBAL/main\""; + TestStsConfig config; + config.entryPoint = "classExtension/ETSGLOBAL::main"; + config.outputFileName = "classExtension.gold"; + TestSts("singlefile", {"classExtension.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"LclassExtension/ETSGLOBAL;", "LclassExtension/Animal;", + "LclassExtension/Dog;"}; + const std::string abcFilePathPrefix = "data/output/singlefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses); +#endif +} + +TEST(linkertests, InterImplDeleteDependency) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"interImpl/ETSGLOBAL/main\""; + TestStsConfig config; + config.entryPoint = "interImpl/ETSGLOBAL::main"; + config.outputFileName = "interImpl.gold"; + TestSts("singlefile", {"interImpl.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"LinterImpl/ETSGLOBAL;", "LinterImpl/Circle;", + "LinterImpl/Rectangle;", "LinterImpl/Shape;"}; + const std::string abcFilePathPrefix = "data/output/singlefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses); +#endif +} + +TEST(linkertests, ObjectLiteralDeleteDependency) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"ObjectLiteral/ETSGLOBAL/main\""; + TestStsConfig config; + config.entryPoint = "ObjectLiteral/ETSGLOBAL::main"; + config.outputFileName = "ObjectLiteral.gold"; + TestSts("singlefile", {"ObjectLiteral.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"LObjectLiteral/ETSGLOBAL;", "LObjectLiteral/Person;"}; + const std::string abcFilePathPrefix = "data/output/singlefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses); +#endif +} + +TEST(linkertests, TesErrorDeleteDependency) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"teserror/ETSGLOBAL/main\""; + TestStsConfig config; + config.entryPoint = "teserror/ETSGLOBAL::main"; + config.outputFileName = "teserror.gold"; + TestSts("singlefile", {"teserror.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Lteserror/ETSGLOBAL;", "Lteserror/TestA;"}; + const std::string abcFilePathPrefix = "data/output/singlefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses); +#endif +} + +TEST(linkertests, DebugInfoClassCallDeleteDependency) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "dependency_debug/ETSGLOBAL/main"; + TestStsConfig config; + config.entryPoint = "dependency_debug/ETSGLOBAL::main"; + config.outputFileName = "outDebug.gold"; + TestSts("classcall_doublefile", {"dependency_debug.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Ldependency_debug/ETSGLOBAL;", + "Ldependency_debug/DependencyClass;"}; + std::unordered_set notAllowedClasses = {}; + const std::string abcFilePathPrefix = "data/output/classcall_doublefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); +#endif +} + TEST(linkertests, MultiClassCallNoDeleteDependency) { #ifdef TEST_STATIC_LINKER_WITH_STS @@ -636,6 +876,61 @@ TEST(linkertests, MultiClassCallDeleteDependency) TestSts("classcall_multifile", {"main_dependencyUser.ets.abc", "dependency.ets.abc", "user_dependency.ets.abc", "product_user.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = {"Lmain_dependencyUser/ETSGLOBAL;", + "Lmain_dependencyUser/MainApplication;", + "Ldependency/ETSGLOBAL;", + "Ldependency/DependencyClass;", + "Luser_dependency/User;", + "Ldependency/UnusedDependencyClass;", + "Luser_dependency/UnusedUserClass;", + "Lproduct_user/Product;", + "Lproduct_user/UnusedProductClass;", + "Lproduct_user/ETSGLOBAL;", + "Luser_dependency/ETSGLOBAL;"}; + const std::string abcFilePathPrefix = "data/output/classcall_multifile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses); +#endif +} +TEST(linkertests, MultiClassCallDeleteDependencyFromEntry) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "\"main_dependencyUser/ETSGLOBAL\""; + TestStsConfig config; + config.entryPoint = "main_dependencyUser/ETSGLOBAL::main"; + TestSts("classcall_multifile", + {"main_dependencyUser.ets.abc", "dependency.ets.abc", "user_dependency.ets.abc", "product_user.ets.abc"}, + true, opts, config); + std::unordered_set allowedClasses = {"Lmain_dependencyUser/ETSGLOBAL;", + "Lmain_dependencyUser/MainApplication;", + "Ldependency/DependencyClass;", "Luser_dependency/User;"}; + std::unordered_set notAllowedClasses = { + "Ldependency/UnusedDependencyClass;", "Luser_dependency/UnusedUserClass;", "Lproduct_user/Product;", + "Lproduct_user/UnusedProductClass;", "Lproduct_user/ETSGLOBAL;"}; + const std::string abcFilePathPrefix = "data/output/classcall_multifile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); +#endif +} + +TEST(linkertests, MultiClassCallDeleteDependencyFromConfig) +{ +#ifdef TEST_STATIC_LINKER_WITH_STS + StripOptions opts; + opts.stripUnused = true; + opts.stripUnusedSkiplist = "@data/ets/classcall_multifile/configfile.txt"; + TestStsConfig config; + config.entryPoint = "main_dependencyUser/ETSGLOBAL::main"; + TestSts("classcall_multifile", + {"main_dependencyUser.ets.abc", "dependency.ets.abc", "user_dependency.ets.abc", "product_user.ets.abc"}, + true, opts, config); + std::unordered_set allowedClasses = { + "Lmain_dependencyUser/ETSGLOBAL;", "Lmain_dependencyUser/MainApplication;", "Ldependency/DependencyClass;", + "Luser_dependency/User;", "Lproduct_user/Product;"}; + std::unordered_set notAllowedClasses = {"Luser_dependency/UnusedUserClass;", + "Lproduct_user/ETSGLOBAL;", "Luser_dependency/ETSGLOBAL;"}; + const std::string abcFilePathPrefix = "data/output/classcall_multifile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses, notAllowedClasses); #endif } @@ -648,6 +943,11 @@ TEST(linkertests, ClassCallDeleteDependencyAll) TestStsConfig config; config.entryPoint = "dependency/ETSGLOBAL::main"; TestSts("classcall_doublefile", {"dependency.ets.abc", "bedependent.ets.abc"}, true, opts, config); + std::unordered_set allowedClasses = { + "Ldependency/ETSGLOBAL;", "Lbedependent/ETSGLOBAL;", "Ldependency/AnotherClass;", "Ldependency/User;", + "Lbedependent/DependencyClass;", "Lbedependent/UnusedClass1;", "Lbedependent/UnusedClass2;"}; + const std::string abcFilePathPrefix = "data/output/classcall_doublefile/"; + VerifyDeletedDependencies(abcFilePathPrefix + "linked.abc", allowedClasses); #endif } -- Gitee