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