Ai
6 Star 10 Fork 1.2K

Anton Soldatov/arkcompiler_runtime_core

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
file_items.cpp 42.91 KB
一键复制 编辑 原始数据 按行查看 历史
huyunhui1 提交于 2024-07-12 22:48 +08:00 . Enable sub version controlling
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722
/**
* 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 "file_items.h"
#include "file_item_container.h"
#include "macros.h"
#include "utils/bit_utils.h"
#include "utils/leb128.h"
#include "utils/utf.h"
#include <iomanip>
namespace panda::panda_file {
bool IsDynamicLanguage(panda::panda_file::SourceLang lang)
{
return lang == panda::panda_file::SourceLang::ECMASCRIPT;
}
std::optional<panda::panda_file::SourceLang> LanguageFromString(const std::string_view &lang)
{
if (lang == "ECMAScript") {
return panda::panda_file::SourceLang::ECMASCRIPT;
}
return panda::panda_file::SourceLang::PANDA_ASSEMBLY;
}
const char *LanguageToString(panda::panda_file::SourceLang lang)
{
if (lang == panda::panda_file::SourceLang::ECMASCRIPT) {
return "ECMAScript";
}
return "PandaAssembly";
}
const char *GetCtorName([[maybe_unused]] panda::panda_file::SourceLang lang)
{
return ".ctor";
}
const char *GetCctorName([[maybe_unused]] panda::panda_file::SourceLang lang)
{
return ".cctor";
}
const char *GetStringClassDescriptor(panda::panda_file::SourceLang lang)
{
if (lang == panda::panda_file::SourceLang::ECMASCRIPT) {
return "Lpanda/JSString;";
}
return "Lpanda/String;";
}
template <class Tag, class Val>
static bool WriteUlebTaggedValue(Writer *writer, Tag tag, Val v)
{
if (!writer->WriteByte(static_cast<uint8_t>(tag))) {
return false;
}
if (!writer->WriteUleb128(v)) {
return false;
}
return true;
}
template <class Tag, class Val>
static bool WriteSlebTaggedValue(Writer *writer, Tag tag, Val v)
{
if (!writer->WriteByte(static_cast<uint8_t>(tag))) {
return false;
}
if (!writer->WriteSleb128(v)) {
return false;
}
return true;
}
template <class Tag, class Val>
static bool WriteTaggedValue(Writer *writer, Tag tag, Val v)
{
if (!writer->WriteByte(static_cast<uint8_t>(tag))) {
return false;
}
if (!writer->Write(v)) {
return false;
}
return true;
}
template <class Tag>
static bool WriteIdTaggedValue(Writer *writer, Tag tag, BaseItem *item)
{
ASSERT(item->GetOffset() != 0);
return WriteTaggedValue(writer, tag, item->GetOffset());
}
std::string ItemTypeToString(ItemTypes type)
{
switch (type) {
case ItemTypes::ANNOTATION_ITEM:
return "annotation_item";
case ItemTypes::CATCH_BLOCK_ITEM:
return "catch_block_item";
case ItemTypes::CLASS_INDEX_ITEM:
return "class_index_item";
case ItemTypes::CLASS_ITEM:
return "class_item";
case ItemTypes::CODE_ITEM:
return "code_item";
case ItemTypes::DEBUG_INFO_ITEM:
return "debug_info_item";
case ItemTypes::END_ITEM:
return "end_item";
case ItemTypes::FIELD_INDEX_ITEM:
return "field_index_item";
case ItemTypes::FIELD_ITEM:
return "field_item";
case ItemTypes::FOREIGN_CLASS_ITEM:
return "foreign_class_item";
case ItemTypes::FOREIGN_FIELD_ITEM:
return "foreign_field_item";
case ItemTypes::FOREIGN_METHOD_ITEM:
return "foreign_method_item";
case ItemTypes::INDEX_HEADER:
return "index_header";
case ItemTypes::INDEX_SECTION:
return "index_section";
case ItemTypes::LINE_NUMBER_PROGRAM_INDEX_ITEM:
return "line_number_program_index_item";
case ItemTypes::LINE_NUMBER_PROGRAM_ITEM:
return "line_number_program_item";
case ItemTypes::LITERAL_ARRAY_ITEM:
return "literal_array_item";
case ItemTypes::LITERAL_ITEM:
return "literal_item";
case ItemTypes::METHOD_HANDLE_ITEM:
return "method_handle_item";
case ItemTypes::METHOD_INDEX_ITEM:
return "method_index_item";
case ItemTypes::METHOD_ITEM:
return "method_item";
case ItemTypes::PARAM_ANNOTATIONS_ITEM:
return "param_annotations_item";
case ItemTypes::PRIMITIVE_TYPE_ITEM:
return "primitive_type_item";
case ItemTypes::PROTO_INDEX_ITEM:
return "proto_index_item";
case ItemTypes::PROTO_ITEM:
return "proto_item";
case ItemTypes::STRING_ITEM:
return "string_item";
case ItemTypes::TRY_BLOCK_ITEM:
return "try_block_item";
case ItemTypes::VALUE_ITEM:
return "value_item";
default:
return "";
}
}
std::string BaseItem::GetName() const
{
return ItemTypeToString(GetItemType());
}
IndexedItem::IndexedItem(ItemContainer *container)
{
if (container != nullptr) {
item_global_index_ = container->GetIndexedItemCount();
container->IncIndexedItemCount();
}
}
StringItem::StringItem(std::string str, ItemContainer *container) : IndexedItem(container), str_(std::move(str))
{
str_.push_back(0);
utf16_length_ = utf::MUtf8ToUtf16Size(utf::CStringAsMutf8(str_.data()));
is_ascii_ = 1;
for (auto c : str_) {
if (static_cast<uint8_t>(c) > utf::MUTF8_1B_MAX) {
is_ascii_ = 0;
break;
}
}
}
StringItem::StringItem(File::StringData data, ItemContainer *container)
: IndexedItem(container), str_(reinterpret_cast<const char *>(data.data)), utf16_length_(data.utf16_length)
{
}
size_t StringItem::CalculateSize() const
{
size_t n = str_.size();
return leb128::UnsignedEncodingSize((utf16_length_ << 1U) | is_ascii_) + n;
}
bool StringItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
constexpr size_t MAX_LENGTH = 0x7fffffffU;
if (utf16_length_ > MAX_LENGTH) {
LOG(ERROR, PANDAFILE) << "Writing StringItem with size greater than 0x7fffffffU is not supported!";
return false;
}
if (!writer->WriteUleb128((utf16_length_ << 1U) | is_ascii_)) {
return false;
}
for (auto c : str_) {
if (!writer->WriteByte(static_cast<uint8_t>(c))) {
return false;
}
}
return true;
}
size_t BaseClassItem::CalculateSize() const
{
return name_.GetSize();
}
void BaseClassItem::ComputeLayout()
{
uint32_t offset = GetOffset();
ASSERT(offset != 0);
name_.SetOffset(offset);
}
bool BaseClassItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
return name_.Write(writer);
}
size_t ClassItem::CalculateSizeWithoutFieldsAndMethods() const
{
size_t size = BaseClassItem::CalculateSize() + ID_SIZE + leb128::UnsignedEncodingSize(access_flags_);
size += leb128::UnsignedEncodingSize(fields_.size());
size += leb128::UnsignedEncodingSize(methods_.size());
if (!ifaces_.empty()) {
size += TAG_SIZE + leb128::UnsignedEncodingSize(ifaces_.size()) + IDX_SIZE * ifaces_.size();
}
if (source_lang_ != SourceLang::PANDA_ASSEMBLY) {
size += TAG_SIZE + sizeof(SourceLang);
}
size += (TAG_SIZE + ID_SIZE) * runtime_annotations_.size();
size += (TAG_SIZE + ID_SIZE) * annotations_.size();
size += (TAG_SIZE + ID_SIZE) * runtime_type_annotations_.size();
size += (TAG_SIZE + ID_SIZE) * type_annotations_.size();
if (source_file_ != nullptr) {
size += TAG_SIZE + ID_SIZE;
}
size += TAG_SIZE; // null tag
return size;
}
size_t ClassItem::CalculateSize() const
{
size_t size = CalculateSizeWithoutFieldsAndMethods();
for (auto &field : fields_) {
size += field->GetSize();
}
for (auto &method : methods_) {
size += method->GetSize();
}
return size;
}
void ClassItem::ComputeLayout()
{
BaseClassItem::ComputeLayout();
uint32_t offset = GetOffset();
offset += CalculateSizeWithoutFieldsAndMethods();
for (auto &field : fields_) {
field->SetOffset(offset);
field->ComputeLayout();
offset += field->GetSize();
}
for (auto &method : methods_) {
method->SetOffset(offset);
method->ComputeLayout();
offset += method->GetSize();
}
}
bool ClassItem::WriteIfaces(Writer *writer)
{
if (!ifaces_.empty()) {
if (!writer->WriteByte(static_cast<uint8_t>(ClassTag::INTERFACES))) {
return false;
}
if (!writer->WriteUleb128(ifaces_.size())) {
return false;
}
for (auto iface : ifaces_) {
ASSERT(iface->HasIndex(this));
if (!writer->Write<uint16_t>(iface->GetIndex(this))) {
return false;
}
}
}
return true;
}
bool ClassItem::WriteAnnotations(Writer *writer)
{
for (auto runtime_annotation : runtime_annotations_) {
if (!WriteIdTaggedValue(writer, ClassTag::RUNTIME_ANNOTATION, runtime_annotation)) {
return false;
}
}
for (auto annotation : annotations_) {
if (!WriteIdTaggedValue(writer, ClassTag::ANNOTATION, annotation)) {
return false;
}
}
for (auto runtime_type_annotation : runtime_type_annotations_) {
if (!WriteIdTaggedValue(writer, ClassTag::RUNTIME_TYPE_ANNOTATION, runtime_type_annotation)) {
return false;
}
}
for (auto type_annotation : type_annotations_) {
if (!WriteIdTaggedValue(writer, ClassTag::TYPE_ANNOTATION, type_annotation)) {
return false;
}
}
return true;
}
bool ClassItem::WriteTaggedData(Writer *writer)
{
if (!WriteIfaces(writer)) {
return false;
}
if (source_lang_ != SourceLang::PANDA_ASSEMBLY) {
if (!WriteTaggedValue(writer, ClassTag::SOURCE_LANG, static_cast<uint8_t>(source_lang_))) {
return false;
}
}
if (!WriteAnnotations(writer)) {
return false;
}
if (source_file_ != nullptr) {
if (!WriteIdTaggedValue(writer, ClassTag::SOURCE_FILE, source_file_)) {
return false;
}
}
return writer->WriteByte(static_cast<uint8_t>(ClassTag::NOTHING));
}
bool ClassItem::Write(Writer *writer)
{
if (!BaseClassItem::Write(writer)) {
return false;
}
uint32_t offset = super_class_ != nullptr ? super_class_->GetOffset() : 0;
if (!writer->Write(offset)) {
return false;
}
if (!writer->WriteUleb128(access_flags_)) {
return false;
}
if (!writer->WriteUleb128(fields_.size())) {
return false;
}
if (!writer->WriteUleb128(methods_.size())) {
return false;
}
if (!WriteTaggedData(writer)) {
return false;
}
for (auto &field : fields_) {
if (!field->Write(writer)) {
return false;
}
}
for (auto &method : methods_) {
if (!method->Write(writer)) {
return false;
}
}
return true;
}
ParamAnnotationsItem::ParamAnnotationsItem(MethodItem *method, bool is_runtime_annotations)
{
for (const auto &param : method->GetParams()) {
if (is_runtime_annotations) {
annotations_.push_back(param.GetRuntimeAnnotations());
} else {
annotations_.push_back(param.GetAnnotations());
}
}
if (is_runtime_annotations) {
method->SetRuntimeParamAnnotationItem(this);
} else {
method->SetParamAnnotationItem(this);
}
}
size_t ParamAnnotationsItem::CalculateSize() const
{
size_t size = sizeof(uint32_t); // size
for (const auto &param_annotations : annotations_) {
size += sizeof(uint32_t); // count
size += param_annotations.size() * ID_SIZE;
}
return size;
}
bool ParamAnnotationsItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
if (!writer->Write(static_cast<uint32_t>(annotations_.size()))) {
return false;
}
for (const auto &param_annotations : annotations_) {
if (!writer->Write(static_cast<uint32_t>(param_annotations.size()))) {
return false;
}
for (auto *item : param_annotations) {
ASSERT(item->GetOffset() != 0);
if (!writer->Write(item->GetOffset())) {
return false;
}
}
}
return true;
}
ProtoItem::ProtoItem(TypeItem *ret_type, const std::vector<MethodParamItem> &params, ItemContainer *itemContainer)
: IndexedItem(itemContainer)
{
size_t n = 0;
shorty_.push_back(0);
AddType(ret_type, &n);
for (auto &p : params) {
AddType(p.GetType(), &n);
}
const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi());
if (bc_version.value().front() >= API_12) {
// no need to emit protoItem
SetNeedsEmit(false);
}
}
void ProtoItem::AddType(TypeItem *type, size_t *n)
{
constexpr size_t SHORTY_ELEMS_COUNT = std::numeric_limits<uint16_t>::digits / SHORTY_ELEM_SIZE;
uint16_t v = shorty_.back();
size_t shift = (*n % SHORTY_ELEMS_COUNT) * SHORTY_ELEM_SIZE;
v |= static_cast<uint16_t>(static_cast<uint16_t>(type->GetType().GetEncoding()) << shift);
shorty_.back() = v;
if (!type->GetType().IsPrimitive()) {
reference_types_.push_back(type);
AddIndexDependency(type);
}
*n += 1;
if (*n % SHORTY_ELEMS_COUNT == 0) {
shorty_.push_back(0);
}
}
bool ProtoItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
for (auto s : shorty_) {
if (!writer->Write(s)) {
return false;
}
}
for (auto r : reference_types_) {
ASSERT(r->HasIndex(this));
if (!writer->Write<uint16_t>(r->GetIndex(this))) {
return false;
}
}
return true;
}
BaseMethodItem::BaseMethodItem(BaseClassItem *cls, StringItem *name, ProtoItem *proto, uint32_t access_flags,
ItemContainer *container)
: IndexedItem(container), class_(cls), name_(name), proto_(proto), access_flags_(access_flags)
{
AddIndexDependency(cls);
AddIndexDependency(proto);
}
size_t BaseMethodItem::CalculateSize() const
{
// class id + proto id + name id + access flags
return IDX_SIZE + IDX_SIZE + ID_SIZE + leb128::UnsignedEncodingSize(access_flags_);
}
bool BaseMethodItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
ASSERT(class_ != nullptr);
ASSERT(class_->HasIndex(this));
if (!writer->Write<uint16_t>(class_->GetIndex(this))) {
return false;
}
const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi());
if (bc_version.value().front() >= API_12) {
// reserve [proto_idx] field, write invalid index
if (!writer->Write<uint16_t>(INVALID_INDEX_16)) {
return false;
}
} else {
ASSERT(proto_->HasIndex(this));
if (!writer->Write<uint16_t>(proto_->GetIndex(this))) {
return false;
}
}
ASSERT(name_->GetOffset() != 0);
if (!writer->Write(name_->GetOffset())) {
return false;
}
return writer->WriteUleb128(access_flags_);
}
MethodItem::MethodItem(ClassItem *cls, StringItem *name, ProtoItem *proto, uint32_t access_flags,
std::vector<MethodParamItem> params, ItemContainer *container)
: BaseMethodItem(cls, name, proto, access_flags, container),
params_(std::move(params)),
source_lang_(SourceLang::PANDA_ASSEMBLY),
code_(nullptr),
debug_info_(nullptr)
{
}
size_t MethodItem::CalculateSize() const
{
size_t size = BaseMethodItem::CalculateSize();
if (code_ != nullptr) {
size += TAG_SIZE + ID_SIZE;
}
if (source_lang_ != SourceLang::PANDA_ASSEMBLY) {
size += TAG_SIZE + sizeof(SourceLang);
}
size += (TAG_SIZE + ID_SIZE) * runtime_annotations_.size();
if (runtime_param_annotations_ != nullptr) {
size += TAG_SIZE + ID_SIZE;
}
size += (TAG_SIZE + ID_SIZE) * annotations_.size();
if (param_annotations_ != nullptr) {
size += TAG_SIZE + ID_SIZE;
}
size += (TAG_SIZE + ID_SIZE) * runtime_type_annotations_.size();
size += (TAG_SIZE + ID_SIZE) * type_annotations_.size();
if (debug_info_ != nullptr) {
size += TAG_SIZE + ID_SIZE;
}
size += TAG_SIZE; // null tag
return size;
}
bool MethodItem::WriteRuntimeAnnotations(Writer *writer)
{
for (auto runtime_annotation : runtime_annotations_) {
if (!WriteIdTaggedValue(writer, MethodTag::RUNTIME_ANNOTATION, runtime_annotation)) {
return false;
}
}
if (runtime_param_annotations_ != nullptr) {
if (!WriteIdTaggedValue(writer, MethodTag::RUNTIME_PARAM_ANNOTATION, runtime_param_annotations_)) {
return false;
}
}
return true;
}
bool MethodItem::WriteTypeAnnotations(Writer *writer)
{
for (auto runtime_type_annotation : runtime_type_annotations_) {
if (!WriteIdTaggedValue(writer, MethodTag::RUNTIME_TYPE_ANNOTATION, runtime_type_annotation)) {
return false;
}
}
for (auto type_annotation : type_annotations_) {
if (!WriteIdTaggedValue(writer, MethodTag::TYPE_ANNOTATION, type_annotation)) {
return false;
}
}
return true;
}
bool MethodItem::WriteTaggedData(Writer *writer)
{
if (code_ != nullptr) {
if (!WriteIdTaggedValue(writer, MethodTag::CODE, code_)) {
return false;
}
}
if (source_lang_ != SourceLang::PANDA_ASSEMBLY) {
if (!WriteTaggedValue(writer, MethodTag::SOURCE_LANG, static_cast<uint8_t>(source_lang_))) {
return false;
}
}
if (!WriteRuntimeAnnotations(writer)) {
return false;
}
if (debug_info_ != nullptr) {
if (!WriteIdTaggedValue(writer, MethodTag::DEBUG_INFO, debug_info_)) {
return false;
}
}
for (auto annotation : annotations_) {
if (!WriteIdTaggedValue(writer, MethodTag::ANNOTATION, annotation)) {
return false;
}
}
if (!WriteTypeAnnotations(writer)) {
return false;
}
if (param_annotations_ != nullptr) {
if (!WriteIdTaggedValue(writer, MethodTag::PARAM_ANNOTATION, param_annotations_)) {
return false;
}
}
return writer->WriteByte(static_cast<uint8_t>(MethodTag::NOTHING));
}
bool MethodItem::Write(Writer *writer)
{
if (!BaseMethodItem::Write(writer)) {
return false;
}
return WriteTaggedData(writer);
}
size_t CodeItem::CatchBlock::CalculateSize() const
{
ASSERT(type_ == nullptr || type_->HasIndex(method_));
uint32_t type_off = type_ != nullptr ? type_->GetIndex(method_) + 1 : 0;
return leb128::UnsignedEncodingSize(type_off) + leb128::UnsignedEncodingSize(handler_pc_) +
leb128::UnsignedEncodingSize(code_size_);
}
bool CodeItem::CatchBlock::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
ASSERT(type_ == nullptr || type_->HasIndex(method_));
uint32_t type_off = type_ != nullptr ? type_->GetIndex(method_) + 1 : 0;
if (!writer->WriteUleb128(type_off)) {
return false;
}
if (!writer->WriteUleb128(handler_pc_)) {
return false;
}
if (!writer->WriteUleb128(code_size_)) {
return false;
}
return true;
}
void CodeItem::TryBlock::ComputeLayout()
{
size_t offset = GetOffset();
offset += CalculateSizeWithoutCatchBlocks();
for (auto &catch_block : catch_blocks_) {
catch_block.SetOffset(offset);
catch_block.ComputeLayout();
offset += catch_block.GetSize();
}
}
size_t CodeItem::TryBlock::CalculateSizeWithoutCatchBlocks() const
{
return leb128::UnsignedEncodingSize(start_pc_) + leb128::UnsignedEncodingSize(length_) +
leb128::UnsignedEncodingSize(catch_blocks_.size());
}
size_t CodeItem::TryBlock::CalculateSize() const
{
size_t size = CalculateSizeWithoutCatchBlocks();
for (auto &catch_block : catch_blocks_) {
size += catch_block.GetSize();
}
return size;
}
bool CodeItem::TryBlock::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
if (!writer->WriteUleb128(start_pc_)) {
return false;
}
if (!writer->WriteUleb128(length_)) {
return false;
}
if (!writer->WriteUleb128(catch_blocks_.size())) {
return false;
}
for (auto &catch_block : catch_blocks_) {
if (!catch_block.Write(writer)) {
return false;
}
}
return true;
}
void CodeItem::ComputeLayout()
{
uint32_t offset = GetOffset();
offset += CalculateSizeWithoutTryBlocks();
for (auto &try_block : try_blocks_) {
try_block.SetOffset(offset);
try_block.ComputeLayout();
offset += try_block.GetSize();
}
}
size_t CodeItem::CalculateSizeWithoutTryBlocks() const
{
size_t size = leb128::UnsignedEncodingSize(num_vregs_) + leb128::UnsignedEncodingSize(num_args_) +
leb128::UnsignedEncodingSize(instructions_.size()) + leb128::UnsignedEncodingSize(try_blocks_.size());
size += instructions_.size();
return size;
}
size_t CodeItem::GetCodeSize() const
{
return instructions_.size();
}
size_t CodeItem::CalculateSize() const
{
size_t size = CalculateSizeWithoutTryBlocks();
for (auto &try_block : try_blocks_) {
size += try_block.GetSize();
}
return size;
}
bool CodeItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
if (!writer->WriteUleb128(num_vregs_)) {
return false;
}
if (!writer->WriteUleb128(num_args_)) {
return false;
}
if (!writer->WriteUleb128(instructions_.size())) {
return false;
}
if (!writer->WriteUleb128(try_blocks_.size())) {
return false;
}
if (!writer->WriteBytes(instructions_)) {
return false;
}
for (auto &try_block : try_blocks_) {
if (!try_block.Write(writer)) {
return false;
}
}
return true;
}
ScalarValueItem *ValueItem::GetAsScalar()
{
ASSERT(!IsArray());
return static_cast<ScalarValueItem *>(this);
}
ArrayValueItem *ValueItem::GetAsArray()
{
ASSERT(IsArray());
return static_cast<ArrayValueItem *>(this);
}
size_t ScalarValueItem::GetULeb128EncodedSize()
{
switch (GetType()) {
case Type::INTEGER:
return leb128::UnsignedEncodingSize(GetValue<uint32_t>());
case Type::LONG:
return leb128::UnsignedEncodingSize(GetValue<uint64_t>());
case Type::ID:
return leb128::UnsignedEncodingSize(GetId().GetOffset());
default:
return 0;
}
}
size_t ScalarValueItem::GetSLeb128EncodedSize()
{
switch (GetType()) {
case Type::INTEGER:
return leb128::SignedEncodingSize(static_cast<int32_t>(GetValue<uint32_t>()));
case Type::LONG:
return leb128::SignedEncodingSize(static_cast<int64_t>(GetValue<uint64_t>()));
default:
return 0;
}
}
size_t ScalarValueItem::CalculateSize() const
{
size_t size = 0;
switch (GetType()) {
case Type::INTEGER: {
size = sizeof(uint32_t);
break;
}
case Type::LONG: {
size = sizeof(uint64_t);
break;
}
case Type::FLOAT: {
size = sizeof(float);
break;
}
case Type::DOUBLE: {
size = sizeof(double);
break;
}
case Type::ID: {
size = ID_SIZE;
break;
}
default: {
UNREACHABLE();
break;
}
}
return size;
}
size_t ScalarValueItem::Alignment()
{
return GetSize();
}
bool ScalarValueItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
switch (GetType()) {
case Type::INTEGER:
return writer->Write(GetValue<uint32_t>());
case Type::LONG:
return writer->Write(GetValue<uint64_t>());
case Type::FLOAT:
return writer->Write(bit_cast<uint32_t>(GetValue<float>()));
case Type::DOUBLE:
return writer->Write(bit_cast<uint64_t>(GetValue<double>()));
case Type::ID: {
ASSERT(GetId().IsValid());
return writer->Write(GetId().GetOffset());
}
default: {
UNREACHABLE();
break;
}
}
return true;
}
bool ScalarValueItem::WriteAsUleb128(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
switch (GetType()) {
case Type::INTEGER:
return writer->WriteUleb128(GetValue<uint32_t>());
case Type::LONG:
return writer->WriteUleb128(GetValue<uint64_t>());
case Type::ID: {
ASSERT(GetId().IsValid());
return writer->WriteUleb128(GetId().GetOffset());
}
default:
return false;
}
}
size_t ArrayValueItem::CalculateSize() const
{
size_t size = leb128::UnsignedEncodingSize(items_.size()) + items_.size() * GetComponentSize();
return size;
}
void ArrayValueItem::ComputeLayout()
{
uint32_t offset = GetOffset();
ASSERT(offset != 0);
offset += leb128::UnsignedEncodingSize(items_.size());
for (auto &item : items_) {
item.SetOffset(offset);
offset += GetComponentSize();
}
}
bool ArrayValueItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
if (!writer->WriteUleb128(items_.size())) {
return false;
}
switch (component_type_.GetId()) {
case panda_file::Type::TypeId::U1:
case panda_file::Type::TypeId::I8:
case panda_file::Type::TypeId::U8: {
for (auto &item : items_) {
auto value = static_cast<uint8_t>(item.GetValue<uint32_t>());
if (!writer->Write(value)) {
return false;
}
}
break;
}
case panda_file::Type::TypeId::I16:
case panda_file::Type::TypeId::U16: {
for (auto &item : items_) {
auto value = static_cast<uint16_t>(item.GetValue<uint32_t>());
if (!writer->Write(value)) {
return false;
}
}
break;
}
default: {
for (auto &item : items_) {
if (!item.Write(writer)) {
return false;
}
}
break;
}
}
return true;
}
size_t ArrayValueItem::GetComponentSize() const
{
switch (component_type_.GetId()) {
case panda_file::Type::TypeId::U1:
case panda_file::Type::TypeId::I8:
case panda_file::Type::TypeId::U8:
return sizeof(uint8_t);
case panda_file::Type::TypeId::I16:
case panda_file::Type::TypeId::U16:
return sizeof(uint16_t);
case panda_file::Type::TypeId::I32:
case panda_file::Type::TypeId::U32:
case panda_file::Type::TypeId::F32:
return sizeof(uint32_t);
case panda_file::Type::TypeId::I64:
case panda_file::Type::TypeId::U64:
case panda_file::Type::TypeId::F64:
return sizeof(uint64_t);
case panda_file::Type::TypeId::REFERENCE:
return ID_SIZE;
case panda_file::Type::TypeId::VOID:
return 0;
default: {
UNREACHABLE();
// Avoid cpp warning
return 0;
}
}
}
size_t LiteralItem::CalculateSize() const
{
size_t size = 0;
switch (GetType()) {
case Type::B1: {
size = sizeof(uint8_t);
break;
}
case Type::B2: {
size = sizeof(uint16_t);
break;
}
case Type::B4: {
size = sizeof(uint32_t);
break;
}
case Type::B8: {
size = sizeof(uint64_t);
break;
}
case Type::STRING:
case Type::METHOD:
case Type::LITERALARRAY: {
size = ID_SIZE;
break;
}
default: {
UNREACHABLE();
break;
}
}
return size;
}
size_t LiteralItem::Alignment()
{
return GetSize();
}
File::EntityId LiteralItem::GetLiteralArrayFileId() const
{
return File::EntityId(GetValue<LiteralArrayItem *>()->GetOffset());
}
bool LiteralItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
switch (GetType()) {
case Type::B1: {
return writer->Write(GetValue<uint8_t>());
}
case Type::B2: {
return writer->Write(GetValue<uint16_t>());
}
case Type::B4: {
return writer->Write(GetValue<uint32_t>());
}
case Type::B8: {
return writer->Write(GetValue<uint64_t>());
}
case Type::STRING: {
ASSERT(GetId().IsValid());
return writer->Write(GetId().GetOffset());
}
case Type::METHOD: {
ASSERT(GetMethodId().IsValid());
return writer->Write(GetMethodId().GetOffset());
}
case Type::LITERALARRAY: {
ASSERT(GetLiteralArrayFileId().IsValid());
return writer->Write(GetLiteralArrayFileId().GetOffset());
}
default: {
UNREACHABLE();
break;
}
}
return true;
}
void LiteralArrayItem::AddItems(const std::vector<LiteralItem> &item)
{
items_.assign(item.begin(), item.end());
}
size_t LiteralArrayItem::CalculateSize() const
{
size_t size = sizeof(uint32_t);
for (auto &item : items_) {
size += item.CalculateSize();
}
return size;
}
void LiteralArrayItem::ComputeLayout()
{
uint32_t offset = GetOffset();
ASSERT(offset != 0);
offset += sizeof(uint32_t);
for (auto &item : items_) {
item.SetOffset(offset);
offset += item.CalculateSize();
}
}
bool LiteralArrayItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
if (!writer->Write(static_cast<uint32_t>(items_.size()))) {
return false;
}
for (auto &item : items_) {
if (!item.Write(writer)) {
return false;
}
}
return true;
}
BaseFieldItem::BaseFieldItem(BaseClassItem *cls, StringItem *name, TypeItem *type, ItemContainer *container)
: IndexedItem(container), class_(cls), name_(name), type_(type)
{
AddIndexDependency(cls);
AddIndexDependency(type);
}
size_t BaseFieldItem::CalculateSize() const
{
// class id + type id + name id
return IDX_SIZE + IDX_SIZE + ID_SIZE;
}
bool BaseFieldItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
ASSERT(class_->HasIndex(this));
ASSERT(type_->HasIndex(this));
if (!writer->Write<uint16_t>(class_->GetIndex(this))) {
return false;
}
if (!writer->Write<uint16_t>(type_->GetIndex(this))) {
return false;
}
return writer->Write(name_->GetOffset());
}
FieldItem::FieldItem(ClassItem *cls, StringItem *name, TypeItem *type, uint32_t access_flags, ItemContainer *container)
: BaseFieldItem(cls, name, type, container), access_flags_(access_flags), value_(nullptr)
{
}
void FieldItem::SetValue(ValueItem *value)
{
value_ = value;
value_->SetNeedsEmit(!value_->Is32bit());
}
size_t FieldItem::CalculateSize() const
{
size_t size = BaseFieldItem::CalculateSize() + leb128::UnsignedEncodingSize(access_flags_);
if (value_ != nullptr) {
if (value_->GetType() == ValueItem::Type::INTEGER) {
size += TAG_SIZE + value_->GetAsScalar()->GetSLeb128EncodedSize();
} else {
size += TAG_SIZE + ID_SIZE;
}
}
size += (TAG_SIZE + ID_SIZE) * runtime_annotations_.size();
size += (TAG_SIZE + ID_SIZE) * annotations_.size();
size += (TAG_SIZE + ID_SIZE) * runtime_type_annotations_.size();
size += (TAG_SIZE + ID_SIZE) * type_annotations_.size();
size += TAG_SIZE; // null tag
return size;
}
bool FieldItem::WriteValue(Writer *writer)
{
if (value_ == nullptr) {
return true;
}
if (value_->GetType() == ValueItem::Type::INTEGER) {
auto v = static_cast<int32_t>(value_->GetAsScalar()->GetValue<uint32_t>());
if (!WriteSlebTaggedValue(writer, FieldTag::INT_VALUE, v)) {
return false;
}
} else if (value_->GetType() == ValueItem::Type::FLOAT) {
auto v = bit_cast<uint32_t>(value_->GetAsScalar()->GetValue<float>());
if (!WriteTaggedValue(writer, FieldTag::VALUE, v)) {
return false;
}
} else if (value_->GetType() == ValueItem::Type::ID) {
auto id = value_->GetAsScalar()->GetId();
ASSERT(id.GetOffset() != 0);
if (!WriteTaggedValue(writer, FieldTag::VALUE, id.GetOffset())) {
return false;
}
} else {
ASSERT(!value_->Is32bit());
if (!WriteIdTaggedValue(writer, FieldTag::VALUE, value_)) {
return false;
}
}
return true;
}
bool FieldItem::WriteAnnotations(Writer *writer)
{
for (auto runtime_annotation : runtime_annotations_) {
if (!WriteIdTaggedValue(writer, FieldTag::RUNTIME_ANNOTATION, runtime_annotation)) {
return false;
}
}
for (auto annotation : annotations_) {
if (!WriteIdTaggedValue(writer, FieldTag::ANNOTATION, annotation)) {
return false;
}
}
for (auto runtime_type_annotation : runtime_type_annotations_) {
if (!WriteIdTaggedValue(writer, FieldTag::RUNTIME_TYPE_ANNOTATION, runtime_type_annotation)) {
return false;
}
}
for (auto type_annotation : type_annotations_) {
if (!WriteIdTaggedValue(writer, FieldTag::TYPE_ANNOTATION, type_annotation)) {
return false;
}
}
return true;
}
bool FieldItem::WriteTaggedData(Writer *writer)
{
if (!WriteValue(writer)) {
return false;
}
if (!WriteAnnotations(writer)) {
return false;
}
return writer->WriteByte(static_cast<uint8_t>(FieldTag::NOTHING));
}
bool FieldItem::Write(Writer *writer)
{
if (!BaseFieldItem::Write(writer)) {
return false;
}
if (!writer->WriteUleb128(access_flags_)) {
return false;
}
return WriteTaggedData(writer);
}
size_t AnnotationItem::CalculateSize() const
{
// class id + count + (name id + value id) * count + tag size * count
size_t size = IDX_SIZE + sizeof(uint16_t) + (ID_SIZE + ID_SIZE) * elements_.size() + sizeof(uint8_t) * tags_.size();
return size;
}
bool AnnotationItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
ASSERT(class_->HasIndex(this));
if (!writer->Write<uint16_t>(class_->GetIndex(this))) {
return false;
}
if (!writer->Write(static_cast<uint16_t>(elements_.size()))) {
return false;
}
for (auto elem : elements_) {
ASSERT(elem.GetName()->GetOffset() != 0);
if (!writer->Write(elem.GetName()->GetOffset())) {
return false;
}
ValueItem *value_item = elem.GetValue();
switch (value_item->GetType()) {
case ValueItem::Type::INTEGER: {
if (!writer->Write(value_item->GetAsScalar()->GetValue<uint32_t>())) {
return false;
}
break;
}
case ValueItem::Type::FLOAT: {
if (!writer->Write(bit_cast<uint32_t>(value_item->GetAsScalar()->GetValue<float>()))) {
return false;
}
break;
}
case ValueItem::Type::ID: {
if (!writer->Write(value_item->GetAsScalar()->GetId().GetOffset())) {
return false;
}
break;
}
default: {
ASSERT(value_item->GetOffset() != 0);
if (!writer->Write(value_item->GetOffset())) {
return false;
}
break;
}
}
}
for (auto tag : tags_) {
if (!writer->Write(tag.GetItem())) {
return false;
}
}
return true;
}
void LineNumberProgramItem::EmitEnd()
{
EmitOpcode(Opcode::END_SEQUENCE);
}
void LineNumberProgramItem::EmitAdvancePc(std::vector<uint8_t> *constant_pool, uint32_t value)
{
EmitOpcode(Opcode::ADVANCE_PC);
EmitUleb128(constant_pool, value);
}
void LineNumberProgramItem::EmitAdvanceLine(std::vector<uint8_t> *constant_pool, int32_t value)
{
EmitOpcode(Opcode::ADVANCE_LINE);
EmitSleb128(constant_pool, value);
}
void LineNumberProgramItem::EmitColumn(std::vector<uint8_t> *constant_pool, uint32_t pc_inc, uint32_t column)
{
if (pc_inc != 0U) {
EmitAdvancePc(constant_pool, pc_inc);
}
EmitOpcode(Opcode::SET_COLUMN);
EmitUleb128(constant_pool, column);
}
void LineNumberProgramItem::EmitStartLocal(std::vector<uint8_t> *constant_pool, int32_t register_number,
StringItem *name, StringItem *type)
{
EmitStartLocalExtended(constant_pool, register_number, name, type, nullptr);
}
void LineNumberProgramItem::EmitStartLocalExtended(std::vector<uint8_t> *constant_pool, int32_t register_number,
StringItem *name, StringItem *type, StringItem *type_signature)
{
ASSERT(name != nullptr);
ASSERT(type != nullptr);
EmitOpcode(type_signature == nullptr ? Opcode::START_LOCAL : Opcode::START_LOCAL_EXTENDED);
EmitRegister(register_number);
ASSERT(name->GetOffset() != 0);
EmitUleb128(constant_pool, name->GetOffset());
ASSERT(type->GetOffset() != 0);
EmitUleb128(constant_pool, type->GetOffset());
if (type_signature != nullptr) {
ASSERT(type_signature->GetOffset() != 0);
EmitUleb128(constant_pool, type_signature->GetOffset());
}
}
void LineNumberProgramItem::EmitEndLocal(int32_t register_number)
{
EmitOpcode(Opcode::END_LOCAL);
EmitRegister(register_number);
}
void LineNumberProgramItem::EmitRestartLocal(int32_t register_number)
{
EmitOpcode(Opcode::RESTART_LOCAL);
EmitRegister(register_number);
}
bool LineNumberProgramItem::EmitSpecialOpcode(uint32_t pc_inc, int32_t line_inc)
{
if (line_inc < LINE_BASE || (line_inc - LINE_BASE) >= LINE_RANGE) {
return false;
}
auto opcode = static_cast<size_t>(line_inc - LINE_BASE) + static_cast<size_t>(pc_inc * LINE_RANGE) + OPCODE_BASE;
if (opcode > std::numeric_limits<uint8_t>::max()) {
return false;
}
data_.push_back(static_cast<uint8_t>(opcode));
return true;
}
void LineNumberProgramItem::EmitPrologEnd()
{
EmitOpcode(Opcode::SET_PROLOGUE_END);
}
void LineNumberProgramItem::EmitEpilogBegin()
{
EmitOpcode(Opcode::SET_EPILOGUE_BEGIN);
}
void LineNumberProgramItem::EmitSetFile(std::vector<uint8_t> *constant_pool, StringItem *source_file)
{
EmitOpcode(Opcode::SET_FILE);
if (source_file == nullptr) {
return;
}
ASSERT(source_file->GetOffset() != 0);
EmitUleb128(constant_pool, source_file->GetOffset());
}
void LineNumberProgramItem::EmitSetSourceCode(std::vector<uint8_t> *constant_pool, StringItem *source_code)
{
EmitOpcode(Opcode::SET_SOURCE_CODE);
if (source_code == nullptr) {
return;
}
ASSERT(source_code->GetOffset() != 0);
EmitUleb128(constant_pool, source_code->GetOffset());
}
void LineNumberProgramItem::EmitOpcode(Opcode opcode)
{
data_.push_back(static_cast<uint8_t>(opcode));
}
void LineNumberProgramItem::EmitRegister(int32_t register_number)
{
EmitSleb128(&data_, register_number);
}
/* static */
void LineNumberProgramItem::EmitUleb128(std::vector<uint8_t> *data, uint32_t value)
{
size_t n = leb128::UnsignedEncodingSize(value);
std::vector<uint8_t> out(n);
leb128::EncodeUnsigned(value, out.data());
if (data == nullptr) {
return;
}
data->insert(data->end(), out.cbegin(), out.cend());
}
/* static */
void LineNumberProgramItem::EmitSleb128(std::vector<uint8_t> *data, int32_t value)
{
size_t n = leb128::SignedEncodingSize(value);
std::vector<uint8_t> out(n);
leb128::EncodeSigned(value, out.data());
data->insert(data->end(), out.cbegin(), out.cend());
}
size_t LineNumberProgramItem::CalculateSize() const
{
return data_.size();
}
bool LineNumberProgramItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
return writer->WriteBytes(data_);
}
void LineNumberProgramItem::SetData(std::vector<uint8_t> &&data)
{
data_ = std::move(data);
}
size_t DebugInfoItem::CalculateSize() const
{
size_t n = leb128::UnsignedEncodingSize(line_num_) + leb128::UnsignedEncodingSize(parameters_.size());
for (auto *p : parameters_) {
ASSERT(p == nullptr || p->GetOffset() != 0);
n += leb128::UnsignedEncodingSize(p == nullptr ? 0 : p->GetOffset());
}
n += leb128::UnsignedEncodingSize(constant_pool_.size());
n += constant_pool_.size();
n += leb128::UnsignedEncodingSize(program_->GetIndex(this));
return n;
}
bool DebugInfoItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
if (!writer->WriteUleb128(line_num_)) {
return false;
}
if (!writer->WriteUleb128(parameters_.size())) {
return false;
}
for (auto *p : parameters_) {
ASSERT(p == nullptr || p->GetOffset() != 0);
if (!writer->WriteUleb128(p == nullptr ? 0 : p->GetOffset())) {
return false;
}
}
if (!writer->WriteUleb128(constant_pool_.size())) {
return false;
}
if (!writer->WriteBytes(constant_pool_)) {
return false;
}
ASSERT(program_ != nullptr);
ASSERT(program_->HasIndex(this));
return writer->WriteUleb128(program_->GetIndex(this));
}
void DebugInfoItem::Dump(std::ostream &os) const
{
os << "line_start = " << line_num_ << std::endl;
os << "num_parameters = " << parameters_.size() << std::endl;
for (auto *item : parameters_) {
if (item != nullptr) {
os << " string_item[" << item->GetOffset() << "]" << std::endl;
} else {
os << " string_item[INVALID_OFFSET]" << std::endl;
}
}
os << "constant_pool = [";
for (size_t i = 0; i < constant_pool_.size(); i++) {
size_t b = constant_pool_[i];
os << "0x" << std::setfill('0') << std::setw(2U) << std::right << std::hex << b << std::dec;
if (i < constant_pool_.size() - 1) {
os << ", ";
}
}
os << "]" << std::endl;
os << "line_number_program = line_number_program_idx[";
if (program_ != nullptr && program_->HasIndex(this)) {
os << program_->GetIndex(this);
} else {
os << "NO_INDEX";
}
os << "]";
}
bool MethodHandleItem::Write(Writer *writer)
{
ASSERT(GetOffset() == writer->GetOffset());
if (!writer->WriteByte(static_cast<uint8_t>(type_))) {
return false;
}
return writer->WriteUleb128(entity_->GetOffset());
}
} // namespace panda::panda_file
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/igelhaus/arkcompiler_runtime_core.git
git@gitee.com:igelhaus/arkcompiler_runtime_core.git
igelhaus
arkcompiler_runtime_core
arkcompiler_runtime_core
master

搜索帮助