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 "libpandafile/bytecode_instruction-inl.h"
19#include "libpandafile/line_number_program.h"
20#include "libpandafile/literal_data_accessor-inl.h"
21#include "libpandafile/class_data_accessor-inl.h"
22#include "libpandafile/proto_data_accessor-inl.h"
23#include "libpandafile/code_data_accessor-inl.h"
24#include "libpandafile/debug_data_accessor-inl.h"
25#include "libpandafile/field_data_accessor-inl.h"
26#include "libpandafile/method_data_accessor-inl.h"
27
28#include "file.h"
29
30#include "libpandabase/utils/utf.h"
31
32#include "libpandafile/file_reader.h"
33
34namespace panda::panda_file {
35
36bool FileReader::ReadContainer()
37{
38    if (!ReadClasses()) {
39        return false;
40    }
41    if (!ReadLiteralArrayItems()) {
42        return false;
43    }
44    if (!ReadIndexHeaders()) {
45        return false;
46    }
47
48    ComputeLayoutAndUpdateIndices();
49
50    return true;
51}
52
53/* static */
54bool FileReader::CreateLiteralArrayItem(const LiteralDataAccessor::LiteralValue &lit_value, const LiteralTag &tag,
55                                        File::EntityId array_id)
56{
57    auto it = items_done_.find(array_id);
58    if (it != items_done_.end()) {
59        return true;
60    }
61
62    LiteralArrayItem *item = container_.GetOrCreateLiteralArrayItem(std::to_string(array_id.GetOffset()));
63    items_done_.insert({array_id, static_cast<BaseItem *>(item)});
64
65    File::EntityId id(std::get<uint32_t>(lit_value));
66    auto sp = file_->GetSpanFromId(id);
67
68    std::vector<panda_file::LiteralItem> literal_array;
69    literal_array.emplace_back(static_cast<uint8_t>(tag));
70    switch (tag) {
71        case panda_file::LiteralTag::BOOL: {
72            auto v = helpers::Read<sizeof(bool)>(&sp);
73            literal_array.emplace_back(static_cast<uint8_t>(v));
74            break;
75        }
76        case panda_file::LiteralTag::TAGVALUE:
77        case panda_file::LiteralTag::ACCESSOR:
78        case panda_file::LiteralTag::NULLVALUE: {
79            auto v = helpers::Read<sizeof(uint8_t)>(&sp);
80            literal_array.emplace_back(v);
81            break;
82        }
83        case panda_file::LiteralTag::ARRAY_U1:
84        case panda_file::LiteralTag::ARRAY_I8:
85        case panda_file::LiteralTag::ARRAY_U8: {
86            auto len = helpers::Read<sizeof(uint32_t)>(&sp);
87            literal_array.emplace_back(len);
88            for (size_t i = 0; i < len; i++) {
89                auto v = helpers::Read<sizeof(uint8_t)>(&sp);
90                literal_array.emplace_back(v);
91            }
92            break;
93        }
94        case panda_file::LiteralTag::ARRAY_I16:
95        case panda_file::LiteralTag::ARRAY_U16: {
96            auto len = helpers::Read<sizeof(uint32_t)>(&sp);
97            literal_array.emplace_back(len);
98            for (size_t i = 0; i < len; i++) {
99                auto v = helpers::Read<sizeof(uint16_t)>(&sp);
100                literal_array.emplace_back(v);
101            }
102            break;
103        }
104        case panda_file::LiteralTag::INTEGER: {
105            auto v = helpers::Read<sizeof(uint32_t)>(&sp);
106            literal_array.emplace_back(v);
107            break;
108        }
109        case panda_file::LiteralTag::ARRAY_I32:
110        case panda_file::LiteralTag::ARRAY_U32:
111        case panda_file::LiteralTag::ARRAY_F32: {
112            auto len = helpers::Read<sizeof(uint32_t)>(&sp);
113            literal_array.emplace_back(len);
114            for (size_t i = 0; i < len; i++) {
115                auto v = helpers::Read<sizeof(uint32_t)>(&sp);
116                literal_array.emplace_back(v);
117            }
118            break;
119        }
120        case panda_file::LiteralTag::ARRAY_I64:
121        case panda_file::LiteralTag::ARRAY_U64:
122        case panda_file::LiteralTag::ARRAY_F64: {
123            auto len = helpers::Read<sizeof(uint32_t)>(&sp);
124            literal_array.emplace_back(len);
125            for (size_t i = 0; i < len; i++) {
126                auto v = helpers::Read<sizeof(uint64_t)>(&sp);
127                literal_array.emplace_back(v);
128            }
129            break;
130        }
131        case panda_file::LiteralTag::FLOAT: {
132            auto v = helpers::Read<sizeof(uint32_t)>(&sp);
133            literal_array.emplace_back(v);
134            break;
135        }
136        case panda_file::LiteralTag::DOUBLE: {
137            auto v = panda_file::helpers::Read<sizeof(uint64_t)>(&sp);
138            literal_array.emplace_back(v);
139            break;
140        }
141        case panda_file::LiteralTag::STRING: {
142            File::EntityId str_id(helpers::Read<sizeof(uint32_t)>(&sp));
143            auto data = file_->GetStringData(str_id);
144            std::string item_str(utf::Mutf8AsCString(data.data));
145            auto *string_item = container_.GetOrCreateStringItem(item_str);
146            literal_array.emplace_back(string_item);
147            break;
148        }
149        case panda_file::LiteralTag::ARRAY_STRING: {
150            auto len = helpers::Read<sizeof(uint32_t)>(&sp);
151            literal_array.emplace_back(len);
152            for (size_t i = 0; i < len; i++) {
153                File::EntityId str_id(helpers::Read<sizeof(uint32_t)>(&sp));
154                auto data = file_->GetStringData(str_id);
155                std::string item_str(utf::Mutf8AsCString(data.data));
156                auto *string_item = container_.GetOrCreateStringItem(item_str);
157                literal_array.emplace_back(string_item);
158            }
159            break;
160        }
161        case panda_file::LiteralTag::METHOD:
162        case panda_file::LiteralTag::GETTER:
163        case panda_file::LiteralTag::SETTER:
164        case panda_file::LiteralTag::GENERATORMETHOD:
165        case panda_file::LiteralTag::ASYNCGENERATORMETHOD: {
166            File::EntityId method_id(helpers::Read<sizeof(uint32_t)>(&sp));
167            MethodDataAccessor method_acc(*file_, method_id);
168            File::EntityId class_id(method_acc.GetClassId());
169            auto *class_item = CreateClassItem(class_id);
170            literal_array.emplace_back(CreateMethodItem(class_item, method_id));
171            break;
172        }
173        default:
174            UNREACHABLE();
175    }
176
177    item->AddItems(literal_array);
178
179    return true;
180}
181
182// NOLINTNEXTLINE(readability-function-size)
183AnnotationItem *FileReader::CreateAnnotationItem(File::EntityId ann_id)
184{
185    auto it = items_done_.find(ann_id);
186    if (it != items_done_.end()) {
187        return static_cast<AnnotationItem *>(it->second);
188    }
189
190    AnnotationDataAccessor ann_acc(*file_, ann_id);
191    File::EntityId ann_class_id {ann_acc.GetClassId()};
192    AnnotationItem *ann_item = nullptr;
193
194    if (!file_->IsExternal(ann_class_id)) {
195        auto *ann_class_item = CreateClassItem(ann_class_id);
196        ann_item = container_.CreateItem<AnnotationItem>(ann_class_item, std::vector<AnnotationItem::Elem>(),
197                                                         std::vector<AnnotationItem::Tag>());
198    } else {
199        auto *ann_class_item = CreateForeignClassItem(ann_class_id);
200        ann_item = container_.CreateItem<AnnotationItem>(ann_class_item, std::vector<AnnotationItem::Elem>(),
201                                                         std::vector<AnnotationItem::Tag>());
202    }
203
204    ASSERT(ann_item != nullptr);
205
206    items_done_.insert({ann_id, static_cast<BaseItem *>(ann_item)});
207
208    std::vector<AnnotationItem::Elem> item_elements;
209    std::vector<AnnotationItem::Tag> tag_elements;
210
211    for (size_t i = 0; i < ann_acc.GetCount(); i++) {
212        AnnotationDataAccessor::Tag ann_tag = ann_acc.GetTag(i);
213        AnnotationDataAccessor::Elem ann_elem = ann_acc.GetElement(i);
214        ValueItem *elem_value_item = nullptr;
215        switch (ann_tag.GetItem()) {
216            case '1':
217            case '2':
218            case '3': {
219                auto scalar = ann_elem.GetScalarValue();
220                elem_value_item = container_.GetOrCreateIntegerValueItem(scalar.Get<uint8_t>());
221                break;
222            }
223            case '4':
224            case '5': {
225                auto scalar = ann_elem.GetScalarValue();
226                elem_value_item = container_.GetOrCreateIntegerValueItem(scalar.Get<uint16_t>());
227                break;
228            }
229            case '6':
230            case '7': {
231                auto scalar = ann_elem.GetScalarValue();
232                elem_value_item = container_.GetOrCreateIntegerValueItem(scalar.Get<uint32_t>());
233                break;
234            }
235            case '8':
236            case '9': {
237                auto scalar = ann_elem.GetScalarValue();
238                elem_value_item = container_.GetOrCreateLongValueItem(scalar.Get<uint64_t>());
239                break;
240            }
241            case 'A': {
242                auto scalar = ann_elem.GetScalarValue();
243                elem_value_item = container_.GetOrCreateFloatValueItem(scalar.Get<float>());
244                break;
245            }
246            case 'B': {
247                auto scalar = ann_elem.GetScalarValue();
248                elem_value_item = container_.GetOrCreateDoubleValueItem(scalar.Get<double>());
249                break;
250            }
251            case 'C': {
252                auto scalar = ann_elem.GetScalarValue();
253                const File::EntityId str_id(scalar.Get<uint32_t>());
254                auto data = file_->GetStringData(str_id);
255                std::string item_str(utf::Mutf8AsCString(data.data));
256                auto *str_item = container_.GetOrCreateStringItem(item_str);
257                elem_value_item = container_.GetOrCreateIdValueItem(str_item);
258                break;
259            }
260            case 'D': {
261                auto scalar = ann_elem.GetScalarValue();
262                const File::EntityId class_id {scalar.Get<uint32_t>()};
263                elem_value_item = container_.GetOrCreateIdValueItem(CreateGenericClassItem(class_id));
264                break;
265            }
266            case 'E': {
267                auto scalar = ann_elem.GetScalarValue();
268                const File::EntityId method_id {scalar.Get<uint32_t>()};
269                MethodDataAccessor method_acc(*file_, method_id);
270                auto *cls_item = CreateGenericClassItem(method_acc.GetClassId());
271                elem_value_item = container_.GetOrCreateIdValueItem(CreateGenericMethodItem(cls_item, method_id));
272                break;
273            }
274            case 'F': {
275                auto scalar = ann_elem.GetScalarValue();
276                const File::EntityId field_id {scalar.Get<uint32_t>()};
277                FieldDataAccessor field_acc(*file_, field_id);
278                auto *cls_item = CreateGenericClassItem(field_acc.GetClassId());
279                elem_value_item = container_.GetOrCreateIdValueItem(CreateGenericFieldItem(cls_item, field_id));
280                break;
281            }
282            case 'G': {
283                auto scalar = ann_elem.GetScalarValue();
284                const File::EntityId ann_item_id {scalar.Get<uint32_t>()};
285                elem_value_item = container_.GetOrCreateIdValueItem(CreateAnnotationItem(ann_item_id));
286                break;
287            }
288            case 'J': {
289                LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far";
290                break;
291            }
292            case '*': {
293                elem_value_item = container_.GetOrCreateIntegerValueItem(0);
294                break;
295            }
296            case 'K': {
297                auto array = ann_elem.GetArrayValue();
298                std::vector<ScalarValueItem> items;
299                for (size_t j = 0; j < array.GetCount(); j++) {
300                    ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint8_t>(j)));
301                    items.emplace_back(std::move(scalar));
302                }
303                elem_value_item = static_cast<ValueItem *>(
304                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U1), std::move(items)));
305                break;
306            }
307            case 'L': {
308                auto array = ann_elem.GetArrayValue();
309                std::vector<ScalarValueItem> items;
310                for (size_t j = 0; j < array.GetCount(); j++) {
311                    ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint8_t>(j)));
312                    items.emplace_back(std::move(scalar));
313                }
314                elem_value_item = static_cast<ValueItem *>(
315                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::I8), std::move(items)));
316                break;
317            }
318            case 'M': {
319                auto array = ann_elem.GetArrayValue();
320                std::vector<ScalarValueItem> items;
321                for (size_t j = 0; j < array.GetCount(); j++) {
322                    ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint8_t>(j)));
323                    items.emplace_back(std::move(scalar));
324                }
325                elem_value_item = static_cast<ValueItem *>(
326                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U8), std::move(items)));
327                break;
328            }
329            case 'N': {
330                auto array = ann_elem.GetArrayValue();
331                std::vector<ScalarValueItem> items;
332                for (size_t j = 0; j < array.GetCount(); j++) {
333                    ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint16_t>(j)));
334                    items.emplace_back(std::move(scalar));
335                }
336                elem_value_item = static_cast<ValueItem *>(
337                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::I16), std::move(items)));
338                break;
339            }
340            case 'O': {
341                auto array = ann_elem.GetArrayValue();
342                std::vector<ScalarValueItem> items;
343                for (size_t j = 0; j < array.GetCount(); j++) {
344                    ScalarValueItem scalar(static_cast<uint32_t>(array.Get<uint16_t>(j)));
345                    items.emplace_back(std::move(scalar));
346                }
347                elem_value_item = static_cast<ValueItem *>(
348                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U16), std::move(items)));
349                break;
350            }
351            case 'P': {
352                auto array = ann_elem.GetArrayValue();
353                std::vector<ScalarValueItem> items;
354                for (size_t j = 0; j < array.GetCount(); j++) {
355                    ScalarValueItem scalar(array.Get<uint32_t>(j));
356                    items.emplace_back(std::move(scalar));
357                }
358                elem_value_item = static_cast<ValueItem *>(
359                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::I32), std::move(items)));
360                break;
361            }
362            case 'Q': {
363                auto array = ann_elem.GetArrayValue();
364                std::vector<ScalarValueItem> items;
365                for (size_t j = 0; j < array.GetCount(); j++) {
366                    ScalarValueItem scalar(array.Get<uint32_t>(j));
367                    items.emplace_back(std::move(scalar));
368                }
369                elem_value_item = static_cast<ValueItem *>(
370                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U32), std::move(items)));
371                break;
372            }
373            case 'R': {
374                auto array = ann_elem.GetArrayValue();
375                std::vector<ScalarValueItem> items;
376                for (size_t j = 0; j < array.GetCount(); j++) {
377                    ScalarValueItem scalar(array.Get<uint64_t>(j));
378                    items.emplace_back(std::move(scalar));
379                }
380                elem_value_item = static_cast<ValueItem *>(
381                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::I64), std::move(items)));
382                break;
383            }
384            case 'S': {
385                auto array = ann_elem.GetArrayValue();
386                std::vector<ScalarValueItem> items;
387                for (size_t j = 0; j < array.GetCount(); j++) {
388                    ScalarValueItem scalar(array.Get<uint64_t>(j));
389                    items.emplace_back(std::move(scalar));
390                }
391                elem_value_item = static_cast<ValueItem *>(
392                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::U64), std::move(items)));
393                break;
394            }
395            case 'T': {
396                auto array = ann_elem.GetArrayValue();
397                std::vector<ScalarValueItem> items;
398                for (size_t j = 0; j < array.GetCount(); j++) {
399                    ScalarValueItem scalar(array.Get<float>(j));
400                    items.emplace_back(std::move(scalar));
401                }
402                elem_value_item = static_cast<ValueItem *>(
403                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::F32), std::move(items)));
404                break;
405            }
406            case 'U': {
407                auto array = ann_elem.GetArrayValue();
408                std::vector<ScalarValueItem> items;
409                for (size_t j = 0; j < array.GetCount(); j++) {
410                    ScalarValueItem scalar(array.Get<double>(j));
411                    items.emplace_back(std::move(scalar));
412                }
413                elem_value_item = static_cast<ValueItem *>(
414                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::F64), std::move(items)));
415                break;
416            }
417            case 'V': {
418                auto array = ann_elem.GetArrayValue();
419                std::vector<ScalarValueItem> items;
420                for (size_t j = 0; j < array.GetCount(); j++) {
421                    const File::EntityId str_id(array.Get<uint32_t>(j));
422                    auto data = file_->GetStringData(str_id);
423                    std::string item_str(utf::Mutf8AsCString(data.data));
424                    items.emplace_back(ScalarValueItem(container_.GetOrCreateStringItem(item_str)));
425                }
426                elem_value_item = static_cast<ValueItem *>(
427                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
428                break;
429            }
430            case 'W': {
431                auto array = ann_elem.GetArrayValue();
432                std::vector<ScalarValueItem> items;
433                for (size_t j = 0; j < array.GetCount(); j++) {
434                    const File::EntityId class_id {array.Get<uint32_t>(j)};
435                    BaseClassItem *cls_item = nullptr;
436                    if (file_->IsExternal(class_id)) {
437                        cls_item = CreateForeignClassItem(class_id);
438                    } else {
439                        cls_item = CreateClassItem(class_id);
440                    }
441                    ASSERT(cls_item != nullptr);
442                    items.emplace_back(ScalarValueItem(cls_item));
443                }
444                elem_value_item = static_cast<ValueItem *>(
445                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
446                break;
447            }
448            case 'X': {
449                auto array = ann_elem.GetArrayValue();
450                std::vector<ScalarValueItem> items;
451                for (size_t j = 0; j < array.GetCount(); j++) {
452                    const File::EntityId method_id {array.Get<uint32_t>(j)};
453                    MethodDataAccessor method_acc(*file_, method_id);
454                    auto *cls_item = CreateGenericClassItem(method_acc.GetClassId());
455                    items.emplace_back(ScalarValueItem(CreateGenericMethodItem(cls_item, method_id)));
456                }
457                elem_value_item = static_cast<ValueItem *>(
458                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
459                break;
460            }
461            case 'Y': {
462                auto array = ann_elem.GetArrayValue();
463                std::vector<ScalarValueItem> items;
464                for (size_t j = 0; j < array.GetCount(); j++) {
465                    const File::EntityId field_id {array.Get<uint32_t>(j)};
466                    FieldDataAccessor field_acc(*file_, field_id);
467                    auto *cls_item = CreateGenericClassItem(field_acc.GetClassId());
468                    items.emplace_back(ScalarValueItem(CreateGenericFieldItem(cls_item, field_id)));
469                }
470                elem_value_item = static_cast<ValueItem *>(
471                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
472                break;
473            }
474            case 'H': {
475                // ARRAY can appear for empty arrays only
476                ASSERT(ann_elem.GetArrayValue().GetCount() == 0);
477                elem_value_item = static_cast<ValueItem *>(
478                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::VOID), std::vector<ScalarValueItem>()));
479                break;
480            }
481            case 'Z': {
482                auto array = ann_elem.GetArrayValue();
483                std::vector<ScalarValueItem> items;
484                for (size_t j = 0; j < array.GetCount(); j++) {
485                    const File::EntityId ann_item_id {array.Get<uint32_t>(j)};
486                    items.emplace_back(CreateAnnotationItem(ann_item_id));
487                }
488                elem_value_item = static_cast<ValueItem *>(
489                    container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
490                break;
491            }
492            case '@': {
493                // TODO(nsizov): support it
494                LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far";
495                break;
496            }
497                // array
498            case 'I':
499                // VOID(I) and ARRAY(H) value should not appear
500            default:
501                UNREACHABLE();
502        }
503
504        ASSERT(elem_value_item != nullptr);
505
506        tag_elements.emplace_back(AnnotationItem::Tag(static_cast<char>(ann_tag.GetItem())));
507        File::EntityId name_id(ann_elem.GetNameId());
508        std::string annot_name_str(utf::Mutf8AsCString(file_->GetStringData(name_id).data));
509        auto elem_name_item = container_.GetOrCreateStringItem(annot_name_str);
510        item_elements.emplace_back(AnnotationItem::Elem(elem_name_item, elem_value_item));
511    }
512
513    ann_item->SetElements(std::move(item_elements));
514    ann_item->SetTags(std::move(tag_elements));
515
516    return ann_item;
517}
518
519TypeItem *FileReader::CreateParamTypeItem(ProtoDataAccessor *proto_acc, size_t param_num, size_t reference_num)
520{
521    Type param_type = proto_acc->GetArgType(param_num);
522    TypeItem *param_type_item = nullptr;
523    if (param_type.IsPrimitive()) {
524        param_type_item = container_.GetOrCreatePrimitiveTypeItem(param_type);
525    } else {
526        const File::EntityId type_cls_id = proto_acc->GetReferenceType(reference_num);
527        if (file_->IsExternal(type_cls_id)) {
528            param_type_item = CreateForeignClassItem(type_cls_id);
529        } else {
530            param_type_item = CreateClassItem(type_cls_id);
531        }
532    }
533
534    ASSERT(param_type_item != nullptr);
535
536    return param_type_item;
537}
538
539std::vector<MethodParamItem> FileReader::CreateMethodParamItems(ProtoDataAccessor *proto_acc,
540                                                                MethodDataAccessor *method_acc, size_t reference_num)
541{
542    std::vector<MethodParamItem> param_items;
543
544    for (size_t i = 0; i < proto_acc->GetNumArgs(); i++) {
545        TypeItem *param_type_item = CreateParamTypeItem(proto_acc, i, reference_num);
546        if (param_type_item->GetType().IsReference()) {
547            reference_num++;
548        }
549        param_items.emplace_back(MethodParamItem(param_type_item));
550    }
551
552    auto param_ann_id = method_acc->GetParamAnnotationId();
553    if (param_ann_id) {
554        ParamAnnotationsDataAccessor param_acc(*file_, param_ann_id.value());
555        for (size_t i = 0; i < proto_acc->GetNumArgs(); i++) {
556            ParamAnnotationsDataAccessor::AnnotationArray ann_arr = param_acc.GetAnnotationArray(i);
557            ann_arr.EnumerateAnnotations([&](File::EntityId ann_id) {
558                auto ann_item = CreateAnnotationItem(ann_id);
559                param_items[i].AddAnnotation(ann_item);
560            });
561        }
562    }
563
564    auto runtime_param_ann_id = method_acc->GetRuntimeParamAnnotationId();
565    if (runtime_param_ann_id) {
566        ParamAnnotationsDataAccessor param_acc(*file_, runtime_param_ann_id.value());
567        for (size_t i = 0; i < proto_acc->GetNumArgs(); i++) {
568            ParamAnnotationsDataAccessor::AnnotationArray ann_arr = param_acc.GetAnnotationArray(i);
569            ann_arr.EnumerateAnnotations([&](File::EntityId ann_id) {
570                auto ann_item = CreateAnnotationItem(ann_id);
571                param_items[i].AddRuntimeAnnotation(ann_item);
572            });
573        }
574    }
575
576    return param_items;
577}
578
579DebugInfoItem *FileReader::CreateDebugInfoItem(File::EntityId debug_info_id)
580{
581    auto it = items_done_.find(debug_info_id);
582    if (it != items_done_.end()) {
583        return static_cast<DebugInfoItem *>(it->second);
584    }
585
586    auto *lnp_item = container_.CreateLineNumberProgramItem();
587    auto *debug_info_item = container_.CreateItem<DebugInfoItem>(lnp_item);
588    items_done_.insert({debug_info_id, static_cast<BaseItem *>(debug_info_item)});
589
590    DebugInfoDataAccessor debug_acc(*file_, debug_info_id);
591
592    debug_info_item->SetLineNumber(debug_acc.GetLineStart());
593    debug_acc.EnumerateParameters([&](File::EntityId param_id) {
594        auto data = file_->GetStringData(param_id);
595        std::string item_str(utf::Mutf8AsCString(data.data));
596        auto *string_item = container_.GetOrCreateStringItem(item_str);
597        debug_info_item->AddParameter(string_item);
598    });
599
600    return debug_info_item;
601}
602
603TypeItem *FileReader::GetReturnTypeItem(Type ret_type, size_t &reference_num)
604{
605    TypeItem *ret_type_item = nullptr;
606    if (ret_type.IsPrimitive()) {
607        ret_type_item = container_.GetOrCreatePrimitiveTypeItem(ret_type);
608    } else {
609        const File::EntityId type_cls_id = proto_acc.GetReferenceType(reference_num);
610        if (file_->IsExternal(type_cls_id)) {
611            ret_type_item = CreateForeignClassItem(type_cls_id);
612        } else {
613            ret_type_item = CreateClassItem(type_cls_id);
614        }
615        reference_num++;
616    }
617    return ret_type_item;
618}
619
620void FileReader::EnumerateBlocks(MethodDataAccessor method_acc, MethodItem *method_item)
621{
622    // quick check
623    auto code_id = method_acc.GetCodeId();
624    if (code_id == std::nullopt) {
625        return;
626    }
627
628    CodeDataAccessor code_acc(*file_, code_id.value());
629    std::vector<uint8_t> instructions(code_acc.GetCodeSize());
630    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
631    instructions.assign(code_acc.GetInstructions(), code_acc.GetInstructions() + code_acc.GetCodeSize());
632    auto *code_item =
633        container_.CreateItem<CodeItem>(code_acc.GetNumVregs(), code_acc.GetNumArgs(), std::move(instructions));
634
635    code_acc.EnumerateTryBlocks([&](CodeDataAccessor::TryBlock &try_block) {
636        std::vector<CodeItem::CatchBlock> catch_blocks;
637        try_block.EnumerateCatchBlocks([&](CodeDataAccessor::CatchBlock &catch_block) {
638            BaseClassItem *catch_type_item = nullptr;
639            auto type_idx = catch_block.GetTypeIdx();
640            if (type_idx != panda_file::INVALID_INDEX) {
641                File::EntityId catch_cls_id = file_->ResolveClassIndex(method_id, catch_block.GetTypeIdx());
642                catch_type_item = (file_->IsExternal(catch_cls_id)) ? CreateForeignClassItem(catch_cls_id) :
643                                                                      CreateClassItem(catch_cls_id);
644                method_item->AddIndexDependency(catch_type_item);
645            }
646            // Add new CatchBlock
647            catch_blocks.emplace_back(CodeItem::CatchBlock(method_item, catch_type_item, catch_block.GetHandlerPc(),
648                                                           catch_block.GetCodeSize()));
649            return true;
650        });
651        code_item->AddTryBlock(
652            CodeItem::TryBlock(try_block.GetStartPc(), try_block.GetLength(), std::move(catch_blocks)));
653        return true;
654    });
655
656    method_item->SetCode(code_item);
657}
658
659MethodItem *FileReader::CreateMethodItem(ClassItem *cls, File::EntityId method_id)
660{
661    // Check if we have done this method
662    auto it = items_done_.find(method_id);
663    if (it != items_done_.end()) {
664        return static_cast<MethodItem *>(it->second);
665    }
666
667    MethodDataAccessor method_acc(*file_, method_id);
668    auto data = file_->GetStringData(method_acc.GetNameId());
669    std::string method_name(utf::Mutf8AsCString(data.data));
670    auto method_str_item = container_.GetOrCreateStringItem(method_name);
671
672    ProtoDataAccessor proto_acc(*file_, method_acc.GetProtoId());
673    Type ret_type = proto_acc.GetReturnType();
674    size_t reference_num = 0;
675    TypeItem *ret_type_item = GetReturnTypeItem(ret_type, reference_num);
676    ASSERT(ret_type_item != nullptr);
677    auto param_items = CreateMethodParamItems(&proto_acc, &method_acc, reference_num);
678
679    // Double check if we have done this method while computing params
680    auto it_check = items_done_.find(method_id);
681    if (it_check != items_done_.end()) {
682        return static_cast<MethodItem *>(it_check->second);
683    }
684
685    auto proto_item = container_.GetOrCreateProtoItem(ret_type_item, param_items);
686    auto method_item =
687        cls->AddMethod(method_str_item, proto_item, method_acc.GetAccessFlags(), std::move(param_items));
688    if (method_item->HasRuntimeParamAnnotations()) {
689        container_.CreateItem<ParamAnnotationsItem>(method_item, true);
690    }
691
692    if (method_item->HasParamAnnotations()) {
693        container_.CreateItem<ParamAnnotationsItem>(method_item, false);
694    }
695    items_done_.insert({method_id, static_cast<BaseItem *>(method_item)});
696
697    method_acc.EnumerateAnnotations(
698        [&](File::EntityId ann_id) { method_item->AddAnnotation(CreateAnnotationItem(ann_id)); });
699
700    method_acc.EnumerateRuntimeAnnotations(
701        [&](File::EntityId ann_id) { method_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); });
702
703    method_acc.EnumerateTypeAnnotations(
704        [&](File::EntityId ann_id) { method_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); });
705
706    method_acc.EnumerateRuntimeTypeAnnotations(
707        [&](File::EntityId ann_id) { method_item->AddRuntimeTypeAnnotation(CreateAnnotationItem(ann_id)); });
708
709    EnumerateBlocks(method_acc, method_item);
710
711    auto debug_info_id = method_acc.GetDebugInfoId();
712    if (debug_info_id) {
713        method_item->SetDebugInfo(CreateDebugInfoItem(debug_info_id.value()));
714    }
715
716    auto source_lang = method_acc.GetSourceLang();
717    if (source_lang) {
718        method_item->SetSourceLang(source_lang.value());
719    }
720
721    return method_item;
722}
723
724MethodHandleItem *FileReader::CreateMethodHandleItem(File::EntityId mh_id)
725{
726    (void)mh_id;
727    ASSERT(false);
728    return nullptr;  // STUB
729}
730
731FieldItem *FileReader::CreateFieldItem(ClassItem *cls, File::EntityId field_id)
732{
733    auto it = items_done_.find(field_id);
734    if (it != items_done_.end()) {
735        return static_cast<FieldItem *>(it->second);
736    }
737
738    FieldDataAccessor field_acc(*file_, field_id);
739
740    auto data = file_->GetStringData(field_acc.GetNameId());
741    std::string string_name(utf::Mutf8AsCString(data.data));
742    auto *field_name = container_.GetOrCreateStringItem(string_name);
743    Type field_type = Type::GetTypeFromFieldEncoding(field_acc.GetType());
744
745    TypeItem *field_type_item = nullptr;
746    if (field_type.IsReference()) {
747        File::EntityId type_id(field_acc.GetType());
748        if (file_->IsExternal(type_id)) {
749            field_type_item = CreateForeignClassItem(type_id);
750        } else {
751            field_type_item = CreateClassItem(type_id);
752            // Double check if we done this field while generated class item
753            auto it_check = items_done_.find(field_id);
754            if (it_check != items_done_.end()) {
755                return static_cast<FieldItem *>(it_check->second);
756            }
757        }
758    } else {
759        field_type_item = container_.GetOrCreatePrimitiveTypeItem(field_type.GetId());
760    }
761
762    ASSERT(field_type_item != nullptr);
763
764    FieldItem *field_item = cls->AddField(field_name, field_type_item, field_acc.GetAccessFlags());
765    items_done_.insert({field_id, static_cast<BaseItem *>(field_item)});
766
767    switch (field_type.GetId()) {
768        case Type::TypeId::U1:
769        case Type::TypeId::I8:
770        case Type::TypeId::U8:
771            SetIntegerFieldValue<uint8_t>(&field_acc, field_item);
772            break;
773        case Type::TypeId::I16:
774        case Type::TypeId::U16:
775            SetIntegerFieldValue<uint16_t>(&field_acc, field_item);
776            break;
777        case Type::TypeId::I32:
778        case Type::TypeId::U32:
779            SetIntegerFieldValue<uint32_t>(&field_acc, field_item);
780            break;
781        case Type::TypeId::I64:
782        case Type::TypeId::U64:
783            SetIntegerFieldValue<uint64_t>(&field_acc, field_item);
784            break;
785        case Type::TypeId::F32:
786            SetFloatFieldValue<float>(&field_acc, field_item);
787            break;
788        case Type::TypeId::F64:
789            SetFloatFieldValue<double>(&field_acc, field_item);
790            break;
791        case Type::TypeId::REFERENCE:
792            SetStringFieldValue(&field_acc, field_item);
793            break;
794        case Type::TypeId::TAGGED:
795        default:
796            UNREACHABLE();
797            break;
798    }
799
800    field_acc.EnumerateAnnotations(
801        [&](File::EntityId ann_id) { field_item->AddAnnotation(CreateAnnotationItem(ann_id)); });
802
803    field_acc.EnumerateRuntimeAnnotations(
804        [&](File::EntityId ann_id) { field_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); });
805
806    field_acc.EnumerateRuntimeTypeAnnotations(
807        [&](File::EntityId ann_id) { field_item->AddRuntimeTypeAnnotation(CreateAnnotationItem(ann_id)); });
808
809    field_acc.EnumerateTypeAnnotations(
810        [&](File::EntityId ann_id) { field_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); });
811
812    return field_item;
813}
814
815ForeignMethodItem *FileReader::CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId method_id)
816{
817    auto it = items_done_.find(method_id);
818    if (it != items_done_.end()) {
819        return static_cast<ForeignMethodItem *>(it->second);
820    }
821
822    MethodDataAccessor method_acc(*file_, method_id);
823    auto data = file_->GetStringData(method_acc.GetNameId());
824    std::string method_name(utf::Mutf8AsCString(data.data));
825    auto *method_str_item = container_.GetOrCreateStringItem(method_name);
826
827    ProtoDataAccessor proto_acc(*file_, method_acc.GetProtoId());
828    Type ret_type = proto_acc.GetReturnType();
829    size_t reference_num = 0;
830    TypeItem *ret_type_item = nullptr;
831    if (ret_type.IsPrimitive()) {
832        ret_type_item = container_.GetOrCreatePrimitiveTypeItem(ret_type);
833    } else {
834        const File::EntityId type_cls_id = proto_acc.GetReferenceType(reference_num);
835        if (file_->IsExternal(type_cls_id)) {
836            ret_type_item = CreateForeignClassItem(type_cls_id);
837        } else {
838            ret_type_item = CreateClassItem(type_cls_id);
839        }
840        reference_num++;
841    }
842    ASSERT(ret_type_item != nullptr);
843    auto param_items = CreateMethodParamItems(&proto_acc, &method_acc, reference_num);
844    // Double check if we done this method while computing params
845    auto it_check = items_done_.find(method_id);
846    if (it_check != items_done_.end()) {
847        return static_cast<ForeignMethodItem *>(it_check->second);
848    }
849    auto *proto_item = container_.GetOrCreateProtoItem(ret_type_item, param_items);
850
851    auto *method_item =
852        container_.CreateItem<ForeignMethodItem>(fcls, method_str_item, proto_item, method_acc.GetAccessFlags());
853
854    items_done_.insert({method_id, static_cast<BaseItem *>(method_item)});
855
856    return method_item;
857}
858
859ForeignFieldItem *FileReader::CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId field_id)
860{
861    auto it = items_done_.find(field_id);
862    if (it != items_done_.end()) {
863        return static_cast<ForeignFieldItem *>(it->second);
864    }
865
866    FieldDataAccessor field_acc(*file_, field_id);
867
868    auto data = file_->GetStringData(field_acc.GetNameId());
869    std::string string_name(utf::Mutf8AsCString(data.data));
870    auto *field_name = container_.GetOrCreateStringItem(string_name);
871    Type field_type = Type::GetTypeFromFieldEncoding(field_acc.GetType());
872    TypeItem *field_type_item = nullptr;
873    if (field_type.IsReference()) {
874        File::EntityId type_id(field_acc.GetType());
875        if (file_->IsExternal(type_id)) {
876            field_type_item = CreateForeignClassItem(type_id);
877        } else {
878            field_type_item = CreateClassItem(type_id);
879            // Double check if we done this field while generated class item
880            auto it_check = items_done_.find(field_id);
881            if (it_check != items_done_.end()) {
882                return static_cast<ForeignFieldItem *>(it_check->second);
883            }
884        }
885    } else {
886        field_type_item = container_.GetOrCreatePrimitiveTypeItem(field_type.GetId());
887    }
888
889    ASSERT(field_type_item != nullptr);
890
891    auto *field_item = container_.CreateItem<ForeignFieldItem>(fcls, field_name, field_type_item);
892    items_done_.insert({field_id, static_cast<BaseItem *>(field_item)});
893
894    return field_item;
895}
896
897ForeignClassItem *FileReader::CreateForeignClassItem(File::EntityId class_id)
898{
899    auto it = items_done_.find(class_id);
900    if (it != items_done_.end()) {
901        return static_cast<ForeignClassItem *>(it->second);
902    }
903
904    std::string class_name(utf::Mutf8AsCString(file_->GetStringData(class_id).data));
905    auto *class_item = container_.GetOrCreateForeignClassItem(class_name);
906
907    items_done_.insert({class_id, static_cast<BaseItem *>(class_item)});
908
909    return class_item;
910}
911
912void FileReader::CreateSuperClassItem(ClassDataAccessor& class_acc,
913                                      ClassItem* class_item,
914                                      const std::string& class_name)
915{
916    auto super_class_id = class_acc.GetSuperClassId();
917    if (super_class_id.GetOffset() != 0) {
918        if (super_class_id.GetOffset() == class_id.GetOffset()) {
919            LOG(FATAL, PANDAFILE) << "Class " << class_name << " has cyclic inheritance";
920        }
921
922        if (file_->IsExternal(super_class_id)) {
923            auto *super_class_item = CreateForeignClassItem(super_class_id);
924            class_item->SetSuperClass(super_class_item);
925        } else {
926            auto *super_class_item = CreateClassItem(super_class_id);
927            class_item->SetSuperClass(super_class_item);
928        }
929    }
930}
931
932ClassItem *FileReader::CreateClassItem(File::EntityId class_id)
933{
934    auto it = items_done_.find(class_id);
935    if (it != items_done_.end()) {
936        return static_cast<ClassItem *>(it->second);
937    }
938    ClassDataAccessor class_acc(*file_, class_id);
939
940    std::string class_name(utf::Mutf8AsCString(file_->GetStringData(class_id).data));
941    auto *class_item = container_.GetOrCreateClassItem(class_name);
942
943    items_done_.insert({class_id, static_cast<BaseItem *>(class_item)});
944
945    class_item->SetAccessFlags(class_acc.GetAccessFlags());
946
947    auto source_lang_opt = class_acc.GetSourceLang();
948    if (source_lang_opt) {
949        class_item->SetSourceLang(source_lang_opt.value());
950    }
951
952    CreateSuperClassItem(class_acc, class_item, class_name);
953
954    class_acc.EnumerateInterfaces([&](File::EntityId iface_id) {
955        if (file_->IsExternal(iface_id)) {
956            class_item->AddInterface(CreateForeignClassItem(iface_id));
957        } else {
958            class_item->AddInterface(CreateClassItem(iface_id));
959        }
960    });
961
962    class_acc.EnumerateAnnotations(
963        [&](File::EntityId ann_id) { class_item->AddAnnotation(CreateAnnotationItem(ann_id)); });
964
965    class_acc.EnumerateRuntimeAnnotations(
966        [&](File::EntityId ann_id) { class_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); });
967
968    class_acc.EnumerateTypeAnnotations(
969        [&](File::EntityId ann_id) { class_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); });
970
971    class_acc.EnumerateFields(
972        [&](FieldDataAccessor &field_acc) { CreateFieldItem(class_item, field_acc.GetFieldId()); });
973
974    class_acc.EnumerateMethods(
975        [&](MethodDataAccessor &method_acc) { CreateMethodItem(class_item, method_acc.GetMethodId()); });
976
977    auto source_file_id = class_acc.GetSourceFileId();
978    if (source_file_id) {
979        std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id.value()).data);
980        class_item->SetSourceFile(container_.GetOrCreateStringItem(source_file));
981    }
982
983    ASSERT(class_item != nullptr);
984
985    return class_item;
986}
987
988bool FileReader::ReadLiteralArrayItems()
989{
990    const auto lit_arrays_id = file_->GetLiteralArraysId();
991    LiteralDataAccessor lit_array_accessor(*file_, lit_arrays_id);
992    size_t num_litarrays = lit_array_accessor.GetLiteralNum();
993
994    for (size_t i = 0; i < num_litarrays; i++) {
995        auto id = lit_array_accessor.GetLiteralArrayId(i);
996        lit_array_accessor.EnumerateLiteralVals(
997            id, [id, this](const panda_file::LiteralDataAccessor::LiteralValue &value,
998                           const panda_file::LiteralTag &tag) { CreateLiteralArrayItem(value, tag, id); });
999    }
1000
1001    return true;
1002}
1003
1004bool FileReader::ReadIndexHeaders()
1005{
1006    auto index_headers = file_->GetIndexHeaders();
1007    for (const auto &header : index_headers) {
1008        auto method_index = file_->GetMethodIndex(&header);
1009        for (auto method_id : method_index) {
1010            MethodDataAccessor method_acc(*file_, method_id);
1011            File::EntityId class_id(method_acc.GetClassId());
1012            if (file_->IsExternal(class_id)) {
1013                auto *fclass_item = CreateForeignClassItem(class_id);
1014                ASSERT(file_->IsExternal(method_id));
1015                if (CreateForeignMethodItem(fclass_item, method_id) == nullptr) {
1016                    return false;
1017                }
1018            } else {
1019                auto *class_item = CreateClassItem(class_id);
1020                if (file_->IsExternal(method_id)) {
1021                    if (CreateForeignMethodItem(class_item, method_id) == nullptr) {
1022                        return false;
1023                    }
1024                } else if (CreateMethodItem(class_item, method_id) == nullptr) {
1025                    return false;
1026                }
1027            }
1028        }
1029        auto field_index = file_->GetFieldIndex(&header);
1030        for (auto field_id : field_index) {
1031            FieldDataAccessor field_acc(*file_, field_id);
1032            File::EntityId class_id(field_acc.GetClassId());
1033            if (file_->IsExternal(class_id)) {
1034                ASSERT(file_->IsExternal(field_id));
1035                auto *fclass_item = CreateForeignClassItem(field_acc.GetClassId());
1036                if (CreateForeignFieldItem(fclass_item, field_id) == nullptr) {
1037                    return false;
1038                }
1039            } else {
1040                auto *class_item = CreateClassItem(field_acc.GetClassId());
1041                if (file_->IsExternal(field_id)) {
1042                    if (CreateForeignFieldItem(class_item, field_id) == nullptr) {
1043                        return false;
1044                    }
1045                } else if (CreateFieldItem(class_item, field_id) == nullptr) {
1046                    return false;
1047                }
1048            }
1049        }
1050    }
1051    return true;
1052}
1053
1054bool FileReader::ReadClasses()
1055{
1056    const auto class_idx = file_->GetClasses();
1057
1058    for (unsigned int id : class_idx) {
1059        File::EntityId eid(id);
1060        if (file_->IsExternal(eid)) {
1061            CreateForeignClassItem(eid);
1062        } else {
1063            CreateClassItem(eid);
1064        }
1065    }
1066
1067    return true;
1068}
1069
1070void FileReader::UpdateDebugInfoDependecies(File::EntityId debug_info_id)
1071{
1072    DebugInfoDataAccessor debug_acc(*file_, debug_info_id);
1073    const uint8_t *program = debug_acc.GetLineNumberProgram();
1074    auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size();
1075    auto opcode_sp = Span(program, size);
1076
1077    size_t i = 0;
1078    LineNumberProgramItem::Opcode opcode;
1079    panda_file::LineProgramState state(*file_, File::EntityId(0), debug_acc.GetLineStart(),
1080                                       debug_acc.GetConstantPool());
1081    while ((opcode = LineNumberProgramItem::Opcode(opcode_sp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) {
1082        switch (opcode) {
1083            case LineNumberProgramItem::Opcode::ADVANCE_PC:
1084            case LineNumberProgramItem::Opcode::ADVANCE_LINE:
1085            case LineNumberProgramItem::Opcode::SET_PROLOGUE_END:
1086            case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: {
1087                break;
1088            }
1089            case LineNumberProgramItem::Opcode::START_LOCAL: {
1090                [[maybe_unused]] int32_t reg_number;
1091                size_t n;
1092                bool is_full;
1093                std::tie(reg_number, n, is_full) = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1094                LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1095                i += n;
1096
1097                auto name_id = File::EntityId(state.ReadULeb128());
1098                std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1099                container_.GetOrCreateStringItem(name);
1100
1101                auto type_id = File::EntityId(state.ReadULeb128());
1102                std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1103                if (file_->IsExternal(type_id)) {
1104                    container_.GetOrCreateForeignClassItem(type_name);
1105                } else {
1106                    container_.GetOrCreateClassItem(type_name);
1107                }
1108                break;
1109            }
1110            case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: {
1111                [[maybe_unused]] int32_t reg_number;
1112                size_t n;
1113                bool is_full;
1114                std::tie(reg_number, n, is_full) = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1115                LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1116                i += n;
1117
1118                auto name_id = File::EntityId(state.ReadULeb128());
1119                std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1120                container_.GetOrCreateStringItem(name);
1121
1122                auto type_id = File::EntityId(state.ReadULeb128());
1123                std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1124                if (file_->IsExternal(type_id)) {
1125                    container_.GetOrCreateForeignClassItem(type_name);
1126                } else {
1127                    container_.GetOrCreateClassItem(type_name);
1128                }
1129
1130                auto type_signature_id = File::EntityId(state.ReadULeb128());
1131                std::string type_signature = utf::Mutf8AsCString(file_->GetStringData(type_signature_id).data);
1132                container_.GetOrCreateStringItem(type_signature);
1133                break;
1134            }
1135            case LineNumberProgramItem::Opcode::END_LOCAL:
1136            case LineNumberProgramItem::Opcode::RESTART_LOCAL: {
1137                [[maybe_unused]] int32_t reg_number;
1138                size_t n;
1139                bool is_full;
1140                std::tie(reg_number, n, is_full) = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1141                LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1142                i += n;
1143                break;
1144            }
1145            case LineNumberProgramItem::Opcode::SET_FILE: {
1146                auto source_file_id = File::EntityId(state.ReadULeb128());
1147                std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id).data);
1148                container_.GetOrCreateStringItem(source_file);
1149                break;
1150            }
1151            case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: {
1152                auto source_code_id = File::EntityId(state.ReadULeb128());
1153                std::string source_code = utf::Mutf8AsCString(file_->GetStringData(source_code_id).data);
1154                container_.GetOrCreateStringItem(source_code);
1155                break;
1156            }
1157            default: {
1158                break;
1159            }
1160        }
1161    }
1162}
1163
1164void FileReader::UpdateDebugInfo(DebugInfoItem *debug_info_item, File::EntityId debug_info_id)
1165{
1166    auto *lnp_item = debug_info_item->GetLineNumberProgram();
1167    DebugInfoDataAccessor debug_acc(*file_, debug_info_id);
1168    const uint8_t *program = debug_acc.GetLineNumberProgram();
1169    auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size();
1170    auto opcode_sp = Span(program, size);
1171
1172    size_t i = 0;
1173    LineNumberProgramItem::Opcode opcode;
1174    panda_file::LineProgramState state(*file_, File::EntityId(0), debug_acc.GetLineStart(),
1175                                       debug_acc.GetConstantPool());
1176    while ((opcode = LineNumberProgramItem::Opcode(opcode_sp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) {
1177        switch (opcode) {
1178            case LineNumberProgramItem::Opcode::ADVANCE_PC: {
1179                lnp_item->EmitAdvancePc(debug_info_item->GetConstantPool(), state.ReadULeb128());
1180                break;
1181            }
1182            case LineNumberProgramItem::Opcode::ADVANCE_LINE: {
1183                lnp_item->EmitAdvanceLine(debug_info_item->GetConstantPool(), state.ReadSLeb128());
1184                break;
1185            }
1186            case LineNumberProgramItem::Opcode::START_LOCAL: {
1187                auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1188                LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1189                i += n;
1190
1191                auto name_id = File::EntityId(state.ReadULeb128());
1192                std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1193                auto *name_item = container_.GetOrCreateStringItem(name);
1194
1195                auto type_id = File::EntityId(state.ReadULeb128());
1196                std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1197                auto *type_item = file_->IsExternal(type_id)
1198                                      ? static_cast<BaseClassItem *>(container_.GetOrCreateForeignClassItem(type_name))
1199                                      : static_cast<BaseClassItem *>(container_.GetOrCreateClassItem(type_name));
1200
1201                lnp_item->EmitStartLocal(debug_info_item->GetConstantPool(), reg_number, name_item,
1202                                         type_item->GetNameItem());
1203                break;
1204            }
1205            case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: {
1206                auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1207                LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1208                i += n;
1209
1210                auto name_id = File::EntityId(state.ReadULeb128());
1211                std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data);
1212                auto *name_item = container_.GetOrCreateStringItem(name);
1213
1214                auto type_id = File::EntityId(state.ReadULeb128());
1215                std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data);
1216                auto *type_item = file_->IsExternal(type_id)
1217                                      ? static_cast<BaseClassItem *>(container_.GetOrCreateForeignClassItem(type_name))
1218                                      : static_cast<BaseClassItem *>(container_.GetOrCreateClassItem(type_name));
1219
1220                auto type_signature_id = File::EntityId(state.ReadULeb128());
1221                std::string type_signature = utf::Mutf8AsCString(file_->GetStringData(type_signature_id).data);
1222                auto *type_signature_item = container_.GetOrCreateStringItem(type_signature);
1223
1224                lnp_item->EmitStartLocalExtended(debug_info_item->GetConstantPool(), reg_number, name_item,
1225                                                 type_item->GetNameItem(), type_signature_item);
1226                break;
1227            }
1228            case LineNumberProgramItem::Opcode::END_LOCAL: {
1229                auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1230                LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1231                i += n;
1232
1233                lnp_item->EmitEndLocal(reg_number);
1234                break;
1235            }
1236            case LineNumberProgramItem::Opcode::RESTART_LOCAL: {
1237                auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcode_sp[i]);
1238                LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number";
1239                i += n;
1240
1241                lnp_item->EmitRestartLocal(reg_number);
1242                break;
1243            }
1244            case LineNumberProgramItem::Opcode::SET_PROLOGUE_END: {
1245                lnp_item->EmitPrologEnd();
1246                break;
1247            }
1248            case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: {
1249                lnp_item->EmitEpilogBegin();
1250                break;
1251            }
1252            case LineNumberProgramItem::Opcode::SET_FILE: {
1253                auto source_file_id = File::EntityId(state.ReadULeb128());
1254                std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id).data);
1255                auto *source_file_item = container_.GetOrCreateStringItem(source_file);
1256                lnp_item->EmitSetFile(debug_info_item->GetConstantPool(), source_file_item);
1257                break;
1258            }
1259            case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: {
1260                auto source_code_id = File::EntityId(state.ReadULeb128());
1261                std::string source_code = utf::Mutf8AsCString(file_->GetStringData(source_code_id).data);
1262                auto *source_code_item = container_.GetOrCreateStringItem(source_code);
1263                lnp_item->EmitSetFile(debug_info_item->GetConstantPool(), source_code_item);
1264                break;
1265            }
1266            default: {
1267                auto opcode_value = static_cast<uint8_t>(opcode);
1268                auto adjust_opcode = opcode_value - LineNumberProgramItem::OPCODE_BASE;
1269                uint32_t pc_diff = adjust_opcode / LineNumberProgramItem::LINE_RANGE;
1270                int32_t line_diff =
1271                    adjust_opcode % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE;
1272                lnp_item->EmitSpecialOpcode(pc_diff, line_diff);
1273                break;
1274            }
1275        }
1276    }
1277    lnp_item->EmitEnd();
1278}
1279
1280void AddIndexDependencyInstFlag(CodeItem *code_item, MethodItem *method_item,
1281                                const std::unordered_map<File::EntityId, File::EntityId> &reverse_done)
1282{
1283    using Flags = panda::BytecodeInst<panda::BytecodeInstMode::FAST>::Flags;
1284
1285    size_t offset = 0;
1286    BytecodeInstruction inst(code_item->GetInstructions()->data());
1287    while (offset < code_item->GetCodeSize()) {
1288        if (inst.HasFlag(Flags::TYPE_ID)) {
1289            BytecodeId b_id = inst.GetId();
1290            File::Index idx = b_id.AsIndex();
1291            File::EntityId method_id = reverse_done.find(method_item)->second;
1292            File::EntityId old_id = file_->ResolveClassIndex(method_id, idx);
1293            ASSERT(items_done_.find(old_id) != items_done_.end());
1294            auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1295            method_item->AddIndexDependency(idx_item);
1296        } else if (inst.HasFlag(Flags::METHOD_ID)) {
1297            BytecodeId b_id = inst.GetId();
1298            File::Index idx = b_id.AsIndex();
1299            File::EntityId method_id = reverse_done.find(method_item)->second;
1300            File::EntityId old_id = file_->ResolveMethodIndex(method_id, idx);
1301            ASSERT(items_done_.find(old_id) != items_done_.end());
1302            auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1303            method_item->AddIndexDependency(idx_item);
1304        } else if (inst.HasFlag(Flags::FIELD_ID)) {
1305            BytecodeId b_id = inst.GetId();
1306            File::Index idx = b_id.AsIndex();
1307            File::EntityId method_id = reverse_done.find(method_item)->second;
1308            File::EntityId old_id = file_->ResolveFieldIndex(method_id, idx);
1309            ASSERT(items_done_.find(old_id) != items_done_.end());
1310            auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1311            method_item->AddIndexDependency(idx_item);
1312        } else if (inst.HasFlag(Flags::STRING_ID)) {
1313            BytecodeId b_id = inst.GetId();
1314            File::EntityId old_id = b_id.AsFileId();
1315            auto data = file_->GetStringData(old_id);
1316            std::string item_str(utf::Mutf8AsCString(data.data));
1317            container_.GetOrCreateStringItem(item_str);
1318        }
1319        offset += inst.GetSize();
1320        inst = inst.GetNext();
1321    }
1322}
1323
1324void FileReader::UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverse_done)
1325{
1326    auto *class_map = container_.GetClassMap();
1327
1328    // First pass, add dependencies bytecode -> new items
1329    for (const auto &it : *class_map) {
1330        auto *base_class_item = it.second;
1331        if (base_class_item->IsForeign()) {
1332            continue;
1333        }
1334        auto *class_item = static_cast<ClassItem *>(base_class_item);
1335        class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) {
1336            auto *method_item = static_cast<MethodItem *>(param_item);
1337            auto *code_item = method_item->GetCode();
1338            if (code_item == nullptr) {
1339                return true;
1340            }
1341
1342            auto *debug_info_item = method_item->GetDebugInfo();
1343            if (debug_info_item != nullptr) {
1344                UpdateDebugInfoDependecies(reverse_done.find(debug_info_item)->second);
1345            }
1346
1347            AddIndexDependencyInstFlag(inst, method_item, reverse_done);
1348
1349            return true;
1350        });
1351    }
1352}
1353
1354void UpdateIdInstFlag(CodeItem *code_item, MethodItem *method_item,
1355                      const std::unordered_map<File::EntityId, File::EntityId> &reverse_done)
1356{
1357    using Flags = panda::BytecodeInst<panda::BytecodeInstMode::FAST>::Flags;
1358
1359    size_t offset = 0;
1360    BytecodeInstruction inst(code_item->GetInstructions()->data());
1361    while (offset < code_item->GetCodeSize()) {
1362        if (inst.HasFlag(Flags::TYPE_ID)) {
1363            BytecodeId b_id = inst.GetId();
1364            File::Index idx = b_id.AsIndex();
1365            File::EntityId method_id = reverse_done.find(method_item)->second;
1366            File::EntityId old_id = file_->ResolveClassIndex(method_id, idx);
1367            ASSERT(items_done_.find(old_id) != items_done_.end());
1368            auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1369            uint32_t index = idx_item->GetIndex(method_item);
1370            inst.UpdateId(BytecodeId(index));
1371        } else if (inst.HasFlag(Flags::METHOD_ID)) {
1372            BytecodeId b_id = inst.GetId();
1373            File::Index idx = b_id.AsIndex();
1374            File::EntityId method_id = reverse_done.find(method_item)->second;
1375            File::EntityId old_id = file_->ResolveMethodIndex(method_id, idx);
1376            ASSERT(items_done_.find(old_id) != items_done_.end());
1377            auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1378            uint32_t index = idx_item->GetIndex(method_item);
1379            inst.UpdateId(BytecodeId(index));
1380        } else if (inst.HasFlag(Flags::FIELD_ID)) {
1381            BytecodeId b_id = inst.GetId();
1382            File::Index idx = b_id.AsIndex();
1383            File::EntityId method_id = reverse_done.find(method_item)->second;
1384            File::EntityId old_id = file_->ResolveFieldIndex(method_id, idx);
1385            ASSERT(items_done_.find(old_id) != items_done_.end());
1386            auto *idx_item = static_cast<IndexedItem *>(items_done_.find(old_id)->second);
1387            uint32_t index = idx_item->GetIndex(method_item);
1388            inst.UpdateId(BytecodeId(index));
1389        } else if (inst.HasFlag(Flags::STRING_ID)) {
1390            BytecodeId b_id = inst.GetId();
1391            File::EntityId old_id = b_id.AsFileId();
1392            auto data = file_->GetStringData(old_id);
1393            std::string item_str(utf::Mutf8AsCString(data.data));
1394            auto *string_item = container_.GetOrCreateStringItem(item_str);
1395            inst.UpdateId(BytecodeId(string_item->GetFileId().GetOffset()));
1396        } else if (inst.HasFlag(Flags::LITERALARRAY_ID)) {
1397            BytecodeId b_id = inst.GetId();
1398            File::EntityId old_id = b_id.AsFileId();
1399            ASSERT(items_done_.find(old_id) != items_done_.end());
1400            auto *array_item = items_done_.find(old_id)->second;
1401            inst.UpdateId(BytecodeId(array_item->GetFileId().GetOffset()));
1402        }
1403        offset += inst.GetSize();
1404        inst = inst.GetNext();
1405    }
1406}
1407
1408void FileReader::ComputeLayoutAndUpdateIndices()
1409{
1410    std::map<BaseItem *, File::EntityId> reverse_done;
1411    for (const auto &it : items_done_) {
1412        reverse_done.insert({it.second, it.first});
1413    }
1414
1415    auto *class_map = container_.GetClassMap();
1416
1417    UpdateCodeAndDebugInfoDependencies(reverse_done);
1418
1419    container_.ComputeLayout();
1420
1421    // Second pass, update debug info
1422    for (const auto &it : *class_map) {
1423        auto *base_class_item = it.second;
1424        if (base_class_item->IsForeign()) {
1425            continue;
1426        }
1427        auto *class_item = static_cast<ClassItem *>(base_class_item);
1428        class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) {
1429            auto *method_item = static_cast<MethodItem *>(param_item);
1430            auto *code_item = method_item->GetCode();
1431            if (code_item == nullptr) {
1432                return true;
1433            }
1434
1435            auto *debug_info_item = method_item->GetDebugInfo();
1436            if (debug_info_item != nullptr) {
1437                UpdateDebugInfo(debug_info_item, reverse_done.find(debug_info_item)->second);
1438            }
1439
1440            return true;
1441        });
1442    }
1443
1444    container_.DeduplicateItems(false);
1445    container_.ComputeLayout();
1446
1447    // Third pass, update bytecode indices
1448    for (const auto &it : *class_map) {
1449        auto *base_class_item = it.second;
1450        if (base_class_item->IsForeign()) {
1451            continue;
1452        }
1453        auto *class_item = static_cast<ClassItem *>(base_class_item);
1454        class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) {
1455            auto *method_item = static_cast<MethodItem *>(param_item);
1456            auto *code_item = method_item->GetCode();
1457            if (code_item == nullptr) {
1458                return true;
1459            }
1460
1461            UpdateIdInstFlag(code_item, method_item, reverse_done);
1462
1463            return true;
1464        });
1465    }
1466}
1467
1468}  // namespace panda::panda_file
1469