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