• 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 <string>
17 #include <vector>
18 
19 #include "assembler/assembly-program.h"
20 #include "assembler/assembly-emitter.h"
21 #include "common.h"
22 #include "compiler/optimizer/ir/datatype.h"
23 #include "runtime_adapter.h"
24 #include "utils/utf.h"
25 
26 namespace panda::bytecodeopt::test {
27 
ParseAndEmit(const std::string & source)28 std::unique_ptr<const panda_file::File> ParseAndEmit(const std::string &source)
29 {
30     panda::pandasm::Parser parser;
31     auto res = parser.Parse(source);
32     if (parser.ShowError().err != pandasm::Error::ErrorType::ERR_NONE) {
33         std::cerr << "Parse failed: " << parser.ShowError().message << std::endl
34                   << parser.ShowError().whole_line << std::endl;
35         ADD_FAILURE();
36     }
37     auto &program = res.Value();
38     return pandasm::AsmEmitter::Emit(program);
39 }
40 
41 struct Pointers {
42     std::vector<RuntimeInterface::MethodPtr> method;
43     std::vector<RuntimeInterface::ClassPtr> klass;
44     std::vector<RuntimeInterface::FieldPtr> field;
45 };
46 
GetPointers(const panda_file::File * arkf)47 Pointers GetPointers(const panda_file::File *arkf)
48 {
49     Pointers pointers;
50 
51     for (uint32_t id : arkf->GetClasses()) {
52         panda_file::File::EntityId record_id {id};
53 
54         if (arkf->IsExternal(record_id)) {
55             continue;
56         }
57 
58         panda_file::ClassDataAccessor cda {*arkf, record_id};
59         auto class_id = cda.GetClassId().GetOffset();
60         auto class_ptr = reinterpret_cast<compiler::RuntimeInterface::ClassPtr>(class_id);
61         pointers.klass.push_back(class_ptr);
62 
63         cda.EnumerateFields([&pointers](panda_file::FieldDataAccessor &fda) {
64             auto field_ptr = reinterpret_cast<compiler::RuntimeInterface::FieldPtr>(fda.GetFieldId().GetOffset());
65             pointers.field.push_back(field_ptr);
66         });
67 
68         cda.EnumerateMethods([&pointers](panda_file::MethodDataAccessor &mda) {
69             auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(mda.GetMethodId().GetOffset());
70             pointers.method.push_back(method_ptr);
71         });
72     }
73 
74     return pointers;
75 }
76 
TEST(RuntimeAdapter,Common)77 TEST(RuntimeAdapter, Common)
78 {
79     auto source = std::string(R"(
80         .function u1 main() {
81             ldai 1
82             return
83         }
84         )");
85     std::unique_ptr<const panda_file::File> arkf = ParseAndEmit(source);
86     auto pointers = GetPointers(arkf.get());
87 
88     ASSERT_EQ(pointers.method.size(), 1);
89     ASSERT_EQ(pointers.klass.size(), 1);
90     ASSERT_EQ(pointers.field.size(), 0);
91 
92     BytecodeOptimizerRuntimeAdapter adapter(*arkf.get());
93     auto main = pointers.method[0];
94     auto global = pointers.klass[0];
95 
96     EXPECT_FALSE(adapter.IsMethodIntrinsic(main));
97     EXPECT_NE(adapter.GetBinaryFileForMethod(main), nullptr);
98     EXPECT_EQ(adapter.GetMethodById(main, 0), nullptr);
99     EXPECT_NE(adapter.GetMethodId(main), 0);
100     EXPECT_EQ(adapter.GetMethodTotalArgumentType(main, 0), compiler::DataType::Type::ANY);
101     EXPECT_EQ(adapter.GetMethodReturnType(pointers.method[0]), compiler::DataType::Type::BOOL);
102     EXPECT_EQ(adapter.GetMethodRegistersCount(main), 0);
103     EXPECT_NE(adapter.GetMethodCode(main), nullptr);
104     EXPECT_NE(adapter.GetMethodCodeSize(main), 0);
105     EXPECT_TRUE(adapter.IsMethodStatic(main));
106     EXPECT_FALSE(adapter.HasNativeException(main));
107     EXPECT_EQ(adapter.GetClassNameFromMethod(main), std::string("L_GLOBAL;"));
108     EXPECT_EQ(adapter.GetMethodName(main), std::string("main"));
109     EXPECT_EQ(adapter.GetMethodFullName(main, false), std::string("L_GLOBAL;::main"));
110     EXPECT_EQ(adapter.GetBytecodeString(main, 0), std::string("ldai 1"));
111 
112     EXPECT_EQ(adapter.GetClassName(global), std::string("L_GLOBAL;"));
113     EXPECT_EQ(adapter.GetClass(main), global);
114 }
115 
TEST(RuntimeAdapter,Klass)116 TEST(RuntimeAdapter, Klass)
117 {
118     auto source = std::string(R"(
119         .record R {
120             i32 field
121         }
122 
123         .function void R.ctor(R a0) <ctor> {
124             return.void
125         }
126 
127         .function void main() {}
128         )");
129     std::unique_ptr<const panda_file::File> arkf = ParseAndEmit(source);
130     auto pointers = GetPointers(arkf.get());
131 
132     ASSERT_EQ(pointers.method.size(), 2);
133     ASSERT_EQ(pointers.klass.size(), 2);
134     ASSERT_EQ(pointers.field.size(), 1);
135 
136     BytecodeOptimizerRuntimeAdapter adapter(*arkf.get());
137     auto klass = pointers.klass[0];
138     auto ctor = pointers.method[0];
139     auto main = pointers.method[1];
140 
141     EXPECT_EQ(adapter.GetMethodName(main), std::string("main"));
142     EXPECT_EQ(adapter.GetMethodName(ctor), std::string(".ctor"));
143 
144     auto class_id = reinterpret_cast<uint64_t>(klass);
145     EXPECT_FALSE(adapter.IsMethodExternal(main, ctor));
146     EXPECT_FALSE(adapter.IsConstructor(main, class_id));
147     EXPECT_EQ(adapter.GetMethodTotalArgumentType(ctor, 0), compiler::DataType::Type::REFERENCE);
148     EXPECT_EQ(adapter.GetMethodTotalArgumentType(ctor, 1), compiler::DataType::Type::ANY);
149     EXPECT_EQ(adapter.IsArrayClass(ctor, class_id), false);
150 }
151 
TEST(RuntimeAdapter,Methods)152 TEST(RuntimeAdapter, Methods)
153 {
154     auto source = std::string(R"(
155         .record System <external>
156         .function void System.exit(i32 a0) <external>
157 
158         .function u64 func_ret_u64(u64 a0) {
159             return
160         }
161 
162         .function i16 func_ret_i16(i16 a0) {
163             return
164         }
165 
166         .function u1 main(u32 a0, u16 a1, f32 a2, f64 a3) {
167             movi v0, 0
168             call System.exit, v0
169             ldai 1
170             return
171         }
172         )");
173     std::unique_ptr<const panda_file::File> arkf = ParseAndEmit(source);
174     auto pointers = GetPointers(arkf.get());
175 
176     ASSERT_EQ(pointers.method.size(), 3);
177     ASSERT_EQ(pointers.klass.size(), 1);
178     ASSERT_EQ(pointers.field.size(), 0);
179 
180     BytecodeOptimizerRuntimeAdapter adapter(*arkf.get());
181     auto main = pointers.method[0];
182     auto func_ret_i16 = pointers.method[1];
183     auto func_ret_u64 = pointers.method[2];
184 
185     EXPECT_EQ(adapter.GetMethodName(func_ret_u64), std::string("func_ret_u64"));
186     EXPECT_EQ(adapter.GetMethodName(func_ret_i16), std::string("func_ret_i16"));
187     EXPECT_EQ(adapter.GetMethodName(main), std::string("main"));
188 
189     EXPECT_EQ(adapter.GetMethodReturnType(func_ret_i16), compiler::DataType::Type::INT16);
190     EXPECT_EQ(adapter.GetMethodReturnType(func_ret_u64), compiler::DataType::Type::UINT64);
191 
192     const auto method_id = adapter.ResolveMethodIndex(main, 0);
193     EXPECT_NE(method_id, 0);
194     EXPECT_NE(adapter.GetClassIdForMethod(main, method_id), 0);
195     EXPECT_EQ(adapter.GetMethodArgumentType(main, method_id, 0), compiler::DataType::Type::INT32);
196 
197     EXPECT_EQ(adapter.GetMethodTotalArgumentType(main, 0), compiler::DataType::Type::UINT32);
198     EXPECT_EQ(adapter.GetMethodTotalArgumentType(main, 1), compiler::DataType::Type::UINT16);
199     EXPECT_EQ(adapter.GetMethodTotalArgumentType(main, 2), compiler::DataType::Type::FLOAT32);
200     EXPECT_EQ(adapter.GetMethodTotalArgumentType(main, 3), compiler::DataType::Type::FLOAT64);
201 }
202 
TEST(RuntimeAdapter,Fields)203 TEST(RuntimeAdapter, Fields)
204 {
205     auto source = std::string(R"(
206         .record R {
207             i32 field
208         }
209 
210         .record Record {
211             i64 v_i64             <static>
212         }
213 
214         .function void store_to_static(i64 a0){
215             lda.64 a0
216             ststatic.64 Record.v_i64
217             return.void
218         }
219         )");
220     std::unique_ptr<const panda_file::File> arkf = ParseAndEmit(source);
221     auto pointers = GetPointers(arkf.get());
222 
223     ASSERT_EQ(pointers.method.size(), 1);
224     ASSERT_EQ(pointers.klass.size(), 3);
225     ASSERT_EQ(pointers.field.size(), 2);
226 
227     BytecodeOptimizerRuntimeAdapter adapter(*arkf.get());
228     auto store_to_static = pointers.method[0];
229     auto record_with_static_field = pointers.klass[1];
230     auto field = pointers.field[0];
231 
232     EXPECT_EQ(adapter.GetMethodName(store_to_static), std::string("store_to_static"));
233 
234     EXPECT_EQ(adapter.GetFieldName(field), std::string("field"));
235     EXPECT_EQ(adapter.GetFieldType(field), compiler::DataType::Type::INT32);
236     const auto field_id = adapter.ResolveFieldIndex(store_to_static, 0);
237     EXPECT_NE(field_id, 0);
238     EXPECT_EQ(adapter.GetClassIdForField(store_to_static, field_id),
239               reinterpret_cast<uint64_t>(record_with_static_field));
240     uint32_t immut_var = 0;
241     const auto field_ptr = adapter.ResolveField(store_to_static, field_id, false, &immut_var);
242     EXPECT_EQ(immut_var, 0);
243     EXPECT_EQ(adapter.GetClassForField(field_ptr), record_with_static_field);
244     EXPECT_EQ(adapter.GetFieldTypeById(store_to_static, field_id), compiler::DataType::Type::INT64);
245     EXPECT_EQ(adapter.IsFieldVolatile(field_ptr), false);
246 }
247 
248 }  // namespace panda::bytecodeopt::test
249