• 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 "ir_impl.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 
54             return true;
55         });
56     };
57 
58     g_implI->fileEnumerateModules(file, &cbModule, [](AbckitCoreModule *m, void *cb) {
59         (*reinterpret_cast<std::function<void(AbckitCoreModule *)> *>(cb))(m);
60         return true;
61     });
62 }
63 
EnumerateAllMethods(AbckitFile * file,const CB & cbUserFunc)64 void EnumerateAllMethods(AbckitFile *file, const CB &cbUserFunc)
65 {
66     CB cbFunc;
67     std::function<void(AbckitCoreClass *)> cbClass;
68 
69     cbFunc = [&](AbckitCoreFunction *f) {
70         cbUserFunc(f);
71         g_implI->functionEnumerateNestedFunctions(f, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
72             (*reinterpret_cast<CB *>(cb))(f);
73             return true;
74         });
75         g_implI->functionEnumerateNestedClasses(f, &cbClass, [](AbckitCoreClass *c, void *cb) {
76             (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
77             return true;
78         });
79     };
80 
81     cbClass = [&](AbckitCoreClass *c) {
82         g_implI->classEnumerateMethods(c, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
83             (*reinterpret_cast<CB *>(cb))(m);
84             return true;
85         });
86     };
87 
88     std::function<void(AbckitCoreNamespace *)> cbNamespace = [&](AbckitCoreNamespace *n) {
89         g_implI->namespaceEnumerateNamespaces(n, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
90             (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
91             return true;
92         });
93         g_implI->namespaceEnumerateClasses(n, &cbClass, [](AbckitCoreClass *c, void *cb) {
94             (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
95             return true;
96         });
97         g_implI->namespaceEnumerateTopLevelFunctions(n, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
98             (*reinterpret_cast<CB *>(cb))(f);
99             return true;
100         });
101     };
102 
103     EnumerateAllMethodsInModule(file, cbNamespace, cbClass, cbFunc);
104 }
105 
106 }  // namespace
107 
108 namespace libabckit::test {
109 
110 class AbckitScenarioCTestClean : public ::testing::Test {};
111 
112 struct UserData {
113     AbckitString *print = nullptr;
114     AbckitString *date = nullptr;
115     AbckitString *getTime = nullptr;
116     AbckitString *str = nullptr;
117     AbckitString *consume = nullptr;
118 };
119 
120 struct VisitData {
121     UserData *ud = nullptr;
122     AbckitInst *time = nullptr;
123 };
124 
125 // CC-OFFNXT(G.FUN.01-CPP) huge function
CreateEpilog(AbckitInst * inst,AbckitBasicBlock * bb,UserData * userData,AbckitInst * time)126 static void CreateEpilog(AbckitInst *inst, AbckitBasicBlock *bb, UserData *userData, AbckitInst *time)
127 {
128     auto *graph = g_implG->bbGetGraph(bb);
129     while (inst != nullptr) {
130         if (g_dynG->iGetOpcode(inst) == ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURNUNDEFINED) {
131             // Epilog
132             auto *dateClass2 = g_dynG->iCreateTryldglobalbyname(graph, userData->date);
133             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
134             g_implG->iInsertBefore(dateClass2, inst);
135             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
136             auto *dateObj2 = g_dynG->iCreateNewobjrange(graph, 1, dateClass2);
137             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
138             g_implG->iInsertAfter(dateObj2, dateClass2);
139             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
140             auto *getTime2 = g_dynG->iCreateLdobjbyname(graph, dateObj2, userData->getTime);
141             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
142             g_implG->iInsertAfter(getTime2, dateObj2);
143             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
144             auto *time2 = g_dynG->iCreateCallthis0(graph, getTime2, dateObj2);
145             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
146             g_implG->iInsertAfter(time2, getTime2);
147             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
148             auto *consume = g_dynG->iCreateLoadString(graph, userData->consume);
149             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
150             g_implG->iInsertAfter(consume, time2);
151             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
152 
153             auto *print2 = g_dynG->iCreateTryldglobalbyname(graph, userData->print);
154             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
155             g_implG->iInsertAfter(print2, consume);
156             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
157             auto *callArg2 = g_dynG->iCreateCallarg1(graph, print2, consume);
158             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
159             g_implG->iInsertAfter(callArg2, print2);
160             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
161             auto *sub = g_dynG->iCreateSub2(graph, time, time2);
162             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
163             g_implG->iInsertAfter(sub, callArg2);
164             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
165 
166             auto *print3 = g_dynG->iCreateTryldglobalbyname(graph, userData->print);
167             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
168             g_implG->iInsertAfter(print3, sub);
169             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
170             auto *callArg3 = g_dynG->iCreateCallarg1(graph, print3, sub);
171             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
172             g_implG->iInsertAfter(callArg3, print3);
173             ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
174         }
175         inst = g_implG->iGetNext(inst);
176     }
177 }
178 
BBgetSuccBlocks(AbckitBasicBlock * bb)179 static std::vector<AbckitBasicBlock *> BBgetSuccBlocks(AbckitBasicBlock *bb)
180 {
181     std::vector<AbckitBasicBlock *> succBBs;
182     g_implG->bbVisitSuccBlocks(bb, &succBBs, [](AbckitBasicBlock *succBasicBlock, void *d) {
183         auto *succs = reinterpret_cast<std::vector<AbckitBasicBlock *> *>(d);
184         succs->emplace_back(succBasicBlock);
185         return true;
186     });
187     return succBBs;
188 }
189 
TransformIr(AbckitGraph * graph,UserData * userData)190 static void TransformIr(AbckitGraph *graph, UserData *userData)
191 {
192     AbckitBasicBlock *startBB = g_implG->gGetStartBasicBlock(graph);
193     std::vector<AbckitBasicBlock *> succBBs = BBgetSuccBlocks(startBB);
194     auto *bb = succBBs[0];
195 
196     // Prolog
197     auto *str = g_dynG->iCreateLoadString(graph, userData->str);
198     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
199     g_implG->bbAddInstFront(bb, str);
200     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
201     auto *print = g_dynG->iCreateTryldglobalbyname(graph, userData->print);
202     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
203     g_implG->iInsertAfter(print, str);
204     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
205     auto *callArg = g_dynG->iCreateCallarg1(graph, print, str);
206     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
207     g_implG->iInsertAfter(callArg, print);
208     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
209 
210     auto *dateClass = g_dynG->iCreateTryldglobalbyname(graph, userData->date);
211     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
212     g_implG->iInsertAfter(dateClass, callArg);
213     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
214     auto *dateObj = g_dynG->iCreateNewobjrange(graph, 1, dateClass);
215     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
216     g_implG->iInsertAfter(dateObj, dateClass);
217     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
218     auto *getTime = g_dynG->iCreateLdobjbyname(graph, dateObj, userData->getTime);
219     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
220     g_implG->iInsertAfter(getTime, dateObj);
221     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
222     auto *time = g_dynG->iCreateCallthis0(graph, getTime, dateObj);
223     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
224     g_implG->iInsertAfter(time, getTime);
225     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
226 
227     VisitData vd;
228     vd.ud = userData;
229     vd.time = time;
230 
231     g_implG->gVisitBlocksRpo(graph, &vd, [](AbckitBasicBlock *bb, void *data) {
232         auto *inst = g_implG->bbGetFirstInst(bb);
233 
234         auto *visitData = reinterpret_cast<VisitData *>(data);
235         CreateEpilog(inst, bb, visitData->ud, visitData->time);
236         return true;
237     });
238 }
239 
GetMethodName(AbckitCoreFunction * method)240 static std::string GetMethodName(AbckitCoreFunction *method)
241 {
242     auto mname = g_implI->functionGetName(method);
243     std::string fullSig = g_implI->abckitStringToString(mname);
244     auto fullName = fullSig.substr(0, fullSig.find(':'));
245     return fullName;
246 }
247 
248 // CC-OFFNXT(huge_method, C_RULE_ID_FUNCTION_SIZE) test, solid logic
249 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(AbckitScenarioCTestClean,LibAbcKitTestDynamicAddLogClean)250 TEST_F(AbckitScenarioCTestClean, LibAbcKitTestDynamicAddLogClean)
251 {
252     // ExecuteDynamicAbc is helper function needed for testing. Вoes not affect the logic of IR transformation
253     auto output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/add_log/add_log_dynamic.abc",
254                                              "add_log_dynamic");
255     EXPECT_TRUE(helpers::Match(output, "abckit\n"));
256 
257     constexpr auto INPUT_PATH = ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/add_log/add_log_dynamic.abc";
258     AbckitFile *file = g_impl->openAbc(INPUT_PATH, strlen(INPUT_PATH));
259     UserData data = {};
260     data.print = g_implM->createString(file, "print", strlen("print"));
261     data.date = g_implM->createString(file, "Date", strlen("Date"));
262     data.getTime = g_implM->createString(file, "getTime", strlen("getTime"));
263     data.str = g_implM->createString(file, "file: src/MyClass, function: MyClass.handle",
264                                      strlen("file: src/MyClass, function: MyClass.handle"));
265     data.consume = g_implM->createString(file, "Ellapsed time:", strlen("Ellapsed time:"));
266 
267     AbckitCoreFunction *handleMethod;
268     EnumerateAllMethods(file, [&](AbckitCoreFunction *method) {
269         auto methodName = GetMethodName(method);
270         if (methodName == "handle") {
271             handleMethod = method;
272         }
273     });
274 
275     AbckitGraph *graph = g_implI->createGraphFromFunction(handleMethod);
276     TransformIr(graph, &data);
277     g_implM->functionSetGraph(handleMethod, graph);
278     constexpr auto OUTPUT_PATH = ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/add_log/add_log_dynamic_modified.abc";
279     g_impl->writeAbc(file, OUTPUT_PATH, strlen(OUTPUT_PATH));
280     g_impl->destroyGraph(graph);
281     g_impl->closeFile(file);
282 
283     output = helpers::ExecuteDynamicAbc(OUTPUT_PATH, "add_log_dynamic");
284     EXPECT_TRUE(helpers::Match(output,
285                                "file: src/MyClass, function: MyClass.handle\n"
286                                "abckit\n"
287                                "Ellapsed time:\n"
288                                "\\d+\n"));
289 }
290 
291 }  // namespace libabckit::test
292