• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "abc_method_processor.h"
17 #include "abc_code_processor.h"
18 #include "assembly-function.h"
19 #include "mangling.h"
20 #include "source_lang_enum.h"
21 #include "proto_data_accessor-inl.h"
22 
23 namespace ark::abc2program {
24 
AbcMethodProcessor(panda_file::File::EntityId entityId,Abc2ProgramKeyData & keyData)25 AbcMethodProcessor::AbcMethodProcessor(panda_file::File::EntityId entityId, Abc2ProgramKeyData &keyData)
26     : AbcFileEntityProcessor(entityId, keyData), function_(pandasm::Function("", keyData.GetFileLanguage()))
27 {
28     methodDataAccessor_ = std::make_unique<panda_file::MethodDataAccessor>(*file_, entityId_);
29     FillProgramData();
30 }
31 
FillProgramData()32 void AbcMethodProcessor::FillProgramData()
33 {
34     FillFunction();
35 }
36 
FillFunction()37 void AbcMethodProcessor::FillFunction()
38 {
39     GetMethodName();
40 
41     methodSignature_ = pandasm::MangleFunctionName(function_.name, function_.params, function_.returnType);
42     if (keyData_.GetMethodNameToIdTable().find(methodSignature_) != keyData_.GetMethodNameToIdTable().end()) {
43         return;
44     }
45 
46     keyData_.GetMethodNameToIdTable().emplace(methodSignature_, entityId_);
47 
48     GetMethodCode();
49 
50     program_->AddToFunctionTable(std::move(function_), methodSignature_);
51 }
52 
GetMethodName()53 void AbcMethodProcessor::GetMethodName()
54 {
55     function_.name = keyData_.GetFullFunctionNameById(entityId_);
56 
57     LOG(DEBUG, ABC2PROGRAM) << "name: " << function_.name;
58 
59     GetParams(methodDataAccessor_->GetProtoId());
60     GetMetaData();
61 }
62 
GetMethodCode()63 void AbcMethodProcessor::GetMethodCode()
64 {
65     if (!function_.HasImplementation()) {
66         return;
67     }
68 
69     std::optional<panda_file::File::EntityId> codeId = methodDataAccessor_->GetCodeId();
70     if (codeId.has_value()) {
71         AbcCodeProcessor codeProcessor(codeId.value(), keyData_, entityId_);
72         function_.ins = codeProcessor.GetIns();
73         function_.regsNum = codeProcessor.GetNumVregs();
74         function_.catchBlocks = codeProcessor.GetCatchBlocks();
75     } else {
76         LOG(ERROR, ABC2PROGRAM) << "> error encountered at " << entityId_ << " (0x" << std::hex << entityId_
77                                 << "). implementation of method expected, but no \'CODE\' tag was found!";
78 
79         return;
80     }
81 }
82 
GetMetaData()83 void AbcMethodProcessor::GetMetaData()
84 {
85     LOG(DEBUG, ABC2PROGRAM) << "[getting metadata]\nmethod id: " << entityId_ << " (0x" << std::hex << entityId_ << ")";
86 
87     const auto methodNameRaw = stringTable_->GetStringById((methodDataAccessor_->GetNameId()));
88 
89     if (!methodDataAccessor_->IsStatic()) {
90         auto className = stringTable_->GetStringById((methodDataAccessor_->GetClassId()));
91         std::replace(className.begin(), className.end(), '/', '.');
92         auto thisType = pandasm::Type::FromDescriptor(className);
93 
94         LOG(DEBUG, ABC2PROGRAM) << "method (raw: \'" << methodNameRaw
95                                 << "\') is not static. emplacing self-argument of type " << thisType.GetName();
96 
97         function_.params.insert(function_.params.begin(),
98                                 pandasm::Function::Parameter(thisType, keyData_.GetFileLanguage()));
99     }
100     SetEntityAttribute(
101         function_, [this]() { return methodDataAccessor_->IsStatic(); }, "static");
102 
103     SetEntityAttribute(
104         function_, [this]() { return file_->IsExternal(methodDataAccessor_->GetMethodId()); }, "external");
105 
106     SetEntityAttribute(
107         function_, [this]() { return methodDataAccessor_->IsNative(); }, "native");
108 
109     SetEntityAttribute(
110         function_, [this]() { return methodDataAccessor_->IsAbstract(); }, "noimpl");
111 
112     SetEntityAttributeValue(
113         function_, [this]() { return methodDataAccessor_->IsPublic(); }, "access.function", "public");
114 
115     SetEntityAttributeValue(
116         function_, [this]() { return methodDataAccessor_->IsProtected(); }, "access.function", "protected");
117 
118     SetEntityAttributeValue(
119         function_, [this]() { return methodDataAccessor_->IsPrivate(); }, "access.function", "private");
120 
121     SetEntityAttribute(
122         function_, [this]() { return methodDataAccessor_->IsFinal(); }, "final");
123 
124     std::string ctorName = ark::panda_file::GetCtorName(keyData_.GetFileLanguage());
125     std::string cctorName = ark::panda_file::GetCctorName(keyData_.GetFileLanguage());
126 
127     const bool isCtor = (methodNameRaw == ctorName);
128     const bool isCctor = (methodNameRaw == cctorName);
129 
130     if (isCtor) {
131         function_.metadata->SetAttribute("ctor");
132         function_.name.replace(function_.name.find(ctorName), ctorName.length(), "_ctor_");
133     } else if (isCctor) {
134         function_.metadata->SetAttribute("cctor");
135         function_.name.replace(function_.name.find(cctorName), cctorName.length(), "_cctor_");
136     }
137 }
138 
GetParams(const panda_file::File::EntityId & protoId)139 void AbcMethodProcessor::GetParams(const panda_file::File::EntityId &protoId)
140 {
141     /// frame size - 2^16 - 1
142     static const uint32_t MAX_ARG_NUM = 0xFFFF;
143 
144     LOG(DEBUG, ABC2PROGRAM) << "[getting params]\nproto id: " << protoId << " (0x" << std::hex << protoId << ")";
145 
146     panda_file::ProtoDataAccessor protoAccessor(*file_, protoId);
147 
148     if (protoAccessor.GetNumArgs() > MAX_ARG_NUM) {
149         LOG(ERROR, ABC2PROGRAM) << "> error encountered at " << protoId << " (0x" << std::hex << protoId
150                                 << "). number of function's arguments (" << std::dec << protoAccessor.GetNumArgs()
151                                 << ") exceeds MAX_ARG_NUM (" << MAX_ARG_NUM << ") !";
152 
153         return;
154     }
155 
156     size_t refIdx = 0;
157     function_.returnType = PFTypeToPandasmType(protoAccessor.GetReturnType(), protoAccessor, refIdx);
158 
159     for (size_t i = 0; i < protoAccessor.GetNumArgs(); i++) {
160         auto argType = PFTypeToPandasmType(protoAccessor.GetArgType(i), protoAccessor, refIdx);
161         function_.params.emplace_back(argType, keyData_.GetFileLanguage());
162     }
163 }
164 
PFTypeToPandasmType(const panda_file::Type & type,panda_file::ProtoDataAccessor & pda,size_t & refIdx) const165 pandasm::Type AbcMethodProcessor::PFTypeToPandasmType(const panda_file::Type &type, panda_file::ProtoDataAccessor &pda,
166                                                       size_t &refIdx) const
167 {
168     pandasm::Type pandasmType;
169 
170     static const std::unordered_map<panda_file::Type::TypeId, std::string> ID_TO_STRING = {
171         {panda_file::Type::TypeId::INVALID, "invalid"}, {panda_file::Type::TypeId::VOID, "void"},
172         {panda_file::Type::TypeId::U1, "u1"},           {panda_file::Type::TypeId::I8, "i8"},
173         {panda_file::Type::TypeId::U8, "u8"},           {panda_file::Type::TypeId::I16, "i16"},
174         {panda_file::Type::TypeId::U16, "u16"},         {panda_file::Type::TypeId::I32, "i32"},
175         {panda_file::Type::TypeId::U32, "u32"},         {panda_file::Type::TypeId::F32, "f32"},
176         {panda_file::Type::TypeId::F64, "f64"},         {panda_file::Type::TypeId::I64, "i64"},
177         {panda_file::Type::TypeId::U64, "u64"},         {panda_file::Type::TypeId::TAGGED, "any"},
178     };
179 
180     if (type.GetId() != panda_file::Type::TypeId::REFERENCE) {
181         pandasmType = pandasm::Type(ID_TO_STRING.at(type.GetId()), 0);
182     } else {
183         std::string typeName = stringTable_->GetStringById(pda.GetReferenceType(refIdx++));
184         std::replace(typeName.begin(), typeName.end(), '/', '.');
185         pandasmType = pandasm::Type::FromDescriptor(typeName);
186     }
187 
188     return pandasmType;
189 }
190 
GetMethodSignature()191 std::string AbcMethodProcessor::GetMethodSignature()
192 {
193     return methodSignature_;
194 }
195 
196 }  // namespace ark::abc2program
197