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