1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <cstddef>
17 #include <cstdint>
18 
19 #include "annotation_data_accessor.h"
20 #include "bytecode_instruction.h"
21 #include "code_data_accessor.h"
22 #include "field_data_accessor.h"
23 #include "file.h"
24 #include "debug_info_updater-inl.h"
25 #include "file_items.h"
26 #include "libpandafile/file_reader.h"
27 #include "libpandafile/bytecode_instruction-inl.h"
28 #include "libpandafile/line_number_program.h"
29 #include "libpandafile/literal_data_accessor-inl.h"
30 #include "libpandafile/class_data_accessor-inl.h"
31 #include "libpandafile/proto_data_accessor-inl.h"
32 #include "libpandafile/code_data_accessor-inl.h"
33 #include "libpandafile/debug_data_accessor-inl.h"
34 #include "libpandafile/field_data_accessor-inl.h"
35 #include "libpandafile/method_data_accessor-inl.h"
36 
37 #include "libpandabase/utils/utf.h"
38 #include "proto_data_accessor.h"
39 
40 namespace ark::panda_file {
41 
42 namespace {
43 class FileReaderDebugInfoUpdater : public DebugInfoUpdater<FileReaderDebugInfoUpdater> {
44 public:
45     using Super = DebugInfoUpdater<FileReaderDebugInfoUpdater>;
46 
FileReaderDebugInfoUpdater(const File *file, ItemContainer *cont)47     FileReaderDebugInfoUpdater(const File *file, ItemContainer *cont) : Super(file), cont_(cont) {}
48 
GetOrCreateStringItem(const std::string &s)49     StringItem *GetOrCreateStringItem(const std::string &s)
50     {
51         return cont_->GetOrCreateStringItem(s);
52     }
53 
GetType(File::EntityId typeId, const std::string &typeName)54     BaseClassItem *GetType(File::EntityId typeId, const std::string &typeName)
55     {
56         if (GetFile()->IsExternal(typeId)) {
57             return cont_->GetOrCreateForeignClassItem(typeName);
58         }
59         return cont_->GetOrCreateClassItem(typeName);
60     }
61 
62 private:
63     ItemContainer *cont_;
64 };
65 }  // namespace
66 
ReadContainer(bool shouldRebuildIndices)67 bool FileReader::ReadContainer(bool shouldRebuildIndices)
68 {
69     const File::Header *header = file_->GetHeader();
70     LOG_IF(header->quickenedFlag, FATAL, PANDAFILE) << "File " << file_->GetFullFileName() << " is already quickened";
71 
72     if (!ReadClasses()) {
73         return false;
74     }
75     if (!ReadLiteralArrayItems()) {
76         return false;
77     }
78     if (!ReadRegionHeaders()) {
79         return false;
80     }
81 
82     if (shouldRebuildIndices) {
83         ComputeLayoutAndUpdateIndices();
84     }
85 
86     return true;
87 }
88 
89 template <typename T>
EmplaceLiteralArray(const panda_file::LiteralDataAccessor::LiteralValue &value, std::vector<panda_file::LiteralItem> &literalArray, std::unique_ptr<const File> &file)90 static void EmplaceLiteralArray(const panda_file::LiteralDataAccessor::LiteralValue &value,
91                                 std::vector<panda_file::LiteralItem> &literalArray, std::unique_ptr<const File> &file)
92 {
93     File::EntityId id(std::get<uint32_t>(value));
94     auto sp = file->GetSpanFromId(id);
95     auto len = helpers::Read<sizeof(uint32_t)>(&sp);
96     literalArray.emplace_back(len);
97     for (size_t i = 0; i < len; i++) {
98         auto v = helpers::Read<sizeof(T)>(&sp);
99         literalArray.emplace_back(v);
100     }
101 }
102 
EmplaceLiteralString(const panda_file::LiteralDataAccessor::LiteralValue &value, std::vector<panda_file::LiteralItem> &literalArray, std::unique_ptr<const File> &file, ItemContainer &container)103 static void EmplaceLiteralString(const panda_file::LiteralDataAccessor::LiteralValue &value,
104                                  std::vector<panda_file::LiteralItem> &literalArray, std::unique_ptr<const File> &file,
105                                  ItemContainer &container)
106 {
107     File::EntityId id(std::get<uint32_t>(value));
108     auto data = file->GetStringData(id);
109     std::string itemStr(utf::Mutf8AsCString(data.data));
110     auto *stringItem = container.GetOrCreateStringItem(itemStr);
111     literalArray.emplace_back(stringItem);
112 }
113 
EmplaceLiteralArrayString(const panda_file::LiteralDataAccessor::LiteralValue &value, std::vector<panda_file::LiteralItem> &literalArray, std::unique_ptr<const File> &file, ItemContainer &container)114 static void EmplaceLiteralArrayString(const panda_file::LiteralDataAccessor::LiteralValue &value,
115                                       std::vector<panda_file::LiteralItem> &literalArray,
116                                       std::unique_ptr<const File> &file, ItemContainer &container)
117 {
118     File::EntityId id(std::get<uint32_t>(value));
119     auto sp = file->GetSpanFromId(id);
120     auto len = helpers::Read<sizeof(uint32_t)>(&sp);
121     literalArray.emplace_back(len);
122     for (size_t i = 0; i < len; i++) {
123         File::EntityId strId(helpers::Read<sizeof(uint32_t)>(&sp));
124         auto data = file->GetStringData(strId);
125         std::string itemStr(utf::Mutf8AsCString(data.data));
126         auto *stringItem = container.GetOrCreateStringItem(itemStr);
127         literalArray.emplace_back(stringItem);
128     }
129 }
130 
131 // CC-OFFNXT(G.FUN.01-CPP, huge_method[C++]) big switch case
EmplaceLiteralVals(std::vector<panda_file::LiteralItem> &literalArray, const panda_file::LiteralDataAccessor::LiteralValue &value, const panda_file::LiteralTag &tag)132 void FileReader::EmplaceLiteralVals(std::vector<panda_file::LiteralItem> &literalArray,
133                                     const panda_file::LiteralDataAccessor::LiteralValue &value,
134                                     const panda_file::LiteralTag &tag)
135 {
136     literalArray.emplace_back(static_cast<uint8_t>(tag));
137     switch (tag) {
138         case panda_file::LiteralTag::BOOL: {
139             literalArray.emplace_back(static_cast<uint8_t>(std::get<bool>(value)));
140             break;
141         }
142         case panda_file::LiteralTag::TAGVALUE:
143         case panda_file::LiteralTag::ACCESSOR:
144         case panda_file::LiteralTag::NULLVALUE: {
145             literalArray.emplace_back(std::get<uint8_t>(value));
146             break;
147         }
148         case panda_file::LiteralTag::ARRAY_U1:
149         case panda_file::LiteralTag::ARRAY_I8:
150         case panda_file::LiteralTag::ARRAY_U8: {
151             EmplaceLiteralArray<uint8_t>(value, literalArray, file_);
152             break;
153         }
154         case panda_file::LiteralTag::ARRAY_I16:
155         case panda_file::LiteralTag::ARRAY_U16: {
156             EmplaceLiteralArray<uint16_t>(value, literalArray, file_);
157             break;
158         }
159         case panda_file::LiteralTag::INTEGER: {
160             literalArray.emplace_back(std::get<uint32_t>(value));
161             break;
162         }
163         case panda_file::LiteralTag::ARRAY_I32:
164         case panda_file::LiteralTag::ARRAY_U32:
165         case panda_file::LiteralTag::ARRAY_F32: {
166             EmplaceLiteralArray<uint32_t>(value, literalArray, file_);
167             break;
168         }
169         case panda_file::LiteralTag::ARRAY_I64:
170         case panda_file::LiteralTag::ARRAY_U64:
171         case panda_file::LiteralTag::ARRAY_F64: {
172             EmplaceLiteralArray<uint64_t>(value, literalArray, file_);
173             break;
174         }
175         case panda_file::LiteralTag::FLOAT: {
176             literalArray.emplace_back(bit_cast<uint32_t>(std::get<float>(value)));
177             break;
178         }
179         case panda_file::LiteralTag::DOUBLE: {
180             literalArray.emplace_back(bit_cast<uint64_t>(std::get<double>(value)));
181             break;
182         }
183         case panda_file::LiteralTag::STRING: {
184             EmplaceLiteralString(value, literalArray, file_, container_);
185             break;
186         }
187         case panda_file::LiteralTag::ARRAY_STRING: {
188             EmplaceLiteralArrayString(value, literalArray, file_, container_);
189             break;
190         }
191         case panda_file::LiteralTag::METHOD:
192         case panda_file::LiteralTag::GENERATORMETHOD:
193         case panda_file::LiteralTag::ASYNCMETHOD:
194         case panda_file::LiteralTag::ASYNCGENERATORMETHOD: {
195             File::EntityId methodId(std::get<uint32_t>(value));
196             MethodDataAccessor methodAcc(*file_, methodId);
197             File::EntityId classId(methodAcc.GetClassId());
198             auto *classItem = CreateClassItem(classId);
199             literalArray.emplace_back(CreateMethodItem(classItem, methodId));
200             break;
201         }
202         default:
203             UNREACHABLE();
204     }
205 }
206 
207 /* static */
CreateLiteralArrayItem(LiteralDataAccessor *litArrayAccessor, File::EntityId arrayId, uint32_t index)208 bool FileReader::CreateLiteralArrayItem(LiteralDataAccessor *litArrayAccessor, File::EntityId arrayId, uint32_t index)
209 {
210     auto it = itemsDone_.find(arrayId);
211     if (it != itemsDone_.end()) {
212         return true;
213     }
214 
215     LiteralArrayItem *item = container_.GetOrCreateLiteralArrayItem(std::to_string(index));
216     itemsDone_.insert({arrayId, static_cast<BaseItem *>(item)});
217 
218     std::vector<panda_file::LiteralItem> literalArray;
219 
220     litArrayAccessor->EnumerateLiteralVals(
221         arrayId, [&literalArray, this](const panda_file::LiteralDataAccessor::LiteralValue &value,
222                                        const panda_file::LiteralTag &tag) {
223             this->EmplaceLiteralVals(literalArray, value, tag);
224         });
225 
226     item->AddItems(literalArray);
227 
228     return true;
229 }
230 
231 template <typename T>
GeneratePrimitiveItemLesserInt32(AnnotationDataAccessor::Elem &annElem, ItemContainer &container, ark::panda_file::Type::TypeId typeId)232 static ValueItem *GeneratePrimitiveItemLesserInt32(AnnotationDataAccessor::Elem &annElem, ItemContainer &container,
233                                                    ark::panda_file::Type::TypeId typeId)
234 {
235     auto array = annElem.GetArrayValue();
236     std::vector<ScalarValueItem> items;
237     for (size_t j = 0; j < array.GetCount(); j++) {
238         ScalarValueItem scalar(static_cast<uint32_t>(array.Get<T>(j)));
239         items.emplace_back(std::move(scalar));
240     }
241     return static_cast<ValueItem *>(container.CreateItem<ArrayValueItem>(Type(typeId), std::move(items)));
242 }
243 
244 template <typename T>
GeneratePrimitiveItem(AnnotationDataAccessor::Elem &annElem, ItemContainer &container, ark::panda_file::Type::TypeId typeId)245 static ValueItem *GeneratePrimitiveItem(AnnotationDataAccessor::Elem &annElem, ItemContainer &container,
246                                         ark::panda_file::Type::TypeId typeId)
247 {
248     auto array = annElem.GetArrayValue();
249     std::vector<ScalarValueItem> items;
250     for (size_t j = 0; j < array.GetCount(); j++) {
251         ScalarValueItem scalar(array.Get<T>(j));
252         items.emplace_back(std::move(scalar));
253     }
254     return static_cast<ValueItem *>(container.CreateItem<ArrayValueItem>(Type(typeId), std::move(items)));
255 }
256 
257 // CC-OFFNXT(G.FUN.01-CPP, huge_cyclomatic_complexity[C++], huge_method[C++]) big switch case
258 // NOLINTNEXTLINE(readability-function-size)
SetElemValueItem(AnnotationDataAccessor::Tag &annTag, AnnotationDataAccessor::Elem &annElem)259 ValueItem *FileReader::SetElemValueItem(AnnotationDataAccessor::Tag &annTag, AnnotationDataAccessor::Elem &annElem)
260 {
261     switch (annTag.GetItem()) {
262         case '1':
263         case '2':
264         case '3': {
265             auto scalar = annElem.GetScalarValue();
266             return container_.GetOrCreateIntegerValueItem(scalar.Get<uint8_t>());
267         }
268         case '4':
269         case '5': {
270             auto scalar = annElem.GetScalarValue();
271             return container_.GetOrCreateIntegerValueItem(scalar.Get<uint16_t>());
272         }
273         case '6':
274         case '7': {
275             auto scalar = annElem.GetScalarValue();
276             return container_.GetOrCreateIntegerValueItem(scalar.Get<uint32_t>());
277         }
278         case '8':
279         case '9': {
280             auto scalar = annElem.GetScalarValue();
281             return container_.GetOrCreateLongValueItem(scalar.Get<uint64_t>());
282         }
283         case 'A': {
284             auto scalar = annElem.GetScalarValue();
285             return container_.GetOrCreateFloatValueItem(scalar.Get<float>());
286         }
287         case 'B': {
288             auto scalar = annElem.GetScalarValue();
289             return container_.GetOrCreateDoubleValueItem(scalar.Get<double>());
290         }
291         case 'C': {
292             auto scalar = annElem.GetScalarValue();
293             const File::EntityId strId(scalar.Get<uint32_t>());
294             auto data = file_->GetStringData(strId);
295             std::string itemStr(utf::Mutf8AsCString(data.data));
296             auto *strItem = container_.GetOrCreateStringItem(itemStr);
297             return container_.GetOrCreateIdValueItem(strItem);
298         }
299         case 'D': {
300             auto scalar = annElem.GetScalarValue();
301             const File::EntityId classId {scalar.Get<uint32_t>()};
302             return container_.GetOrCreateIdValueItem(CreateGenericClassItem(classId));
303         }
304         case 'E': {
305             auto scalar = annElem.GetScalarValue();
306             const File::EntityId methodId {scalar.Get<uint32_t>()};
307             MethodDataAccessor methodAcc(*file_, methodId);
308             auto *clsItem = CreateGenericClassItem(methodAcc.GetClassId());
309             return container_.GetOrCreateIdValueItem(CreateGenericMethodItem(clsItem, methodId));
310         }
311         case 'F': {
312             auto scalar = annElem.GetScalarValue();
313             const File::EntityId fieldId {scalar.Get<uint32_t>()};
314             FieldDataAccessor fieldAcc(*file_, fieldId);
315             auto *clsItem = CreateGenericClassItem(fieldAcc.GetClassId());
316             return container_.GetOrCreateIdValueItem(CreateGenericFieldItem(clsItem, fieldId));
317         }
318         case 'G': {
319             auto scalar = annElem.GetScalarValue();
320             const File::EntityId annItemId {scalar.Get<uint32_t>()};
321             return container_.GetOrCreateIdValueItem(CreateAnnotationItem(annItemId));
322         }
323         case 'J': {
324             LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far";
325             break;
326         }
327         case '*': {
328             return container_.GetOrCreateIntegerValueItem(0);
329         }
330         case 'K': {
331             return GeneratePrimitiveItemLesserInt32<uint8_t>(annElem, container_, Type::TypeId::U1);
332         }
333         case 'L': {
334             return GeneratePrimitiveItemLesserInt32<uint8_t>(annElem, container_, Type::TypeId::I8);
335         }
336         case 'M': {
337             return GeneratePrimitiveItemLesserInt32<uint8_t>(annElem, container_, Type::TypeId::U8);
338         }
339         case 'N': {
340             return GeneratePrimitiveItemLesserInt32<uint16_t>(annElem, container_, Type::TypeId::I16);
341         }
342         case 'O': {
343             return GeneratePrimitiveItemLesserInt32<uint16_t>(annElem, container_, Type::TypeId::U16);
344         }
345         case 'P': {
346             return GeneratePrimitiveItem<uint32_t>(annElem, container_, Type::TypeId::I32);
347         }
348         case 'Q': {
349             return GeneratePrimitiveItem<uint32_t>(annElem, container_, Type::TypeId::U32);
350         }
351         case 'R': {
352             return GeneratePrimitiveItem<uint64_t>(annElem, container_, Type::TypeId::I64);
353         }
354         case 'S': {
355             return GeneratePrimitiveItem<uint64_t>(annElem, container_, Type::TypeId::U64);
356         }
357         case 'T': {
358             return GeneratePrimitiveItem<float>(annElem, container_, Type::TypeId::F32);
359         }
360         case 'U': {
361             return GeneratePrimitiveItem<double>(annElem, container_, Type::TypeId::F64);
362         }
363         case 'V': {
364             auto array = annElem.GetArrayValue();
365             std::vector<ScalarValueItem> items;
366             for (size_t j = 0; j < array.GetCount(); j++) {
367                 const File::EntityId strId(array.Get<uint32_t>(j));
368                 auto data = file_->GetStringData(strId);
369                 std::string itemStr(utf::Mutf8AsCString(data.data));
370                 items.emplace_back(ScalarValueItem(container_.GetOrCreateStringItem(itemStr)));
371             }
372             return static_cast<ValueItem *>(
373                 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
374         }
375         case 'W': {
376             auto array = annElem.GetArrayValue();
377             std::vector<ScalarValueItem> items;
378             for (size_t j = 0; j < array.GetCount(); j++) {
379                 const File::EntityId classId {array.Get<uint32_t>(j)};
380                 BaseClassItem *clsItem = nullptr;
381                 if (file_->IsExternal(classId)) {
382                     clsItem = CreateForeignClassItem(classId);
383                 } else {
384                     clsItem = CreateClassItem(classId);
385                 }
386                 ASSERT(clsItem != nullptr);
387                 items.emplace_back(ScalarValueItem(clsItem));
388             }
389             return static_cast<ValueItem *>(
390                 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
391         }
392         case 'X': {
393             auto array = annElem.GetArrayValue();
394             std::vector<ScalarValueItem> items;
395             for (size_t j = 0; j < array.GetCount(); j++) {
396                 const File::EntityId methodId {array.Get<uint32_t>(j)};
397                 MethodDataAccessor methodAcc(*file_, methodId);
398                 auto *clsItem = CreateGenericClassItem(methodAcc.GetClassId());
399                 items.emplace_back(ScalarValueItem(CreateGenericMethodItem(clsItem, methodId)));
400             }
401             return static_cast<ValueItem *>(
402                 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
403         }
404         case 'Y': {
405             auto array = annElem.GetArrayValue();
406             std::vector<ScalarValueItem> items;
407             for (size_t j = 0; j < array.GetCount(); j++) {
408                 const File::EntityId fieldId {array.Get<uint32_t>(j)};
409                 FieldDataAccessor fieldAcc(*file_, fieldId);
410                 auto *clsItem = CreateGenericClassItem(fieldAcc.GetClassId());
411                 items.emplace_back(ScalarValueItem(CreateGenericFieldItem(clsItem, fieldId)));
412             }
413             return static_cast<ValueItem *>(
414                 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
415         }
416         case 'H': {
417             // ARRAY can appear for empty arrays only
418             ASSERT(annElem.GetArrayValue().GetCount() == 0);
419             return static_cast<ValueItem *>(
420                 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::VOID), std::vector<ScalarValueItem>()));
421         }
422         case 'Z': {
423             auto array = annElem.GetArrayValue();
424             std::vector<ScalarValueItem> items;
425             for (size_t j = 0; j < array.GetCount(); j++) {
426                 const File::EntityId annItemId {array.Get<uint32_t>(j)};
427                 items.emplace_back(CreateAnnotationItem(annItemId));
428             }
429             return static_cast<ValueItem *>(
430                 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
431         }
432         case '@': {
433             // NOTE(nsizov): support it
434             LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far";
435             break;
436         }
437             // array
438         case 'I':
439             // VOID(I) and ARRAY(H) value should not appear
440         default:
441             UNREACHABLE();
442     }
443     return nullptr;
444 }
445 
CreateAnnotationItem(File::EntityId annId)446 AnnotationItem *FileReader::CreateAnnotationItem(File::EntityId annId)
447 {
448     auto it = itemsDone_.find(annId);
449     if (it != itemsDone_.end()) {
450         return static_cast<AnnotationItem *>(it->second);
451     }
452 
453     AnnotationDataAccessor annAcc(*file_, annId);
454     File::EntityId annClassId {annAcc.GetClassId()};
455     AnnotationItem *annItem = nullptr;
456 
457     if (!file_->IsExternal(annClassId)) {
458         auto *annClassItem = CreateClassItem(annClassId);
459         annItem = container_.CreateItem<AnnotationItem>(annClassItem, std::vector<AnnotationItem::Elem>(),
460                                                         std::vector<AnnotationItem::Tag>());
461     } else {
462         auto *annClassItem = CreateForeignClassItem(annClassId);
463         annItem = container_.CreateItem<AnnotationItem>(annClassItem, std::vector<AnnotationItem::Elem>(),
464                                                         std::vector<AnnotationItem::Tag>());
465     }
466 
467     ASSERT(annItem != nullptr);
468 
469     itemsDone_.insert({annId, static_cast<BaseItem *>(annItem)});
470 
471     std::vector<AnnotationItem::Elem> itemElements;
472     std::vector<AnnotationItem::Tag> tagElements;
473 
474     for (size_t i = 0; i < annAcc.GetCount(); i++) {
475         AnnotationDataAccessor::Tag annTag = annAcc.GetTag(i);
476         AnnotationDataAccessor::Elem annElem = annAcc.GetElement(i);
477         ValueItem *elemValueItem = SetElemValueItem(annTag, annElem);
478 
479         ASSERT(elemValueItem != nullptr);
480 
481         tagElements.emplace_back(AnnotationItem::Tag(static_cast<char>(annTag.GetItem())));
482         File::EntityId nameId(annElem.GetNameId());
483         std::string annotNameStr(utf::Mutf8AsCString(file_->GetStringData(nameId).data));
484         auto elemNameItem = container_.GetOrCreateStringItem(annotNameStr);
485         itemElements.emplace_back(AnnotationItem::Elem(elemNameItem, elemValueItem));
486     }
487 
488     annItem->SetElements(std::move(itemElements));
489     annItem->SetTags(std::move(tagElements));
490 
491     return annItem;
492 }
493 
CreateParamTypeItem(ProtoDataAccessor *protoAcc, size_t paramNum, size_t referenceNum)494 TypeItem *FileReader::CreateParamTypeItem(ProtoDataAccessor *protoAcc, size_t paramNum, size_t referenceNum)
495 {
496     Type paramType = protoAcc->GetArgType(paramNum);
497     TypeItem *paramTypeItem = nullptr;
498     if (paramType.IsPrimitive()) {
499         paramTypeItem = container_.GetOrCreatePrimitiveTypeItem(paramType);
500     } else {
501         const File::EntityId typeClsId = protoAcc->GetReferenceType(referenceNum);
502         if (file_->IsExternal(typeClsId)) {
503             paramTypeItem = CreateForeignClassItem(typeClsId);
504         } else {
505             paramTypeItem = CreateClassItem(typeClsId);
506         }
507     }
508 
509     ASSERT(paramTypeItem != nullptr);
510 
511     return paramTypeItem;
512 }
513 
CreateMethodParamItems(ProtoDataAccessor *protoAcc, MethodDataAccessor *methodAcc, size_t referenceNum)514 std::vector<MethodParamItem> FileReader::CreateMethodParamItems(ProtoDataAccessor *protoAcc,
515                                                                 MethodDataAccessor *methodAcc, size_t referenceNum)
516 {
517     std::vector<MethodParamItem> paramItems;
518 
519     for (size_t i = 0; i < protoAcc->GetNumArgs(); i++) {
520         TypeItem *paramTypeItem = CreateParamTypeItem(protoAcc, i, referenceNum);
521         if (paramTypeItem->GetType().IsReference()) {
522             referenceNum++;
523         }
524         paramItems.emplace_back(MethodParamItem(paramTypeItem));
525     }
526 
527     auto paramAnnId = methodAcc->GetParamAnnotationId();
528     if (paramAnnId) {
529         ParamAnnotationsDataAccessor paramAcc(*file_, paramAnnId.value());
530         for (size_t i = 0; i < protoAcc->GetNumArgs(); i++) {
531             ParamAnnotationsDataAccessor::AnnotationArray annArr = paramAcc.GetAnnotationArray(i);
532             annArr.EnumerateAnnotations([this, &paramItems, &i](File::EntityId annId) {
533                 auto annItem = CreateAnnotationItem(annId);
534                 paramItems[i].AddAnnotation(annItem);
535             });
536         }
537     }
538 
539     auto runtimeParamAnnId = methodAcc->GetRuntimeParamAnnotationId();
540     if (runtimeParamAnnId) {
541         ParamAnnotationsDataAccessor paramAcc(*file_, runtimeParamAnnId.value());
542         for (size_t i = 0; i < protoAcc->GetNumArgs(); i++) {
543             ParamAnnotationsDataAccessor::AnnotationArray annArr = paramAcc.GetAnnotationArray(i);
544             annArr.EnumerateAnnotations([this, &paramItems, &i](File::EntityId annId) {
545                 auto annItem = CreateAnnotationItem(annId);
546                 paramItems[i].AddRuntimeAnnotation(annItem);
547             });
548         }
549     }
550 
551     return paramItems;
552 }
553 
CreateDebugInfoItem(File::EntityId debugInfoId)554 DebugInfoItem *FileReader::CreateDebugInfoItem(File::EntityId debugInfoId)
555 {
556     auto it = itemsDone_.find(debugInfoId);
557     if (it != itemsDone_.end()) {
558         return static_cast<DebugInfoItem *>(it->second);
559     }
560 
561     panda_file::DebugInfoDataAccessor debugAcc(*file_, debugInfoId);
562 
563     const auto lnpId = file_->GetIdFromPointer(debugAcc.GetLineNumberProgram());
564 
565     LineNumberProgramItem *lnpItem;
566 
567     if (auto oldLnp = itemsDone_.find(lnpId); oldLnp != itemsDone_.end()) {
568         ASSERT(oldLnp->second->GetItemType() == ItemTypes::LINE_NUMBER_PROGRAM_ITEM);
569         lnpItem = static_cast<LineNumberProgramItem *>(oldLnp->second);
570         container_.IncRefLineNumberProgramItem(lnpItem);
571     } else {
572         lnpItem = container_.CreateLineNumberProgramItem();
573         itemsDone_.emplace(lnpId, lnpItem);
574     }
575 
576     auto *debugInfoItem = container_.CreateItem<DebugInfoItem>(lnpItem);
577     itemsDone_.insert({debugInfoId, static_cast<BaseItem *>(debugInfoItem)});
578 
579     debugInfoItem->SetLineNumber(debugAcc.GetLineStart());
580     debugAcc.EnumerateParameters([this, &debugInfoItem](File::EntityId paramId) {
581         auto data = file_->GetStringData(paramId);
582         std::string itemStr(utf::Mutf8AsCString(data.data));
583         auto *stringItem = container_.GetOrCreateStringItem(itemStr);
584         debugInfoItem->AddParameter(stringItem);
585     });
586 
587     return debugInfoItem;
588 }
589 
GetCatchTypeItem(CodeDataAccessor::CatchBlock &catchBlock, File::EntityId methodId, MethodItem *methodItem)590 BaseClassItem *FileReader::GetCatchTypeItem(CodeDataAccessor::CatchBlock &catchBlock, File::EntityId methodId,
591                                             MethodItem *methodItem)
592 {
593     BaseClassItem *catchTypeItem = nullptr;
594     auto typeIdx = catchBlock.GetTypeIdx();
595     if (typeIdx != panda_file::INVALID_INDEX) {
596         File::EntityId catchClsId = file_->ResolveClassIndex(methodId, catchBlock.GetTypeIdx());
597         if (file_->IsExternal(catchClsId)) {
598             catchTypeItem = CreateForeignClassItem(catchClsId);
599         } else {
600             catchTypeItem = CreateClassItem(catchClsId);
601         }
602         methodItem->AddIndexDependency(catchTypeItem);
603     }
604     return catchTypeItem;
605 }
606 
SetMethodCodeIfPresent(std::optional<File::EntityId> &codeId, MethodItem *methodItem, File::EntityId &methodId)607 void FileReader::SetMethodCodeIfPresent(std::optional<File::EntityId> &codeId, MethodItem *methodItem,
608                                         File::EntityId &methodId)
609 {
610     CodeDataAccessor codeAcc(*file_, codeId.value());
611     std::vector<uint8_t> instructions(codeAcc.GetCodeSize());
612     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
613     instructions.assign(codeAcc.GetInstructions(), codeAcc.GetInstructions() + codeAcc.GetCodeSize());
614     auto *codeItem =
615         container_.CreateItem<CodeItem>(codeAcc.GetNumVregs(), codeAcc.GetNumArgs(), std::move(instructions));
616 
617     codeAcc.EnumerateTryBlocks([this, &methodItem, &methodId, &codeItem](CodeDataAccessor::TryBlock &tryBlock) {
618         std::vector<CodeItem::CatchBlock> catchBlocks;
619         tryBlock.EnumerateCatchBlocks(
620             [this, &methodItem, &methodId, &catchBlocks](CodeDataAccessor::CatchBlock &catchBlock) {
621                 BaseClassItem *catchTypeItem = this->GetCatchTypeItem(catchBlock, methodId, methodItem);
622                 catchBlocks.emplace_back(CodeItem::CatchBlock(methodItem, catchTypeItem, catchBlock.GetHandlerPc(),
623                                                               catchBlock.GetCodeSize()));
624                 return true;
625             });
626         codeItem->AddTryBlock(CodeItem::TryBlock(tryBlock.GetStartPc(), tryBlock.GetLength(), std::move(catchBlocks)));
627         return true;
628     });
629 
630     methodItem->SetCode(codeItem);
631 }
632 
SetRetType(ProtoDataAccessor &protoAcc, size_t &referenceNum)633 TypeItem *FileReader::SetRetType(ProtoDataAccessor &protoAcc, size_t &referenceNum)
634 
635 {
636     Type retType = protoAcc.GetReturnType();
637     TypeItem *retTypeItem = nullptr;
638     if (retType.IsPrimitive()) {
639         retTypeItem = container_.GetOrCreatePrimitiveTypeItem(retType);
640     } else {
641         const File::EntityId typeClsId = protoAcc.GetReferenceType(referenceNum);
642         if (file_->IsExternal(typeClsId)) {
643             retTypeItem = CreateForeignClassItem(typeClsId);
644         } else {
645             retTypeItem = CreateClassItem(typeClsId);
646         }
647         referenceNum++;
648     }
649     return retTypeItem;
650 }
651 
CreateMethodItem(ClassItem *cls, File::EntityId methodId)652 MethodItem *FileReader::CreateMethodItem(ClassItem *cls, File::EntityId methodId)
653 {
654     auto it = itemsDone_.find(methodId);
655     if (it != itemsDone_.end()) {
656         return static_cast<MethodItem *>(it->second);
657     }
658 
659     MethodDataAccessor methodAcc(*file_, methodId);
660     auto data = file_->GetStringData(methodAcc.GetNameId());
661     std::string methodName(utf::Mutf8AsCString(data.data));
662     auto *methodStrItem = container_.GetOrCreateStringItem(methodName);
663 
664     ProtoDataAccessor protoAcc(*file_, methodAcc.GetProtoId());
665     size_t referenceNum = 0;
666     TypeItem *retTypeItem = SetRetType(protoAcc, referenceNum);
667     ASSERT(retTypeItem != nullptr);
668     auto paramItems = CreateMethodParamItems(&protoAcc, &methodAcc, referenceNum);
669     // Double check if we done this method while computing params
670     auto itCheck = itemsDone_.find(methodId);
671     if (itCheck != itemsDone_.end()) {
672         return static_cast<MethodItem *>(itCheck->second);
673     }
674     auto *protoItem = container_.GetOrCreateProtoItem(retTypeItem, paramItems);
675 
676     auto *methodItem = cls->AddMethod(methodStrItem, protoItem, methodAcc.GetAccessFlags(), std::move(paramItems));
677 
678     if (methodItem->HasRuntimeParamAnnotations()) {
679         container_.CreateItem<ParamAnnotationsItem>(methodItem, true);
680     }
681 
682     if (methodItem->HasParamAnnotations()) {
683         container_.CreateItem<ParamAnnotationsItem>(methodItem, false);
684     }
685 
686     itemsDone_.insert({methodId, static_cast<BaseItem *>(methodItem)});
687 
688     methodAcc.EnumerateAnnotations(
689         [this, &methodItem](File::EntityId annId) { methodItem->AddAnnotation(CreateAnnotationItem(annId)); });
690 
691     methodAcc.EnumerateRuntimeAnnotations(
692         [this, &methodItem](File::EntityId annId) { methodItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
693 
694     methodAcc.EnumerateTypeAnnotations(
695         [this, &methodItem](File::EntityId annId) { methodItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
696 
697     methodAcc.EnumerateRuntimeTypeAnnotations([this, &methodItem](File::EntityId annId) {
698         methodItem->AddRuntimeTypeAnnotation(CreateAnnotationItem(annId));
699     });
700 
701     auto codeId = methodAcc.GetCodeId();
702     if (codeId) {
703         SetMethodCodeIfPresent(codeId, methodItem, methodId);
704     }
705 
706     auto debugInfoId = methodAcc.GetDebugInfoId();
707     if (debugInfoId) {
708         methodItem->SetDebugInfo(CreateDebugInfoItem(debugInfoId.value()));
709     }
710 
711     auto sourceLang = methodAcc.GetSourceLang();
712     if (sourceLang) {
713         methodItem->SetSourceLang(sourceLang.value());
714     }
715 
716     return methodItem;
717 }
718 
CreateMethodHandleItem(File::EntityId mhId)719 MethodHandleItem *FileReader::CreateMethodHandleItem(File::EntityId mhId)
720 {
721     (void)mhId;
722     ASSERT(false);
723     return nullptr;  // STUB
724 }
725 
SetFieldValue(FieldItem *fieldItem, Type fieldType, FieldDataAccessor &fieldAcc)726 void FileReader::SetFieldValue(FieldItem *fieldItem, Type fieldType, FieldDataAccessor &fieldAcc)
727 {
728     switch (fieldType.GetId()) {
729         case Type::TypeId::U1:
730         case Type::TypeId::I8:
731         case Type::TypeId::U8:
732             SetIntegerFieldValue<uint8_t>(&fieldAcc, fieldItem);
733             break;
734         case Type::TypeId::I16:
735         case Type::TypeId::U16:
736             SetIntegerFieldValue<uint16_t>(&fieldAcc, fieldItem);
737             break;
738         case Type::TypeId::I32:
739         case Type::TypeId::U32:
740             SetIntegerFieldValue<uint32_t>(&fieldAcc, fieldItem);
741             break;
742         case Type::TypeId::I64:
743         case Type::TypeId::U64:
744             SetIntegerFieldValue<uint64_t>(&fieldAcc, fieldItem);
745             break;
746         case Type::TypeId::F32:
747             SetFloatFieldValue<float>(&fieldAcc, fieldItem);
748             break;
749         case Type::TypeId::F64:
750             SetFloatFieldValue<double>(&fieldAcc, fieldItem);
751             break;
752         case Type::TypeId::REFERENCE:
753             SetStringFieldValue(&fieldAcc, fieldItem);
754             break;
755         case Type::TypeId::TAGGED:
756         default:
757             UNREACHABLE();
758             break;
759     }
760 }
761 
CreateFieldItem(ClassItem *cls, File::EntityId fieldId)762 FieldItem *FileReader::CreateFieldItem(ClassItem *cls, File::EntityId fieldId)
763 {
764     auto it = itemsDone_.find(fieldId);
765     if (it != itemsDone_.end()) {
766         return static_cast<FieldItem *>(it->second);
767     }
768 
769     FieldDataAccessor fieldAcc(*file_, fieldId);
770 
771     auto data = file_->GetStringData(fieldAcc.GetNameId());
772     std::string stringName(utf::Mutf8AsCString(data.data));
773     auto *fieldName = container_.GetOrCreateStringItem(stringName);
774     Type fieldType = Type::GetTypeFromFieldEncoding(fieldAcc.GetType());
775 
776     TypeItem *fieldTypeItem = nullptr;
777     if (fieldType.IsReference()) {
778         File::EntityId typeId(fieldAcc.GetType());
779         if (file_->IsExternal(typeId)) {
780             fieldTypeItem = CreateForeignClassItem(typeId);
781         } else {
782             fieldTypeItem = CreateClassItem(typeId);
783             // Double check if we done this field while generated class item
784             auto itCheck = itemsDone_.find(fieldId);
785             if (itCheck != itemsDone_.end()) {
786                 return static_cast<FieldItem *>(itCheck->second);
787             }
788         }
789     } else {
790         fieldTypeItem = container_.GetOrCreatePrimitiveTypeItem(fieldType.GetId());
791     }
792 
793     ASSERT(fieldTypeItem != nullptr);
794 
795     FieldItem *fieldItem = cls->AddField(fieldName, fieldTypeItem, fieldAcc.GetAccessFlags());
796     itemsDone_.insert({fieldId, static_cast<BaseItem *>(fieldItem)});
797 
798     SetFieldValue(fieldItem, fieldType, fieldAcc);
799 
800     fieldAcc.EnumerateAnnotations(
801         [this, &fieldItem](File::EntityId annId) { fieldItem->AddAnnotation(CreateAnnotationItem(annId)); });
802 
803     fieldAcc.EnumerateRuntimeAnnotations(
804         [this, &fieldItem](File::EntityId annId) { fieldItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
805 
806     fieldAcc.EnumerateRuntimeTypeAnnotations(
807         [this, &fieldItem](File::EntityId annId) { fieldItem->AddRuntimeTypeAnnotation(CreateAnnotationItem(annId)); });
808 
809     fieldAcc.EnumerateTypeAnnotations(
810         [this, &fieldItem](File::EntityId annId) { fieldItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
811 
812     return fieldItem;
813 }
814 
CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId methodId)815 ForeignMethodItem *FileReader::CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId methodId)
816 {
817     auto it = itemsDone_.find(methodId);
818     if (it != itemsDone_.end()) {
819         return static_cast<ForeignMethodItem *>(it->second);
820     }
821 
822     MethodDataAccessor methodAcc(*file_, methodId);
823     auto data = file_->GetStringData(methodAcc.GetNameId());
824     std::string methodName(utf::Mutf8AsCString(data.data));
825     auto *methodStrItem = container_.GetOrCreateStringItem(methodName);
826 
827     ProtoDataAccessor protoAcc(*file_, methodAcc.GetProtoId());
828     Type retType = protoAcc.GetReturnType();
829     size_t referenceNum = 0;
830     TypeItem *retTypeItem = nullptr;
831     if (retType.IsPrimitive()) {
832         retTypeItem = container_.GetOrCreatePrimitiveTypeItem(retType);
833     } else {
834         const File::EntityId typeClsId = protoAcc.GetReferenceType(referenceNum);
835         if (file_->IsExternal(typeClsId)) {
836             retTypeItem = CreateForeignClassItem(typeClsId);
837         } else {
838             retTypeItem = CreateClassItem(typeClsId);
839         }
840         referenceNum++;
841     }
842     ASSERT(retTypeItem != nullptr);
843     auto paramItems = CreateMethodParamItems(&protoAcc, &methodAcc, referenceNum);
844     // Double check if we done this method while computing params
845     auto itCheck = itemsDone_.find(methodId);
846     if (itCheck != itemsDone_.end()) {
847         return static_cast<ForeignMethodItem *>(itCheck->second);
848     }
849     auto *protoItem = container_.GetOrCreateProtoItem(retTypeItem, paramItems);
850 
851     auto *methodItem =
852         container_.CreateItem<ForeignMethodItem>(fcls, methodStrItem, protoItem, methodAcc.GetAccessFlags());
853 
854     itemsDone_.insert({methodId, static_cast<BaseItem *>(methodItem)});
855 
856     return methodItem;
857 }
858 
CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId fieldId)859 ForeignFieldItem *FileReader::CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId fieldId)
860 {
861     auto it = itemsDone_.find(fieldId);
862     if (it != itemsDone_.end()) {
863         return static_cast<ForeignFieldItem *>(it->second);
864     }
865 
866     FieldDataAccessor fieldAcc(*file_, fieldId);
867 
868     auto data = file_->GetStringData(fieldAcc.GetNameId());
869     std::string stringName(utf::Mutf8AsCString(data.data));
870     auto *fieldName = container_.GetOrCreateStringItem(stringName);
871     Type fieldType = Type::GetTypeFromFieldEncoding(fieldAcc.GetType());
872     TypeItem *fieldTypeItem = nullptr;
873     if (fieldType.IsReference()) {
874         File::EntityId typeId(fieldAcc.GetType());
875         if (file_->IsExternal(typeId)) {
876             fieldTypeItem = CreateForeignClassItem(typeId);
877         } else {
878             fieldTypeItem = CreateClassItem(typeId);
879             // Double check if we done this field while generated class item
880             auto itCheck = itemsDone_.find(fieldId);
881             if (itCheck != itemsDone_.end()) {
882                 return static_cast<ForeignFieldItem *>(itCheck->second);
883             }
884         }
885     } else {
886         fieldTypeItem = container_.GetOrCreatePrimitiveTypeItem(fieldType.GetId());
887     }
888 
889     ASSERT(fieldTypeItem != nullptr);
890 
891     auto *fieldItem = container_.CreateItem<ForeignFieldItem>(fcls, fieldName, fieldTypeItem);
892     itemsDone_.insert({fieldId, static_cast<BaseItem *>(fieldItem)});
893 
894     return fieldItem;
895 }
896 
CreateForeignClassItem(File::EntityId classId)897 ForeignClassItem *FileReader::CreateForeignClassItem(File::EntityId classId)
898 {
899     auto it = itemsDone_.find(classId);
900     if (it != itemsDone_.end()) {
901         return static_cast<ForeignClassItem *>(it->second);
902     }
903 
904     std::string className(utf::Mutf8AsCString(file_->GetStringData(classId).data));
905     auto *classItem = container_.GetOrCreateForeignClassItem(className);
906 
907     itemsDone_.insert({classId, static_cast<BaseItem *>(classItem)});
908 
909     return classItem;
910 }
911 
CreateClassItem(File::EntityId classId)912 ClassItem *FileReader::CreateClassItem(File::EntityId classId)
913 {
914     auto it = itemsDone_.find(classId);
915     if (it != itemsDone_.end()) {
916         return static_cast<ClassItem *>(it->second);
917     }
918     ClassDataAccessor classAcc(*file_, classId);
919 
920     std::string className(utf::Mutf8AsCString(file_->GetStringData(classId).data));
921     auto *classItem = container_.GetOrCreateClassItem(className);
922 
923     itemsDone_.insert({classId, static_cast<BaseItem *>(classItem)});
924 
925     classItem->SetAccessFlags(classAcc.GetAccessFlags());
926 
927     auto sourceLangOpt = classAcc.GetSourceLang();
928     if (sourceLangOpt) {
929         classItem->SetSourceLang(sourceLangOpt.value());
930     }
931 
932     auto superClassId = classAcc.GetSuperClassId();
933     if (superClassId.GetOffset() != 0) {
934         if (superClassId.GetOffset() == classId.GetOffset()) {
935             LOG(FATAL, PANDAFILE) << "Class " << className << " has cyclic inheritance";
936         }
937 
938         if (file_->IsExternal(superClassId)) {
939             classItem->SetSuperClass(CreateForeignClassItem(superClassId));
940         } else {
941             classItem->SetSuperClass(CreateClassItem(superClassId));
942         }
943     }
944 
945     classAcc.EnumerateInterfaces([this, &classItem](File::EntityId ifaceId) {
946         if (file_->IsExternal(ifaceId)) {
947             classItem->AddInterface(CreateForeignClassItem(ifaceId));
948         } else {
949             classItem->AddInterface(CreateClassItem(ifaceId));
950         }
951     });
952 
953     classAcc.EnumerateAnnotations(
954         [this, &classItem](File::EntityId annId) { classItem->AddAnnotation(CreateAnnotationItem(annId)); });
955 
956     classAcc.EnumerateRuntimeAnnotations(
957         [this, &classItem](File::EntityId annId) { classItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
958 
959     classAcc.EnumerateTypeAnnotations(
960         [this, &classItem](File::EntityId annId) { classItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
961 
962     classAcc.EnumerateFields(
963         [this, &classItem](FieldDataAccessor &fieldAcc) { CreateFieldItem(classItem, fieldAcc.GetFieldId()); });
964 
965     classAcc.EnumerateMethods(
966         [this, &classItem](MethodDataAccessor &methodAcc) { CreateMethodItem(classItem, methodAcc.GetMethodId()); });
967 
968     auto sourceFileId = classAcc.GetSourceFileId();
969     if (sourceFileId) {
970         std::string sourceFile = utf::Mutf8AsCString(file_->GetStringData(sourceFileId.value()).data);
971         classItem->SetSourceFile(container_.GetOrCreateStringItem(sourceFile));
972     }
973 
974     ASSERT(classItem != nullptr);
975 
976     return classItem;
977 }
978 
ReadLiteralArrayItems()979 bool FileReader::ReadLiteralArrayItems()
980 {
981     const auto litArraysId = file_->GetLiteralArraysId();
982     LiteralDataAccessor litArrayAccessor(*file_, litArraysId);
983     size_t numLitarrays = litArrayAccessor.GetLiteralNum();
984 
985     for (size_t i = 0; i < numLitarrays; i++) {
986         auto id = litArrayAccessor.GetLiteralArrayId(i);
987         if (!CreateLiteralArrayItem(&litArrayAccessor, id, i)) {
988             return false;
989         }
990     }
991 
992     return true;
993 }
994 
TryCreateMethodItem(File::EntityId methodId)995 bool FileReader::TryCreateMethodItem(File::EntityId methodId)
996 {
997     MethodDataAccessor methodAcc(*file_, methodId);
998     File::EntityId classId(methodAcc.GetClassId());
999     if (file_->IsExternal(classId)) {
1000         auto *fclassItem = CreateForeignClassItem(classId);
1001         ASSERT(file_->IsExternal(methodId));
1002         if (CreateForeignMethodItem(fclassItem, methodId) == nullptr) {
1003             return false;
1004         }
1005     } else {
1006         auto *classItem = CreateClassItem(classId);
1007         if (file_->IsExternal(methodId)) {
1008             if (CreateForeignMethodItem(classItem, methodId) == nullptr) {
1009                 return false;
1010             }
1011         } else if (CreateMethodItem(classItem, methodId) == nullptr) {
1012             return false;
1013         }
1014     }
1015 
1016     return true;
1017 }
1018 
TryCreateFieldItem(File::EntityId fieldId)1019 bool FileReader::TryCreateFieldItem(File::EntityId fieldId)
1020 {
1021     FieldDataAccessor fieldAcc(*file_, fieldId);
1022     File::EntityId classId(fieldAcc.GetClassId());
1023     if (file_->IsExternal(classId)) {
1024         ASSERT(file_->IsExternal(fieldId));
1025         auto *fclassItem = CreateForeignClassItem(fieldAcc.GetClassId());
1026         if (CreateForeignFieldItem(fclassItem, fieldId) == nullptr) {
1027             return false;
1028         }
1029     } else {
1030         auto *classItem = CreateClassItem(fieldAcc.GetClassId());
1031         if (file_->IsExternal(fieldId)) {
1032             if (CreateForeignFieldItem(classItem, fieldId) == nullptr) {
1033                 return false;
1034             }
1035         } else if (CreateFieldItem(classItem, fieldId) == nullptr) {
1036             return false;
1037         }
1038     }
1039 
1040     return true;
1041 }
1042 
ReadRegionHeaders()1043 bool FileReader::ReadRegionHeaders()
1044 {
1045     auto indexHeaders = file_->GetRegionHeaders();
1046     for (const auto &header : indexHeaders) {
1047         auto methodIndex = file_->GetMethodIndex(&header);
1048         for (auto methodId : methodIndex) {
1049             if (!TryCreateMethodItem(methodId)) {
1050                 return false;
1051             }
1052         }
1053         auto fieldIndex = file_->GetFieldIndex(&header);
1054         for (auto fieldId : fieldIndex) {
1055             if (!TryCreateFieldItem(fieldId)) {
1056                 return false;
1057             }
1058         }
1059     }
1060     return true;
1061 }
1062 
ReadClasses()1063 bool FileReader::ReadClasses()
1064 {
1065     const auto classIdx = file_->GetClasses();
1066 
1067     for (unsigned int id : classIdx) {
1068         File::EntityId eid(id);
1069         if (file_->IsExternal(eid)) {
1070             CreateForeignClassItem(eid);
1071         } else {
1072             CreateClassItem(eid);
1073         }
1074     }
1075 
1076     return true;
1077 }
1078 
UpdateDebugInfoDependecies(File::EntityId debugInfoId)1079 void FileReader::UpdateDebugInfoDependecies(File::EntityId debugInfoId)
1080 {
1081     auto updater = FileReaderDebugInfoUpdater(file_.get(), &container_);
1082     updater.Scrap(debugInfoId);
1083 }
1084 
UpdateDebugInfo(DebugInfoItem *debugInfoItem, File::EntityId debugInfoId)1085 void FileReader::UpdateDebugInfo(DebugInfoItem *debugInfoItem, File::EntityId debugInfoId)
1086 {
1087     auto updater = FileReaderDebugInfoUpdater(file_.get(), &container_);
1088     updater.Emit(debugInfoItem->GetLineNumberProgram(), debugInfoItem->GetConstantPool(), debugInfoId);
1089 }
1090 
InstCheckByFlags(BytecodeInstruction &inst, MethodItem *methodItem, const std::map<BaseItem *, File::EntityId> &reverseDone)1091 void FileReader::InstCheckByFlags(BytecodeInstruction &inst, MethodItem *methodItem,
1092                                   const std::map<BaseItem *, File::EntityId> &reverseDone)
1093 {
1094     using Flags = ark::BytecodeInst<ark::BytecodeInstMode::FAST>::Flags;
1095 
1096     if (inst.HasFlag(Flags::TYPE_ID)) {
1097         BytecodeId bId = inst.GetId();
1098         File::Index idx = bId.AsIndex();
1099         File::EntityId methodId = reverseDone.find(methodItem)->second;
1100         File::EntityId oldId = file_->ResolveClassIndex(methodId, idx);
1101         ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1102         auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1103         methodItem->AddIndexDependency(idxItem);
1104     } else if (inst.HasFlag(Flags::METHOD_ID)) {
1105         BytecodeId bId = inst.GetId();
1106         File::Index idx = bId.AsIndex();
1107         File::EntityId methodId = reverseDone.find(methodItem)->second;
1108         File::EntityId oldId = file_->ResolveMethodIndex(methodId, idx);
1109         ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1110         auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1111         methodItem->AddIndexDependency(idxItem);
1112     } else if (inst.HasFlag(Flags::FIELD_ID)) {
1113         BytecodeId bId = inst.GetId();
1114         File::Index idx = bId.AsIndex();
1115         File::EntityId methodId = reverseDone.find(methodItem)->second;
1116         File::EntityId oldId = file_->ResolveFieldIndex(methodId, idx);
1117         ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1118         auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1119         methodItem->AddIndexDependency(idxItem);
1120     } else if (inst.HasFlag(Flags::STRING_ID)) {
1121         BytecodeId bId = inst.GetId();
1122         File::EntityId oldId = bId.AsFileId();
1123         auto data = file_->GetStringData(oldId);
1124         std::string itemStr(utf::Mutf8AsCString(data.data));
1125         container_.GetOrCreateStringItem(itemStr);
1126     }
1127 }
1128 
UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverseDone)1129 void FileReader::UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverseDone)
1130 {
1131     auto *classMap = container_.GetClassMap();
1132 
1133     // First pass, add dependencies bytecode -> new items
1134     for (const auto &it : *classMap) {
1135         auto *baseClassItem = it.second;
1136         if (baseClassItem->IsForeign()) {
1137             continue;
1138         }
1139         auto *classItem = static_cast<ClassItem *>(baseClassItem);
1140         classItem->VisitMethods([this, &reverseDone](BaseItem *paramItem) {
1141             auto *methodItem = static_cast<MethodItem *>(paramItem);
1142             auto *codeItem = methodItem->GetCode();
1143             if (codeItem == nullptr) {
1144                 return true;
1145             }
1146 
1147             auto *debugInfoItem = methodItem->GetDebugInfo();
1148             if (debugInfoItem != nullptr) {
1149                 UpdateDebugInfoDependecies(reverseDone.find(debugInfoItem)->second);
1150             }
1151 
1152             size_t offset = 0;
1153             BytecodeInstruction inst(codeItem->GetInstructions()->data());
1154             while (offset < codeItem->GetCodeSize()) {
1155                 InstCheckByFlags(inst, methodItem, reverseDone);
1156 
1157                 offset += inst.GetSize();
1158                 inst = inst.GetNext();
1159             }
1160             return true;
1161         });
1162     }
1163 }
1164 
InstUpdateId(CodeItem *codeItem, MethodItem *methodItem, std::map<BaseItem *, File::EntityId> &reverseDone)1165 void FileReader::InstUpdateId(CodeItem *codeItem, MethodItem *methodItem,
1166                               std::map<BaseItem *, File::EntityId> &reverseDone)
1167 {
1168     using Flags = ark::BytecodeInst<ark::BytecodeInstMode::FAST>::Flags;
1169 
1170     size_t offset = 0;
1171     BytecodeInstruction inst(codeItem->GetInstructions()->data());
1172     while (offset < codeItem->GetCodeSize()) {
1173         if (inst.HasFlag(Flags::TYPE_ID)) {
1174             BytecodeId bId = inst.GetId();
1175             File::Index idx = bId.AsIndex();
1176 
1177             File::EntityId methodId = reverseDone.find(methodItem)->second;
1178             File::EntityId oldId = file_->ResolveClassIndex(methodId, idx);
1179             ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1180 
1181             auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1182             uint32_t index = idxItem->GetIndex(methodItem);
1183             inst.UpdateId(BytecodeId(index));
1184         } else if (inst.HasFlag(Flags::METHOD_ID)) {
1185             BytecodeId bId = inst.GetId();
1186             File::Index idx = bId.AsIndex();
1187 
1188             File::EntityId methodId = reverseDone.find(methodItem)->second;
1189             File::EntityId oldId = file_->ResolveMethodIndex(methodId, idx);
1190             ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1191 
1192             auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1193             uint32_t index = idxItem->GetIndex(methodItem);
1194             inst.UpdateId(BytecodeId(index));
1195         } else if (inst.HasFlag(Flags::FIELD_ID)) {
1196             BytecodeId bId = inst.GetId();
1197             File::Index idx = bId.AsIndex();
1198 
1199             File::EntityId methodId = reverseDone.find(methodItem)->second;
1200             File::EntityId oldId = file_->ResolveFieldIndex(methodId, idx);
1201             ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1202 
1203             auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1204             uint32_t index = idxItem->GetIndex(methodItem);
1205             inst.UpdateId(BytecodeId(index));
1206         } else if (inst.HasFlag(Flags::STRING_ID)) {
1207             BytecodeId bId = inst.GetId();
1208             File::EntityId oldId = bId.AsFileId();
1209             auto data = file_->GetStringData(oldId);
1210 
1211             std::string itemStr(utf::Mutf8AsCString(data.data));
1212             auto *stringItem = container_.GetOrCreateStringItem(itemStr);
1213             inst.UpdateId(BytecodeId(stringItem->GetFileId().GetOffset()));
1214         }
1215 
1216         offset += inst.GetSize();
1217         inst = inst.GetNext();
1218     }
1219 }
1220 
ComputeLayoutAndUpdateIndices()1221 void FileReader::ComputeLayoutAndUpdateIndices()
1222 {
1223     std::map<BaseItem *, File::EntityId> reverseDone;
1224     for (const auto &it : itemsDone_) {
1225         reverseDone.insert({it.second, it.first});
1226     }
1227 
1228     auto *classMap = container_.GetClassMap();
1229 
1230     UpdateCodeAndDebugInfoDependencies(reverseDone);
1231 
1232     container_.ComputeLayout();
1233 
1234     // Second pass, update debug info
1235     for (const auto &it : *classMap) {
1236         auto *baseClassItem = it.second;
1237         if (baseClassItem->IsForeign()) {
1238             continue;
1239         }
1240         auto *classItem = static_cast<ClassItem *>(baseClassItem);
1241         classItem->VisitMethods([this, &reverseDone](BaseItem *paramItem) {
1242             auto *methodItem = static_cast<MethodItem *>(paramItem);
1243             auto *codeItem = methodItem->GetCode();
1244             if (codeItem == nullptr) {
1245                 return true;
1246             }
1247 
1248             auto *debugInfoItem = methodItem->GetDebugInfo();
1249             if (debugInfoItem != nullptr) {
1250                 UpdateDebugInfo(debugInfoItem, reverseDone.find(debugInfoItem)->second);
1251             }
1252 
1253             return true;
1254         });
1255     }
1256 
1257     container_.DeduplicateItems(false);
1258     container_.ComputeLayout();
1259 
1260     std::unordered_set<CodeItem *> codeItemsDone;
1261 
1262     // Third pass, update bytecode indices
1263     for (const auto &it : *classMap) {
1264         auto *baseClassItem = it.second;
1265         if (baseClassItem->IsForeign()) {
1266             continue;
1267         }
1268         auto *classItem = static_cast<ClassItem *>(baseClassItem);
1269         classItem->VisitMethods([this, &reverseDone, &codeItemsDone](BaseItem *paramItem) {
1270             auto *methodItem = static_cast<MethodItem *>(paramItem);
1271             auto *codeItem = methodItem->GetCode();
1272 
1273             auto codeIt = codeItemsDone.find(codeItem);
1274             if (codeItem == nullptr || codeIt != codeItemsDone.end()) {
1275                 return true;
1276             }
1277 
1278             InstUpdateId(codeItem, methodItem, reverseDone);
1279 
1280             codeItemsDone.insert(codeItem);
1281 
1282             return true;
1283         });
1284     }
1285 }
1286 
1287 }  // namespace ark::panda_file
1288