• 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/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