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 "annotation_data_accessor.h"
17 #include "class_data_accessor-inl.h"
18 #include "code_data_accessor-inl.h"
19 #include "debug_data_accessor-inl.h"
20 #include "debug_info_extractor.h"
21 #include "field_data_accessor-inl.h"
22 #include "file.h"
23 #include "file_item_container.h"
24 #include "file_writer.h"
25 #include "helpers.h"
26 #include "method_data_accessor-inl.h"
27 #include "method_handle_data_accessor.h"
28 #include "modifiers.h"
29 #include "os/file.h"
30 #include "proto_data_accessor-inl.h"
31 #include "pgo.h"
32 #include "value.h"
33
34 #include "zlib.h"
35
36 #include <cstddef>
37
38 #include <memory>
39 #include <vector>
40
41 #include <gtest/gtest.h>
42 #include <gmock/gmock.h>
43
44 namespace panda::panda_file::test {
45 constexpr uint8_t ISA_VERSION_FIRST_NUMBER = panda::panda_file::version[0];
46 constexpr uint8_t ISA_VERSION_SECOND_NUMBER = panda::panda_file::version[1];
47 constexpr uint8_t ISA_VERSION_THIRD_NUMBER = panda::panda_file::version[2]; // 2: the third number of ISA version
48 constexpr uint8_t ISA_VERSION_FOURTH_NUMBER = panda::panda_file::version[3]; // 3: the fourth number of ISA version
49
50 HWTEST(ItemContainer, DeduplicationTest, testing::ext::TestSize.Level0)
51 {
52 ItemContainer container;
53
54 StringItem *string_item = container.GetOrCreateStringItem("1");
55 EXPECT_EQ(string_item, container.GetOrCreateStringItem("1"));
56
57 ClassItem *class_item = container.GetOrCreateClassItem("1");
58 EXPECT_EQ(class_item, container.GetOrCreateClassItem("1"));
59
60 ValueItem *int_item = container.GetOrCreateIntegerValueItem(1);
61 EXPECT_EQ(int_item, container.GetOrCreateIntegerValueItem(1));
62
63 ValueItem *long_item = container.GetOrCreateLongValueItem(1);
64 EXPECT_EQ(long_item, container.GetOrCreateLongValueItem(1));
65 EXPECT_NE(long_item, int_item);
66
67 ValueItem *float_item = container.GetOrCreateFloatValueItem(1.0);
68 EXPECT_EQ(float_item, container.GetOrCreateFloatValueItem(1.0));
69 EXPECT_NE(float_item, int_item);
70 EXPECT_NE(float_item, long_item);
71
72 ValueItem *double_item = container.GetOrCreateDoubleValueItem(1.0);
73 EXPECT_EQ(double_item, container.GetOrCreateDoubleValueItem(1.0));
74 EXPECT_NE(double_item, int_item);
75 EXPECT_NE(double_item, long_item);
76 EXPECT_NE(double_item, float_item);
77 }
78
79 HWTEST(ItemContainer, TestFileOpen, testing::ext::TestSize.Level0)
80 {
81 using panda::os::file::Mode;
82 using panda::os::file::Open;
83
84 // Write panda file to disk
85 ItemContainer container;
86
87 const std::string file_name = "test_file_open.panda";
88 auto writer = FileWriter(file_name);
89
90 ASSERT_TRUE(container.Write(&writer));
91
92 // Read panda file from disk
93 EXPECT_NE(File::Open(file_name), nullptr);
94 }
95
96 HWTEST(ItemContainer, TestFileFormatVersionTooOld, testing::ext::TestSize.Level0)
97 {
98 const std::string file_name = "test_file_format_version_too_old.abc";
99 {
100 ItemContainer container;
101 auto writer = FileWriter(file_name);
102
103 File::Header header;
104 errno_t res = memset_s(&header, sizeof(header), 0, sizeof(header));
105 if (res != EOK) {
106 UNREACHABLE();
107 }
108 header.magic = File::MAGIC;
109
110 auto old = std::array<uint8_t, File::VERSION_SIZE>(minVersion);
111 --old[3];
112
113 header.version = old;
114 header.file_size = sizeof(File::Header);
115
116 for (uint8_t b : Span<uint8_t>(reinterpret_cast<uint8_t *>(&header), sizeof(header))) {
117 writer.WriteByte(b);
118 }
119 EXPECT_TRUE(writer.FinishWrite());
120 }
121
122 EXPECT_EQ(File::Open(file_name), nullptr);
123 }
124
125 HWTEST(ItemContainer, TestRewriteChecksum, testing::ext::TestSize.Level0)
126 {
127 const std::string file_name = "test_rewrite_checksum.abc";
128 {
129 ItemContainer container;
130 auto writer = FileWriter(file_name);
131 File::Header header;
132 errno_t res = memset_s(&header, sizeof(header), 0, sizeof(header));
133 EXPECT_EQ(res, EOK);
134 header.magic = File::MAGIC;
135 header.version = std::array<uint8_t, File::VERSION_SIZE>(minVersion);
136 header.file_size = sizeof(File::Header);
137 EXPECT_EQ(header.checksum, 0u);
138 writer.CountChecksum(true);
139 for (uint8_t b : Span<uint8_t>(reinterpret_cast<uint8_t *>(&header), sizeof(header))) {
140 writer.WriteByte(b);
141 }
142 EXPECT_NE(writer.GetChecksum(), 0u);
143 writer.CountChecksum(false);
144 size_t offset = static_cast<size_t>(reinterpret_cast<uint8_t *>(&(header.checksum)) -
145 reinterpret_cast<uint8_t *>(&header));
146 EXPECT_TRUE(writer.RewriteChecksum(offset));
147 EXPECT_TRUE(writer.FinishWrite());
148 }
149 const auto &file = File::Open(file_name);
150 EXPECT_NE(file, nullptr);
151 EXPECT_NE(file->GetHeader()->checksum, 0u);
152 }
153
154 HWTEST(ItemContainer, TestReserveBufferCapacity, testing::ext::TestSize.Level0)
155 {
156 const std::string file_name = "test_reserve_buffer_capacity.abc";
157 {
158 auto writer = FileWriter(file_name);
159 static constexpr size_t CAPACITY = 2000u;
160 EXPECT_LT(writer.GetBuffer().capacity(), CAPACITY);
161 writer.ReserveBufferCapacity(CAPACITY);
162 EXPECT_GE(writer.GetBuffer().capacity(), CAPACITY);
163 }
164 }
165
166 HWTEST(ItemContainer, TestFileFormatVersionTooNew, testing::ext::TestSize.Level0)
167 {
168 const std::string file_name = "test_file_format_version_too_new.abc";
169 {
170 ItemContainer container;
171 auto writer = FileWriter(file_name);
172
173 File::Header header;
174 errno_t res = memset_s(&header, sizeof(header), 0, sizeof(header));
175 if (res != EOK) {
176 UNREACHABLE();
177 }
178 header.magic = File::MAGIC;
179 if (ISA_VERSION_FIRST_NUMBER + 1 < 256 && ISA_VERSION_SECOND_NUMBER + 1 < 256) {
180 header.version = {ISA_VERSION_FIRST_NUMBER + 1, ISA_VERSION_SECOND_NUMBER + 1,
181 ISA_VERSION_THIRD_NUMBER, ISA_VERSION_FOURTH_NUMBER};
182 } else {
183 header.version = {ISA_VERSION_FIRST_NUMBER, ISA_VERSION_SECOND_NUMBER,
184 ISA_VERSION_THIRD_NUMBER, ISA_VERSION_FOURTH_NUMBER};
185 }
186 header.file_size = sizeof(File::Header);
187
188 for (uint8_t b : Span<uint8_t>(reinterpret_cast<uint8_t *>(&header), sizeof(header))) {
189 writer.WriteByte(b);
190 }
191 EXPECT_TRUE(writer.FinishWrite());
192 }
193
194 EXPECT_EQ(File::Open(file_name), nullptr);
195 }
196
197 HWTEST(ItemContainer, TestFileFormatVersionValid, testing::ext::TestSize.Level0)
198 {
199 const std::string file_name = "test_file_format_version_valid.abc";
200 {
201 ItemContainer container;
202 auto writer = FileWriter(file_name);
203
204 File::Header header;
205 errno_t res = memset_s(&header, sizeof(header), 0, sizeof(header));
206 if (res != EOK) {
207 UNREACHABLE();
208 }
209 header.magic = File::MAGIC;
210 header.version = {0, 0, 0, 2};
211 header.file_size = sizeof(File::Header);
212
213 for (uint8_t b : Span<uint8_t>(reinterpret_cast<uint8_t *>(&header), sizeof(header))) {
214 writer.WriteByte(b);
215 }
216 EXPECT_TRUE(writer.FinishWrite());
217 }
218
219 EXPECT_NE(File::Open(file_name), nullptr);
220 }
221
GetPandaFile(std::vector<uint8_t> & data)222 static std::unique_ptr<const File> GetPandaFile(std::vector<uint8_t> &data)
223 {
224 os::mem::ConstBytePtr ptr(reinterpret_cast<std::byte *>(data.data()), data.size(),
225 [](std::byte *, size_t) noexcept {});
226 return File::OpenFromMemory(std::move(ptr));
227 }
228
229 HWTEST(ItemContainer, TestClasses, testing::ext::TestSize.Level0)
230 {
231 // Write panda file to memory
232
233 ItemContainer container;
234
235 ClassItem *empty_class_item = container.GetOrCreateClassItem("Foo");
236
237 ClassItem *class_item = container.GetOrCreateClassItem("Bar");
238 class_item->SetAccessFlags(ACC_PUBLIC);
239 class_item->SetSuperClass(empty_class_item);
240
241 // Add interface
242
243 ClassItem *iface_item = container.GetOrCreateClassItem("Iface");
244 iface_item->SetAccessFlags(ACC_PUBLIC);
245
246 class_item->AddInterface(iface_item);
247
248 // Add method
249
250 StringItem *method_name = container.GetOrCreateStringItem("foo");
251
252 PrimitiveTypeItem *ret_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
253 std::vector<MethodParamItem> params;
254 ProtoItem *proto_item = container.GetOrCreateProtoItem(ret_type, params);
255
256 MethodItem *method_item = class_item->AddMethod(method_name, proto_item, ACC_PUBLIC | ACC_STATIC, params);
257
258 // Add field
259
260 StringItem *field_name = container.GetOrCreateStringItem("field");
261 PrimitiveTypeItem *field_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32);
262
263 FieldItem *field_item = class_item->AddField(field_name, field_type, ACC_PUBLIC);
264
265 // Add runtime annotation
266
267 std::vector<AnnotationItem::Elem> runtime_elems;
268 std::vector<AnnotationItem::Tag> runtime_tags;
269 AnnotationItem *runtime_annotation_item =
270 container.CreateItem<AnnotationItem>(class_item, runtime_elems, runtime_tags);
271
272 class_item->AddRuntimeAnnotation(runtime_annotation_item);
273
274 // Add annotation
275
276 std::vector<AnnotationItem::Elem> elems;
277 std::vector<AnnotationItem::Tag> tags;
278 AnnotationItem *annotation_item = container.CreateItem<AnnotationItem>(class_item, elems, tags);
279
280 class_item->AddAnnotation(annotation_item);
281
282 // Add source file
283
284 StringItem *source_file = container.GetOrCreateStringItem("source_file");
285
286 class_item->SetSourceFile(source_file);
287
288 MemoryWriter mem_writer;
289
290 ASSERT_TRUE(container.Write(&mem_writer));
291
292 // Read panda file from memory
293
294 auto data = mem_writer.GetData();
295 auto panda_file = GetPandaFile(data);
296
297 ASSERT_NE(panda_file, nullptr);
298
299 EXPECT_THAT(panda_file->GetHeader()->version, ::testing::ElementsAre(ISA_VERSION_FIRST_NUMBER,
300 ISA_VERSION_SECOND_NUMBER, ISA_VERSION_THIRD_NUMBER, ISA_VERSION_FOURTH_NUMBER));
301 EXPECT_EQ(panda_file->GetHeader()->file_size, mem_writer.GetData().size());
302 EXPECT_EQ(panda_file->GetHeader()->foreign_off, 0U);
303 EXPECT_EQ(panda_file->GetHeader()->foreign_size, 0U);
304 EXPECT_EQ(panda_file->GetHeader()->num_classes, 3U);
305 EXPECT_EQ(panda_file->GetHeader()->class_idx_off, sizeof(File::Header));
306
307 const uint32_t *class_index =
308 reinterpret_cast<const uint32_t *>(panda_file->GetBase() + panda_file->GetHeader()->class_idx_off);
309 EXPECT_EQ(class_index[0], class_item->GetOffset());
310 EXPECT_EQ(class_index[1], empty_class_item->GetOffset());
311
312 std::vector<uint8_t> class_name {'B', 'a', 'r', '\0'};
313 auto class_id = panda_file->GetClassId(class_name.data());
314 EXPECT_EQ(class_id.GetOffset(), class_item->GetOffset());
315
316 ClassDataAccessor class_data_accessor(*panda_file, class_id);
317 EXPECT_EQ(class_data_accessor.GetSuperClassId().GetOffset(), empty_class_item->GetOffset());
318 EXPECT_EQ(class_data_accessor.GetAccessFlags(), ACC_PUBLIC);
319 EXPECT_EQ(class_data_accessor.GetFieldsNumber(), 1U);
320 EXPECT_EQ(class_data_accessor.GetMethodsNumber(), 1U);
321 EXPECT_EQ(class_data_accessor.GetIfacesNumber(), 1U);
322 EXPECT_TRUE(class_data_accessor.GetSourceFileId().has_value());
323 EXPECT_EQ(class_data_accessor.GetSourceFileId().value().GetOffset(), source_file->GetOffset());
324 EXPECT_EQ(class_data_accessor.GetSize(), class_item->GetSize());
325
__anona8d9bbf90202(File::EntityId id) 326 class_data_accessor.EnumerateInterfaces([&](File::EntityId id) {
327 EXPECT_EQ(id.GetOffset(), iface_item->GetOffset());
328
329 ClassDataAccessor iface_class_data_accessor(*panda_file, id);
330 EXPECT_EQ(iface_class_data_accessor.GetSuperClassId().GetOffset(), 0U);
331 EXPECT_EQ(iface_class_data_accessor.GetAccessFlags(), ACC_PUBLIC);
332 EXPECT_EQ(iface_class_data_accessor.GetFieldsNumber(), 0U);
333 EXPECT_EQ(iface_class_data_accessor.GetMethodsNumber(), 0U);
334 EXPECT_EQ(iface_class_data_accessor.GetIfacesNumber(), 0U);
335 EXPECT_FALSE(iface_class_data_accessor.GetSourceFileId().has_value());
336 EXPECT_EQ(iface_class_data_accessor.GetSize(), iface_item->GetSize());
337 });
338
__anona8d9bbf90302(File::EntityId id) 339 class_data_accessor.EnumerateRuntimeAnnotations([&](File::EntityId id) {
340 EXPECT_EQ(id.GetOffset(), runtime_annotation_item->GetOffset());
341
342 AnnotationDataAccessor data_accessor(*panda_file, id);
343 EXPECT_EQ(data_accessor.GetAnnotationId().GetOffset(), runtime_annotation_item->GetOffset());
344 EXPECT_EQ(data_accessor.GetClassId().GetOffset(), class_item->GetOffset());
345 EXPECT_EQ(data_accessor.GetCount(), 0U);
346 });
347
348 // Annotation is the same as the runtime one, so we deduplicate it
349 EXPECT_FALSE(annotation_item->NeedsEmit());
350 annotation_item = runtime_annotation_item;
351
__anona8d9bbf90402(File::EntityId id) 352 class_data_accessor.EnumerateAnnotations([&](File::EntityId id) {
353 EXPECT_EQ(id.GetOffset(), annotation_item->GetOffset());
354
355 AnnotationDataAccessor data_accessor(*panda_file, id);
356 EXPECT_EQ(data_accessor.GetAnnotationId().GetOffset(), annotation_item->GetOffset());
357 EXPECT_EQ(data_accessor.GetClassId().GetOffset(), class_item->GetOffset());
358 EXPECT_EQ(data_accessor.GetCount(), 0U);
359 });
360
__anona8d9bbf90502(FieldDataAccessor &data_accessor) 361 class_data_accessor.EnumerateFields([&](FieldDataAccessor &data_accessor) {
362 EXPECT_EQ(data_accessor.GetFieldId().GetOffset(), field_item->GetOffset());
363 EXPECT_EQ(data_accessor.GetClassId().GetOffset(), class_item->GetOffset());
364 EXPECT_EQ(data_accessor.GetNameId().GetOffset(), field_name->GetOffset());
365 EXPECT_EQ(data_accessor.GetType(), Type(Type::TypeId::I32).GetFieldEncoding());
366 EXPECT_EQ(data_accessor.GetAccessFlags(), ACC_PUBLIC);
367 EXPECT_FALSE(data_accessor.GetValue<int32_t>().has_value());
368 EXPECT_EQ(data_accessor.GetSize(), field_item->GetSize());
369
370 data_accessor.EnumerateRuntimeAnnotations([](File::EntityId) { EXPECT_TRUE(false); });
371 data_accessor.EnumerateAnnotations([](File::EntityId) { EXPECT_TRUE(false); });
372 });
373
__anona8d9bbf90802(MethodDataAccessor &data_accessor) 374 class_data_accessor.EnumerateMethods([&](MethodDataAccessor &data_accessor) {
375 EXPECT_FALSE(data_accessor.IsExternal());
376 EXPECT_EQ(data_accessor.GetMethodId().GetOffset(), method_item->GetOffset());
377 EXPECT_EQ(data_accessor.GetClassId().GetOffset(), class_item->GetOffset());
378 EXPECT_EQ(data_accessor.GetNameId().GetOffset(), method_name->GetOffset());
379 EXPECT_EQ(data_accessor.GetProtoId().GetOffset(), proto_item->GetOffset());
380 EXPECT_EQ(data_accessor.GetAccessFlags(), ACC_PUBLIC | ACC_STATIC);
381 EXPECT_FALSE(data_accessor.GetCodeId().has_value());
382 EXPECT_EQ(data_accessor.GetSize(), method_item->GetSize());
383 EXPECT_FALSE(data_accessor.GetRuntimeParamAnnotationId().has_value());
384 EXPECT_FALSE(data_accessor.GetParamAnnotationId().has_value());
385 EXPECT_FALSE(data_accessor.GetDebugInfoId().has_value());
386
387 data_accessor.EnumerateRuntimeAnnotations([](File::EntityId) { EXPECT_TRUE(false); });
388 data_accessor.EnumerateAnnotations([](File::EntityId) { EXPECT_TRUE(false); });
389 });
390
391 ClassDataAccessor empty_class_data_accessor(*panda_file, File::EntityId(empty_class_item->GetOffset()));
392 EXPECT_EQ(empty_class_data_accessor.GetSuperClassId().GetOffset(), 0U);
393 EXPECT_EQ(empty_class_data_accessor.GetAccessFlags(), 0U);
394 EXPECT_EQ(empty_class_data_accessor.GetFieldsNumber(), 0U);
395 EXPECT_EQ(empty_class_data_accessor.GetMethodsNumber(), 0U);
396 EXPECT_EQ(empty_class_data_accessor.GetIfacesNumber(), 0U);
397 EXPECT_FALSE(empty_class_data_accessor.GetSourceFileId().has_value());
398 EXPECT_EQ(empty_class_data_accessor.GetSize(), empty_class_item->GetSize());
399 }
400
401 HWTEST(ItemContainer, TestMethods, testing::ext::TestSize.Level0)
402 {
403 // Write panda file to memory
404
405 ItemContainer container;
406
407 ClassItem *class_item = container.GetOrCreateClassItem("A");
408 class_item->SetAccessFlags(ACC_PUBLIC);
409
410 StringItem *method_name = container.GetOrCreateStringItem("foo");
411
412 PrimitiveTypeItem *ret_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
413 std::vector<MethodParamItem> params;
414 ProtoItem *proto_item = container.GetOrCreateProtoItem(ret_type, params);
415
416 MethodItem *method_item = class_item->AddMethod(method_name, proto_item, ACC_PUBLIC | ACC_STATIC, params);
417
418 std::vector<uint8_t> instructions {1, 2, 3, 4};
419 CodeItem *code_item = container.CreateItem<CodeItem>(0, 2, instructions);
420
421 method_item->SetCode(code_item);
422
423 MemoryWriter mem_writer;
424
425 ASSERT_TRUE(container.Write(&mem_writer));
426
427 // Read panda file from memory
428
429 auto data = mem_writer.GetData();
430 auto panda_file = GetPandaFile(data);
431
432 ASSERT_NE(panda_file, nullptr);
433
434 ClassDataAccessor class_data_accessor(*panda_file, File::EntityId(class_item->GetOffset()));
435
__anona8d9bbf90b02(MethodDataAccessor &data_accessor) 436 class_data_accessor.EnumerateMethods([&](MethodDataAccessor &data_accessor) {
437 EXPECT_FALSE(data_accessor.IsExternal());
438 EXPECT_EQ(data_accessor.GetMethodId().GetOffset(), method_item->GetOffset());
439 EXPECT_EQ(data_accessor.GetClassId().GetOffset(), class_item->GetOffset());
440 EXPECT_EQ(data_accessor.GetNameId().GetOffset(), method_name->GetOffset());
441 EXPECT_EQ(data_accessor.GetProtoId().GetOffset(), proto_item->GetOffset());
442 EXPECT_EQ(data_accessor.GetAccessFlags(), ACC_PUBLIC | ACC_STATIC);
443 EXPECT_EQ(data_accessor.GetSize(), method_item->GetSize());
444
445 auto code_id = data_accessor.GetCodeId();
446 EXPECT_TRUE(code_id.has_value());
447 EXPECT_EQ(code_id.value().GetOffset(), code_item->GetOffset());
448
449 CodeDataAccessor code_data_accessor(*panda_file, code_id.value());
450 EXPECT_EQ(code_data_accessor.GetNumVregs(), 0U);
451 EXPECT_EQ(code_data_accessor.GetNumArgs(), 2U);
452 EXPECT_EQ(code_data_accessor.GetCodeSize(), instructions.size());
453 EXPECT_THAT(instructions, ::testing::ElementsAreArray(code_data_accessor.GetInstructions(),
454 code_data_accessor.GetCodeSize()));
455
456 EXPECT_EQ(code_data_accessor.GetTriesSize(), 0U);
457 EXPECT_EQ(code_data_accessor.GetSize(), code_item->GetSize());
458
459 code_data_accessor.EnumerateTryBlocks([](const CodeDataAccessor::TryBlock &) {
460 EXPECT_TRUE(false);
461 return false;
462 });
463
464 EXPECT_FALSE(data_accessor.GetDebugInfoId().has_value());
465
466 EXPECT_FALSE(data_accessor.GetRuntimeParamAnnotationId().has_value());
467
468 EXPECT_FALSE(data_accessor.GetParamAnnotationId().has_value());
469
470 data_accessor.EnumerateRuntimeAnnotations([](File::EntityId) { EXPECT_TRUE(false); });
471
472 data_accessor.EnumerateAnnotations([](File::EntityId) { EXPECT_TRUE(false); });
473 });
474 }
475
TestProtos(size_t n)476 void TestProtos(size_t n)
477 {
478 constexpr size_t ELEM_WIDTH = 4;
479 constexpr size_t ELEM_PER16 = 16 / ELEM_WIDTH;
480
481 // Write panda file to memory
482
483 ItemContainer container;
484
485 ClassItem *class_item = container.GetOrCreateClassItem("A");
486 class_item->SetAccessFlags(ACC_PUBLIC);
487
488 StringItem *method_name = container.GetOrCreateStringItem("foo");
489
490 std::vector<Type::TypeId> types {Type::TypeId::VOID, Type::TypeId::I32};
491 std::vector<ClassItem *> ref_types;
492
493 PrimitiveTypeItem *ret_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
494 std::vector<MethodParamItem> params;
495
496 params.emplace_back(container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32));
497
498 for (size_t i = 0; i < ELEM_PER16 * 2 - 2; i++) {
499 params.emplace_back(container.GetOrCreateClassItem("B"));
500 types.push_back(Type::TypeId::REFERENCE);
501 ref_types.push_back(container.GetOrCreateClassItem("B"));
502 params.emplace_back(container.GetOrCreatePrimitiveTypeItem(Type::TypeId::F64));
503 types.push_back(Type::TypeId::F64);
504 }
505
506 for (size_t i = 0; i < n; i++) {
507 params.emplace_back(container.GetOrCreatePrimitiveTypeItem(Type::TypeId::F32));
508 types.push_back(Type::TypeId::F32);
509 }
510
511 ProtoItem *proto_item = container.GetOrCreateProtoItem(ret_type, params);
512
513 MethodItem *method_item = class_item->AddMethod(method_name, proto_item, ACC_PUBLIC | ACC_STATIC, params);
514
515 MemoryWriter mem_writer;
516
517 ASSERT_TRUE(container.Write(&mem_writer));
518
519 // Read panda file from memory
520
521 auto data = mem_writer.GetData();
522 auto panda_file = GetPandaFile(data);
523
524 ASSERT_NE(panda_file, nullptr);
525
526 ClassDataAccessor class_data_accessor(*panda_file, File::EntityId(class_item->GetOffset()));
527
528 class_data_accessor.EnumerateMethods([&](MethodDataAccessor &data_accessor) {
529 EXPECT_EQ(data_accessor.GetMethodId().GetOffset(), method_item->GetOffset());
530 EXPECT_EQ(data_accessor.GetProtoId().GetOffset(), proto_item->GetOffset());
531
532 ProtoDataAccessor proto_data_accessor(*panda_file, data_accessor.GetProtoId());
533 EXPECT_EQ(proto_data_accessor.GetProtoId().GetOffset(), proto_item->GetOffset());
534
535 size_t num = 0;
536 size_t nref = 0;
537 proto_data_accessor.EnumerateTypes([&](Type t) {
538 EXPECT_EQ(t.GetEncoding(), Type(types[num]).GetEncoding());
539 ++num;
540
541 if (!t.IsPrimitive()) {
542 ++nref;
543 }
544 });
545
546 EXPECT_EQ(num, types.size());
547
548 for (size_t i = 0; i < num - 1; i++) {
549 EXPECT_EQ(proto_data_accessor.GetArgType(i).GetEncoding(), Type(types[i + 1]).GetEncoding());
550 }
551
552 EXPECT_EQ(proto_data_accessor.GetReturnType().GetEncoding(), Type(types[0]).GetEncoding());
553
554 EXPECT_EQ(nref, ref_types.size());
555
556 for (size_t i = 0; i < nref; i++) {
557 EXPECT_EQ(proto_data_accessor.GetReferenceType(0).GetOffset(), ref_types[i]->GetOffset());
558 }
559
560 size_t size = ((num + ELEM_PER16) / ELEM_PER16 + nref) * sizeof(uint16_t);
561
562 EXPECT_EQ(proto_data_accessor.GetSize(), size);
563 EXPECT_EQ(proto_data_accessor.GetSize(), proto_item->GetSize());
564 });
565 }
566
567 HWTEST(ItemContainer, TestProtos, testing::ext::TestSize.Level0)
568 {
569 TestProtos(0);
570 TestProtos(1);
571 TestProtos(2);
572 TestProtos(7);
573 }
574
575 HWTEST(ItemContainer, TestDebugInfo, testing::ext::TestSize.Level0)
576 {
577 // Write panda file to memory
578
579 ItemContainer container;
580
581 ClassItem *class_item = container.GetOrCreateClassItem("A");
582 class_item->SetAccessFlags(ACC_PUBLIC);
583
584 StringItem *method_name = container.GetOrCreateStringItem("foo");
585
586 PrimitiveTypeItem *ret_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
587 std::vector<MethodParamItem> params;
588 params.emplace_back(container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32));
589 ProtoItem *proto_item = container.GetOrCreateProtoItem(ret_type, params);
590 MethodItem *method_item = class_item->AddMethod(method_name, proto_item, ACC_PUBLIC | ACC_STATIC, params);
591
592 StringItem *source_file_item = container.GetOrCreateStringItem("<source>");
593 StringItem *source_code_item = container.GetOrCreateStringItem("let a = 1;");
594 StringItem *param_string_item = container.GetOrCreateStringItem("a0");
595
596 LineNumberProgramItem *line_number_program_item = container.CreateLineNumberProgramItem();
597 DebugInfoItem *debug_info_item = container.CreateItem<DebugInfoItem>(line_number_program_item);
598 method_item->SetDebugInfo(debug_info_item);
599
600 // Create foreign class
601 ForeignClassItem *class_item_foreign = container.GetOrCreateForeignClassItem("ForeignClass");
602
603 // Create foreign method
604 StringItem *method_name_foreign = container.GetOrCreateStringItem("ForeignMethod");
605 PrimitiveTypeItem *ret_type_foreign = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
606 std::vector<MethodParamItem> params_foreign;
607 params_foreign.emplace_back(container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32));
608 ProtoItem *proto_item_foreign = container.GetOrCreateProtoItem(ret_type_foreign, params_foreign);
609 container.CreateItem<ForeignMethodItem>(class_item_foreign,
610 method_name_foreign, proto_item_foreign, 0);
611
612 // Add debug info
613
614 container.ComputeLayout();
615
616 std::vector<uint8_t> opcodes {
617 static_cast<uint8_t>(LineNumberProgramItem::Opcode::SET_SOURCE_CODE),
618 static_cast<uint8_t>(LineNumberProgramItem::Opcode::SET_FILE),
619 static_cast<uint8_t>(LineNumberProgramItem::Opcode::SET_PROLOGUE_END),
620 static_cast<uint8_t>(LineNumberProgramItem::Opcode::ADVANCE_PC),
621 static_cast<uint8_t>(LineNumberProgramItem::Opcode::ADVANCE_LINE),
622 static_cast<uint8_t>(LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN),
623 static_cast<uint8_t>(LineNumberProgramItem::Opcode::END_SEQUENCE),
624 };
625
626 auto *constant_pool = debug_info_item->GetConstantPool();
627 debug_info_item->SetLineNumber(5);
628 line_number_program_item->EmitSetSourceCode(constant_pool, source_code_item);
629 line_number_program_item->EmitSetFile(constant_pool, source_file_item);
630 line_number_program_item->EmitPrologEnd();
631 line_number_program_item->EmitAdvancePc(constant_pool, 10);
632 line_number_program_item->EmitAdvanceLine(constant_pool, -5);
633 line_number_program_item->EmitEpilogBegin();
634 line_number_program_item->EmitEnd();
635
636 debug_info_item->AddParameter(param_string_item);
637
638 method_item->SetDebugInfo(debug_info_item);
639
640 MemoryWriter mem_writer;
641
642 ASSERT_TRUE(container.Write(&mem_writer));
643
644 // Read panda file from memory
645
646 auto data = mem_writer.GetData();
647 auto panda_file = GetPandaFile(data);
648
649 ASSERT_NE(panda_file, nullptr);
650
651 ClassDataAccessor class_data_accessor(*panda_file, File::EntityId(class_item->GetOffset()));
652
__anona8d9bbf91102(MethodDataAccessor &data_accessor) 653 class_data_accessor.EnumerateMethods([&](MethodDataAccessor &data_accessor) {
654 EXPECT_EQ(data_accessor.GetMethodId().GetOffset(), method_item->GetOffset());
655 EXPECT_EQ(data_accessor.GetSize(), method_item->GetSize());
656
657 auto debug_info_id = data_accessor.GetDebugInfoId();
658 EXPECT_TRUE(debug_info_id.has_value());
659
660 EXPECT_EQ(debug_info_id.value().GetOffset(), debug_info_item->GetOffset());
661
662 DebugInfoDataAccessor dda(*panda_file, debug_info_id.value());
663 EXPECT_EQ(dda.GetDebugInfoId().GetOffset(), debug_info_item->GetOffset());
664 EXPECT_EQ(dda.GetLineStart(), 5U);
665 EXPECT_EQ(dda.GetNumParams(), params.size());
666
667 dda.EnumerateParameters([&](File::EntityId id) { EXPECT_EQ(id.GetOffset(), param_string_item->GetOffset()); });
668
669 auto cp = dda.GetConstantPool();
670 EXPECT_EQ(cp.size(), constant_pool->size());
671 EXPECT_THAT(*constant_pool, ::testing::ElementsAreArray(cp.data(), cp.Size()));
672
673 EXPECT_EQ(helpers::ReadULeb128(&cp), source_code_item->GetOffset());
674 EXPECT_EQ(helpers::ReadULeb128(&cp), source_file_item->GetOffset());
675 EXPECT_EQ(helpers::ReadULeb128(&cp), 10U);
676 EXPECT_EQ(helpers::ReadLeb128(&cp), -5);
677
678 const uint8_t *line_number_program = dda.GetLineNumberProgram();
679 EXPECT_EQ(panda_file->GetIdFromPointer(line_number_program).GetOffset(), line_number_program_item->GetOffset());
680 EXPECT_EQ(line_number_program_item->GetSize(), opcodes.size());
681
682 EXPECT_THAT(opcodes, ::testing::ElementsAreArray(line_number_program, opcodes.size()));
683
684 EXPECT_EQ(dda.GetSize(), debug_info_item->GetSize());
685 });
686
687 DebugInfoExtractor extractor(panda_file.get());
688 const auto &methods = extractor.GetMethodIdList();
689 for (const auto &method_id : methods) {
690 for (const auto &info : extractor.GetParameterInfo(method_id)) {
691 EXPECT_EQ(info.name, "a0");
692 }
693 }
694 }
695
696 HWTEST(ItemContainer, ForeignItems, testing::ext::TestSize.Level0)
697 {
698 ItemContainer container;
699
700 // Create foreign class
701 ForeignClassItem *class_item = container.GetOrCreateForeignClassItem("ForeignClass");
702
703 // Create foreign field
704 StringItem *field_name = container.GetOrCreateStringItem("foreign_field");
705 PrimitiveTypeItem *field_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32);
706 ForeignFieldItem *field_item = container.CreateItem<ForeignFieldItem>(class_item, field_name, field_type);
707
708 // Create foreign method
709 StringItem *method_name = container.GetOrCreateStringItem("ForeignMethod");
710 PrimitiveTypeItem *ret_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
711 std::vector<MethodParamItem> params;
712 params.emplace_back(container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32));
713 ProtoItem *proto_item = container.GetOrCreateProtoItem(ret_type, params);
714 ForeignMethodItem *method_item = container.CreateItem<ForeignMethodItem>(class_item, method_name, proto_item, 0);
715
716 MemoryWriter mem_writer;
717
718 ASSERT_TRUE(container.Write(&mem_writer));
719
720 // Read panda file from memory
721
722 auto data = mem_writer.GetData();
723 auto panda_file = GetPandaFile(data);
724
725 ASSERT_NE(panda_file, nullptr);
726
727 EXPECT_EQ(panda_file->GetHeader()->foreign_off, class_item->GetOffset());
728
729 size_t foreign_size = class_item->GetSize() + field_item->GetSize() + method_item->GetSize();
730 EXPECT_EQ(panda_file->GetHeader()->foreign_size, foreign_size);
731
732 ASSERT_TRUE(panda_file->IsExternal(class_item->GetFileId()));
733
734 MethodDataAccessor method_data_accessor(*panda_file, method_item->GetFileId());
735 EXPECT_EQ(method_data_accessor.GetMethodId().GetOffset(), method_item->GetOffset());
736 EXPECT_EQ(method_data_accessor.GetSize(), method_item->GetSize());
737 EXPECT_EQ(method_data_accessor.GetClassId().GetOffset(), class_item->GetOffset());
738 EXPECT_EQ(method_data_accessor.GetNameId().GetOffset(), method_name->GetOffset());
739 EXPECT_EQ(method_data_accessor.GetProtoId().GetOffset(), proto_item->GetOffset());
740 EXPECT_TRUE(method_data_accessor.IsExternal());
741
742 FieldDataAccessor field_data_accessor(*panda_file, field_item->GetFileId());
743 EXPECT_EQ(field_data_accessor.GetFieldId().GetOffset(), field_item->GetOffset());
744 EXPECT_EQ(field_data_accessor.GetSize(), field_item->GetSize());
745 EXPECT_EQ(field_data_accessor.GetClassId().GetOffset(), class_item->GetOffset());
746 EXPECT_EQ(field_data_accessor.GetNameId().GetOffset(), field_name->GetOffset());
747 EXPECT_EQ(field_data_accessor.GetType(), field_type->GetType().GetFieldEncoding());
748 EXPECT_TRUE(field_data_accessor.IsExternal());
749 }
750
751 HWTEST(ItemContainer, EmptyContainerChecksum, testing::ext::TestSize.Level0)
752 {
753 using panda::os::file::Mode;
754 using panda::os::file::Open;
755
756 // Write panda file to disk
757 ItemContainer container;
758
759 const std::string file_name = "test_empty_checksum.ark";
760 auto writer = FileWriter(file_name);
761
762 // Initial value of adler32
763 EXPECT_EQ(writer.GetChecksum(), 1U);
764 ASSERT_TRUE(container.Write(&writer));
765
766 // At least header was written so the checksum should be changed
767 auto container_checksum = writer.GetChecksum();
768 EXPECT_NE(container_checksum, 1U);
769
770 // Read panda file from disk
771 auto file = File::Open(file_name);
772 EXPECT_NE(file, nullptr);
773 EXPECT_EQ(file->GetHeader()->checksum, container_checksum);
774
775 constexpr size_t DATA_OFFSET = 12U;
776 auto checksum = adler32(1, file->GetBase() + DATA_OFFSET, file->GetHeader()->file_size - DATA_OFFSET);
777 EXPECT_EQ(file->GetHeader()->checksum, checksum);
778 }
779
780 HWTEST(ItemContainer, ContainerChecksum, testing::ext::TestSize.Level0)
781 {
782 using panda::os::file::Mode;
783 using panda::os::file::Open;
784
785 uint32_t empty_checksum = 0;
786 {
787 ItemContainer container;
788 const std::string file_name = "test_checksum_empty.ark";
789 auto writer = FileWriter(file_name);
790 ASSERT_TRUE(container.Write(&writer));
791 empty_checksum = writer.GetChecksum();
792 }
793 ASSERT(empty_checksum != 0);
794
795 // Create not empty container
796 ItemContainer container;
797 container.GetOrCreateClassItem("C");
798
799 const std::string file_name = "test_checksum.ark";
800 auto writer = FileWriter(file_name);
801
802 ASSERT_TRUE(container.Write(&writer));
803
804 // This checksum must be different from the empty one (collision may happen though)
805 auto container_checksum = writer.GetChecksum();
806 EXPECT_NE(empty_checksum, container_checksum);
807
808 // Read panda file from disk
809 auto file = File::Open(file_name);
810 EXPECT_NE(file, nullptr);
811 EXPECT_EQ(file->GetHeader()->checksum, container_checksum);
812
813 constexpr size_t DATA_OFFSET = 12U;
814 auto checksum = adler32(1, file->GetBase() + DATA_OFFSET, file->GetHeader()->file_size - DATA_OFFSET);
815 EXPECT_EQ(file->GetHeader()->checksum, checksum);
816 }
817
818 HWTEST(ItemContainer, TestProfileGuidedRelayout, testing::ext::TestSize.Level0)
819 {
820 ItemContainer container;
821
822 // Add classes
823 ClassItem *empty_class_item = container.GetOrCreateClassItem("LTest;");
824 ClassItem *class_item_a = container.GetOrCreateClassItem("LAA;");
825 class_item_a->SetSuperClass(empty_class_item);
826 ClassItem *class_item_b = container.GetOrCreateClassItem("LBB;");
827
828 // Add method1
829 StringItem *method_name_1 = container.GetOrCreateStringItem("foo1");
830 PrimitiveTypeItem *ret_type_1 = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
831 std::vector<MethodParamItem> params_1;
832 ProtoItem *proto_item_1 = container.GetOrCreateProtoItem(ret_type_1, params_1);
833 MethodItem *method_item_1 = class_item_a->AddMethod(method_name_1, proto_item_1, ACC_PUBLIC | ACC_STATIC, params_1);
834 // Set code_1
835 std::vector<uint8_t> instructions_1 {1, 2, 3, 4};
836 CodeItem *code_item_1 = container.CreateItem<CodeItem>(0, 2, instructions_1);
837 method_item_1->SetCode(code_item_1);
838 code_item_1->AddMethod(method_item_1);
839
840 // Add method2
841 StringItem *method_name_2 = container.GetOrCreateStringItem("foo2");
842 PrimitiveTypeItem *ret_type_2 = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32);
843 std::vector<MethodParamItem> params_2;
844 ProtoItem *proto_item_2 = container.GetOrCreateProtoItem(ret_type_2, params_2);
845 MethodItem *method_item_2 = class_item_b->AddMethod(method_name_2, proto_item_2, ACC_PUBLIC | ACC_STATIC, params_2);
846 // Set code_2
847 std::vector<uint8_t> instructions_2 {5, 6, 7, 8};
848 CodeItem *code_item_2 = container.CreateItem<CodeItem>(0, 2, instructions_2);
849 method_item_2->SetCode(code_item_2);
850 code_item_2->AddMethod(method_item_2);
851
852 // Add method_3
853 StringItem *method_name_3 = container.GetOrCreateStringItem("foo3");
854 auto *method_item_3 = empty_class_item->AddMethod(method_name_3, proto_item_1, ACC_PUBLIC | ACC_STATIC, params_1);
855 // Set code_3
856 std::vector<uint8_t> instructions_3 {3, 4, 5, 6};
857 CodeItem *code_item_3 = container.CreateItem<CodeItem>(0, 2, instructions_3);
858 method_item_3->SetCode(code_item_3);
859 code_item_3->AddMethod(method_item_3);
860
861 // Add method_4
862 StringItem *method_name_4 = container.GetOrCreateStringItem("foo4");
863 auto *method_item_4 = empty_class_item->AddMethod(method_name_4, proto_item_1, ACC_PUBLIC | ACC_STATIC, params_1);
864 // Set code. method_4 and method_3 share code_item_3
865 method_item_4->SetCode(code_item_3);
866 code_item_3->AddMethod(method_item_4);
867
868 // Add field
869 StringItem *field_name = container.GetOrCreateStringItem("test_field");
870 PrimitiveTypeItem *field_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32);
871 class_item_a->AddField(field_name, field_type, ACC_PUBLIC);
872
873 // Add source file
874 StringItem *source_file = container.GetOrCreateStringItem("source_file");
875 class_item_a->SetSourceFile(source_file);
876
877 constexpr std::string_view PRIMITIVE_TYPE_ITEM = "primitive_type_item";
878 constexpr std::string_view PROTO_ITEM = "proto_item";
879 constexpr std::string_view END_ITEM = "end_item";
880
881 // Items before PGO
882 const auto &items = container.GetItems();
883 auto item = items.begin();
884 EXPECT_EQ((*item)->GetName(), CLASS_ITEM);
885 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "Test");
886 item++;
887 EXPECT_EQ((*item)->GetName(), CLASS_ITEM);
888 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "AA");
889 item++;
890 EXPECT_EQ((*item)->GetName(), CLASS_ITEM);
891 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "BB");
892 item++;
893 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
894 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "foo1");
895 item++;
896 EXPECT_EQ((*item)->GetName(), PRIMITIVE_TYPE_ITEM);
897 item++;
898 EXPECT_EQ((*item)->GetName(), PROTO_ITEM);
899 item++;
900 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
901 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "foo2");
902 item++;
903 EXPECT_EQ((*item)->GetName(), PRIMITIVE_TYPE_ITEM);
904 item++;
905 EXPECT_EQ((*item)->GetName(), PROTO_ITEM);
906 item++;
907 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
908 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "foo3");
909 item++;
910 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
911 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "foo4");
912 item++;
913 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
914 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "test_field");
915 item++;
916 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
917 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "source_file");
918 item++;
919 EXPECT_EQ((*item)->GetName(), END_ITEM);
920 item++;
921 EXPECT_EQ((*item)->GetName(), CODE_ITEM);
922 EXPECT_EQ(static_cast<CodeItem *>((*item).get())->GetMethodNames()[0], "AA::foo1");
923 item++;
924 EXPECT_EQ((*item)->GetName(), CODE_ITEM);
925 EXPECT_EQ(static_cast<CodeItem *>((*item).get())->GetMethodNames()[0], "BB::foo2");
926 item++;
927 EXPECT_EQ((*item)->GetName(), CODE_ITEM);
928 EXPECT_EQ(static_cast<CodeItem *>((*item).get())->GetMethodNames()[0], "Test::foo3");
929 EXPECT_EQ(static_cast<CodeItem *>((*item).get())->GetMethodNames()[1], "Test::foo4");
930 item++;
931 EXPECT_EQ((*item)->GetName(), END_ITEM);
932 item++;
933 EXPECT_EQ((*item)->GetName(), END_ITEM);
934 item++;
935 EXPECT_EQ(item, items.end());
936
937 // Prepare profile data
938 std::string profile_path = "TestProfileGuidedRelayout_profile_test_data.txt";
939 std::ofstream test_file;
940 test_file.open(profile_path);
941 test_file << "string_item:test_field" << std::endl;
942 test_file << "class_item:BB" << std::endl;
943 test_file << "code_item:BB::foo2" << std::endl;
944 test_file << "code_item:Test::foo4" << std::endl;
945 test_file.close();
946
947 // Run PGO
948 panda::panda_file::pgo::ProfileOptimizer profile_opt;
949 profile_opt.SetProfilePath(profile_path);
950 container.ReorderItems(&profile_opt);
951
952 // Items after PGO
953 item = items.begin();
954 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
955 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "test_field");
956 item++;
957 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
958 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "foo1");
959 item++;
960 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
961 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "foo2");
962 item++;
963 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
964 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "foo3");
965 item++;
966 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
967 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "foo4");
968 item++;
969 EXPECT_EQ((*item)->GetName(), STRING_ITEM);
970 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "source_file");
971 item++;
972 EXPECT_EQ((*item)->GetName(), CLASS_ITEM);
973 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "BB");
974 item++;
975 EXPECT_EQ((*item)->GetName(), CLASS_ITEM);
976 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "Test");
977 item++;
978 EXPECT_EQ((*item)->GetName(), CLASS_ITEM);
979 EXPECT_EQ(panda::panda_file::pgo::ProfileOptimizer::GetNameInfo(*item), "AA");
980 item++;
981 EXPECT_EQ((*item)->GetName(), PRIMITIVE_TYPE_ITEM);
982 item++;
983 EXPECT_EQ((*item)->GetName(), PROTO_ITEM);
984 item++;
985 EXPECT_EQ((*item)->GetName(), PRIMITIVE_TYPE_ITEM);
986 item++;
987 EXPECT_EQ((*item)->GetName(), PROTO_ITEM);
988 item++;
989 EXPECT_EQ((*item)->GetName(), END_ITEM);
990 item++;
991 EXPECT_EQ((*item)->GetName(), END_ITEM);
992 item++;
993 EXPECT_EQ((*item)->GetName(), END_ITEM);
994 item++;
995 EXPECT_EQ((*item)->GetName(), CODE_ITEM);
996 EXPECT_EQ(static_cast<CodeItem *>((*item).get())->GetMethodNames()[0], "BB::foo2");
997 item++;
998 EXPECT_EQ((*item)->GetName(), CODE_ITEM);
999 EXPECT_EQ(static_cast<CodeItem *>((*item).get())->GetMethodNames()[0], "Test::foo3");
1000 EXPECT_EQ(static_cast<CodeItem *>((*item).get())->GetMethodNames()[1], "Test::foo4");
1001 item++;
1002 EXPECT_EQ((*item)->GetName(), CODE_ITEM);
1003 EXPECT_EQ(static_cast<CodeItem *>((*item).get())->GetMethodNames()[0], "AA::foo1");
1004 item++;
1005 EXPECT_EQ(item, items.end());
1006 }
1007
1008 HWTEST(ItemContainer, GettersTest, testing::ext::TestSize.Level0)
1009 {
1010 ItemContainer container;
1011
1012 ClassItem *empty_class_item = container.GetOrCreateClassItem("Foo");
1013
1014 ClassItem *class_item = container.GetOrCreateClassItem("Bar");
1015 class_item->SetAccessFlags(ACC_PUBLIC);
1016 class_item->SetSuperClass(empty_class_item);
1017
1018 // Add methods
1019
1020 StringItem *method_name1 = container.GetOrCreateStringItem("foo1");
1021
1022 PrimitiveTypeItem *ret_type1 = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
1023 std::vector<MethodParamItem> params1;
1024 params1.emplace_back(container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32));
1025 ProtoItem *proto_item1 = container.GetOrCreateProtoItem(ret_type1, params1);
1026
1027 class_item->AddMethod(method_name1, proto_item1, ACC_PUBLIC | ACC_STATIC, params1);
1028
1029 StringItem *method_name2 = container.GetOrCreateStringItem("foo2");
1030
1031 PrimitiveTypeItem *ret_type2 = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32);
1032 std::vector<MethodParamItem> params2;
1033 params2.emplace_back(container.GetOrCreatePrimitiveTypeItem(Type::TypeId::F32));
1034 ProtoItem *proto_item2 = container.GetOrCreateProtoItem(ret_type2, params2);
1035
1036 class_item->AddMethod(method_name2, proto_item2, ACC_PUBLIC | ACC_STATIC, params2);
1037
1038 // Add field
1039
1040 StringItem *field_name = container.GetOrCreateStringItem("field");
1041 PrimitiveTypeItem *field_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32);
1042
1043 class_item->AddField(field_name, field_type, ACC_PUBLIC);
1044
1045 // Add source file
1046
1047 StringItem *source_file = container.GetOrCreateStringItem("source_file");
1048
1049 class_item->SetSourceFile(source_file);
1050
1051 // Read items from container
1052
1053 ASSERT_TRUE(container.GetItems().size() == 14);
1054
1055 std::map<std::string, panda_file::BaseClassItem *> *class_map = container.GetClassMap();
1056 ASSERT_TRUE(class_map != nullptr && class_map->size() == 2);
1057 auto it = class_map->find("Bar");
1058 ASSERT_TRUE(it != class_map->end());
1059
1060 std::unordered_map<std::string, StringItem *> *string_map = container.GetStringMap();
1061 ASSERT_TRUE(string_map != nullptr && string_map->size() == 4);
1062 auto sit0 = string_map->find("field");
1063 auto sit1 = string_map->find("source_file");
1064 auto sit2 = string_map->find("foo1");
1065 auto sit3 = string_map->find("foo2");
1066 ASSERT_TRUE(sit0 != string_map->end() && sit1 != string_map->end() && sit2 != string_map->end() &&
1067 sit3 != string_map->end());
1068
1069 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> *primitive_type_map = container.GetPrimitiveTypeMap();
1070 ASSERT_TRUE(primitive_type_map != nullptr && primitive_type_map->size() == 3);
1071 auto pit0 = primitive_type_map->find(Type::TypeId::F32);
1072 auto pit1 = primitive_type_map->find(Type::TypeId::I32);
1073 auto pit2 = primitive_type_map->find(Type::TypeId::VOID);
1074 ASSERT_TRUE(pit0 != primitive_type_map->end() && pit1 != primitive_type_map->end() &&
1075 pit2 != primitive_type_map->end());
1076
1077 auto *rclass_item = static_cast<panda_file::ClassItem *>(it->second);
1078 std::string method_name;
__anona8d9bbf91302(BaseItem *method) 1079 std::function<bool(BaseItem *)> TestMethod = [&](BaseItem *method) {
1080 auto *method_item = static_cast<panda_file::MethodItem *>(method);
1081 ASSERT(method_item != nullptr && method_item->GetItemType() == ItemTypes::METHOD_ITEM);
1082 method_name = method_item->GetNameItem()->GetData();
1083 method_name.pop_back(); // remove '\0'
1084 ASSERT(method_name == "foo1" || method_name == "foo2");
1085 return true;
1086 };
1087
1088 using std::placeholders::_1;
1089 panda_file::BaseItem::VisitorCallBack cb_method = TestMethod;
1090 rclass_item->VisitMethods(cb_method);
1091
1092 std::string f_name;
__anona8d9bbf91402(BaseItem *field) 1093 std::function<bool(BaseItem *)> TestField = [&](BaseItem *field) {
1094 auto *field_item = static_cast<panda_file::FieldItem *>(field);
1095 ASSERT(field_item != nullptr && field_item->GetItemType() == ItemTypes::FIELD_ITEM);
1096 f_name = field_item->GetNameItem()->GetData();
1097 f_name.pop_back(); // remove '\0'
1098 ASSERT(f_name == "field");
1099 return true;
1100 };
1101
1102 panda_file::BaseItem::VisitorCallBack cb_field = TestField;
1103 rclass_item->VisitFields(cb_field);
1104 }
1105
1106 HWTEST(ItemContainer, IndexedItemGlobalIndexTest, testing::ext::TestSize.Level0)
1107 {
1108 ItemContainer container;
1109 EXPECT_EQ(container.GetIndexedItemCount(), 0U);
1110
1111 // Create foreign class
1112 ForeignClassItem *foreign_class_item = container.GetOrCreateForeignClassItem("foreign_class");
1113 EXPECT_EQ(foreign_class_item->GetIndexedItemCount(), 0U);
1114 // BaseClassItem will initialize one StringItem member, which will increase the count by 1.
1115 EXPECT_EQ(container.GetIndexedItemCount(), foreign_class_item->GetIndexedItemCount() + 2);
1116
1117 // Create foreign field
1118 StringItem *foreign_field_name = container.GetOrCreateStringItem("foreign_field");
1119 PrimitiveTypeItem *foreign_field_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32);
1120 ForeignFieldItem *foreign_field_item = container.CreateItem<ForeignFieldItem>(foreign_class_item,
1121 foreign_field_name, foreign_field_type);
1122 EXPECT_EQ(foreign_field_item->GetIndexedItemCount(), 4U);
1123 EXPECT_EQ(container.GetIndexedItemCount(), foreign_field_item->GetIndexedItemCount() + 1);
1124
1125 // Create foreign method
1126 StringItem *foreign_method_name = container.GetOrCreateStringItem("foreign_method");
1127 PrimitiveTypeItem *foreign_ret_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
1128 std::vector<MethodParamItem> foreign_params;
1129 foreign_params.emplace_back(container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I64));
1130 ProtoItem *foreign_proto_item = container.GetOrCreateProtoItem(foreign_ret_type, foreign_params);
1131 ForeignMethodItem *foreign_method_item = container.CreateItem<ForeignMethodItem>(foreign_class_item,
1132 foreign_method_name, foreign_proto_item, 0);
1133 EXPECT_EQ(foreign_method_item->GetIndexedItemCount(), 9U);
1134 EXPECT_EQ(container.GetIndexedItemCount(), foreign_method_item->GetIndexedItemCount() + 1);
1135
1136 // Create class
1137 ClassItem *class_item = container.GetOrCreateClassItem("classA");
1138 EXPECT_EQ(class_item->GetIndexedItemCount(), 10U);
1139 EXPECT_EQ(container.GetIndexedItemCount(), class_item->GetIndexedItemCount() + 2);
1140
1141 // Create method
1142 StringItem *method_name = container.GetOrCreateStringItem("a");
1143 // TypeId::VOID is repeated, count won't increase
1144 PrimitiveTypeItem *ret_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID);
1145 std::vector<MethodParamItem> params;
1146 ProtoItem *proto_item = container.GetOrCreateProtoItem(ret_type, params);
1147 MethodItem *method_item = class_item->AddMethod(method_name, proto_item, ACC_PUBLIC | ACC_STATIC, params);
1148 EXPECT_EQ(method_item->GetIndexedItemCount(), 14U);
1149 EXPECT_EQ(container.GetIndexedItemCount(), method_item->GetIndexedItemCount() + 1);
1150
1151 // Create field
1152 StringItem *field_name = container.GetOrCreateStringItem("field");
1153 PrimitiveTypeItem *field_type = container.GetOrCreatePrimitiveTypeItem(Type::TypeId::I32);
1154 FieldItem *field_item = class_item->AddField(field_name, field_type, ACC_PUBLIC);
1155 EXPECT_EQ(field_item->GetIndexedItemCount(), 16U);
1156 EXPECT_EQ(container.GetIndexedItemCount(), field_item->GetIndexedItemCount() + 1);
1157
1158 // Create code, item count is not expected to increase
1159 std::vector<uint8_t> instructions {1, 2, 3, 4};
1160 CodeItem *code_item = container.CreateItem<CodeItem>(0, 2, instructions);
1161 method_item->SetCode(code_item);
1162 EXPECT_EQ(container.GetIndexedItemCount(), field_item->GetIndexedItemCount() + 1);
1163
1164 // Create line number program
1165 LineNumberProgramItem *line_number_program_item = container.CreateLineNumberProgramItem();
1166 EXPECT_EQ(line_number_program_item->GetIndexedItemCount(), 17U);
1167 EXPECT_EQ(container.GetIndexedItemCount(), line_number_program_item->GetIndexedItemCount() + 1);
1168
1169 // Create value items
1170 ScalarValueItem *scalarValueItem = container.CreateItem<ScalarValueItem>(1.0);
1171 EXPECT_EQ(scalarValueItem->GetIndexedItemCount(), 18U);
1172 EXPECT_EQ(container.GetIndexedItemCount(), scalarValueItem->GetIndexedItemCount() + 1);
1173 }
1174
1175 } // namespace panda::panda_file::test
1176