• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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         auto itemType = it->second->GetBaseItemType();
559         if (itemType != ItemTypes::DEBUG_INFO_ITEM) {
560             LOG(FATAL, PANDAFILE) << "ItemType Error " << static_cast<int>(itemType);
561         }
562         return static_cast<DebugInfoItem *>(it->second);
563     }
564 
565     panda_file::DebugInfoDataAccessor debugAcc(*file_, debugInfoId);
566 
567     const auto lnpId = file_->GetIdFromPointer(debugAcc.GetLineNumberProgram());
568 
569     LineNumberProgramItem *lnpItem;
570 
571     if (auto oldLnp = itemsDone_.find(lnpId); oldLnp != itemsDone_.end()) {
572         ASSERT(oldLnp->second->GetItemType() == ItemTypes::LINE_NUMBER_PROGRAM_ITEM);
573         lnpItem = static_cast<LineNumberProgramItem *>(oldLnp->second);
574         container_.IncRefLineNumberProgramItem(lnpItem);
575     } else {
576         lnpItem = container_.CreateLineNumberProgramItem();
577         itemsDone_.emplace(lnpId, lnpItem);
578     }
579 
580     auto *debugInfoItem = container_.CreateItem<DebugInfoItem>(lnpItem);
581     itemsDone_.insert({debugInfoId, static_cast<BaseItem *>(debugInfoItem)});
582 
583     debugInfoItem->SetLineNumber(debugAcc.GetLineStart());
584     debugAcc.EnumerateParameters([this, &debugInfoItem](File::EntityId paramId) {
585         auto data = file_->GetStringData(paramId);
586         std::string itemStr(utf::Mutf8AsCString(data.data));
587         auto *stringItem = container_.GetOrCreateStringItem(itemStr);
588         debugInfoItem->AddParameter(stringItem);
589     });
590     debugInfoItem->SetBaseItemType(ItemTypes::DEBUG_INFO_ITEM);
591     return debugInfoItem;
592 }
593 
GetCatchTypeItem(CodeDataAccessor::CatchBlock & catchBlock,File::EntityId methodId,MethodItem * methodItem)594 BaseClassItem *FileReader::GetCatchTypeItem(CodeDataAccessor::CatchBlock &catchBlock, File::EntityId methodId,
595                                             MethodItem *methodItem)
596 {
597     BaseClassItem *catchTypeItem = nullptr;
598     auto typeIdx = catchBlock.GetTypeIdx();
599     if (typeIdx != panda_file::INVALID_INDEX) {
600         File::EntityId catchClsId = file_->ResolveClassIndex(methodId, catchBlock.GetTypeIdx());
601         if (file_->IsExternal(catchClsId)) {
602             catchTypeItem = CreateForeignClassItem(catchClsId);
603         } else {
604             catchTypeItem = CreateClassItem(catchClsId);
605         }
606         methodItem->AddIndexDependency(catchTypeItem);
607     }
608     return catchTypeItem;
609 }
610 
SetMethodCodeIfPresent(std::optional<File::EntityId> & codeId,MethodItem * methodItem,File::EntityId & methodId)611 void FileReader::SetMethodCodeIfPresent(std::optional<File::EntityId> &codeId, MethodItem *methodItem,
612                                         File::EntityId &methodId)
613 {
614     CodeDataAccessor codeAcc(*file_, codeId.value());
615     std::vector<uint8_t> instructions(codeAcc.GetCodeSize());
616     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
617     instructions.assign(codeAcc.GetInstructions(), codeAcc.GetInstructions() + codeAcc.GetCodeSize());
618     auto *codeItem =
619         container_.CreateItem<CodeItem>(codeAcc.GetNumVregs(), codeAcc.GetNumArgs(), std::move(instructions));
620 
621     codeAcc.EnumerateTryBlocks([this, &methodItem, &methodId, &codeItem](CodeDataAccessor::TryBlock &tryBlock) {
622         std::vector<CodeItem::CatchBlock> catchBlocks;
623         tryBlock.EnumerateCatchBlocks(
624             [this, &methodItem, &methodId, &catchBlocks](CodeDataAccessor::CatchBlock &catchBlock) {
625                 BaseClassItem *catchTypeItem = this->GetCatchTypeItem(catchBlock, methodId, methodItem);
626                 catchBlocks.emplace_back(CodeItem::CatchBlock(methodItem, catchTypeItem, catchBlock.GetHandlerPc(),
627                                                               catchBlock.GetCodeSize()));
628                 return true;
629             });
630         codeItem->AddTryBlock(CodeItem::TryBlock(tryBlock.GetStartPc(), tryBlock.GetLength(), std::move(catchBlocks)));
631         return true;
632     });
633 
634     methodItem->SetCode(codeItem);
635 }
636 
SetRetType(ProtoDataAccessor & protoAcc,size_t & referenceNum)637 TypeItem *FileReader::SetRetType(ProtoDataAccessor &protoAcc, size_t &referenceNum)
638 
639 {
640     Type retType = protoAcc.GetReturnType();
641     TypeItem *retTypeItem = nullptr;
642     if (retType.IsPrimitive()) {
643         retTypeItem = container_.GetOrCreatePrimitiveTypeItem(retType);
644     } else {
645         const File::EntityId typeClsId = protoAcc.GetReferenceType(referenceNum);
646         if (file_->IsExternal(typeClsId)) {
647             retTypeItem = CreateForeignClassItem(typeClsId);
648         } else {
649             retTypeItem = CreateClassItem(typeClsId);
650         }
651         referenceNum++;
652     }
653     return retTypeItem;
654 }
655 
CreateMethodItem(ClassItem * cls,File::EntityId methodId)656 MethodItem *FileReader::CreateMethodItem(ClassItem *cls, File::EntityId methodId)
657 {
658     auto it = itemsDone_.find(methodId);
659     if (it != itemsDone_.end()) {
660         return static_cast<MethodItem *>(it->second);
661     }
662 
663     MethodDataAccessor methodAcc(*file_, methodId);
664     auto data = file_->GetStringData(methodAcc.GetNameId());
665     std::string methodName(utf::Mutf8AsCString(data.data));
666     auto *methodStrItem = container_.GetOrCreateStringItem(methodName);
667 
668     ProtoDataAccessor protoAcc(*file_, methodAcc.GetProtoId());
669     size_t referenceNum = 0;
670     TypeItem *retTypeItem = SetRetType(protoAcc, referenceNum);
671     ASSERT(retTypeItem != nullptr);
672     auto paramItems = CreateMethodParamItems(&protoAcc, &methodAcc, referenceNum);
673     // Double check if we done this method while computing params
674     auto itCheck = itemsDone_.find(methodId);
675     if (itCheck != itemsDone_.end()) {
676         return static_cast<MethodItem *>(itCheck->second);
677     }
678     auto *protoItem = container_.GetOrCreateProtoItem(retTypeItem, paramItems);
679 
680     auto *methodItem = cls->AddMethod(methodStrItem, protoItem, methodAcc.GetAccessFlags(), std::move(paramItems));
681 
682     if (methodItem->HasRuntimeParamAnnotations()) {
683         container_.CreateItem<ParamAnnotationsItem>(methodItem, true);
684     }
685 
686     if (methodItem->HasParamAnnotations()) {
687         container_.CreateItem<ParamAnnotationsItem>(methodItem, false);
688     }
689 
690     itemsDone_.insert({methodId, static_cast<BaseItem *>(methodItem)});
691 
692     methodAcc.EnumerateAnnotations(
693         [this, &methodItem](File::EntityId annId) { methodItem->AddAnnotation(CreateAnnotationItem(annId)); });
694 
695     methodAcc.EnumerateRuntimeAnnotations(
696         [this, &methodItem](File::EntityId annId) { methodItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
697 
698     methodAcc.EnumerateTypeAnnotations(
699         [this, &methodItem](File::EntityId annId) { methodItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
700 
701     methodAcc.EnumerateRuntimeTypeAnnotations([this, &methodItem](File::EntityId annId) {
702         methodItem->AddRuntimeTypeAnnotation(CreateAnnotationItem(annId));
703     });
704 
705     auto codeId = methodAcc.GetCodeId();
706     if (codeId) {
707         SetMethodCodeIfPresent(codeId, methodItem, methodId);
708     }
709 
710     auto debugInfoId = methodAcc.GetDebugInfoId();
711     if (debugInfoId) {
712         methodItem->SetDebugInfo(CreateDebugInfoItem(debugInfoId.value()));
713     }
714 
715     auto sourceLang = methodAcc.GetSourceLang();
716     if (sourceLang) {
717         methodItem->SetSourceLang(sourceLang.value());
718     }
719 
720     return methodItem;
721 }
722 
CreateMethodHandleItem(File::EntityId mhId)723 MethodHandleItem *FileReader::CreateMethodHandleItem(File::EntityId mhId)
724 {
725     (void)mhId;
726     ASSERT(false);
727     return nullptr;  // STUB
728 }
729 
SetFieldValue(FieldItem * fieldItem,Type fieldType,FieldDataAccessor & fieldAcc)730 void FileReader::SetFieldValue(FieldItem *fieldItem, Type fieldType, FieldDataAccessor &fieldAcc)
731 {
732     switch (fieldType.GetId()) {
733         case Type::TypeId::U1:
734         case Type::TypeId::I8:
735         case Type::TypeId::U8:
736             SetIntegerFieldValue<uint8_t>(&fieldAcc, fieldItem);
737             break;
738         case Type::TypeId::I16:
739         case Type::TypeId::U16:
740             SetIntegerFieldValue<uint16_t>(&fieldAcc, fieldItem);
741             break;
742         case Type::TypeId::I32:
743         case Type::TypeId::U32:
744             SetIntegerFieldValue<uint32_t>(&fieldAcc, fieldItem);
745             break;
746         case Type::TypeId::I64:
747         case Type::TypeId::U64:
748             SetIntegerFieldValue<uint64_t>(&fieldAcc, fieldItem);
749             break;
750         case Type::TypeId::F32:
751             SetFloatFieldValue<float>(&fieldAcc, fieldItem);
752             break;
753         case Type::TypeId::F64:
754             SetFloatFieldValue<double>(&fieldAcc, fieldItem);
755             break;
756         case Type::TypeId::REFERENCE:
757             SetStringFieldValue(&fieldAcc, fieldItem);
758             break;
759         case Type::TypeId::TAGGED:
760         default:
761             UNREACHABLE();
762             break;
763     }
764 }
765 
CreateFieldItem(ClassItem * cls,File::EntityId fieldId)766 FieldItem *FileReader::CreateFieldItem(ClassItem *cls, File::EntityId fieldId)
767 {
768     auto it = itemsDone_.find(fieldId);
769     if (it != itemsDone_.end()) {
770         return static_cast<FieldItem *>(it->second);
771     }
772 
773     FieldDataAccessor fieldAcc(*file_, fieldId);
774 
775     auto data = file_->GetStringData(fieldAcc.GetNameId());
776     std::string stringName(utf::Mutf8AsCString(data.data));
777     auto *fieldName = container_.GetOrCreateStringItem(stringName);
778     Type fieldType = Type::GetTypeFromFieldEncoding(fieldAcc.GetType());
779 
780     TypeItem *fieldTypeItem = nullptr;
781     if (fieldType.IsReference()) {
782         File::EntityId typeId(fieldAcc.GetType());
783         if (file_->IsExternal(typeId)) {
784             fieldTypeItem = CreateForeignClassItem(typeId);
785         } else {
786             fieldTypeItem = CreateClassItem(typeId);
787             // Double check if we done this field while generated class item
788             auto itCheck = itemsDone_.find(fieldId);
789             if (itCheck != itemsDone_.end()) {
790                 return static_cast<FieldItem *>(itCheck->second);
791             }
792         }
793     } else {
794         fieldTypeItem = container_.GetOrCreatePrimitiveTypeItem(fieldType.GetId());
795     }
796 
797     ASSERT(fieldTypeItem != nullptr);
798 
799     FieldItem *fieldItem = cls->AddField(fieldName, fieldTypeItem, fieldAcc.GetAccessFlags());
800     itemsDone_.insert({fieldId, static_cast<BaseItem *>(fieldItem)});
801 
802     SetFieldValue(fieldItem, fieldType, fieldAcc);
803 
804     fieldAcc.EnumerateAnnotations(
805         [this, &fieldItem](File::EntityId annId) { fieldItem->AddAnnotation(CreateAnnotationItem(annId)); });
806 
807     fieldAcc.EnumerateRuntimeAnnotations(
808         [this, &fieldItem](File::EntityId annId) { fieldItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
809 
810     fieldAcc.EnumerateRuntimeTypeAnnotations(
811         [this, &fieldItem](File::EntityId annId) { fieldItem->AddRuntimeTypeAnnotation(CreateAnnotationItem(annId)); });
812 
813     fieldAcc.EnumerateTypeAnnotations(
814         [this, &fieldItem](File::EntityId annId) { fieldItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
815 
816     return fieldItem;
817 }
818 
CreateForeignMethodItem(BaseClassItem * fcls,File::EntityId methodId)819 ForeignMethodItem *FileReader::CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId methodId)
820 {
821     auto it = itemsDone_.find(methodId);
822     if (it != itemsDone_.end()) {
823         return static_cast<ForeignMethodItem *>(it->second);
824     }
825 
826     MethodDataAccessor methodAcc(*file_, methodId);
827     auto data = file_->GetStringData(methodAcc.GetNameId());
828     std::string methodName(utf::Mutf8AsCString(data.data));
829     auto *methodStrItem = container_.GetOrCreateStringItem(methodName);
830 
831     ProtoDataAccessor protoAcc(*file_, methodAcc.GetProtoId());
832     Type retType = protoAcc.GetReturnType();
833     size_t referenceNum = 0;
834     TypeItem *retTypeItem = nullptr;
835     if (retType.IsPrimitive()) {
836         retTypeItem = container_.GetOrCreatePrimitiveTypeItem(retType);
837     } else {
838         const File::EntityId typeClsId = protoAcc.GetReferenceType(referenceNum);
839         if (file_->IsExternal(typeClsId)) {
840             retTypeItem = CreateForeignClassItem(typeClsId);
841         } else {
842             retTypeItem = CreateClassItem(typeClsId);
843         }
844         referenceNum++;
845     }
846     ASSERT(retTypeItem != nullptr);
847     auto paramItems = CreateMethodParamItems(&protoAcc, &methodAcc, referenceNum);
848     // Double check if we done this method while computing params
849     auto itCheck = itemsDone_.find(methodId);
850     if (itCheck != itemsDone_.end()) {
851         return static_cast<ForeignMethodItem *>(itCheck->second);
852     }
853     auto *protoItem = container_.GetOrCreateProtoItem(retTypeItem, paramItems);
854 
855     auto *methodItem =
856         container_.CreateItem<ForeignMethodItem>(fcls, methodStrItem, protoItem, methodAcc.GetAccessFlags());
857 
858     itemsDone_.insert({methodId, static_cast<BaseItem *>(methodItem)});
859 
860     return methodItem;
861 }
862 
CreateForeignFieldItem(BaseClassItem * fcls,File::EntityId fieldId)863 ForeignFieldItem *FileReader::CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId fieldId)
864 {
865     auto it = itemsDone_.find(fieldId);
866     if (it != itemsDone_.end()) {
867         return static_cast<ForeignFieldItem *>(it->second);
868     }
869 
870     FieldDataAccessor fieldAcc(*file_, fieldId);
871 
872     auto data = file_->GetStringData(fieldAcc.GetNameId());
873     std::string stringName(utf::Mutf8AsCString(data.data));
874     auto *fieldName = container_.GetOrCreateStringItem(stringName);
875     Type fieldType = Type::GetTypeFromFieldEncoding(fieldAcc.GetType());
876     TypeItem *fieldTypeItem = nullptr;
877     if (fieldType.IsReference()) {
878         File::EntityId typeId(fieldAcc.GetType());
879         if (file_->IsExternal(typeId)) {
880             fieldTypeItem = CreateForeignClassItem(typeId);
881         } else {
882             fieldTypeItem = CreateClassItem(typeId);
883             // Double check if we done this field while generated class item
884             auto itCheck = itemsDone_.find(fieldId);
885             if (itCheck != itemsDone_.end()) {
886                 return static_cast<ForeignFieldItem *>(itCheck->second);
887             }
888         }
889     } else {
890         fieldTypeItem = container_.GetOrCreatePrimitiveTypeItem(fieldType.GetId());
891     }
892 
893     ASSERT(fieldTypeItem != nullptr);
894 
895     auto *fieldItem =
896         container_.CreateItem<ForeignFieldItem>(fcls, fieldName, fieldTypeItem, fieldAcc.GetAccessFlags());
897     itemsDone_.insert({fieldId, static_cast<BaseItem *>(fieldItem)});
898 
899     return fieldItem;
900 }
901 
CreateForeignClassItem(File::EntityId classId)902 ForeignClassItem *FileReader::CreateForeignClassItem(File::EntityId classId)
903 {
904     auto it = itemsDone_.find(classId);
905     if (it != itemsDone_.end()) {
906         return static_cast<ForeignClassItem *>(it->second);
907     }
908 
909     std::string className(utf::Mutf8AsCString(file_->GetStringData(classId).data));
910     auto *classItem = container_.GetOrCreateForeignClassItem(className);
911 
912     itemsDone_.insert({classId, static_cast<BaseItem *>(classItem)});
913 
914     return classItem;
915 }
916 
CheckAndGetExistingFileItem(File::EntityId id,ItemTypes itemType)917 BaseItem *FileReader::CheckAndGetExistingFileItem(File::EntityId id, ItemTypes itemType)
918 {
919     auto it = itemsDone_.find(id);
920     if (it != itemsDone_.end()) {
921         auto iType = it->second->GetItemType();
922         if (iType != itemType) {
923             LOG(FATAL, PANDAFILE) << ItemTypeToString(itemType) << " ItemType Error " << static_cast<int>(iType);
924         }
925         return it->second;
926     }
927     return nullptr;
928 }
929 
CreateClassItem(File::EntityId classId)930 ClassItem *FileReader::CreateClassItem(File::EntityId classId)
931 {
932     BaseItem *item = CheckAndGetExistingFileItem(classId, ItemTypes::CLASS_ITEM);
933     if (item != nullptr) {
934         return static_cast<ClassItem *>(item);
935     }
936     ClassDataAccessor classAcc(*file_, classId);
937 
938     std::string className(utf::Mutf8AsCString(file_->GetStringData(classId).data));
939     auto *classItem = container_.GetOrCreateClassItem(className);
940 
941     itemsDone_.insert({classId, static_cast<BaseItem *>(classItem)});
942 
943     classItem->SetAccessFlags(classAcc.GetAccessFlags());
944 
945     auto sourceLangOpt = classAcc.GetSourceLang();
946     if (sourceLangOpt) {
947         classItem->SetSourceLang(sourceLangOpt.value());
948     }
949 
950     auto superClassId = classAcc.GetSuperClassId();
951     if (superClassId.GetOffset() != 0) {
952         if (superClassId.GetOffset() == classId.GetOffset()) {
953             LOG(FATAL, PANDAFILE) << "Class " << className << " has cyclic inheritance";
954         }
955 
956         if (file_->IsExternal(superClassId)) {
957             classItem->SetSuperClass(CreateForeignClassItem(superClassId));
958         } else {
959             classItem->SetSuperClass(CreateClassItem(superClassId));
960         }
961     }
962 
963     classAcc.EnumerateInterfaces([this, &classItem](File::EntityId ifaceId) {
964         if (file_->IsExternal(ifaceId)) {
965             classItem->AddInterface(CreateForeignClassItem(ifaceId));
966         } else {
967             classItem->AddInterface(CreateClassItem(ifaceId));
968         }
969     });
970 
971     classAcc.EnumerateAnnotations(
972         [this, &classItem](File::EntityId annId) { classItem->AddAnnotation(CreateAnnotationItem(annId)); });
973 
974     classAcc.EnumerateRuntimeAnnotations(
975         [this, &classItem](File::EntityId annId) { classItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
976 
977     classAcc.EnumerateTypeAnnotations(
978         [this, &classItem](File::EntityId annId) { classItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
979 
980     classAcc.EnumerateFields(
981         [this, &classItem](FieldDataAccessor &fieldAcc) { CreateFieldItem(classItem, fieldAcc.GetFieldId()); });
982 
983     classAcc.EnumerateMethods(
984         [this, &classItem](MethodDataAccessor &methodAcc) { CreateMethodItem(classItem, methodAcc.GetMethodId()); });
985 
986     auto sourceFileId = classAcc.GetSourceFileId();
987     if (sourceFileId) {
988         std::string sourceFile = utf::Mutf8AsCString(file_->GetStringData(sourceFileId.value()).data);
989         classItem->SetSourceFile(container_.GetOrCreateStringItem(sourceFile));
990     }
991 
992     ASSERT(classItem != nullptr);
993 
994     return classItem;
995 }
996 
ReadLiteralArrayItems()997 bool FileReader::ReadLiteralArrayItems()
998 {
999     const auto litArraysId = file_->GetLiteralArraysId();
1000     LiteralDataAccessor litArrayAccessor(*file_, litArraysId);
1001     size_t numLitarrays = litArrayAccessor.GetLiteralNum();
1002 
1003     for (size_t i = 0; i < numLitarrays; i++) {
1004         auto id = litArrayAccessor.GetLiteralArrayId(i);
1005         if (!CreateLiteralArrayItem(&litArrayAccessor, id, i)) {
1006             return false;
1007         }
1008     }
1009 
1010     return true;
1011 }
1012 
TryCreateMethodItem(File::EntityId methodId)1013 bool FileReader::TryCreateMethodItem(File::EntityId methodId)
1014 {
1015     MethodDataAccessor methodAcc(*file_, methodId);
1016     File::EntityId classId(methodAcc.GetClassId());
1017     if (file_->IsExternal(classId)) {
1018         auto *fclassItem = CreateForeignClassItem(classId);
1019         ASSERT(file_->IsExternal(methodId));
1020         if (CreateForeignMethodItem(fclassItem, methodId) == nullptr) {
1021             return false;
1022         }
1023     } else {
1024         auto *classItem = CreateClassItem(classId);
1025         if (file_->IsExternal(methodId)) {
1026             if (CreateForeignMethodItem(classItem, methodId) == nullptr) {
1027                 return false;
1028             }
1029         } else if (CreateMethodItem(classItem, methodId) == nullptr) {
1030             return false;
1031         }
1032     }
1033 
1034     return true;
1035 }
1036 
TryCreateFieldItem(File::EntityId fieldId)1037 bool FileReader::TryCreateFieldItem(File::EntityId fieldId)
1038 {
1039     FieldDataAccessor fieldAcc(*file_, fieldId);
1040     File::EntityId classId(fieldAcc.GetClassId());
1041     if (file_->IsExternal(classId)) {
1042         ASSERT(file_->IsExternal(fieldId));
1043         auto *fclassItem = CreateForeignClassItem(fieldAcc.GetClassId());
1044         if (CreateForeignFieldItem(fclassItem, fieldId) == nullptr) {
1045             return false;
1046         }
1047     } else {
1048         auto *classItem = CreateClassItem(fieldAcc.GetClassId());
1049         if (file_->IsExternal(fieldId)) {
1050             if (CreateForeignFieldItem(classItem, fieldId) == nullptr) {
1051                 return false;
1052             }
1053         } else if (CreateFieldItem(classItem, fieldId) == nullptr) {
1054             return false;
1055         }
1056     }
1057 
1058     return true;
1059 }
1060 
ReadRegionHeaders()1061 bool FileReader::ReadRegionHeaders()
1062 {
1063     auto indexHeaders = file_->GetRegionHeaders();
1064     for (const auto &header : indexHeaders) {
1065         auto methodIndex = file_->GetMethodIndex(&header);
1066         for (auto methodId : methodIndex) {
1067             if (!TryCreateMethodItem(methodId)) {
1068                 return false;
1069             }
1070         }
1071         auto fieldIndex = file_->GetFieldIndex(&header);
1072         for (auto fieldId : fieldIndex) {
1073             if (!TryCreateFieldItem(fieldId)) {
1074                 return false;
1075             }
1076         }
1077     }
1078     return true;
1079 }
1080 
ReadClasses()1081 bool FileReader::ReadClasses()
1082 {
1083     const auto classIdx = file_->GetClasses();
1084 
1085     for (unsigned int id : classIdx) {
1086         File::EntityId eid(id);
1087         if (file_->IsExternal(eid)) {
1088             CreateForeignClassItem(eid);
1089         } else {
1090             CreateClassItem(eid);
1091         }
1092     }
1093 
1094     return true;
1095 }
1096 
UpdateDebugInfoDependecies(File::EntityId debugInfoId)1097 void FileReader::UpdateDebugInfoDependecies(File::EntityId debugInfoId)
1098 {
1099     auto updater = FileReaderDebugInfoUpdater(file_.get(), &container_);
1100     updater.Scrap(debugInfoId);
1101 }
1102 
UpdateDebugInfo(DebugInfoItem * debugInfoItem,File::EntityId debugInfoId)1103 void FileReader::UpdateDebugInfo(DebugInfoItem *debugInfoItem, File::EntityId debugInfoId)
1104 {
1105     auto updater = FileReaderDebugInfoUpdater(file_.get(), &container_);
1106     updater.Emit(debugInfoItem->GetLineNumberProgram(), debugInfoItem->GetConstantPool(), debugInfoId);
1107 }
1108 
InstCheckByFlags(BytecodeInstruction & inst,MethodItem * methodItem,const std::map<BaseItem *,File::EntityId> & reverseDone)1109 void FileReader::InstCheckByFlags(BytecodeInstruction &inst, MethodItem *methodItem,
1110                                   const std::map<BaseItem *, File::EntityId> &reverseDone)
1111 {
1112     using Flags = ark::BytecodeInst<ark::BytecodeInstMode::FAST>::Flags;
1113 
1114     if (inst.HasFlag(Flags::TYPE_ID)) {
1115         BytecodeId bId = inst.GetId();
1116         File::Index idx = bId.AsIndex();
1117         File::EntityId methodId = reverseDone.find(methodItem)->second;
1118         File::EntityId oldId = file_->ResolveClassIndex(methodId, idx);
1119         ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1120         auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1121         methodItem->AddIndexDependency(idxItem);
1122     } else if (inst.HasFlag(Flags::METHOD_ID) || inst.HasFlag(Flags::STATIC_METHOD_ID)) {
1123         BytecodeId bId = inst.GetId();
1124         File::Index idx = bId.AsIndex();
1125         File::EntityId methodId = reverseDone.find(methodItem)->second;
1126         File::EntityId oldId = file_->ResolveMethodIndex(methodId, idx);
1127         ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1128         auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1129         methodItem->AddIndexDependency(idxItem);
1130     } else if (inst.HasFlag(Flags::FIELD_ID) || inst.HasFlag(Flags::STATIC_FIELD_ID)) {
1131         BytecodeId bId = inst.GetId();
1132         File::Index idx = bId.AsIndex();
1133         File::EntityId methodId = reverseDone.find(methodItem)->second;
1134         File::EntityId oldId = file_->ResolveFieldIndex(methodId, idx);
1135         ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1136         auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1137         methodItem->AddIndexDependency(idxItem);
1138     } else if (inst.HasFlag(Flags::STRING_ID)) {
1139         BytecodeId bId = inst.GetId();
1140         File::EntityId oldId = bId.AsFileId();
1141         auto data = file_->GetStringData(oldId);
1142         std::string itemStr(utf::Mutf8AsCString(data.data));
1143         container_.GetOrCreateStringItem(itemStr);
1144     }
1145 }
1146 
UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *,File::EntityId> & reverseDone)1147 void FileReader::UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverseDone)
1148 {
1149     auto *classMap = container_.GetClassMap();
1150 
1151     // First pass, add dependencies bytecode -> new items
1152     for (const auto &it : *classMap) {
1153         auto *baseClassItem = it.second;
1154         if (baseClassItem->IsForeign()) {
1155             continue;
1156         }
1157         auto *classItem = static_cast<ClassItem *>(baseClassItem);
1158         classItem->VisitMethods([this, &reverseDone](BaseItem *paramItem) {
1159             auto *methodItem = static_cast<MethodItem *>(paramItem);
1160             auto *codeItem = methodItem->GetCode();
1161             if (codeItem == nullptr) {
1162                 return true;
1163             }
1164 
1165             auto *debugInfoItem = methodItem->GetDebugInfo();
1166             if (debugInfoItem != nullptr) {
1167                 UpdateDebugInfoDependecies(reverseDone.find(debugInfoItem)->second);
1168             }
1169 
1170             size_t offset = 0;
1171             BytecodeInstruction inst(codeItem->GetInstructions()->data());
1172             while (offset < codeItem->GetCodeSize()) {
1173                 InstCheckByFlags(inst, methodItem, reverseDone);
1174 
1175                 offset += inst.GetSize();
1176                 inst = inst.GetNext();
1177             }
1178             return true;
1179         });
1180     }
1181 }
1182 
InstUpdateId(CodeItem * codeItem,MethodItem * methodItem,std::map<BaseItem *,File::EntityId> & reverseDone)1183 void FileReader::InstUpdateId(CodeItem *codeItem, MethodItem *methodItem,
1184                               std::map<BaseItem *, File::EntityId> &reverseDone)
1185 {
1186     using Flags = ark::BytecodeInst<ark::BytecodeInstMode::FAST>::Flags;
1187 
1188     size_t offset = 0;
1189     BytecodeInstruction inst(codeItem->GetInstructions()->data());
1190     while (offset < codeItem->GetCodeSize()) {
1191         if (inst.HasFlag(Flags::TYPE_ID)) {
1192             BytecodeId bId = inst.GetId();
1193             File::Index idx = bId.AsIndex();
1194 
1195             File::EntityId methodId = reverseDone.find(methodItem)->second;
1196             File::EntityId oldId = file_->ResolveClassIndex(methodId, idx);
1197             ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1198 
1199             auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1200             uint32_t index = idxItem->GetIndex(methodItem);
1201             inst.UpdateId(BytecodeId(index));
1202         } else if (inst.HasFlag(Flags::METHOD_ID) || inst.HasFlag(Flags::STATIC_METHOD_ID)) {
1203             BytecodeId bId = inst.GetId();
1204             File::Index idx = bId.AsIndex();
1205 
1206             File::EntityId methodId = reverseDone.find(methodItem)->second;
1207             File::EntityId oldId = file_->ResolveMethodIndex(methodId, idx);
1208             ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1209 
1210             auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1211             uint32_t index = idxItem->GetIndex(methodItem);
1212             inst.UpdateId(BytecodeId(index));
1213         } else if (inst.HasFlag(Flags::FIELD_ID) || inst.HasFlag(Flags::STATIC_FIELD_ID)) {
1214             BytecodeId bId = inst.GetId();
1215             File::Index idx = bId.AsIndex();
1216 
1217             File::EntityId methodId = reverseDone.find(methodItem)->second;
1218             File::EntityId oldId = file_->ResolveFieldIndex(methodId, idx);
1219             ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1220 
1221             auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1222             uint32_t index = idxItem->GetIndex(methodItem);
1223             inst.UpdateId(BytecodeId(index));
1224         } else if (inst.HasFlag(Flags::STRING_ID)) {
1225             BytecodeId bId = inst.GetId();
1226             File::EntityId oldId = bId.AsFileId();
1227             auto data = file_->GetStringData(oldId);
1228 
1229             std::string itemStr(utf::Mutf8AsCString(data.data));
1230             auto *stringItem = container_.GetOrCreateStringItem(itemStr);
1231             inst.UpdateId(BytecodeId(stringItem->GetFileId().GetOffset()));
1232         }
1233 
1234         offset += inst.GetSize();
1235         inst = inst.GetNext();
1236     }
1237 }
1238 
ComputeLayoutAndUpdateIndices()1239 void FileReader::ComputeLayoutAndUpdateIndices()
1240 {
1241     std::map<BaseItem *, File::EntityId> reverseDone;
1242     for (const auto &it : itemsDone_) {
1243         reverseDone.insert({it.second, it.first});
1244     }
1245 
1246     auto *classMap = container_.GetClassMap();
1247 
1248     UpdateCodeAndDebugInfoDependencies(reverseDone);
1249 
1250     container_.ComputeLayout();
1251 
1252     // Second pass, update debug info
1253     for (const auto &it : *classMap) {
1254         auto *baseClassItem = it.second;
1255         if (baseClassItem->IsForeign()) {
1256             continue;
1257         }
1258         auto *classItem = static_cast<ClassItem *>(baseClassItem);
1259         classItem->VisitMethods([this, &reverseDone](BaseItem *paramItem) {
1260             auto *methodItem = static_cast<MethodItem *>(paramItem);
1261             auto *codeItem = methodItem->GetCode();
1262             if (codeItem == nullptr) {
1263                 return true;
1264             }
1265 
1266             auto *debugInfoItem = methodItem->GetDebugInfo();
1267             if (debugInfoItem != nullptr) {
1268                 UpdateDebugInfo(debugInfoItem, reverseDone.find(debugInfoItem)->second);
1269             }
1270 
1271             return true;
1272         });
1273     }
1274 
1275     container_.DeduplicateItems(false);
1276     container_.ComputeLayout();
1277 
1278     std::unordered_set<CodeItem *> codeItemsDone;
1279 
1280     // Third pass, update bytecode indices
1281     for (const auto &it : *classMap) {
1282         auto *baseClassItem = it.second;
1283         if (baseClassItem->IsForeign()) {
1284             continue;
1285         }
1286         auto *classItem = static_cast<ClassItem *>(baseClassItem);
1287         classItem->VisitMethods([this, &reverseDone, &codeItemsDone](BaseItem *paramItem) {
1288             auto *methodItem = static_cast<MethodItem *>(paramItem);
1289             auto *codeItem = methodItem->GetCode();
1290 
1291             auto codeIt = codeItemsDone.find(codeItem);
1292             if (codeItem == nullptr || codeIt != codeItemsDone.end()) {
1293                 return true;
1294             }
1295 
1296             InstUpdateId(codeItem, methodItem, reverseDone);
1297 
1298             codeItemsDone.insert(codeItem);
1299 
1300             return true;
1301         });
1302     }
1303 }
1304 
1305 }  // namespace ark::panda_file
1306