/** * 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. */ #ifndef LIBPANDAFILE_FILE_ITEMS_H_ #define LIBPANDAFILE_FILE_ITEMS_H_ #include "file.h" #include "file_writer.h" #include "macros.h" #include "modifiers.h" #include "type.h" #include "file_format_version.h" #include "source_lang_enum.h" #include #include #include #include #include #include #include #include #include namespace panda::panda_file { enum class ClassTag : uint8_t { NOTHING = 0x00, INTERFACES = 0x01, SOURCE_LANG = 0x02, RUNTIME_ANNOTATION = 0x03, ANNOTATION = 0x04, RUNTIME_TYPE_ANNOTATION = 0x05, TYPE_ANNOTATION = 0x06, SOURCE_FILE = 0x07 }; enum class MethodTag : uint8_t { NOTHING = 0x00, CODE = 0x01, SOURCE_LANG = 0x02, RUNTIME_ANNOTATION = 0x03, RUNTIME_PARAM_ANNOTATION = 0x04, DEBUG_INFO = 0x05, ANNOTATION = 0x06, PARAM_ANNOTATION = 0x07, TYPE_ANNOTATION = 0x08, RUNTIME_TYPE_ANNOTATION = 0x09 }; enum class FieldTag : uint8_t { NOTHING = 0x00, INT_VALUE = 0x01, VALUE = 0x02, RUNTIME_ANNOTATION = 0x03, ANNOTATION = 0x04, RUNTIME_TYPE_ANNOTATION = 0x05, TYPE_ANNOTATION = 0x06 }; enum class FunctionKind : uint8_t { NONE = 0x0, FUNCTION = 0x1, NC_FUNCTION = 0x2, GENERATOR_FUNCTION = 0x3, ASYNC_FUNCTION = 0x4, ASYNC_GENERATOR_FUNCTION = 0x5, ASYNC_NC_FUNCTION = 0x6, CONCURRENT_FUNCTION = 0x7 }; bool IsDynamicLanguage(panda::panda_file::SourceLang lang); std::optional LanguageFromString(std::string_view lang); const char *LanguageToString(panda::panda_file::SourceLang lang); const char *GetCtorName(panda::panda_file::SourceLang lang); const char *GetCctorName(panda::panda_file::SourceLang lang); const char *GetStringClassDescriptor(panda::panda_file::SourceLang lang); static constexpr size_t ID_SIZE = File::EntityId::GetSize(); static constexpr size_t IDX_SIZE = sizeof(uint16_t); static constexpr size_t TAG_SIZE = 1; static constexpr uint32_t INVALID_OFFSET = std::numeric_limits::max(); static constexpr uint32_t INVALID_INDEX = std::numeric_limits::max(); static constexpr uint32_t MAX_INDEX_16 = std::numeric_limits::max(); static constexpr uint32_t MAX_INDEX_32 = std::numeric_limits::max(); static constexpr uint32_t FLAG_WIDTH = 8; static constexpr uint32_t FUNTION_KIND_WIDTH = 8; static constexpr uint32_t FUNCTION_KIND_MASK = 0xFF00; static constexpr uint32_t FLAG_MASK = 0xFF; constexpr uint32_t PGO_STRING_DEFAULT_COUNT = 5; constexpr uint32_t PGO_CLASS_DEFAULT_COUNT = 3; constexpr uint32_t PGO_CODE_DEFAULT_COUNT = 1; enum class ItemTypes { ANNOTATION_ITEM, CATCH_BLOCK_ITEM, CLASS_INDEX_ITEM, CLASS_ITEM, CODE_ITEM, DEBUG_INFO_ITEM, END_ITEM, FIELD_INDEX_ITEM, FIELD_ITEM, FOREIGN_CLASS_ITEM, FOREIGN_FIELD_ITEM, FOREIGN_METHOD_ITEM, INDEX_HEADER, INDEX_SECTION, LINE_NUMBER_PROGRAM_INDEX_ITEM, LINE_NUMBER_PROGRAM_ITEM, LITERAL_ARRAY_ITEM, LITERAL_ITEM, METHOD_HANDLE_ITEM, METHOD_INDEX_ITEM, METHOD_ITEM, PARAM_ANNOTATIONS_ITEM, PRIMITIVE_TYPE_ITEM, PROTO_INDEX_ITEM, PROTO_ITEM, STRING_ITEM, TRY_BLOCK_ITEM, VALUE_ITEM }; constexpr std::string_view STRING_ITEM = "string_item"; constexpr std::string_view CLASS_ITEM = "class_item"; constexpr std::string_view CODE_ITEM = "code_item"; enum class IndexType { // 16-bit indexes CLASS = 0x0, METHOD_STRING_LITERAL = 0x1, FIELD = 0x2, PROTO = 0x3, LAST_16 = PROTO, // 32-bit indexes LINE_NUMBER_PROG = 0x04, LAST_32 = LINE_NUMBER_PROG, NONE }; static constexpr size_t INDEX_COUNT_16 = static_cast(IndexType::LAST_16) + 1; class IndexedItem; class ItemContainer; class BaseItem { public: using VisitorCallBack = std::function; BaseItem() = default; virtual ~BaseItem() = default; DEFAULT_COPY_SEMANTIC(BaseItem); DEFAULT_MOVE_SEMANTIC(BaseItem); size_t GetSize() const { return CalculateSize(); } virtual size_t CalculateSize() const = 0; virtual void ComputeLayout() {} virtual size_t Alignment() { return 1; } virtual bool IsForeign() const { return false; } uint32_t GetOffset() const { return offset_; } panda_file::File::EntityId GetFileId() const { return panda_file::File::EntityId(offset_); } void SetOffset(uint32_t offset) { offset_ = offset; } bool NeedsEmit() const { return needs_emit_; } void SetNeedsEmit(bool needs_emit) { needs_emit_ = needs_emit; } const std::list &GetIndexDependencies() const { return index_deps_; } void AddIndexDependency(IndexedItem *item) { ASSERT(item != nullptr); index_deps_.push_back(item); } void SetOrderIndex(uint32_t order) { order_ = order; } uint32_t GetOrderIndex() const { return order_; } bool HasOrderIndex() const { return order_ != INVALID_INDEX; } virtual bool Write(Writer *writer) = 0; std::string GetName() const; virtual ItemTypes GetItemType() const = 0; virtual void Dump([[maybe_unused]] std::ostream &os) const {} virtual void Visit([[maybe_unused]] const VisitorCallBack &cb) {} void SetPGORank(uint32_t rank) { pgo_rank_ = rank; } uint32_t GetPGORank() const { return pgo_rank_; } void SetOriginalRank(uint32_t rank) { original_rank_ = rank; } uint32_t GetOriginalRank() const { return original_rank_; } private: bool needs_emit_ {true}; uint32_t offset_ {0}; uint32_t order_ {INVALID_INDEX}; std::list index_deps_; uint32_t pgo_rank_ {0}; uint32_t original_rank_ {0}; }; class IndexedItem : public BaseItem { public: explicit IndexedItem(ItemContainer *container); uint32_t GetIndex(const BaseItem *item) const { auto *idx = FindIndex(item); ASSERT(idx != nullptr); return idx->index; } bool HasIndex(const BaseItem *item) const { return FindIndex(item) != nullptr; } void SetIndex(const BaseItem *start, const BaseItem *end, uint32_t index) { ASSERT(FindIndex(start, end) == nullptr); indexes_.push_back({start, end, index}); } void ClearIndexes() { indexes_.clear(); } void IncRefCount() { ++ref_count_; } void DecRefCount() { ASSERT(ref_count_ != 0); --ref_count_; } size_t GetRefCount() const { return ref_count_; } virtual IndexType GetIndexType() const { return IndexType::NONE; } size_t GetIndexedItemCount() const { return item_global_index_; } private: struct Index { const BaseItem *start; const BaseItem *end; uint32_t index; }; const Index *FindIndex(const BaseItem *start, const BaseItem *end) const { auto it = std::find_if(indexes_.cbegin(), indexes_.cend(), [start, end](const Index &idx) { return idx.start == start && idx.end == end; }); return it != indexes_.cend() ? &*it : nullptr; } const Index *FindIndex(const BaseItem *item) const { ASSERT(item->HasOrderIndex()); auto order_idx = item->GetOrderIndex(); auto it = std::find_if(indexes_.cbegin(), indexes_.cend(), [order_idx](const Index &idx) { if (idx.start == nullptr && idx.end == nullptr) { return true; } if (idx.start == nullptr || idx.end == nullptr) { return false; } ASSERT(idx.start->HasOrderIndex()); ASSERT(idx.end->HasOrderIndex()); return idx.start->GetOrderIndex() <= order_idx && order_idx < idx.end->GetOrderIndex(); }); return it != indexes_.cend() ? &*it : nullptr; } std::vector indexes_; size_t ref_count_ {1}; size_t item_global_index_ {0}; }; class TypeItem : public IndexedItem { public: explicit TypeItem(Type type, ItemContainer *container) : IndexedItem(container), type_(type) {} explicit TypeItem(Type::TypeId type_id, ItemContainer *container) : IndexedItem(container), type_(type_id) {} ~TypeItem() override = default; Type GetType() const { return type_; } IndexType GetIndexType() const override { return IndexType::CLASS; } DEFAULT_MOVE_SEMANTIC(TypeItem); DEFAULT_COPY_SEMANTIC(TypeItem); private: Type type_; }; class PrimitiveTypeItem : public TypeItem { public: explicit PrimitiveTypeItem(Type type, ItemContainer *container) : PrimitiveTypeItem(type.GetId(), container) {} explicit PrimitiveTypeItem(Type::TypeId type_id, ItemContainer *container) : TypeItem(type_id, container) { ASSERT(GetType().IsPrimitive()); SetNeedsEmit(false); SetOffset(GetType().GetFieldEncoding()); } ~PrimitiveTypeItem() override = default; size_t CalculateSize() const override { return 0; } bool Write([[maybe_unused]] Writer *writer) override { return true; } ItemTypes GetItemType() const override { return ItemTypes::PRIMITIVE_TYPE_ITEM; } DEFAULT_MOVE_SEMANTIC(PrimitiveTypeItem); DEFAULT_COPY_SEMANTIC(PrimitiveTypeItem); }; class StringItem : public IndexedItem { public: explicit StringItem(std::string str, ItemContainer *container); explicit StringItem(File::StringData data, ItemContainer *container); ~StringItem() override = default; size_t CalculateSize() const override; bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::STRING_ITEM; } const std::string &GetData() const { return str_; } size_t GetUtf16Len() const { return utf16_length_; } IndexType GetIndexType() const override { return IndexType::METHOD_STRING_LITERAL; } DEFAULT_MOVE_SEMANTIC(StringItem); DEFAULT_COPY_SEMANTIC(StringItem); private: std::string str_; size_t utf16_length_; size_t is_ascii_ = 0; }; class AnnotationItem; class BaseClassItem; class ClassItem; class ForeignClassItem; class ValueItem; class BaseFieldItem : public IndexedItem { public: IndexType GetIndexType() const override { return IndexType::FIELD; } StringItem *GetNameItem() const { return name_; } ~BaseFieldItem() override = default; DEFAULT_MOVE_SEMANTIC(BaseFieldItem); DEFAULT_COPY_SEMANTIC(BaseFieldItem); protected: BaseFieldItem(BaseClassItem *cls, StringItem *name, TypeItem *type, ItemContainer *container); size_t CalculateSize() const override; bool Write(Writer *writer) override; private: BaseClassItem *class_; StringItem *name_; TypeItem *type_; }; class FieldItem : public BaseFieldItem { public: FieldItem(ClassItem *cls, StringItem *name, TypeItem *type, uint32_t access_flags, ItemContainer *container); ~FieldItem() override = default; void SetValue(ValueItem *value); void AddRuntimeAnnotation(AnnotationItem *runtime_annotation) { runtime_annotations_.push_back(runtime_annotation); } void AddAnnotation(AnnotationItem *annotation) { annotations_.push_back(annotation); } void AddRuntimeTypeAnnotation(AnnotationItem *runtime_type_annotation) { runtime_type_annotations_.push_back(runtime_type_annotation); } void AddTypeAnnotation(AnnotationItem *type_annotation) { type_annotations_.push_back(type_annotation); } size_t CalculateSize() const override; bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::FIELD_ITEM; } std::vector *GetRuntimeAnnotations() { return &runtime_annotations_; } std::vector *GetAnnotations() { return &annotations_; } std::vector *GetTypeAnnotations() { return &type_annotations_; } std::vector *GetRuntimeTypeAnnotations() { return &runtime_type_annotations_; } DEFAULT_MOVE_SEMANTIC(FieldItem); DEFAULT_COPY_SEMANTIC(FieldItem); private: bool WriteValue(Writer *writer); bool WriteAnnotations(Writer *writer); bool WriteTaggedData(Writer *writer); uint32_t access_flags_; ValueItem *value_; std::vector runtime_annotations_; std::vector annotations_; std::vector type_annotations_; std::vector runtime_type_annotations_; }; class ProtoItem; class CodeItem; class LineNumberProgramItem : public IndexedItem { public: enum class Opcode : uint8_t { END_SEQUENCE = 0x00, ADVANCE_PC = 0x01, ADVANCE_LINE = 0x02, START_LOCAL = 0x03, START_LOCAL_EXTENDED = 0x04, END_LOCAL = 0x05, RESTART_LOCAL = 0x06, SET_PROLOGUE_END = 0x07, SET_EPILOGUE_BEGIN = 0x08, SET_FILE = 0x09, SET_SOURCE_CODE = 0x0a, SET_COLUMN = 0X0b, LAST }; static constexpr uint8_t OPCODE_BASE = static_cast(Opcode::LAST); static constexpr int32_t LINE_RANGE = 15; static constexpr int32_t LINE_BASE = -4; explicit LineNumberProgramItem(ItemContainer *container) : IndexedItem(container) {} void EmitEnd(); void EmitAdvancePc(std::vector *constant_pool, uint32_t value); void EmitAdvanceLine(std::vector *constant_pool, int32_t value); void EmitColumn(std::vector *constant_pool, uint32_t pc_inc, uint32_t column); void EmitStartLocal(std::vector *constant_pool, int32_t register_number, StringItem *name, StringItem *type); void EmitStartLocalExtended(std::vector *constant_pool, int32_t register_number, StringItem *name, StringItem *type, StringItem *type_signature); void EmitEndLocal(int32_t register_number); void EmitRestartLocal(int32_t register_number); bool EmitSpecialOpcode(uint32_t pc_inc, int32_t line_inc); void EmitPrologEnd(); void EmitEpilogBegin(); void EmitSetFile(std::vector *constant_pool, StringItem *source_file); void EmitSetSourceCode(std::vector *constant_pool, StringItem *source_code); bool Write(Writer *writer) override; size_t CalculateSize() const override; ItemTypes GetItemType() const override { return ItemTypes::LINE_NUMBER_PROGRAM_ITEM; } const std::vector &GetData() const { return data_; } IndexType GetIndexType() const override { return IndexType::LINE_NUMBER_PROG; } void SetData(std::vector &&data); private: void EmitOpcode(Opcode opcode); void EmitRegister(int32_t register_number); static void EmitUleb128(std::vector *data, uint32_t value); static void EmitSleb128(std::vector *data, int32_t value); std::vector data_; }; class DebugInfoItem : public BaseItem { public: explicit DebugInfoItem(LineNumberProgramItem *item) : program_(item) {} ~DebugInfoItem() override = default; DEFAULT_MOVE_SEMANTIC(DebugInfoItem); DEFAULT_COPY_SEMANTIC(DebugInfoItem); size_t GetLineNumber() const { return line_num_; } void SetLineNumber(size_t line_num) { line_num_ = line_num; } LineNumberProgramItem *GetLineNumberProgram() const { return program_; } void SetLineNumberProgram(LineNumberProgramItem *program) { ASSERT(program->GetOffset() != 0); program_ = program; } void AddParameter(StringItem *name) { parameters_.push_back(name); } std::vector *GetConstantPool() { return &constant_pool_; } size_t CalculateSize() const override; bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::DEBUG_INFO_ITEM; } void Dump(std::ostream &os) const override; private: size_t line_num_ {0}; LineNumberProgramItem *program_; std::vector constant_pool_; std::vector parameters_; }; class BaseMethodItem : public IndexedItem { public: ProtoItem *GetProto() const { return proto_; } bool IsStatic() const { return (access_flags_ & ACC_STATIC) != 0; } IndexType GetIndexType() const override { return IndexType::METHOD_STRING_LITERAL; } StringItem *GetNameItem() const { return name_; } BaseClassItem *GetClassItem() const { return class_; } void SetFunctionKind(FunctionKind kind) { access_flags_ &= (~FUNCTION_KIND_MASK); access_flags_ |= (static_cast(kind) << FLAG_WIDTH); } void SetHeaderIndex(uint16_t idx) { access_flags_ &= (FUNCTION_KIND_MASK | FLAG_MASK); access_flags_ |= (static_cast(idx) << (FUNTION_KIND_WIDTH + FLAG_WIDTH)); } ~BaseMethodItem() override = default; DEFAULT_MOVE_SEMANTIC(BaseMethodItem); DEFAULT_COPY_SEMANTIC(BaseMethodItem); protected: BaseMethodItem(BaseClassItem *cls, StringItem *name, ProtoItem *proto, uint32_t access_flags, ItemContainer *container); size_t CalculateSize() const override; bool Write(Writer *writer) override; private: BaseClassItem *class_; StringItem *name_; ProtoItem *proto_; uint32_t access_flags_; // layout: |<- 16-bit header index ->|<- 8-bit FunctionKind ->|<- 8-bit flag ->| }; class MethodParamItem { public: explicit MethodParamItem(TypeItem *type) : type_(type) {} ~MethodParamItem() = default; DEFAULT_MOVE_SEMANTIC(MethodParamItem); DEFAULT_COPY_SEMANTIC(MethodParamItem); void AddRuntimeAnnotation(AnnotationItem *runtime_annotation) { runtime_annotations_.push_back(runtime_annotation); } void AddAnnotation(AnnotationItem *annotation) { annotations_.push_back(annotation); } void AddRuntimeTypeAnnotation(AnnotationItem *runtime_type_annotation) { runtime_type_annotations_.push_back(runtime_type_annotation); } void AddTypeAnnotation(AnnotationItem *type_annotation) { type_annotations_.push_back(type_annotation); } TypeItem *GetType() const { return type_; } const std::vector &GetRuntimeAnnotations() const { return runtime_annotations_; } const std::vector &GetAnnotations() const { return annotations_; } bool HasAnnotations() const { return !annotations_.empty(); } bool HasRuntimeAnnotations() const { return !runtime_annotations_.empty(); } private: TypeItem *type_; std::vector runtime_annotations_; std::vector annotations_; std::vector type_annotations_; std::vector runtime_type_annotations_; }; class ParamAnnotationsItem; class BaseClassItem; class MethodItem : public BaseMethodItem { public: MethodItem(ClassItem *cls, StringItem *name, ProtoItem *proto, uint32_t access_flags, std::vector params, ItemContainer *container); ~MethodItem() override = default; DEFAULT_MOVE_SEMANTIC(MethodItem); DEFAULT_COPY_SEMANTIC(MethodItem); void SetSourceLang(SourceLang lang) { source_lang_ = lang; } void SetCode(CodeItem *code) { code_ = code; } void SetDebugInfo(DebugInfoItem *debug_info) { debug_info_ = debug_info; } void AddRuntimeAnnotation(AnnotationItem *runtime_annotation) { runtime_annotations_.push_back(runtime_annotation); } void AddAnnotation(AnnotationItem *annotation) { annotations_.push_back(annotation); } void AddRuntimeTypeAnnotation(AnnotationItem *runtime_type_annotation) { runtime_type_annotations_.push_back(runtime_type_annotation); } void AddTypeAnnotation(AnnotationItem *type_annotation) { type_annotations_.push_back(type_annotation); } void SetRuntimeParamAnnotationItem(ParamAnnotationsItem *annotations) { runtime_param_annotations_ = annotations; } void SetParamAnnotationItem(ParamAnnotationsItem *annotations) { param_annotations_ = annotations; } bool HasRuntimeParamAnnotations() const { return std::any_of(params_.cbegin(), params_.cend(), [](const MethodParamItem &item) { return item.HasRuntimeAnnotations(); }); } bool HasParamAnnotations() const { return std::any_of(params_.cbegin(), params_.cend(), [](const MethodParamItem &item) { return item.HasAnnotations(); }); } CodeItem *GetCode() const { return code_; } DebugInfoItem *GetDebugInfo() const { return debug_info_; } size_t CalculateSize() const override; bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::METHOD_ITEM; } std::vector &GetParams() { return params_; } std::vector *GetRuntimeAnnotations() { return &runtime_annotations_; } std::vector *GetAnnotations() { return &annotations_; } std::vector *GetTypeAnnotations() { return &type_annotations_; } std::vector *GetRuntimeTypeAnnotations() { return &runtime_type_annotations_; } private: bool WriteRuntimeAnnotations(Writer *writer); bool WriteTypeAnnotations(Writer *writer); bool WriteTaggedData(Writer *writer); std::vector params_; SourceLang source_lang_; CodeItem *code_; DebugInfoItem *debug_info_; std::vector runtime_annotations_; std::vector annotations_; std::vector type_annotations_; std::vector runtime_type_annotations_; ParamAnnotationsItem *runtime_param_annotations_ {nullptr}; ParamAnnotationsItem *param_annotations_ {nullptr}; }; class BaseClassItem : public TypeItem { public: StringItem *GetNameItem() { return &name_; } protected: explicit BaseClassItem(const std::string &name, ItemContainer *container) : TypeItem(Type::TypeId::REFERENCE, container), name_(name, container) {} ~BaseClassItem() override = default; size_t CalculateSize() const override; void ComputeLayout() override; bool Write(Writer *writer) override; DEFAULT_MOVE_SEMANTIC(BaseClassItem); DEFAULT_COPY_SEMANTIC(BaseClassItem); private: StringItem name_; }; class ClassItem : public BaseClassItem { public: explicit ClassItem(const std::string &name, ItemContainer *container) : BaseClassItem(name, container), super_class_(nullptr), access_flags_(0), source_lang_(SourceLang::PANDA_ASSEMBLY), source_file_(nullptr), container_(container) { } ~ClassItem() override = default; void SetAccessFlags(uint32_t access_flags) { access_flags_ = access_flags; } void SetSourceLang(SourceLang lang) { source_lang_ = lang; } void SetSuperClass(BaseClassItem *super_class) { super_class_ = super_class; } void AddInterface(BaseClassItem *iface) { AddIndexDependency(iface); ifaces_.push_back(iface); } void AddRuntimeAnnotation(AnnotationItem *runtime_annotation) { runtime_annotations_.push_back(runtime_annotation); } void AddAnnotation(AnnotationItem *annotation) { annotations_.push_back(annotation); } void AddRuntimeTypeAnnotation(AnnotationItem *runtime_type_annotation) { runtime_type_annotations_.push_back(runtime_type_annotation); } void AddTypeAnnotation(AnnotationItem *type_annotation) { type_annotations_.push_back(type_annotation); } template FieldItem *AddField(Args... args) { fields_.emplace_back(std::make_unique(this, std::forward(args)..., container_)); return fields_.back().get(); } template MethodItem *AddMethod(Args... args) { // insert new method to set ordered by method name return methods_.insert(std::make_unique(this, std::forward(args)..., container_))->get(); } void SetSourceFile(StringItem *item) { source_file_ = item; } size_t CalculateSizeWithoutFieldsAndMethods() const; size_t CalculateSize() const override; void ComputeLayout() override; bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::CLASS_ITEM; } void VisitFields(const VisitorCallBack &cb) { for (auto &field : fields_) { if (!cb(field.get())) { break; } } } void VisitMethods(const VisitorCallBack &cb) { for (auto &method : methods_) { if (!cb(method.get())) { break; } } } void Visit(const VisitorCallBack &cb) override { VisitFields(cb); VisitMethods(cb); } std::vector *GetRuntimeAnnotations() { return &runtime_annotations_; } std::vector *GetAnnotations() { return &annotations_; } std::vector *GetTypeAnnotations() { return &type_annotations_; } std::vector *GetRuntimeTypeAnnotations() { return &runtime_type_annotations_; } DEFAULT_MOVE_SEMANTIC(ClassItem); DEFAULT_COPY_SEMANTIC(ClassItem); private: struct MethodCompByName { bool operator()(const std::unique_ptr &m1, const std::unique_ptr &m2) const { auto *str1 = m1->GetNameItem(); auto *str2 = m2->GetNameItem(); if (str1->GetUtf16Len() == str2->GetUtf16Len()) { return str1->GetData() < str2->GetData(); } return str1->GetUtf16Len() < str2->GetUtf16Len(); } }; bool WriteIfaces(Writer *writer); bool WriteAnnotations(Writer *writer); bool WriteTaggedData(Writer *writer); BaseClassItem *super_class_; uint32_t access_flags_; SourceLang source_lang_; std::vector ifaces_; std::vector runtime_annotations_; std::vector annotations_; std::vector type_annotations_; std::vector runtime_type_annotations_; StringItem *source_file_; std::vector> fields_; std::multiset, MethodCompByName> methods_; ItemContainer *container_; }; class ForeignClassItem : public BaseClassItem { public: explicit ForeignClassItem(const std::string &name, ItemContainer *container) : BaseClassItem(name, container) {} ~ForeignClassItem() override = default; bool IsForeign() const override { return true; } ItemTypes GetItemType() const override { return ItemTypes::FOREIGN_CLASS_ITEM; } DEFAULT_MOVE_SEMANTIC(ForeignClassItem); DEFAULT_COPY_SEMANTIC(ForeignClassItem); }; class ForeignFieldItem : public BaseFieldItem { public: ForeignFieldItem(BaseClassItem *cls, StringItem *name, TypeItem *type, ItemContainer *container) : BaseFieldItem(cls, name, type, container) {} ~ForeignFieldItem() override = default; bool IsForeign() const override { return true; } ItemTypes GetItemType() const override { return ItemTypes::FOREIGN_FIELD_ITEM; } DEFAULT_MOVE_SEMANTIC(ForeignFieldItem); DEFAULT_COPY_SEMANTIC(ForeignFieldItem); }; class ForeignMethodItem : public BaseMethodItem { public: ForeignMethodItem(BaseClassItem *cls, StringItem *name, ProtoItem *proto, uint32_t access_flags, ItemContainer *container) : BaseMethodItem(cls, name, proto, access_flags, container) { } ~ForeignMethodItem() override = default; bool IsForeign() const override { return true; } ItemTypes GetItemType() const override { return ItemTypes::FOREIGN_METHOD_ITEM; } DEFAULT_MOVE_SEMANTIC(ForeignMethodItem); DEFAULT_COPY_SEMANTIC(ForeignMethodItem); }; class ProtoItem; class ParamAnnotationsItem : public BaseItem { public: ParamAnnotationsItem(MethodItem *method, bool is_runtime_annotations); ~ParamAnnotationsItem() override = default; ItemTypes GetItemType() const override { return ItemTypes::PARAM_ANNOTATIONS_ITEM; } size_t CalculateSize() const override; bool Write(Writer *writer) override; DEFAULT_MOVE_SEMANTIC(ParamAnnotationsItem); DEFAULT_COPY_SEMANTIC(ParamAnnotationsItem); private: std::vector> annotations_; }; class ProtoItem : public IndexedItem { public: ProtoItem(TypeItem *ret_type, const std::vector ¶ms, ItemContainer *itemContainer); ~ProtoItem() override = default; DEFAULT_MOVE_SEMANTIC(ProtoItem); DEFAULT_COPY_SEMANTIC(ProtoItem); size_t CalculateSize() const override { size_t size = shorty_.size() * sizeof(uint16_t); size += reference_types_.size() * IDX_SIZE; return size; } bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::PROTO_ITEM; } IndexType GetIndexType() const override { return IndexType::PROTO; } size_t Alignment() override { return sizeof(uint16_t); } private: static constexpr size_t SHORTY_ELEM_SIZE = 4; void AddType(TypeItem *type, size_t *n); std::vector shorty_; std::vector reference_types_; }; class CodeItem : public BaseItem { public: class CatchBlock : public BaseItem { public: CatchBlock(MethodItem *method, BaseClassItem *type, size_t handler_pc, size_t code_size = 0) : method_(method), type_(type), handler_pc_(handler_pc), code_size_(code_size) { } ~CatchBlock() override = default; DEFAULT_MOVE_SEMANTIC(CatchBlock); DEFAULT_COPY_SEMANTIC(CatchBlock); size_t CalculateSize() const override; bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::CATCH_BLOCK_ITEM; } private: MethodItem *method_; BaseClassItem *type_; size_t handler_pc_; size_t code_size_; }; class TryBlock : public BaseItem { public: TryBlock(size_t start_pc, size_t length, std::vector catch_blocks) : start_pc_(start_pc), length_(length), catch_blocks_(std::move(catch_blocks)) { } ~TryBlock() override = default; DEFAULT_MOVE_SEMANTIC(TryBlock); DEFAULT_COPY_SEMANTIC(TryBlock); size_t CalculateSizeWithoutCatchBlocks() const; void ComputeLayout() override; size_t CalculateSize() const override; bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::TRY_BLOCK_ITEM; } private: size_t start_pc_; size_t length_; std::vector catch_blocks_; }; CodeItem(size_t num_vregs, size_t num_args, std::vector instructions) : num_vregs_(num_vregs), num_args_(num_args), instructions_(std::move(instructions)) { } CodeItem() = default; ~CodeItem() override = default; void SetNumVregs(size_t num_vregs) { num_vregs_ = num_vregs; } void SetNumArgs(size_t num_args) { num_args_ = num_args; } std::vector *GetInstructions() { return &instructions_; } void SetNumInstructions(size_t num_ins) { num_ins_ = num_ins; } size_t GetNumInstructions() const { return num_ins_; } void AddTryBlock(const TryBlock &try_block) { try_blocks_.push_back(try_block); } size_t CalculateSizeWithoutTryBlocks() const; void ComputeLayout() override; size_t CalculateSize() const override; size_t GetCodeSize() const; bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::CODE_ITEM; } void AddMethod(BaseMethodItem *method) { methods_.emplace_back(method); } std::vector GetMethodNames() const { std::vector names; for (const auto *method : methods_) { if (method == nullptr) { continue; } std::string class_name; if (method->GetClassItem() != nullptr) { class_name = method->GetClassItem()->GetNameItem()->GetData(); class_name.pop_back(); // remove '\0' ASSERT(class_name.size() > 2); // 2 - L and ; class_name.erase(0, 1); class_name.pop_back(); class_name.append("::"); } class_name.append(method->GetNameItem()->GetData()); class_name.pop_back(); // remove '\0' names.emplace_back(class_name); } return names; } DEFAULT_MOVE_SEMANTIC(CodeItem); DEFAULT_COPY_SEMANTIC(CodeItem); private: size_t num_vregs_ {0}; size_t num_args_ {0}; size_t num_ins_ {0}; std::vector instructions_; std::vector try_blocks_; std::vector methods_; }; class ScalarValueItem; class ArrayValueItem; class ValueItem : public IndexedItem { public: enum class Type { INTEGER, LONG, FLOAT, DOUBLE, ID, ARRAY }; explicit ValueItem(Type type, ItemContainer *container) : IndexedItem(container), type_(type) {} ~ValueItem() override = default; DEFAULT_MOVE_SEMANTIC(ValueItem); DEFAULT_COPY_SEMANTIC(ValueItem); Type GetType() const { return type_; } bool IsArray() const { return type_ == Type::ARRAY; } bool Is32bit() const { return type_ == Type::INTEGER || type_ == Type::FLOAT || type_ == Type::ID; } ItemTypes GetItemType() const override { return ItemTypes::VALUE_ITEM; } ScalarValueItem *GetAsScalar(); ArrayValueItem *GetAsArray(); private: Type type_; }; class ScalarValueItem : public ValueItem { public: explicit ScalarValueItem(uint32_t v, ItemContainer *container) : ValueItem(Type::INTEGER, container), value_(v) {} explicit ScalarValueItem(uint64_t v, ItemContainer *container) : ValueItem(Type::LONG, container), value_(v) {} explicit ScalarValueItem(float v, ItemContainer *container) : ValueItem(Type::FLOAT, container), value_(v) {} explicit ScalarValueItem(double v, ItemContainer *container) : ValueItem(Type::DOUBLE, container), value_(v) {} explicit ScalarValueItem(BaseItem *v, ItemContainer *container) : ValueItem(Type::ID, container), value_(v) {} ~ScalarValueItem() override = default; DEFAULT_MOVE_SEMANTIC(ScalarValueItem); DEFAULT_COPY_SEMANTIC(ScalarValueItem); template T GetValue() const { return std::get(value_); } File::EntityId GetId() const { return File::EntityId(GetValue()->GetOffset()); } size_t GetULeb128EncodedSize(); size_t GetSLeb128EncodedSize(); size_t CalculateSize() const override; size_t Alignment() override; bool Write(Writer *writer) override; bool WriteAsUleb128(Writer *writer); private: std::variant value_; }; class ArrayValueItem : public ValueItem { public: ArrayValueItem(panda_file::Type component_type, std::vector items, ItemContainer *container) : ValueItem(Type::ARRAY, container), component_type_(component_type), items_(std::move(items)) { } ~ArrayValueItem() override = default; DEFAULT_MOVE_SEMANTIC(ArrayValueItem); DEFAULT_COPY_SEMANTIC(ArrayValueItem); size_t CalculateSize() const override; void ComputeLayout() override; bool Write(Writer *writer) override; private: size_t GetComponentSize() const; panda_file::Type component_type_; std::vector items_; }; class LiteralItem; class LiteralArrayItem; class LiteralItem : public BaseItem { public: enum class Type { B1, B2, B4, B8, STRING, METHOD, LITERALARRAY }; explicit LiteralItem(uint8_t v) : type_(Type::B1), value_(v) {} explicit LiteralItem(uint16_t v) : type_(Type::B2), value_(v) {} explicit LiteralItem(uint32_t v) : type_(Type::B4), value_(v) {} explicit LiteralItem(uint64_t v) : type_(Type::B8), value_(v) {} explicit LiteralItem(StringItem *v) : type_(Type::STRING), value_(v) {} explicit LiteralItem(MethodItem *v) : type_(Type::METHOD), value_(v) {} explicit LiteralItem(LiteralArrayItem *v) : type_(Type::LITERALARRAY), value_(v) {} ~LiteralItem() override = default; DEFAULT_MOVE_SEMANTIC(LiteralItem); DEFAULT_COPY_SEMANTIC(LiteralItem); Type GetType() const { return type_; } ItemTypes GetItemType() const override { return ItemTypes::LITERAL_ITEM; } template T GetValue() const { return std::get(value_); } size_t CalculateSize() const override; size_t Alignment() override; File::EntityId GetId() const { return File::EntityId(GetValue()->GetOffset()); } File::EntityId GetLiteralArrayFileId() const; File::EntityId GetMethodId() const { return File::EntityId(GetValue()->GetFileId()); } bool Write(Writer *writer) override; private: Type type_; std::variant value_; }; class LiteralArrayItem : public ValueItem { public: explicit LiteralArrayItem(ItemContainer *container) : ValueItem(Type::ARRAY, container) {} ~LiteralArrayItem() override = default; DEFAULT_MOVE_SEMANTIC(LiteralArrayItem); DEFAULT_COPY_SEMANTIC(LiteralArrayItem); void AddItems(const std::vector &item); size_t CalculateSize() const override; void ComputeLayout() override; bool Write(Writer *writer) override; IndexType GetIndexType() const override { return IndexType::METHOD_STRING_LITERAL; } ItemTypes GetItemType() const override { return ItemTypes::LITERAL_ARRAY_ITEM; } private: std::vector items_; }; class AnnotationItem : public BaseItem { public: class Elem { public: Elem(StringItem *name, ValueItem *value) : name_(name), value_(value) { value_->SetNeedsEmit(!value_->Is32bit()); } ~Elem() = default; DEFAULT_MOVE_SEMANTIC(Elem); DEFAULT_COPY_SEMANTIC(Elem); const StringItem *GetName() { return name_; } ValueItem *GetValue() { return value_; } void SetValue(ValueItem *item) { value_ = item; } private: StringItem *name_; ValueItem *value_; }; class Tag { public: explicit Tag(char item) : item_(item) {} ~Tag() = default; DEFAULT_MOVE_SEMANTIC(Tag); DEFAULT_COPY_SEMANTIC(Tag); uint8_t GetItem() const { return item_; } private: uint8_t item_; }; AnnotationItem(BaseClassItem *cls, std::vector elements, std::vector tags) : class_(cls), elements_(std::move(elements)), tags_(std::move(tags)) { AddIndexDependency(cls); } ~AnnotationItem() override = default; DEFAULT_MOVE_SEMANTIC(AnnotationItem); DEFAULT_COPY_SEMANTIC(AnnotationItem); size_t CalculateSize() const override; bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::ANNOTATION_ITEM; } std::vector *GetElements() { return &elements_; } void SetElements(std::vector &&elements) { elements_ = std::move(elements); } const std::vector &GetTags() const { return tags_; } void SetTags(std::vector &&tags) { tags_ = std::move(tags); } private: BaseClassItem *class_; std::vector elements_; std::vector tags_; }; enum class MethodHandleType : uint8_t { PUT_STATIC = 0x00, GET_STATIC = 0x01, PUT_INSTANCE = 0x02, GET_INSTANCE = 0x03, INVOKE_STATIC = 0x04, INVOKE_INSTANCE = 0x05, INVOKE_CONSTRUCTOR = 0x06, INVOKE_DIRECT = 0x07, INVOKE_INTERFACE = 0x08 }; class MethodHandleItem : public BaseItem { public: MethodHandleItem(MethodHandleType type, BaseItem *entity) : type_(type), entity_(entity) {} ~MethodHandleItem() override = default; DEFAULT_MOVE_SEMANTIC(MethodHandleItem); DEFAULT_COPY_SEMANTIC(MethodHandleItem); size_t CalculateSize() const override { return sizeof(uint8_t) + leb128::UnsignedEncodingSize(entity_->GetOffset()); } bool Write(Writer *writer) override; ItemTypes GetItemType() const override { return ItemTypes::METHOD_HANDLE_ITEM; } MethodHandleType GetType() const { return type_; } private: MethodHandleType type_; BaseItem *entity_; }; enum class ArgumentType : uint8_t { INTEGER = 0x00, LONG = 0x01, FLOAT = 0x02, DOUBLE = 0x03, STRING = 0x04, CLASS = 0x05, METHOD_HANDLE = 0x06, METHOD_TYPE = 0x07 }; } // namespace panda::panda_file #endif // LIBPANDAFILE_FILE_ITEMS_H_