• 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 "libabckit/include/c/metadata_core.h"
18 #include "libabckit/include/c/ir_core.h"
19 #include "libabckit/src/include_v2/c/isa/isa_static.h"
20 
21 #include "helpers/helpers.h"
22 #include "helpers/helpers_runtime.h"
23 #include "libabckit/src/logger.h"
24 
25 #include <string>
26 #include <vector>
27 #include <functional>
28 #include "metadata_inspect_impl.h"
29 
30 #include <gtest/gtest.h>
31 #include <cstddef>
32 
33 // NOTE:
34 // * Printed filename is "NOTE", should be real name
35 // * Use actual stdlib calls (instead of user's DateGetTime, ConsoleLogNum, ConsoleLogStr)
36 // * There are several issues related to SaveState in this test:
37 //   * Start calls are inserted after first SaveState (not at the beginning of function)
38 //   * SaveStates are manipulated by user explicitly
39 //   * SaveStates are "INVALID" operations in validation schema
40 
41 namespace {
42 
43 auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
44 auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
45 auto g_implM = AbckitGetModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
46 auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
47 auto g_statG = AbckitGetIsaApiStaticImpl(ABCKIT_VERSION_RELEASE_1_0_0);
48 
49 using CB = std::function<void(AbckitCoreFunction *)>;
50 
EnumerateAllMethodsInModule(AbckitFile * file,std::function<void (AbckitCoreNamespace *)> & cbNamespace,std::function<void (AbckitCoreClass *)> & cbClass,std::function<void (AbckitCoreFunction *)> & cbFunc)51 void EnumerateAllMethodsInModule(AbckitFile *file, std::function<void(AbckitCoreNamespace *)> &cbNamespace,
52                                  std::function<void(AbckitCoreClass *)> &cbClass,
53                                  std::function<void(AbckitCoreFunction *)> &cbFunc)
54 {
55     std::function<void(AbckitCoreModule *)> cbModule = [&](AbckitCoreModule *m) {
56         g_implI->moduleEnumerateNamespaces(m, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
57             (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
58             return true;
59         });
60         g_implI->moduleEnumerateClasses(m, &cbClass, [](AbckitCoreClass *c, void *cb) {
61             (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
62             return true;
63         });
64         g_implI->moduleEnumerateTopLevelFunctions(m, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
65             (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(m);
66             return true;
67         });
68     };
69 
70     g_implI->fileEnumerateModules(file, &cbModule, [](AbckitCoreModule *m, void *cb) {
71         (*reinterpret_cast<std::function<void(AbckitCoreModule *)> *>(cb))(m);
72         return true;
73     });
74 }
75 
EnumerateAllMethods(AbckitFile * file,const CB & cbUserFunc)76 void EnumerateAllMethods(AbckitFile *file, const CB &cbUserFunc)
77 {
78     CB cbFunc;
79     std::function<void(AbckitCoreClass *)> cbClass;
80 
81     cbFunc = [&](AbckitCoreFunction *f) {
82         cbUserFunc(f);
83         g_implI->functionEnumerateNestedFunctions(f, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
84             (*reinterpret_cast<CB *>(cb))(f);
85             return true;
86         });
87         g_implI->functionEnumerateNestedClasses(f, &cbClass, [](AbckitCoreClass *c, void *cb) {
88             (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
89             return true;
90         });
91     };
92 
93     cbClass = [&](AbckitCoreClass *c) {
94         g_implI->classEnumerateMethods(c, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
95             (*reinterpret_cast<CB *>(cb))(m);
96             return true;
97         });
98     };
99 
100     std::function<void(AbckitCoreNamespace *)> cbNamespace = [&](AbckitCoreNamespace *n) {
101         g_implI->namespaceEnumerateNamespaces(n, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
102             (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
103             return true;
104         });
105         g_implI->namespaceEnumerateClasses(n, &cbClass, [](AbckitCoreClass *c, void *cb) {
106             (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
107             return true;
108         });
109         g_implI->namespaceEnumerateTopLevelFunctions(n, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
110             (*reinterpret_cast<CB *>(cb))(f);
111             return true;
112         });
113     };
114 
115     EnumerateAllMethodsInModule(file, cbNamespace, cbClass, cbFunc);
116 }
117 
118 struct UserData {
119     AbckitString *str1 = nullptr;
120     AbckitString *str2 = nullptr;
121     AbckitCoreFunction *consoleLogStr = nullptr;
122     AbckitCoreFunction *consoleLogNum = nullptr;
123     AbckitCoreFunction *dateGetTime = nullptr;
124     AbckitCoreFunction *handle = nullptr;
125     AbckitInst *startTime = nullptr;
126 };
127 
TransformIr(AbckitGraph * graph,UserData * userData)128 void TransformIr(AbckitGraph *graph, UserData *userData)
129 {
130     // find first inst with opcode ABCKIT_ISA_API_STATIC_OPCODE_CALL_STATIC
131     AbckitInst *callOp = nullptr;
132     std::vector<AbckitBasicBlock *> bbs;
133     g_implG->gVisitBlocksRpo(graph, &bbs, [](AbckitBasicBlock *bb, void *data) {
134         reinterpret_cast<std::vector<AbckitBasicBlock *> *>(data)->emplace_back(bb);
135         return true;
136     });
137     for (auto *bb : bbs) {
138         auto *curInst = g_implG->bbGetFirstInst(bb);
139         while (curInst != nullptr) {
140             if (g_statG->iGetOpcode(curInst) == ABCKIT_ISA_API_STATIC_OPCODE_CALL_STATIC) {
141                 callOp = curInst;
142             }
143             curInst = g_implG->iGetNext(curInst);
144         }
145     }
146 
147     // console.log("file: FileName; function: FunctionName")
148     AbckitInst *loadString = g_statG->iCreateLoadString(graph, userData->str1);
149     g_implG->iInsertBefore(loadString, callOp);
150     AbckitInst *log1 = g_statG->iCreateCallStatic(graph, userData->consoleLogStr, 1, loadString);
151     g_implG->iInsertAfter(log1, loadString);
152 
153     // const start = Date().getTime()
154     userData->startTime = g_statG->iCreateCallStatic(graph, userData->dateGetTime, 0);
155     g_implG->iInsertAfter(userData->startTime, log1);
156 
157     g_implG->gVisitBlocksRpo(graph, userData, [](AbckitBasicBlock *bb, void *data) {
158         auto *inst = g_implG->bbGetFirstInst(bb);
159         auto *userData = reinterpret_cast<UserData *>(data);
160         auto *graph = g_implG->bbGetGraph(bb);
161         while (inst != nullptr) {
162             if (g_statG->iGetOpcode(inst) == ABCKIT_ISA_API_STATIC_OPCODE_RETURN_VOID) {
163                 // const end = Date().getTime()
164                 AbckitInst *endTime = g_statG->iCreateCallStatic(graph, userData->dateGetTime, 0);
165                 g_implG->iInsertBefore(endTime, inst);
166 
167                 // console.log("Elapsed time:")
168                 auto *loadString = g_statG->iCreateLoadString(graph, userData->str2);
169                 g_implG->iInsertAfter(loadString, endTime);
170                 AbckitInst *log = g_statG->iCreateCallStatic(graph, userData->consoleLogStr, 1, loadString);
171                 g_implG->iInsertAfter(log, loadString);
172 
173                 // console.log(end - start)
174                 AbckitInst *sub = g_statG->iCreateSub(graph, endTime, userData->startTime);
175                 g_implG->iInsertAfter(sub, log);
176                 AbckitInst *log2 = g_statG->iCreateCallStatic(graph, userData->consoleLogNum, 1, sub);
177                 g_implG->iInsertAfter(log2, sub);
178             }
179             inst = g_implG->iGetNext(inst);
180         }
181         return true;
182     });
183 }
184 
GetMethodName(AbckitCoreFunction * method)185 std::string GetMethodName(AbckitCoreFunction *method)
186 {
187     auto mname = g_implI->functionGetName(method);
188     std::string fullSig = g_implI->abckitStringToString(mname);
189     auto fullName = fullSig.substr(0, fullSig.find(':'));
190     return fullName;
191 }
192 }  // namespace
193 
194 namespace libabckit::test {
195 
196 class AbckitScenarioCTestClean : public ::testing::Test {};
197 
198 // Test: test-kind=scenario, abc-kind=ArkTS2, category=positive, extension=c
TEST_F(AbckitScenarioCTestClean,LibAbcKitTestStaticAddLogClean)199 TEST_F(AbckitScenarioCTestClean, LibAbcKitTestStaticAddLogClean)
200 {
201     auto output = helpers::ExecuteStaticAbc(ABCKIT_ABC_DIR "clean_scenarios/c_api/static/add_log/add_log_static.abc",
202                                             "add_log_static/ETSGLOBAL", "main");
203     EXPECT_TRUE(helpers::Match(output, "buisiness logic...\n"));
204 
205     constexpr auto INPUT_PATH = ABCKIT_ABC_DIR "clean_scenarios/c_api/static/add_log/add_log_static.abc";
206     AbckitFile *file = g_impl->openAbc(INPUT_PATH, strlen(INPUT_PATH));
207     UserData userData;
208     EnumerateAllMethods(file, [&](AbckitCoreFunction *method) {
209         auto methodName = GetMethodName(method);
210         if (methodName == "ConsoleLogStr") {
211             userData.consoleLogStr = method;
212         }
213         if (methodName == "ConsoleLogNum") {
214             userData.consoleLogNum = method;
215         }
216         if (methodName == "DateGetTime") {
217             userData.dateGetTime = method;
218         }
219         if (methodName == "handle") {
220             userData.handle = method;
221         }
222     });
223 
224     std::string startMsg;
225     EnumerateAllMethods(file, [&](AbckitCoreFunction *method) {
226         auto methodName = GetMethodName(method);
227         if (methodName != "handle") {
228             return;
229         }
230         startMsg = "file: NOTE; function: " + methodName;
231         userData.str1 = g_implM->createString(file, startMsg.c_str(), startMsg.size());
232         userData.str2 = g_implM->createString(file, "Elapsed time:", strlen("Elapsed time:"));
233 
234         AbckitGraph *graph = g_implI->createGraphFromFunction(method);
235         TransformIr(graph, &userData);
236         g_implM->functionSetGraph(method, graph);
237         g_impl->destroyGraph(graph);
238     });
239 
240     constexpr auto OUTPUT_PATH = ABCKIT_ABC_DIR "clean_scenarios/c_api/static/add_log/add_log_static_modified.abc";
241     g_impl->writeAbc(file, OUTPUT_PATH, strlen(OUTPUT_PATH));
242     g_impl->closeFile(file);
243 
244     output = helpers::ExecuteStaticAbc(OUTPUT_PATH, "add_log_static/ETSGLOBAL", "main");
245     EXPECT_TRUE(helpers::Match(output,
246                                "file: NOTE; function: handle\n"
247                                "buisiness logic...\n"
248                                "Elapsed time:\n"
249                                "\\d+\n"));
250 }
251 
252 }  // namespace libabckit::test
253