/** * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "libpandafile/bytecode_instruction-inl.h" #include "libpandafile/line_number_program.h" #include "libpandafile/literal_data_accessor-inl.h" #include "libpandafile/class_data_accessor-inl.h" #include "libpandafile/proto_data_accessor-inl.h" #include "libpandafile/code_data_accessor-inl.h" #include "libpandafile/debug_data_accessor-inl.h" #include "libpandafile/field_data_accessor-inl.h" #include "libpandafile/method_data_accessor-inl.h" #include "file.h" #include "libpandabase/utils/utf.h" #include "libpandafile/file_reader.h" namespace panda::panda_file { bool FileReader::ReadContainer() { if (!ReadClasses()) { return false; } if (!ReadLiteralArrayItems()) { return false; } if (!ReadIndexHeaders()) { return false; } ComputeLayoutAndUpdateIndices(); return true; } /* static */ bool FileReader::CreateLiteralArrayItem(const LiteralDataAccessor::LiteralValue &lit_value, const LiteralTag &tag, File::EntityId array_id) { auto it = items_done_.find(array_id); if (it != items_done_.end()) { return true; } LiteralArrayItem *item = container_.GetOrCreateLiteralArrayItem(std::to_string(array_id.GetOffset())); items_done_.insert({array_id, static_cast(item)}); File::EntityId id(std::get(lit_value)); auto sp = file_->GetSpanFromId(id); std::vector literal_array; literal_array.emplace_back(static_cast(tag)); switch (tag) { case panda_file::LiteralTag::BOOL: { auto v = helpers::Read(&sp); literal_array.emplace_back(static_cast(v)); break; } case panda_file::LiteralTag::TAGVALUE: case panda_file::LiteralTag::ACCESSOR: case panda_file::LiteralTag::NULLVALUE: { auto v = helpers::Read(&sp); literal_array.emplace_back(v); break; } case panda_file::LiteralTag::ARRAY_U1: case panda_file::LiteralTag::ARRAY_I8: case panda_file::LiteralTag::ARRAY_U8: { auto len = helpers::Read(&sp); literal_array.emplace_back(len); for (size_t i = 0; i < len; i++) { auto v = helpers::Read(&sp); literal_array.emplace_back(v); } break; } case panda_file::LiteralTag::ARRAY_I16: case panda_file::LiteralTag::ARRAY_U16: { auto len = helpers::Read(&sp); literal_array.emplace_back(len); for (size_t i = 0; i < len; i++) { auto v = helpers::Read(&sp); literal_array.emplace_back(v); } break; } case panda_file::LiteralTag::INTEGER: { auto v = helpers::Read(&sp); literal_array.emplace_back(v); break; } case panda_file::LiteralTag::ARRAY_I32: case panda_file::LiteralTag::ARRAY_U32: case panda_file::LiteralTag::ARRAY_F32: { auto len = helpers::Read(&sp); literal_array.emplace_back(len); for (size_t i = 0; i < len; i++) { auto v = helpers::Read(&sp); literal_array.emplace_back(v); } break; } case panda_file::LiteralTag::ARRAY_I64: case panda_file::LiteralTag::ARRAY_U64: case panda_file::LiteralTag::ARRAY_F64: { auto len = helpers::Read(&sp); literal_array.emplace_back(len); for (size_t i = 0; i < len; i++) { auto v = helpers::Read(&sp); literal_array.emplace_back(v); } break; } case panda_file::LiteralTag::FLOAT: { auto v = helpers::Read(&sp); literal_array.emplace_back(v); break; } case panda_file::LiteralTag::DOUBLE: { auto v = panda_file::helpers::Read(&sp); literal_array.emplace_back(v); break; } case panda_file::LiteralTag::STRING: { File::EntityId str_id(helpers::Read(&sp)); auto data = file_->GetStringData(str_id); std::string item_str(utf::Mutf8AsCString(data.data)); auto *string_item = container_.GetOrCreateStringItem(item_str); literal_array.emplace_back(string_item); break; } case panda_file::LiteralTag::ARRAY_STRING: { auto len = helpers::Read(&sp); literal_array.emplace_back(len); for (size_t i = 0; i < len; i++) { File::EntityId str_id(helpers::Read(&sp)); auto data = file_->GetStringData(str_id); std::string item_str(utf::Mutf8AsCString(data.data)); auto *string_item = container_.GetOrCreateStringItem(item_str); literal_array.emplace_back(string_item); } break; } case panda_file::LiteralTag::METHOD: case panda_file::LiteralTag::GENERATORMETHOD: case panda_file::LiteralTag::ASYNCGENERATORMETHOD: { File::EntityId method_id(helpers::Read(&sp)); MethodDataAccessor method_acc(*file_, method_id); File::EntityId class_id(method_acc.GetClassId()); auto *class_item = CreateClassItem(class_id); literal_array.emplace_back(CreateMethodItem(class_item, method_id)); break; } default: UNREACHABLE(); } item->AddItems(literal_array); return true; } // NOLINTNEXTLINE(readability-function-size) AnnotationItem *FileReader::CreateAnnotationItem(File::EntityId ann_id) { auto it = items_done_.find(ann_id); if (it != items_done_.end()) { return static_cast(it->second); } AnnotationDataAccessor ann_acc(*file_, ann_id); File::EntityId ann_class_id {ann_acc.GetClassId()}; AnnotationItem *ann_item = nullptr; if (!file_->IsExternal(ann_class_id)) { auto *ann_class_item = CreateClassItem(ann_class_id); ann_item = container_.CreateItem(ann_class_item, std::vector(), std::vector()); } else { auto *ann_class_item = CreateForeignClassItem(ann_class_id); ann_item = container_.CreateItem(ann_class_item, std::vector(), std::vector()); } ASSERT(ann_item != nullptr); items_done_.insert({ann_id, static_cast(ann_item)}); std::vector item_elements; std::vector tag_elements; for (size_t i = 0; i < ann_acc.GetCount(); i++) { AnnotationDataAccessor::Tag ann_tag = ann_acc.GetTag(i); AnnotationDataAccessor::Elem ann_elem = ann_acc.GetElement(i); ValueItem *elem_value_item = nullptr; switch (ann_tag.GetItem()) { case '1': case '2': case '3': { auto scalar = ann_elem.GetScalarValue(); elem_value_item = container_.GetOrCreateIntegerValueItem(scalar.Get()); break; } case '4': case '5': { auto scalar = ann_elem.GetScalarValue(); elem_value_item = container_.GetOrCreateIntegerValueItem(scalar.Get()); break; } case '6': case '7': { auto scalar = ann_elem.GetScalarValue(); elem_value_item = container_.GetOrCreateIntegerValueItem(scalar.Get()); break; } case '8': case '9': { auto scalar = ann_elem.GetScalarValue(); elem_value_item = container_.GetOrCreateLongValueItem(scalar.Get()); break; } case 'A': { auto scalar = ann_elem.GetScalarValue(); elem_value_item = container_.GetOrCreateFloatValueItem(scalar.Get()); break; } case 'B': { auto scalar = ann_elem.GetScalarValue(); elem_value_item = container_.GetOrCreateDoubleValueItem(scalar.Get()); break; } case 'C': { auto scalar = ann_elem.GetScalarValue(); const File::EntityId str_id(scalar.Get()); auto data = file_->GetStringData(str_id); std::string item_str(utf::Mutf8AsCString(data.data)); auto *str_item = container_.GetOrCreateStringItem(item_str); elem_value_item = container_.GetOrCreateIdValueItem(str_item); break; } case 'D': { auto scalar = ann_elem.GetScalarValue(); const File::EntityId class_id {scalar.Get()}; elem_value_item = container_.GetOrCreateIdValueItem(CreateGenericClassItem(class_id)); break; } case 'E': { auto scalar = ann_elem.GetScalarValue(); const File::EntityId method_id {scalar.Get()}; MethodDataAccessor method_acc(*file_, method_id); auto *cls_item = CreateGenericClassItem(method_acc.GetClassId()); elem_value_item = container_.GetOrCreateIdValueItem(CreateGenericMethodItem(cls_item, method_id)); break; } case 'F': { auto scalar = ann_elem.GetScalarValue(); const File::EntityId field_id {scalar.Get()}; FieldDataAccessor field_acc(*file_, field_id); auto *cls_item = CreateGenericClassItem(field_acc.GetClassId()); elem_value_item = container_.GetOrCreateIdValueItem(CreateGenericFieldItem(cls_item, field_id)); break; } case 'G': { auto scalar = ann_elem.GetScalarValue(); const File::EntityId ann_item_id {scalar.Get()}; elem_value_item = container_.GetOrCreateIdValueItem(CreateAnnotationItem(ann_item_id)); break; } case 'J': { LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far"; break; } case '*': { elem_value_item = container_.GetOrCreateIntegerValueItem(0); break; } case 'K': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(static_cast(array.Get(j))); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::U1), std::move(items))); break; } case 'L': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(static_cast(array.Get(j))); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::I8), std::move(items))); break; } case 'M': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(static_cast(array.Get(j))); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::U8), std::move(items))); break; } case 'N': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(static_cast(array.Get(j))); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::I16), std::move(items))); break; } case 'O': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(static_cast(array.Get(j))); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::U16), std::move(items))); break; } case 'P': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(array.Get(j)); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::I32), std::move(items))); break; } case 'Q': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(array.Get(j)); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::U32), std::move(items))); break; } case 'R': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(array.Get(j)); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::I64), std::move(items))); break; } case 'S': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(array.Get(j)); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::U64), std::move(items))); break; } case 'T': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(array.Get(j)); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::F32), std::move(items))); break; } case 'U': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { ScalarValueItem scalar(array.Get(j)); items.emplace_back(std::move(scalar)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::F64), std::move(items))); break; } case 'V': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { const File::EntityId str_id(array.Get(j)); auto data = file_->GetStringData(str_id); std::string item_str(utf::Mutf8AsCString(data.data)); items.emplace_back(ScalarValueItem(container_.GetOrCreateStringItem(item_str))); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::REFERENCE), std::move(items))); break; } case 'W': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { const File::EntityId class_id {array.Get(j)}; BaseClassItem *cls_item = nullptr; if (file_->IsExternal(class_id)) { cls_item = CreateForeignClassItem(class_id); } else { cls_item = CreateClassItem(class_id); } ASSERT(cls_item != nullptr); items.emplace_back(ScalarValueItem(cls_item)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::REFERENCE), std::move(items))); break; } case 'X': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { const File::EntityId method_id {array.Get(j)}; MethodDataAccessor method_acc(*file_, method_id); auto *cls_item = CreateGenericClassItem(method_acc.GetClassId()); items.emplace_back(ScalarValueItem(CreateGenericMethodItem(cls_item, method_id))); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::REFERENCE), std::move(items))); break; } case 'Y': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { const File::EntityId field_id {array.Get(j)}; FieldDataAccessor field_acc(*file_, field_id); auto *cls_item = CreateGenericClassItem(field_acc.GetClassId()); items.emplace_back(ScalarValueItem(CreateGenericFieldItem(cls_item, field_id))); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::REFERENCE), std::move(items))); break; } case 'H': { // ARRAY can appear for empty arrays only ASSERT(ann_elem.GetArrayValue().GetCount() == 0); elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::VOID), std::vector())); break; } case 'Z': { auto array = ann_elem.GetArrayValue(); std::vector items; for (size_t j = 0; j < array.GetCount(); j++) { const File::EntityId ann_item_id {array.Get(j)}; items.emplace_back(CreateAnnotationItem(ann_item_id)); } elem_value_item = static_cast( container_.CreateItem(Type(Type::TypeId::REFERENCE), std::move(items))); break; } case '@': { // TODO(nsizov): support it LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far"; break; } // array case 'I': // VOID(I) and ARRAY(H) value should not appear default: UNREACHABLE(); } ASSERT(elem_value_item != nullptr); tag_elements.emplace_back(AnnotationItem::Tag(static_cast(ann_tag.GetItem()))); File::EntityId name_id(ann_elem.GetNameId()); std::string annot_name_str(utf::Mutf8AsCString(file_->GetStringData(name_id).data)); auto elem_name_item = container_.GetOrCreateStringItem(annot_name_str); item_elements.emplace_back(AnnotationItem::Elem(elem_name_item, elem_value_item)); } ann_item->SetElements(std::move(item_elements)); ann_item->SetTags(std::move(tag_elements)); return ann_item; } TypeItem *FileReader::CreateParamTypeItem(ProtoDataAccessor *proto_acc, size_t param_num, size_t reference_num) { Type param_type = proto_acc->GetArgType(param_num); TypeItem *param_type_item = nullptr; if (param_type.IsPrimitive()) { param_type_item = container_.GetOrCreatePrimitiveTypeItem(param_type); } else { const File::EntityId type_cls_id = proto_acc->GetReferenceType(reference_num); if (file_->IsExternal(type_cls_id)) { param_type_item = CreateForeignClassItem(type_cls_id); } else { param_type_item = CreateClassItem(type_cls_id); } } ASSERT(param_type_item != nullptr); return param_type_item; } std::vector FileReader::CreateMethodParamItems(ProtoDataAccessor *proto_acc, MethodDataAccessor *method_acc, size_t reference_num) { std::vector param_items; for (size_t i = 0; i < proto_acc->GetNumArgs(); i++) { TypeItem *param_type_item = CreateParamTypeItem(proto_acc, i, reference_num); if (param_type_item->GetType().IsReference()) { reference_num++; } param_items.emplace_back(MethodParamItem(param_type_item)); } auto param_ann_id = method_acc->GetParamAnnotationId(); if (param_ann_id) { ParamAnnotationsDataAccessor param_acc(*file_, param_ann_id.value()); for (size_t i = 0; i < proto_acc->GetNumArgs(); i++) { ParamAnnotationsDataAccessor::AnnotationArray ann_arr = param_acc.GetAnnotationArray(i); ann_arr.EnumerateAnnotations([&](File::EntityId ann_id) { auto ann_item = CreateAnnotationItem(ann_id); param_items[i].AddAnnotation(ann_item); }); } } auto runtime_param_ann_id = method_acc->GetRuntimeParamAnnotationId(); if (runtime_param_ann_id) { ParamAnnotationsDataAccessor param_acc(*file_, runtime_param_ann_id.value()); for (size_t i = 0; i < proto_acc->GetNumArgs(); i++) { ParamAnnotationsDataAccessor::AnnotationArray ann_arr = param_acc.GetAnnotationArray(i); ann_arr.EnumerateAnnotations([&](File::EntityId ann_id) { auto ann_item = CreateAnnotationItem(ann_id); param_items[i].AddRuntimeAnnotation(ann_item); }); } } return param_items; } DebugInfoItem *FileReader::CreateDebugInfoItem(File::EntityId debug_info_id) { auto it = items_done_.find(debug_info_id); if (it != items_done_.end()) { return static_cast(it->second); } auto *lnp_item = container_.CreateLineNumberProgramItem(); auto *debug_info_item = container_.CreateItem(lnp_item); items_done_.insert({debug_info_id, static_cast(debug_info_item)}); DebugInfoDataAccessor debug_acc(*file_, debug_info_id); debug_info_item->SetLineNumber(debug_acc.GetLineStart()); debug_acc.EnumerateParameters([&](File::EntityId param_id) { auto data = file_->GetStringData(param_id); std::string item_str(utf::Mutf8AsCString(data.data)); auto *string_item = container_.GetOrCreateStringItem(item_str); debug_info_item->AddParameter(string_item); }); return debug_info_item; } MethodItem *FileReader::CreateMethodItem(ClassItem *cls, File::EntityId method_id) { auto it = items_done_.find(method_id); if (it != items_done_.end()) { return static_cast(it->second); } MethodDataAccessor method_acc(*file_, method_id); auto data = file_->GetStringData(method_acc.GetNameId()); std::string method_name(utf::Mutf8AsCString(data.data)); auto *method_str_item = container_.GetOrCreateStringItem(method_name); ProtoDataAccessor proto_acc(*file_, method_acc.GetProtoId()); Type ret_type = proto_acc.GetReturnType(); size_t reference_num = 0; TypeItem *ret_type_item = nullptr; if (ret_type.IsPrimitive()) { ret_type_item = container_.GetOrCreatePrimitiveTypeItem(ret_type); } else { const File::EntityId type_cls_id = proto_acc.GetReferenceType(reference_num); if (file_->IsExternal(type_cls_id)) { ret_type_item = CreateForeignClassItem(type_cls_id); } else { ret_type_item = CreateClassItem(type_cls_id); } reference_num++; } ASSERT(ret_type_item != nullptr); auto param_items = CreateMethodParamItems(&proto_acc, &method_acc, reference_num); // Double check if we done this method while computing params auto it_check = items_done_.find(method_id); if (it_check != items_done_.end()) { return static_cast(it_check->second); } auto *proto_item = container_.GetOrCreateProtoItem(ret_type_item, param_items); auto *method_item = cls->AddMethod(method_str_item, proto_item, method_acc.GetAccessFlags(), std::move(param_items)); if (method_item->HasRuntimeParamAnnotations()) { container_.CreateItem(method_item, true); } if (method_item->HasParamAnnotations()) { container_.CreateItem(method_item, false); } items_done_.insert({method_id, static_cast(method_item)}); method_acc.EnumerateAnnotations( [&](File::EntityId ann_id) { method_item->AddAnnotation(CreateAnnotationItem(ann_id)); }); method_acc.EnumerateRuntimeAnnotations( [&](File::EntityId ann_id) { method_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); }); method_acc.EnumerateTypeAnnotations( [&](File::EntityId ann_id) { method_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); }); method_acc.EnumerateRuntimeTypeAnnotations( [&](File::EntityId ann_id) { method_item->AddRuntimeTypeAnnotation(CreateAnnotationItem(ann_id)); }); auto code_id = method_acc.GetCodeId(); if (code_id) { CodeDataAccessor code_acc(*file_, code_id.value()); std::vector instructions(code_acc.GetCodeSize()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) instructions.assign(code_acc.GetInstructions(), code_acc.GetInstructions() + code_acc.GetCodeSize()); auto *code_item = container_.CreateItem(code_acc.GetNumVregs(), code_acc.GetNumArgs(), std::move(instructions)); code_acc.EnumerateTryBlocks([&](CodeDataAccessor::TryBlock &try_block) { std::vector catch_blocks; try_block.EnumerateCatchBlocks([&](CodeDataAccessor::CatchBlock &catch_block) { BaseClassItem *catch_type_item = nullptr; auto type_idx = catch_block.GetTypeIdx(); if (type_idx != panda_file::INVALID_INDEX) { File::EntityId catch_cls_id = file_->ResolveClassIndex(method_id, catch_block.GetTypeIdx()); if (file_->IsExternal(catch_cls_id)) { catch_type_item = CreateForeignClassItem(catch_cls_id); } else { catch_type_item = CreateClassItem(catch_cls_id); } method_item->AddIndexDependency(catch_type_item); } catch_blocks.emplace_back(CodeItem::CatchBlock(method_item, catch_type_item, catch_block.GetHandlerPc(), catch_block.GetCodeSize())); return true; }); code_item->AddTryBlock( CodeItem::TryBlock(try_block.GetStartPc(), try_block.GetLength(), std::move(catch_blocks))); return true; }); method_item->SetCode(code_item); } auto debug_info_id = method_acc.GetDebugInfoId(); if (debug_info_id) { method_item->SetDebugInfo(CreateDebugInfoItem(debug_info_id.value())); } auto source_lang = method_acc.GetSourceLang(); if (source_lang) { method_item->SetSourceLang(source_lang.value()); } return method_item; } MethodHandleItem *FileReader::CreateMethodHandleItem(File::EntityId mh_id) { (void)mh_id; ASSERT(false); return nullptr; // STUB } FieldItem *FileReader::CreateFieldItem(ClassItem *cls, File::EntityId field_id) { auto it = items_done_.find(field_id); if (it != items_done_.end()) { return static_cast(it->second); } FieldDataAccessor field_acc(*file_, field_id); auto data = file_->GetStringData(field_acc.GetNameId()); std::string string_name(utf::Mutf8AsCString(data.data)); auto *field_name = container_.GetOrCreateStringItem(string_name); Type field_type = Type::GetTypeFromFieldEncoding(field_acc.GetType()); TypeItem *field_type_item = nullptr; if (field_type.IsReference()) { File::EntityId type_id(field_acc.GetType()); if (file_->IsExternal(type_id)) { field_type_item = CreateForeignClassItem(type_id); } else { field_type_item = CreateClassItem(type_id); // Double check if we done this field while generated class item auto it_check = items_done_.find(field_id); if (it_check != items_done_.end()) { return static_cast(it_check->second); } } } else { field_type_item = container_.GetOrCreatePrimitiveTypeItem(field_type.GetId()); } ASSERT(field_type_item != nullptr); FieldItem *field_item = cls->AddField(field_name, field_type_item, field_acc.GetAccessFlags()); items_done_.insert({field_id, static_cast(field_item)}); switch (field_type.GetId()) { case Type::TypeId::U1: case Type::TypeId::I8: case Type::TypeId::U8: SetIntegerFieldValue(&field_acc, field_item); break; case Type::TypeId::I16: case Type::TypeId::U16: SetIntegerFieldValue(&field_acc, field_item); break; case Type::TypeId::I32: case Type::TypeId::U32: SetIntegerFieldValue(&field_acc, field_item); break; case Type::TypeId::I64: case Type::TypeId::U64: SetIntegerFieldValue(&field_acc, field_item); break; case Type::TypeId::F32: SetFloatFieldValue(&field_acc, field_item); break; case Type::TypeId::F64: SetFloatFieldValue(&field_acc, field_item); break; case Type::TypeId::REFERENCE: SetStringFieldValue(&field_acc, field_item); break; case Type::TypeId::TAGGED: default: UNREACHABLE(); break; } field_acc.EnumerateAnnotations( [&](File::EntityId ann_id) { field_item->AddAnnotation(CreateAnnotationItem(ann_id)); }); field_acc.EnumerateRuntimeAnnotations( [&](File::EntityId ann_id) { field_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); }); field_acc.EnumerateRuntimeTypeAnnotations( [&](File::EntityId ann_id) { field_item->AddRuntimeTypeAnnotation(CreateAnnotationItem(ann_id)); }); field_acc.EnumerateTypeAnnotations( [&](File::EntityId ann_id) { field_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); }); return field_item; } ForeignMethodItem *FileReader::CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId method_id) { auto it = items_done_.find(method_id); if (it != items_done_.end()) { return static_cast(it->second); } MethodDataAccessor method_acc(*file_, method_id); auto data = file_->GetStringData(method_acc.GetNameId()); std::string method_name(utf::Mutf8AsCString(data.data)); auto *method_str_item = container_.GetOrCreateStringItem(method_name); ProtoDataAccessor proto_acc(*file_, method_acc.GetProtoId()); Type ret_type = proto_acc.GetReturnType(); size_t reference_num = 0; TypeItem *ret_type_item = nullptr; if (ret_type.IsPrimitive()) { ret_type_item = container_.GetOrCreatePrimitiveTypeItem(ret_type); } else { const File::EntityId type_cls_id = proto_acc.GetReferenceType(reference_num); if (file_->IsExternal(type_cls_id)) { ret_type_item = CreateForeignClassItem(type_cls_id); } else { ret_type_item = CreateClassItem(type_cls_id); } reference_num++; } ASSERT(ret_type_item != nullptr); auto param_items = CreateMethodParamItems(&proto_acc, &method_acc, reference_num); // Double check if we done this method while computing params auto it_check = items_done_.find(method_id); if (it_check != items_done_.end()) { return static_cast(it_check->second); } auto *proto_item = container_.GetOrCreateProtoItem(ret_type_item, param_items); auto *method_item = container_.CreateItem(fcls, method_str_item, proto_item, method_acc.GetAccessFlags()); items_done_.insert({method_id, static_cast(method_item)}); return method_item; } ForeignFieldItem *FileReader::CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId field_id) { auto it = items_done_.find(field_id); if (it != items_done_.end()) { return static_cast(it->second); } FieldDataAccessor field_acc(*file_, field_id); auto data = file_->GetStringData(field_acc.GetNameId()); std::string string_name(utf::Mutf8AsCString(data.data)); auto *field_name = container_.GetOrCreateStringItem(string_name); Type field_type = Type::GetTypeFromFieldEncoding(field_acc.GetType()); TypeItem *field_type_item = nullptr; if (field_type.IsReference()) { File::EntityId type_id(field_acc.GetType()); if (file_->IsExternal(type_id)) { field_type_item = CreateForeignClassItem(type_id); } else { field_type_item = CreateClassItem(type_id); // Double check if we done this field while generated class item auto it_check = items_done_.find(field_id); if (it_check != items_done_.end()) { return static_cast(it_check->second); } } } else { field_type_item = container_.GetOrCreatePrimitiveTypeItem(field_type.GetId()); } ASSERT(field_type_item != nullptr); auto *field_item = container_.CreateItem(fcls, field_name, field_type_item); items_done_.insert({field_id, static_cast(field_item)}); return field_item; } ForeignClassItem *FileReader::CreateForeignClassItem(File::EntityId class_id) { auto it = items_done_.find(class_id); if (it != items_done_.end()) { return static_cast(it->second); } std::string class_name(utf::Mutf8AsCString(file_->GetStringData(class_id).data)); auto *class_item = container_.GetOrCreateForeignClassItem(class_name); items_done_.insert({class_id, static_cast(class_item)}); return class_item; } ClassItem *FileReader::CreateClassItem(File::EntityId class_id) { auto it = items_done_.find(class_id); if (it != items_done_.end()) { return static_cast(it->second); } ClassDataAccessor class_acc(*file_, class_id); std::string class_name(utf::Mutf8AsCString(file_->GetStringData(class_id).data)); auto *class_item = container_.GetOrCreateClassItem(class_name); items_done_.insert({class_id, static_cast(class_item)}); class_item->SetAccessFlags(class_acc.GetAccessFlags()); auto source_lang_opt = class_acc.GetSourceLang(); if (source_lang_opt) { class_item->SetSourceLang(source_lang_opt.value()); } auto super_class_id = class_acc.GetSuperClassId(); if (super_class_id.GetOffset() != 0) { if (super_class_id.GetOffset() == class_id.GetOffset()) { LOG(FATAL, PANDAFILE) << "Class " << class_name << " has cyclic inheritance"; } if (file_->IsExternal(super_class_id)) { auto *super_class_item = CreateForeignClassItem(super_class_id); class_item->SetSuperClass(super_class_item); } else { auto *super_class_item = CreateClassItem(super_class_id); class_item->SetSuperClass(super_class_item); } } class_acc.EnumerateInterfaces([&](File::EntityId iface_id) { if (file_->IsExternal(iface_id)) { class_item->AddInterface(CreateForeignClassItem(iface_id)); } else { class_item->AddInterface(CreateClassItem(iface_id)); } }); class_acc.EnumerateAnnotations( [&](File::EntityId ann_id) { class_item->AddAnnotation(CreateAnnotationItem(ann_id)); }); class_acc.EnumerateRuntimeAnnotations( [&](File::EntityId ann_id) { class_item->AddRuntimeAnnotation(CreateAnnotationItem(ann_id)); }); class_acc.EnumerateTypeAnnotations( [&](File::EntityId ann_id) { class_item->AddTypeAnnotation(CreateAnnotationItem(ann_id)); }); class_acc.EnumerateFields( [&](FieldDataAccessor &field_acc) { CreateFieldItem(class_item, field_acc.GetFieldId()); }); class_acc.EnumerateMethods( [&](MethodDataAccessor &method_acc) { CreateMethodItem(class_item, method_acc.GetMethodId()); }); auto source_file_id = class_acc.GetSourceFileId(); if (source_file_id) { std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id.value()).data); class_item->SetSourceFile(container_.GetOrCreateStringItem(source_file)); } ASSERT(class_item != nullptr); return class_item; } bool FileReader::ReadLiteralArrayItems() { const auto lit_arrays_id = file_->GetLiteralArraysId(); LiteralDataAccessor lit_array_accessor(*file_, lit_arrays_id); size_t num_litarrays = lit_array_accessor.GetLiteralNum(); for (size_t i = 0; i < num_litarrays; i++) { auto id = lit_array_accessor.GetLiteralArrayId(i); lit_array_accessor.EnumerateLiteralVals( id, [id, this](const panda_file::LiteralDataAccessor::LiteralValue &value, const panda_file::LiteralTag &tag) { CreateLiteralArrayItem(value, tag, id); }); } return true; } bool FileReader::ReadIndexHeaders() { auto index_headers = file_->GetIndexHeaders(); for (const auto &header : index_headers) { auto method_index = file_->GetMethodIndex(&header); for (auto method_id : method_index) { MethodDataAccessor method_acc(*file_, method_id); File::EntityId class_id(method_acc.GetClassId()); if (file_->IsExternal(class_id)) { auto *fclass_item = CreateForeignClassItem(class_id); ASSERT(file_->IsExternal(method_id)); if (CreateForeignMethodItem(fclass_item, method_id) == nullptr) { return false; } } else { auto *class_item = CreateClassItem(class_id); if (file_->IsExternal(method_id)) { if (CreateForeignMethodItem(class_item, method_id) == nullptr) { return false; } } else if (CreateMethodItem(class_item, method_id) == nullptr) { return false; } } } auto field_index = file_->GetFieldIndex(&header); for (auto field_id : field_index) { FieldDataAccessor field_acc(*file_, field_id); File::EntityId class_id(field_acc.GetClassId()); if (file_->IsExternal(class_id)) { ASSERT(file_->IsExternal(field_id)); auto *fclass_item = CreateForeignClassItem(field_acc.GetClassId()); if (CreateForeignFieldItem(fclass_item, field_id) == nullptr) { return false; } } else { auto *class_item = CreateClassItem(field_acc.GetClassId()); if (file_->IsExternal(field_id)) { if (CreateForeignFieldItem(class_item, field_id) == nullptr) { return false; } } else if (CreateFieldItem(class_item, field_id) == nullptr) { return false; } } } } return true; } bool FileReader::ReadClasses() { const auto class_idx = file_->GetClasses(); for (unsigned int id : class_idx) { File::EntityId eid(id); if (file_->IsExternal(eid)) { CreateForeignClassItem(eid); } else { CreateClassItem(eid); } } return true; } void FileReader::UpdateDebugInfoDependecies(File::EntityId debug_info_id) { DebugInfoDataAccessor debug_acc(*file_, debug_info_id); const uint8_t *program = debug_acc.GetLineNumberProgram(); auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size(); auto opcode_sp = Span(program, size); size_t i = 0; LineNumberProgramItem::Opcode opcode; panda_file::LineProgramState state(*file_, File::EntityId(0), debug_acc.GetLineStart(), debug_acc.GetConstantPool()); while ((opcode = LineNumberProgramItem::Opcode(opcode_sp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) { switch (opcode) { case LineNumberProgramItem::Opcode::ADVANCE_PC: case LineNumberProgramItem::Opcode::ADVANCE_LINE: case LineNumberProgramItem::Opcode::SET_PROLOGUE_END: case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: { break; } case LineNumberProgramItem::Opcode::START_LOCAL: { [[maybe_unused]] int32_t reg_number; size_t n; bool is_full; std::tie(reg_number, n, is_full) = leb128::DecodeSigned(&opcode_sp[i]); LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; i += n; auto name_id = File::EntityId(state.ReadULeb128()); std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data); container_.GetOrCreateStringItem(name); auto type_id = File::EntityId(state.ReadULeb128()); std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data); if (file_->IsExternal(type_id)) { container_.GetOrCreateForeignClassItem(type_name); } else { container_.GetOrCreateClassItem(type_name); } break; } case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: { [[maybe_unused]] int32_t reg_number; size_t n; bool is_full; std::tie(reg_number, n, is_full) = leb128::DecodeSigned(&opcode_sp[i]); LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; i += n; auto name_id = File::EntityId(state.ReadULeb128()); std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data); container_.GetOrCreateStringItem(name); auto type_id = File::EntityId(state.ReadULeb128()); std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data); if (file_->IsExternal(type_id)) { container_.GetOrCreateForeignClassItem(type_name); } else { container_.GetOrCreateClassItem(type_name); } auto type_signature_id = File::EntityId(state.ReadULeb128()); std::string type_signature = utf::Mutf8AsCString(file_->GetStringData(type_signature_id).data); container_.GetOrCreateStringItem(type_signature); break; } case LineNumberProgramItem::Opcode::END_LOCAL: case LineNumberProgramItem::Opcode::RESTART_LOCAL: { [[maybe_unused]] int32_t reg_number; size_t n; bool is_full; std::tie(reg_number, n, is_full) = leb128::DecodeSigned(&opcode_sp[i]); LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; i += n; break; } case LineNumberProgramItem::Opcode::SET_FILE: { auto source_file_id = File::EntityId(state.ReadULeb128()); std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id).data); container_.GetOrCreateStringItem(source_file); break; } case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: { auto source_code_id = File::EntityId(state.ReadULeb128()); std::string source_code = utf::Mutf8AsCString(file_->GetStringData(source_code_id).data); container_.GetOrCreateStringItem(source_code); break; } default: { break; } } } } void FileReader::UpdateDebugInfo(DebugInfoItem *debug_info_item, File::EntityId debug_info_id) { auto *lnp_item = debug_info_item->GetLineNumberProgram(); DebugInfoDataAccessor debug_acc(*file_, debug_info_id); const uint8_t *program = debug_acc.GetLineNumberProgram(); auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size(); auto opcode_sp = Span(program, size); size_t i = 0; LineNumberProgramItem::Opcode opcode; panda_file::LineProgramState state(*file_, File::EntityId(0), debug_acc.GetLineStart(), debug_acc.GetConstantPool()); while ((opcode = LineNumberProgramItem::Opcode(opcode_sp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) { switch (opcode) { case LineNumberProgramItem::Opcode::ADVANCE_PC: { lnp_item->EmitAdvancePc(debug_info_item->GetConstantPool(), state.ReadULeb128()); break; } case LineNumberProgramItem::Opcode::ADVANCE_LINE: { lnp_item->EmitAdvanceLine(debug_info_item->GetConstantPool(), state.ReadSLeb128()); break; } case LineNumberProgramItem::Opcode::START_LOCAL: { auto [reg_number, n, is_full] = leb128::DecodeSigned(&opcode_sp[i]); LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; i += n; auto name_id = File::EntityId(state.ReadULeb128()); std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data); auto *name_item = container_.GetOrCreateStringItem(name); auto type_id = File::EntityId(state.ReadULeb128()); std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data); auto *type_item = file_->IsExternal(type_id) ? static_cast(container_.GetOrCreateForeignClassItem(type_name)) : static_cast(container_.GetOrCreateClassItem(type_name)); lnp_item->EmitStartLocal(debug_info_item->GetConstantPool(), reg_number, name_item, type_item->GetNameItem()); break; } case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: { auto [reg_number, n, is_full] = leb128::DecodeSigned(&opcode_sp[i]); LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; i += n; auto name_id = File::EntityId(state.ReadULeb128()); std::string name = utf::Mutf8AsCString(file_->GetStringData(name_id).data); auto *name_item = container_.GetOrCreateStringItem(name); auto type_id = File::EntityId(state.ReadULeb128()); std::string type_name = utf::Mutf8AsCString(file_->GetStringData(type_id).data); auto *type_item = file_->IsExternal(type_id) ? static_cast(container_.GetOrCreateForeignClassItem(type_name)) : static_cast(container_.GetOrCreateClassItem(type_name)); auto type_signature_id = File::EntityId(state.ReadULeb128()); std::string type_signature = utf::Mutf8AsCString(file_->GetStringData(type_signature_id).data); auto *type_signature_item = container_.GetOrCreateStringItem(type_signature); lnp_item->EmitStartLocalExtended(debug_info_item->GetConstantPool(), reg_number, name_item, type_item->GetNameItem(), type_signature_item); break; } case LineNumberProgramItem::Opcode::END_LOCAL: { auto [reg_number, n, is_full] = leb128::DecodeSigned(&opcode_sp[i]); LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; i += n; lnp_item->EmitEndLocal(reg_number); break; } case LineNumberProgramItem::Opcode::RESTART_LOCAL: { auto [reg_number, n, is_full] = leb128::DecodeSigned(&opcode_sp[i]); LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; i += n; lnp_item->EmitRestartLocal(reg_number); break; } case LineNumberProgramItem::Opcode::SET_PROLOGUE_END: { lnp_item->EmitPrologEnd(); break; } case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: { lnp_item->EmitEpilogBegin(); break; } case LineNumberProgramItem::Opcode::SET_FILE: { auto source_file_id = File::EntityId(state.ReadULeb128()); std::string source_file = utf::Mutf8AsCString(file_->GetStringData(source_file_id).data); auto *source_file_item = container_.GetOrCreateStringItem(source_file); lnp_item->EmitSetFile(debug_info_item->GetConstantPool(), source_file_item); break; } case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: { auto source_code_id = File::EntityId(state.ReadULeb128()); std::string source_code = utf::Mutf8AsCString(file_->GetStringData(source_code_id).data); auto *source_code_item = container_.GetOrCreateStringItem(source_code); lnp_item->EmitSetFile(debug_info_item->GetConstantPool(), source_code_item); break; } default: { auto opcode_value = static_cast(opcode); auto adjust_opcode = opcode_value - LineNumberProgramItem::OPCODE_BASE; uint32_t pc_diff = adjust_opcode / LineNumberProgramItem::LINE_RANGE; int32_t line_diff = adjust_opcode % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE; lnp_item->EmitSpecialOpcode(pc_diff, line_diff); break; } } } lnp_item->EmitEnd(); } void FileReader::UpdateCodeAndDebugInfoDependencies(const std::map &reverse_done) { using Flags = panda::BytecodeInst::Flags; auto *class_map = container_.GetClassMap(); // First pass, add dependencies bytecode -> new items for (const auto &it : *class_map) { auto *base_class_item = it.second; if (base_class_item->IsForeign()) { continue; } auto *class_item = static_cast(base_class_item); class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) { auto *method_item = static_cast(param_item); auto *code_item = method_item->GetCode(); if (code_item == nullptr) { return true; } auto *debug_info_item = method_item->GetDebugInfo(); if (debug_info_item != nullptr) { UpdateDebugInfoDependecies(reverse_done.find(debug_info_item)->second); } size_t offset = 0; BytecodeInstruction inst(code_item->GetInstructions()->data()); while (offset < code_item->GetCodeSize()) { if (inst.HasFlag(Flags::TYPE_ID)) { BytecodeId b_id = inst.GetId(); File::Index idx = b_id.AsIndex(); File::EntityId method_id = reverse_done.find(method_item)->second; File::EntityId old_id = file_->ResolveClassIndex(method_id, idx); ASSERT(items_done_.find(old_id) != items_done_.end()); auto *idx_item = static_cast(items_done_.find(old_id)->second); method_item->AddIndexDependency(idx_item); } else if (inst.HasFlag(Flags::METHOD_ID)) { BytecodeId b_id = inst.GetId(); File::Index idx = b_id.AsIndex(); File::EntityId method_id = reverse_done.find(method_item)->second; File::EntityId old_id = file_->ResolveMethodIndex(method_id, idx); ASSERT(items_done_.find(old_id) != items_done_.end()); auto *idx_item = static_cast(items_done_.find(old_id)->second); method_item->AddIndexDependency(idx_item); } else if (inst.HasFlag(Flags::FIELD_ID)) { BytecodeId b_id = inst.GetId(); File::Index idx = b_id.AsIndex(); File::EntityId method_id = reverse_done.find(method_item)->second; File::EntityId old_id = file_->ResolveFieldIndex(method_id, idx); ASSERT(items_done_.find(old_id) != items_done_.end()); auto *idx_item = static_cast(items_done_.find(old_id)->second); method_item->AddIndexDependency(idx_item); } else if (inst.HasFlag(Flags::STRING_ID)) { BytecodeId b_id = inst.GetId(); File::EntityId old_id = b_id.AsFileId(); auto data = file_->GetStringData(old_id); std::string item_str(utf::Mutf8AsCString(data.data)); container_.GetOrCreateStringItem(item_str); } offset += inst.GetSize(); inst = inst.GetNext(); } return true; }); } } void FileReader::ComputeLayoutAndUpdateIndices() { using Flags = panda::BytecodeInst::Flags; std::map reverse_done; for (const auto &it : items_done_) { reverse_done.insert({it.second, it.first}); } auto *class_map = container_.GetClassMap(); UpdateCodeAndDebugInfoDependencies(reverse_done); container_.ComputeLayout(); // Second pass, update debug info for (const auto &it : *class_map) { auto *base_class_item = it.second; if (base_class_item->IsForeign()) { continue; } auto *class_item = static_cast(base_class_item); class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) { auto *method_item = static_cast(param_item); auto *code_item = method_item->GetCode(); if (code_item == nullptr) { return true; } auto *debug_info_item = method_item->GetDebugInfo(); if (debug_info_item != nullptr) { UpdateDebugInfo(debug_info_item, reverse_done.find(debug_info_item)->second); } return true; }); } container_.DeduplicateItems(false); container_.ComputeLayout(); // Third pass, update bytecode indices for (const auto &it : *class_map) { auto *base_class_item = it.second; if (base_class_item->IsForeign()) { continue; } auto *class_item = static_cast(base_class_item); class_item->VisitMethods([this, &reverse_done](BaseItem *param_item) { auto *method_item = static_cast(param_item); auto *code_item = method_item->GetCode(); if (code_item == nullptr) { return true; } size_t offset = 0; BytecodeInstruction inst(code_item->GetInstructions()->data()); while (offset < code_item->GetCodeSize()) { if (inst.HasFlag(Flags::TYPE_ID)) { BytecodeId b_id = inst.GetId(); File::Index idx = b_id.AsIndex(); File::EntityId method_id = reverse_done.find(method_item)->second; File::EntityId old_id = file_->ResolveClassIndex(method_id, idx); ASSERT(items_done_.find(old_id) != items_done_.end()); auto *idx_item = static_cast(items_done_.find(old_id)->second); uint32_t index = idx_item->GetIndex(method_item); inst.UpdateId(BytecodeId(index)); } else if (inst.HasFlag(Flags::METHOD_ID)) { BytecodeId b_id = inst.GetId(); File::Index idx = b_id.AsIndex(); File::EntityId method_id = reverse_done.find(method_item)->second; File::EntityId old_id = file_->ResolveMethodIndex(method_id, idx); ASSERT(items_done_.find(old_id) != items_done_.end()); auto *idx_item = static_cast(items_done_.find(old_id)->second); uint32_t index = idx_item->GetIndex(method_item); inst.UpdateId(BytecodeId(index)); } else if (inst.HasFlag(Flags::FIELD_ID)) { BytecodeId b_id = inst.GetId(); File::Index idx = b_id.AsIndex(); File::EntityId method_id = reverse_done.find(method_item)->second; File::EntityId old_id = file_->ResolveFieldIndex(method_id, idx); ASSERT(items_done_.find(old_id) != items_done_.end()); auto *idx_item = static_cast(items_done_.find(old_id)->second); uint32_t index = idx_item->GetIndex(method_item); inst.UpdateId(BytecodeId(index)); } else if (inst.HasFlag(Flags::STRING_ID)) { BytecodeId b_id = inst.GetId(); File::EntityId old_id = b_id.AsFileId(); auto data = file_->GetStringData(old_id); std::string item_str(utf::Mutf8AsCString(data.data)); auto *string_item = container_.GetOrCreateStringItem(item_str); inst.UpdateId(BytecodeId(string_item->GetFileId().GetOffset())); } else if (inst.HasFlag(Flags::LITERALARRAY_ID)) { BytecodeId b_id = inst.GetId(); File::EntityId old_id = b_id.AsFileId(); ASSERT(items_done_.find(old_id) != items_done_.end()); auto *array_item = items_done_.find(old_id)->second; inst.UpdateId(BytecodeId(array_item->GetFileId().GetOffset())); } offset += inst.GetSize(); inst = inst.GetNext(); } return true; }); } } } // namespace panda::panda_file