• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 <fstream>
17 #include "unit_test.h"
18 #include "code_info/code_info_builder.h"
19 #include "codegen.h"
20 #include "panda_runner.h"
21 #include "events/events.h"
22 
23 using panda::panda_file::File;
24 
25 namespace panda::test {
26 class CodegenRunnerTest : public testing::Test {
27 public:
CodegenRunnerTest()28     CodegenRunnerTest()
29         : default_compiler_non_optimizing_(compiler::options.IsCompilerNonOptimizing()),
30           default_compiler_inlining_(compiler::options.IsCompilerInlining()),
31           default_compiler_regalloc_mask_(compiler::options.GetCompilerRegallocRegMask())
32     {
33     }
34 
~CodegenRunnerTest()35     ~CodegenRunnerTest()
36     {
37         compiler::options.SetCompilerNonOptimizing(default_compiler_non_optimizing_);
38         compiler::options.SetCompilerInlining(default_compiler_inlining_);
39         compiler::options.SetCompilerRegallocRegMask(default_compiler_regalloc_mask_);
40     }
SetUp()41     void SetUp()
42     {
43 #ifdef USE_ADDRESS_SANITIZER
44         GTEST_SKIP();
45 #endif
46         if constexpr (RUNTIME_ARCH == Arch::AARCH32) {
47             GTEST_SKIP();
48         }
49     }
50 
51 private:
52     bool default_compiler_non_optimizing_;
53     bool default_compiler_inlining_;
54     uint64_t default_compiler_regalloc_mask_;
55 };
56 
57 static constexpr auto CODEGEN_OBJECT_PARAMS_SOURCE = R"(
58 .record Value{
59     i32 a
60     i64 b
61     i16 c
62 }
63 
64 .function i32 hook() {
65     ldai 1
66     return
67 }
68 
69 .function i32 get_Value_a(Value a0) {
70     ldobj a0, Value.a
71     return
72 }
73 
74 .function i64 get_Value_b(Value a0) {
75     ldobj a0, Value.b
76     return.64
77 }
78 
79 .function i32 get_Value_c(Value a0) {
80     ldobj a0, Value.c
81     return
82 }
83 
84 #16:
85 #                    +0x800
86 #                    +0x200
87 #                     +0x80
88 #                     +0x20
89 #                      +0x8
90 #                      +0x2
91 # Result              0xAAA
92 #32:
93 #                +0x8000000
94 #                +0x2000000
95 #                 +0x800000
96 #                 +0x200000
97 #                  +0x80000
98 #                  +0x20000
99 # Result          0xAAA0000
100 #64:
101 #        +0x800000000000000
102 #        +0x200000000000000
103 #         +0x80000000000000
104 #         +0x20000000000000
105 #          +0x8000000000000
106 #          +0x2000000000000
107 # Result  0xAAA000000000000
108 # Result  0xAAA00000AAA0AAA
109 
110 .function i64 foo(Value a0, Value a1, Value a2, Value a3, Value a4, Value a5) {
111     ldai.64 0
112     sta.64 v17
113 
114     # Some math for spill parameters to stack
115     ldai.64 0x1234567890123456
116     sta.64 v8
117 
118     ldai.64 0x1000000000000000
119     sta.64 v9
120     ldai.64 0x0200000000000000
121     sta.64 v10
122     ldai.64 0x0030000000000000
123     sta.64 v11
124     ldai.64 0x0004000000000000
125     sta.64 v12
126     ldai.64 0x0000500000000000
127     sta.64 v13
128     ldai.64 0x0000060000000000
129     sta.64 v14
130     ldai.64 0x0000007000000000
131     sta.64 v15
132     ldai.64 0x0000000800000000
133     sta.64 v16
134     ldai.64 0x0000000090000000
135     sta.64 v18
136     ldai.64 0x0000000000100000
137     sta.64 v19
138     ldai.64 0x0000000000020000
139     sta.64 v20
140     ldai.64 0x0000000000003000
141     sta.64 v21
142     ldai.64 0x0000000000000400
143     sta.64 v22
144     ldai.64 0x0000000000000050
145     sta.64 v23
146     ldai.64 0x0000000000000006
147     sta.64 v24
148 
149     lda.64 v8
150     sub2.64 v9
151     sub2.64 v10
152     sub2.64 v11
153     sub2.64 v12
154     sub2.64 v13
155     sub2.64 v14
156     sub2.64 v15
157     sub2.64 v16
158     sub2.64 v18
159     sub2.64 v19
160     sub2.64 v20
161     sub2.64 v21
162     sub2.64 v22
163     sub2.64 v23
164     sub2.64 v24
165 
166     jeq v17, success_label
167     add2.64 v8
168     add2.64 v9
169     add2.64 v10
170     add2.64 v11
171     add2.64 v12
172     add2.64 v13
173     add2.64 v14
174     add2.64 v15
175     add2.64 v16
176 
177     return.64
178 
179 success_label:
180 
181     ## here params lay on stack - need check somehow (emit in cg)
182     ldai 0
183     sta v0
184     call.range get_Value_c, a2
185     # 0x800
186     add2 v0
187     sta v0
188     call.range get_Value_a, a5
189     # 0x200000
190     add2 v0
191     sta v0
192     call.range get_Value_c, a4
193     # 0x800000
194     add2 v0
195     sta v0
196     call.range get_Value_a, a1
197     # 0x20000000
198     add2 v0
199     sta v0
200     call.range get_Value_c, a0
201     # 0x8000
202     add2 v0
203     sta v0
204     call.range get_Value_a, a3
205     # 0x2000000
206     add2 v0
207     sta v0
208     call.range get_Value_c, a5
209     # 0x20
210     add2 v0
211     sta v0
212     call.range get_Value_a, a2
213     # 0x8000000
214     add2 v0
215     sta v0
216     call.range get_Value_c, a1
217     # 0x2000
218     add2 v0
219     sta v0
220     call.range get_Value_a, a4
221     # 0x80
222     add2 v0
223     sta v0
224     call.range get_Value_c, a3
225     # 0x200
226     add2 v0
227     sta v0
228     call.range get_Value_a, a0
229     # 0x80000000
230     add2 v0
231     i32toi64
232     sta.64 v1
233 
234     call.range get_Value_b, a5
235     add2.64 v1
236     sta.64 v1
237     call.range get_Value_b, a0
238     add2.64 v1
239     sta.64 v1
240     call.range get_Value_b, a4
241     add2.64 v1
242     sta.64 v1
243     call.range get_Value_b, a1
244     add2.64 v1
245     sta.64 v1
246     call.range get_Value_b, a3
247     add2.64 v1
248     sta.64 v1
249     call.range get_Value_b, a2
250     add2.64 v1
251 
252     return.64
253 }
254 
255 .function i64 main() {
256     newobj v0, Value
257     newobj v1, Value
258     newobj v2, Value
259     newobj v3, Value
260     newobj v4, Value
261     newobj v5, Value
262     ## c - i16
263     ldai 0x800
264     stobj v0, Value.c
265     ldai 0x200
266     stobj v1, Value.c
267     ldai 0x80
268     stobj v2, Value.c
269     ldai 0x20
270     stobj v3, Value.c
271     ldai 0x8
272     stobj v4, Value.c
273     ldai 0x2
274     stobj v5, Value.c
275     ## a - i32
276     ldai 0x8000000
277     stobj v0, Value.a
278     ldai 0x2000000
279     stobj v1, Value.a
280     ldai 0x800000
281     stobj v2, Value.a
282     ldai 0x200000
283     stobj v3, Value.a
284     ldai 0x80000
285     stobj v4, Value.a
286     ldai 0x20000
287     stobj v5, Value.a
288     ## b - i64
289     ldai.64 0x800000000000000
290     stobj v0, Value.b
291     ldai.64 0x200000000000000
292     stobj v1, Value.b
293     ldai.64 0x80000000000000
294     stobj v2, Value.b
295     ldai.64 0x20000000000000
296     stobj v3, Value.b
297     ldai.64 0x8000000000000
298     stobj v4, Value.b
299     ldai.64 0x2000000000000
300     stobj v5, Value.b
301 
302     ldai.64 0xaaa00000aaa0aaa
303     sta.64 v7
304     # Corrupt stack for call.foo
305     call.short hook
306 
307     call.range  foo, v0
308 
309     jeq v7, success_label
310     return.64
311 
312 success_label:
313     ldai 123
314     return.64
315 }
316 )";
317 
318 constexpr uint64_t CORUPT_SIZE = 0xFFF;
319 // Allocated on stack check
320 [[maybe_unused]] constexpr uint64_t HOOK_OFFSET = 0x10000;
321 constexpr uint64_t CORUPT_DATA = 0xABCDEF0123456789;
322 
Callback(uintptr_t lr,uintptr_t fp)323 NO_OPTIMIZE int Callback([[maybe_unused]] uintptr_t lr, [[maybe_unused]] uintptr_t fp)
324 {
325     uint64_t tmp[CORUPT_SIZE];
326     [[maybe_unused]] auto delta = bit_cast<uintptr_t>(fp) - bit_cast<uintptr_t>(&tmp);
327     ASSERT(delta < HOOK_OFFSET);
328     delta = bit_cast<uintptr_t>(&tmp[CORUPT_SIZE]) - bit_cast<uintptr_t>(&tmp);
329     ASSERT(delta == CORUPT_SIZE * sizeof(uint64_t));
330     for (uintptr_t i = 0; i < CORUPT_SIZE; ++i) {
331         tmp[i] = CORUPT_DATA;
332     }
333     return 0;
334 }
335 
TEST_F(CodegenRunnerTest,ObjectParams)336 TEST_F(CodegenRunnerTest, ObjectParams)
337 {
338 // In Release and FastVerify modes compiler can omit frame pointer, thus, PandaRunner can't work properly in these
339 // modes.
340 #if defined(NDEBUG) || defined(PANDA_FAST_VERIFY)
341     GTEST_SKIP();
342 #endif
343     // hi-part is 1 - to do not rewrite fp, lr in arm64
344     uint64_t reg_masks[] = {
345         0, 0xFFFFFFFFFFFFFFF0, 0xFFFFFFFFF0FFF000, 0xFFFFFFFFFFFFDFD6,
346         // TODO (igorban): enable next variants:
347         // 0xFFFFFFFFFF000FFF,
348         // 0xFFFFFFFFF000000F,
349         // 0xFFFFFFFFF000202A,
350         // 0xFFFFFFFFFFFFF00F,
351     };
352 
353     for (auto &hook_on : {false, true}) {
354         for (auto &mask : reg_masks) {
355             panda::test::PandaRunner runner;
356             runner.GetCompilerOptions().SetCompilerNonOptimizing(true);
357             runner.GetCompilerOptions().SetCompilerInlining(false);
358             runner.GetRuntimeOptions().SetCompilerHotnessThreshold(0);
359             runner.GetRuntimeOptions().SetShouldLoadBootPandaFiles(true);
360             runner.GetRuntimeOptions().SetShouldInitializeIntrinsics(false);
361             runner.GetCompilerOptions().SetCompilerRegallocRegMask(mask);
362 
363             if (hook_on) {
364                 runner.SetHook(Callback);
365             }
366 
367             runner.Run(CODEGEN_OBJECT_PARAMS_SOURCE, 123);
368         }
369     }
370 }
371 
372 }  // namespace panda::test
373