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