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