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/metadata_core.h"
17 #include "libabckit/include/c/ir_core.h"
18 #include "libabckit/include/c/isa/isa_dynamic.h"
19 #include "libabckit/include/c/abckit.h"
20
21 #include "helpers/helpers.h"
22 #include "helpers/helpers_runtime.h"
23 #include "libabckit/include/c/statuses.h"
24
25 #include <gtest/gtest.h>
26
27 // NOLINTBEGIN(readability-magic-numbers)
28 namespace libabckit::test {
29
30 static auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
31 static auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
32 static auto g_implM = AbckitGetModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
33 static auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
34 static auto g_dynG = AbckitGetIsaApiDynamicImpl(ABCKIT_VERSION_RELEASE_1_0_0);
35
36 class LibAbcKitCreateDynThrow : public ::testing::Test {};
37
CreateBBSchemaForDynThrow(AbckitIsaApiDynamicOpcode opcode)38 static std::vector<helpers::BBSchema<AbckitIsaApiDynamicOpcode>> CreateBBSchemaForDynThrow(
39 AbckitIsaApiDynamicOpcode opcode)
40 {
41 std::vector<helpers::InstSchema<AbckitIsaApiDynamicOpcode>> instVector {
42 {3, ABCKIT_ISA_API_DYNAMIC_OPCODE_LOADSTRING, {}}};
43 switch (opcode) {
44 case ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW:
45 instVector.push_back({4, opcode, {3}});
46 break;
47 case ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_NOTEXISTS:
48 case ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_PATTERNNONCOERCIBLE:
49 case ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_DELETESUPERPROPERTY:
50 instVector.push_back({4, opcode, {}});
51 break;
52 case ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_IFNOTOBJECT:
53 case ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_CONSTASSIGNMENT:
54 instVector.push_back({4, opcode, {3}});
55 break;
56 case ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_UNDEFINEDIFHOLE:
57 instVector.push_back({4, opcode, {3, 3}});
58 break;
59 case ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_UNDEFINEDIFHOLEWITHNAME:
60 case ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_IFSUPERNOTCORRECTCALL:
61 instVector.push_back({4, opcode, {3}});
62 break;
63 default:
64 LIBABCKIT_UNREACHABLE_TEST(DEBUG);
65 }
66 if (opcode != ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW) {
67 instVector.push_back({5, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN, {3}});
68 }
69 return {{{},
70 {1},
71 {{0, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
72 {1, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
73 {2, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}}}},
74 {{0}, {2}, {instVector}},
75 {{1}, {}, {}}};
76 }
77
TransformThrowValid(void (* transformIrThrow)(AbckitGraph * graph),AbckitIsaApiDynamicOpcode opcode,const std::string & expectedOutput)78 static void TransformThrowValid(void (*transformIrThrow)(AbckitGraph *graph), AbckitIsaApiDynamicOpcode opcode,
79 const std::string &expectedOutput)
80 {
81 auto output =
82 helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "ut/isa/isa_dynamic/throw/throw_dynamic.abc", "throw_dynamic");
83 EXPECT_TRUE(helpers::Match(output, ""));
84
85 helpers::TransformMethod(
86 ABCKIT_ABC_DIR "ut/isa/isa_dynamic/throw/throw_dynamic.abc",
87 ABCKIT_ABC_DIR "ut/isa/isa_dynamic/throw/throw_dynamic_modified.abc", "bar",
88 [&](AbckitFile * /*file*/, AbckitCoreFunction * /*method*/, AbckitGraph *graph) {
89 transformIrThrow(graph);
90 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
91 },
92 [&](AbckitGraph *graph) {
93 std::vector<helpers::BBSchema<AbckitIsaApiDynamicOpcode>> bbSchemas(CreateBBSchemaForDynThrow(opcode));
94 helpers::VerifyGraph(graph, bbSchemas);
95 });
96
97 output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "ut/isa/isa_dynamic/throw/throw_dynamic_modified.abc",
98 "throw_dynamic");
99 EXPECT_TRUE(helpers::Match(output, expectedOutput));
100 }
101
TransformIr1ArgValid(AbckitGraph * graph,AbckitInst * (* throwInstToCheck)(AbckitGraph * graph))102 static void TransformIr1ArgValid(AbckitGraph *graph, AbckitInst *(*throwInstToCheck)(AbckitGraph *graph))
103 {
104 auto retOp = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN);
105 ASSERT_NE(retOp, nullptr);
106 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
107
108 AbckitInst *mainInst = throwInstToCheck(graph);
109 ASSERT_NE(mainInst, nullptr);
110 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
111
112 g_implG->iInsertBefore(mainInst, retOp);
113 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
114 }
115
TransformIr2ArgValid(AbckitGraph * graph,AbckitInst * (* throwInstToCheck)(AbckitGraph * graph,AbckitInst * input0))116 static void TransformIr2ArgValid(AbckitGraph *graph,
117 AbckitInst *(*throwInstToCheck)(AbckitGraph *graph, AbckitInst *input0))
118 {
119 auto loadStr = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_LOADSTRING);
120 ASSERT_NE(loadStr, nullptr);
121
122 auto retOp = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN);
123 ASSERT_NE(retOp, nullptr);
124 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
125
126 AbckitInst *mainInst = throwInstToCheck(graph, loadStr);
127 ASSERT_NE(mainInst, nullptr);
128 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
129
130 g_implG->iInsertBefore(mainInst, retOp);
131 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
132 }
133
TransformIr3ArgValid(AbckitGraph * graph,AbckitInst * (* throwInstToCheck)(AbckitGraph * graph,AbckitInst * input0,AbckitInst * input1))134 static void TransformIr3ArgValid(AbckitGraph *graph,
135 AbckitInst *(*throwInstToCheck)(AbckitGraph *graph, AbckitInst *input0,
136 AbckitInst *input1))
137 {
138 auto loadStr = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_LOADSTRING);
139 ASSERT_NE(loadStr, nullptr);
140
141 auto retOp = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN);
142 ASSERT_NE(retOp, nullptr);
143 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
144
145 AbckitInst *mainInst = throwInstToCheck(graph, loadStr, loadStr);
146 ASSERT_NE(mainInst, nullptr);
147 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
148
149 g_implG->iInsertBefore(mainInst, retOp);
150 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
151 }
152
TransformIrThrowValid(AbckitGraph * graph)153 void TransformIrThrowValid(AbckitGraph *graph)
154 {
155 TransformIr2ArgValid(graph, g_dynG->iCreateThrow);
156 }
157
TransformIrThrowConstassignmentValid(AbckitGraph * graph)158 void TransformIrThrowConstassignmentValid(AbckitGraph *graph)
159 {
160 TransformIr2ArgValid(graph, g_dynG->iCreateThrowConstassignment);
161 }
162
TransformIrThrowIfnotobjectValid(AbckitGraph * graph)163 void TransformIrThrowIfnotobjectValid(AbckitGraph *graph)
164 {
165 TransformIr2ArgValid(graph, g_dynG->iCreateThrowIfnotobject);
166 }
167
TransformIrThrowNotexistsValid(AbckitGraph * graph)168 void TransformIrThrowNotexistsValid(AbckitGraph *graph)
169 {
170 TransformIr1ArgValid(graph, g_dynG->iCreateThrowNotexists);
171 }
172
TransformIrThrowPatternnoncoercibleValid(AbckitGraph * graph)173 void TransformIrThrowPatternnoncoercibleValid(AbckitGraph *graph)
174 {
175 TransformIr1ArgValid(graph, g_dynG->iCreateThrowPatternnoncoercible);
176 }
177
TransformIrThrowDeletesuperpropertyValid(AbckitGraph * graph)178 void TransformIrThrowDeletesuperpropertyValid(AbckitGraph *graph)
179 {
180 TransformIr1ArgValid(graph, g_dynG->iCreateThrowDeletesuperproperty);
181 }
182
TransformIrThrowUndefinedifholeValid(AbckitGraph * graph)183 void TransformIrThrowUndefinedifholeValid(AbckitGraph *graph)
184 {
185 TransformIr3ArgValid(graph, g_dynG->iCreateThrowUndefinedifhole);
186 }
187
188 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrow, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowValid)189 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowValid)
190 {
191 TransformThrowValid(TransformIrThrowValid, ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW, "Ok\n");
192 }
193
194 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrowNotexists, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowNotexistsValid)195 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowNotexistsValid)
196 {
197 TransformThrowValid(TransformIrThrowNotexistsValid, ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_NOTEXISTS,
198 "TypeError: Throw method is not defined\n");
199 }
200
201 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrowPatternnoncoercible, abc-kind=ArkTS1, category=positive,
202 // extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowPatternnoncoercibleValid)203 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowPatternnoncoercibleValid)
204 {
205 TransformThrowValid(TransformIrThrowPatternnoncoercibleValid,
206 ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_PATTERNNONCOERCIBLE, "TypeError: objectnotcoercible\n");
207 }
208
209 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrowDeletesuperproperty, abc-kind=ArkTS1, category=positive,
210 // extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowDeletesuperpropertyValid)211 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowDeletesuperpropertyValid)
212 {
213 TransformThrowValid(TransformIrThrowDeletesuperpropertyValid,
214 ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_DELETESUPERPROPERTY,
215 "ReferenceError: Can not delete super property\n");
216 }
217
218 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrowConstassignment, abc-kind=ArkTS1, category=positive,
219 // extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowConstassignmentValid)220 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowConstassignmentValid)
221 {
222 TransformThrowValid(TransformIrThrowConstassignmentValid, ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_CONSTASSIGNMENT,
223 "TypeError: Assignment to const variable Ok\n");
224 }
225
226 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrowIfnotobject, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowIfnotobjectValid)227 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowIfnotobjectValid)
228 {
229 TransformThrowValid(TransformIrThrowIfnotobjectValid, ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_IFNOTOBJECT,
230 "TypeError: Inner return result is not object\n");
231 }
232
233 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrowUndefinedifhole, abc-kind=ArkTS1, category=positive,
234 // extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowUndefinedifholeValid)235 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowUndefinedifholeValid)
236 {
237 TransformThrowValid(TransformIrThrowUndefinedifholeValid, ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_UNDEFINEDIFHOLE, "");
238 }
239 /*--------------------------------------------------------------\
240 | Not generalized cases |
241 \--------------------------------------------------------------*/
242
TransformIrThrowIfsupernotcorrectcallValid(AbckitGraph * graph)243 static void TransformIrThrowIfsupernotcorrectcallValid(AbckitGraph *graph)
244 {
245 auto loadStr = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_LOADSTRING);
246 ASSERT_NE(loadStr, nullptr);
247
248 auto retOp = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN);
249 ASSERT_NE(retOp, nullptr);
250 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
251
252 AbckitInst *mainInst = g_dynG->iCreateThrowIfsupernotcorrectcall(graph, loadStr, 0);
253 ASSERT_NE(mainInst, nullptr);
254 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
255
256 g_implG->iInsertBefore(mainInst, retOp);
257 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
258 }
259
TransformIrThrowIfsupernotcorrectcallValidLarge(AbckitGraph * graph)260 static void TransformIrThrowIfsupernotcorrectcallValidLarge(AbckitGraph *graph)
261 {
262 auto loadStr = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_LOADSTRING);
263 ASSERT_NE(loadStr, nullptr);
264
265 auto retOp = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN);
266 ASSERT_NE(retOp, nullptr);
267 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
268
269 AbckitInst *mainInst = g_dynG->iCreateThrowIfsupernotcorrectcall(graph, loadStr, 0x100);
270 ASSERT_NE(mainInst, nullptr);
271 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
272
273 g_implG->iInsertBefore(mainInst, retOp);
274 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
275 }
276
TransformIrThrowUndefinedifholewithnameValid(AbckitGraph * graph,AbckitString * str)277 static void TransformIrThrowUndefinedifholewithnameValid(AbckitGraph *graph, AbckitString *str)
278 {
279 auto loadStr = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_LOADSTRING);
280 ASSERT_NE(loadStr, nullptr);
281
282 auto retOp = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN);
283 ASSERT_NE(retOp, nullptr);
284 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
285
286 AbckitInst *mainInst = g_dynG->iCreateThrowUndefinedifholewithname(graph, loadStr, str);
287 ASSERT_NE(mainInst, nullptr);
288 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
289
290 g_implG->iInsertBefore(mainInst, retOp);
291 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
292 }
293
294 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrowIfsupernotcorrectcall, abc-kind=ArkTS1, category=positive,
295 // extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowIfsupernotcorrectcallValid_imm8)296 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowIfsupernotcorrectcallValid_imm8)
297 {
298 TransformThrowValid(TransformIrThrowIfsupernotcorrectcallValid,
299 ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_IFSUPERNOTCORRECTCALL, "");
300 }
301
302 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrowIfsupernotcorrectcall, abc-kind=ArkTS1, category=positive,
303 // extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowIfsupernotcorrectcallValid_imm16)304 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowIfsupernotcorrectcallValid_imm16)
305 {
306 TransformThrowValid(TransformIrThrowIfsupernotcorrectcallValidLarge,
307 ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_IFSUPERNOTCORRECTCALL, "");
308 }
309
310 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateThrowUndefinedifholewithname, abc-kind=ArkTS1, category=positive,
311 // extension=c
TEST_F(LibAbcKitCreateDynThrow,CreateDynThrowUndefinedifholewithnameValid)312 TEST_F(LibAbcKitCreateDynThrow, CreateDynThrowUndefinedifholewithnameValid)
313 {
314 auto output =
315 helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "ut/isa/isa_dynamic/throw/throw_dynamic.abc", "throw_dynamic");
316 EXPECT_TRUE(helpers::Match(output, ""));
317
318 helpers::TransformMethod(
319 ABCKIT_ABC_DIR "ut/isa/isa_dynamic/throw/throw_dynamic.abc",
320 ABCKIT_ABC_DIR "ut/isa/isa_dynamic/throw/throw_dynamic_modified.abc", "bar",
321 [](AbckitFile *file, AbckitCoreFunction * /*method*/, AbckitGraph *graph) {
322 AbckitString *str = g_implM->createString(file, "GeneratedStr", strlen("GeneratedStr"));
323 TransformIrThrowUndefinedifholewithnameValid(graph, str);
324 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
325 },
326 [](AbckitGraph *graph) {
327 std::vector<helpers::BBSchema<AbckitIsaApiDynamicOpcode>> bbSchemas(
328 CreateBBSchemaForDynThrow(ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_UNDEFINEDIFHOLEWITHNAME));
329 helpers::VerifyGraph(graph, bbSchemas);
330 });
331
332 output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "ut/isa/isa_dynamic/throw/throw_dynamic_modified.abc",
333 "throw_dynamic");
334 EXPECT_TRUE(helpers::Match(output, ""));
335 }
336
337 } // namespace libabckit::test
338 // NOLINTEND(readability-magic-numbers)
339