• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "libabckit/include/c/abckit.h"
17 #include "adapter_static/ir_static.h"
18 #include "libabckit/include/c/metadata_core.h"
19 #include "libabckit/include/c/ir_core.h"
20 #include "libabckit/include/c/isa/isa_dynamic.h"
21 
22 #include "helpers/helpers.h"
23 #include "helpers/helpers_runtime.h"
24 #include "libabckit/src/logger.h"
25 
26 #include <gtest/gtest.h>
27 
28 namespace {
29 
30 auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
31 auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
32 auto g_implM = AbckitGetModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
33 auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
34 auto g_dynG = AbckitGetIsaApiDynamicImpl(ABCKIT_VERSION_RELEASE_1_0_0);
35 
36 using CB = std::function<void(AbckitCoreFunction *)>;
37 
EnumerateAllMethodsInModule(AbckitFile * file,std::function<void (AbckitCoreNamespace *)> & cbNamespace,std::function<void (AbckitCoreClass *)> & cbClass,std::function<void (AbckitCoreFunction *)> & cbFunc)38 void EnumerateAllMethodsInModule(AbckitFile *file, std::function<void(AbckitCoreNamespace *)> &cbNamespace,
39                                  std::function<void(AbckitCoreClass *)> &cbClass,
40                                  std::function<void(AbckitCoreFunction *)> &cbFunc)
41 {
42     std::function<void(AbckitCoreModule *)> cbModule = [&](AbckitCoreModule *m) {
43         g_implI->moduleEnumerateNamespaces(m, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
44             (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
45             return true;
46         });
47         g_implI->moduleEnumerateClasses(m, &cbClass, [](AbckitCoreClass *c, void *cb) {
48             (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
49             return true;
50         });
51         g_implI->moduleEnumerateTopLevelFunctions(m, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
52             (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(m);
53             return true;
54         });
55     };
56 
57     g_implI->fileEnumerateModules(file, &cbModule, [](AbckitCoreModule *m, void *cb) {
58         (*reinterpret_cast<std::function<void(AbckitCoreModule *)> *>(cb))(m);
59         return true;
60     });
61 }
62 
EnumerateAllMethods(AbckitFile * file,const CB & cbUserFunc)63 void EnumerateAllMethods(AbckitFile *file, const CB &cbUserFunc)
64 {
65     CB cbFunc = [&](AbckitCoreFunction *f) {
66         cbUserFunc(f);
67         g_implI->functionEnumerateNestedFunctions(f, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
68             (*reinterpret_cast<CB *>(cb))(m);
69             return true;
70         });
71     };
72 
73     std::function<void(AbckitCoreClass *)> cbClass = [&](AbckitCoreClass *c) {
74         g_implI->classEnumerateMethods(c, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
75             (*reinterpret_cast<CB *>(cb))(m);
76             return true;
77         });
78     };
79 
80     std::function<void(AbckitCoreNamespace *)> cbNamespace = [&](AbckitCoreNamespace *n) {
81         g_implI->namespaceEnumerateNamespaces(n, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
82             (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
83             return true;
84         });
85         g_implI->namespaceEnumerateClasses(n, &cbClass, [](AbckitCoreClass *c, void *cb) {
86             (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
87             return true;
88         });
89         g_implI->namespaceEnumerateTopLevelFunctions(n, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
90             (*reinterpret_cast<CB *>(cb))(f);
91             return true;
92         });
93     };
94 
95     EnumerateAllMethodsInModule(file, cbNamespace, cbClass, cbFunc);
96 }
97 
GetMethodName(AbckitCoreFunction * method)98 std::string GetMethodName(AbckitCoreFunction *method)
99 {
100     auto mname = g_implI->functionGetName(method);
101     std::string fullSig = g_implI->abckitStringToString(mname);
102     auto fullName = fullSig.substr(0, fullSig.find(':'));
103     return fullName;
104 }
105 
106 struct UserData {
107     AbckitString *print = nullptr;
108 };
109 
BBgetPredBlocks(AbckitBasicBlock * bb)110 std::vector<AbckitBasicBlock *> BBgetPredBlocks(AbckitBasicBlock *bb)
111 {
112     std::vector<AbckitBasicBlock *> predBBs;
113     g_implG->bbVisitPredBlocks(bb, &predBBs, [](AbckitBasicBlock *succBasicBlock, void *d) {
114         auto *preds = reinterpret_cast<std::vector<AbckitBasicBlock *> *>(d);
115         preds->emplace_back(succBasicBlock);
116         return true;
117     });
118     return predBBs;
119 }
120 
BBgetSuccBlocks(AbckitBasicBlock * bb)121 std::vector<AbckitBasicBlock *> BBgetSuccBlocks(AbckitBasicBlock *bb)
122 {
123     std::vector<AbckitBasicBlock *> succBBs;
124     g_implG->bbVisitSuccBlocks(bb, &succBBs, [](AbckitBasicBlock *succBasicBlock, void *d) {
125         auto *succs = reinterpret_cast<std::vector<AbckitBasicBlock *> *>(d);
126         succs->emplace_back(succBasicBlock);
127         return true;
128     });
129     return succBBs;
130 }
131 
TransformIr(AbckitGraph * graph,UserData * userData)132 void TransformIr(AbckitGraph *graph, UserData *userData)
133 {
134     AbckitBasicBlock *startBB = g_implG->gGetStartBasicBlock(graph);
135     AbckitBasicBlock *endBB = g_implG->gGetEndBasicBlock(graph);
136     std::vector<AbckitBasicBlock *> succBBs = BBgetSuccBlocks(startBB);
137     AbckitBasicBlock *bb = succBBs[0];
138     AbckitInst *initInst = g_implG->bbGetFirstInst(bb);
139     AbckitInst *prevRetInst = g_implG->iGetPrev(g_implG->bbGetLastInst(bb));
140 
141     AbckitBasicBlock *tryBegin =
142         g_implG->bbSplitBlockAfterInstruction(g_implG->iGetBasicBlock(initInst), initInst, true);
143     AbckitBasicBlock *tryEnd =
144         g_implG->bbSplitBlockAfterInstruction(g_implG->iGetBasicBlock(prevRetInst), prevRetInst, true);
145 
146     // Fill catchBlock
147     AbckitBasicBlock *catchBlock = g_implG->bbCreateEmpty(graph);
148     AbckitInst *catchPhi = g_implG->bbCreateCatchPhi(catchBlock, 0);
149     AbckitInst *print = g_dynG->iCreateTryldglobalbyname(graph, userData->print);
150     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
151     g_implG->bbAddInstBack(catchBlock, print);
152     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
153     AbckitInst *callArg = g_dynG->iCreateCallarg1(graph, print, catchPhi);
154     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
155     g_implG->bbAddInstBack(catchBlock, callArg);
156 
157     AbckitBasicBlock *epilogueBB = BBgetPredBlocks(endBB)[0];
158     AbckitInst *retInst = g_implG->bbGetLastInst(epilogueBB);
159     AbckitInst *firstPhiInput = g_implG->iGetInput(retInst, 0);
160     AbckitInst *secondPhiInput = g_dynG->iCreateLdfalse(graph);
161     g_implG->bbAddInstBack(bb, secondPhiInput);
162     AbckitInst *phiInst = g_implG->bbCreatePhi(epilogueBB, 2, firstPhiInput, secondPhiInput);
163     g_implG->iSetInput(retInst, phiInst, 0);
164 
165     g_implG->gInsertTryCatch(tryBegin, tryEnd, catchBlock, catchBlock);
166 }
167 }  // namespace
168 
169 namespace libabckit::test {
170 
171 class AbckitScenarioCTestClean : public ::testing::Test {};
172 
173 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(AbckitScenarioCTestClean,LibAbcKitTestDynamicAddTryCatchClean)174 TEST_F(AbckitScenarioCTestClean, LibAbcKitTestDynamicAddTryCatchClean)
175 {
176     constexpr auto INPUT_PATH = ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/add_try_catch/add_try_catch.abc";
177     auto output = helpers::ExecuteDynamicAbc(INPUT_PATH, "add_try_catch");
178     EXPECT_TRUE(helpers::Match(output, "THROW\n"));
179 
180     AbckitFile *file = g_impl->openAbc(INPUT_PATH, strlen(INPUT_PATH));
181     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
182 
183     AbckitCoreFunction *runMethod;
184     EnumerateAllMethods(file, [&](AbckitCoreFunction *method) {
185         auto methodName = GetMethodName(method);
186         if (methodName == "run") {
187             runMethod = method;
188         }
189     });
190 
191     AbckitGraph *graph = g_implI->createGraphFromFunction(runMethod);
192     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
193 
194     UserData uData {};
195     uData.print = g_implM->createString(file, "print", strlen("print"));
196     TransformIr(graph, &uData);
197 
198     g_implM->functionSetGraph(runMethod, graph);
199     g_impl->destroyGraph(graph);
200     constexpr auto OUTPUT_PATH =
201         ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/add_try_catch/add_try_catch_modified.abc";
202     g_impl->writeAbc(file, OUTPUT_PATH, strlen(OUTPUT_PATH));
203     g_impl->closeFile(file);
204     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
205 
206     output = helpers::ExecuteDynamicAbc(OUTPUT_PATH, "add_try_catch");
207     EXPECT_TRUE(helpers::Match(output,
208                                "THROW\n"
209                                "Error: DUMMY_ERROR\n"
210                                "false\n"));
211 }
212 
213 }  // namespace libabckit::test
214