1 /**
2 * Copyright (c) 2021-2022 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 #ifndef LIBPANDAFILE_METHOD_DATA_ACCESSOR_INL_H
17 #define LIBPANDAFILE_METHOD_DATA_ACCESSOR_INL_H
18
19 #include "helpers.h"
20 #include "method_data_accessor.h"
21 #include "annotation_data_accessor.h"
22 #include "proto_data_accessor.h"
23
24 namespace panda::panda_file {
25
26 // static
GetNameId(const File & panda_file,File::EntityId method_id)27 inline File::EntityId MethodDataAccessor::GetNameId(const File &panda_file, File::EntityId method_id)
28 {
29 constexpr size_t SKIP_NUM = 2; // skip class_idx and proto_idx
30 auto sp = panda_file.GetSpanFromId(method_id).SubSpan(IDX_SIZE * SKIP_NUM);
31 return File::EntityId(helpers::Read<ID_SIZE>(&sp));
32 }
33
34 // static
GetName(const File & panda_file,File::EntityId method_id)35 inline panda_file::File::StringData MethodDataAccessor::GetName(const File &panda_file, File::EntityId method_id)
36 {
37 return panda_file.GetStringData(GetNameId(panda_file, method_id));
38 }
39
40 // static
GetProtoId(const File & panda_file,File::EntityId method_id)41 inline File::EntityId MethodDataAccessor::GetProtoId(const File &panda_file, File::EntityId method_id)
42 {
43 constexpr size_t SKIP_NUM = 1; // skip class_idx
44 auto sp = panda_file.GetSpanFromId(method_id).SubSpan(IDX_SIZE * SKIP_NUM);
45 auto proto_idx_ = helpers::Read<IDX_SIZE>(&sp);
46 return File::EntityId(panda_file.ResolveProtoIndex(method_id, proto_idx_).GetOffset());
47 }
48
49 // static
GetClassId(const File & panda_file,File::EntityId method_id)50 inline File::EntityId MethodDataAccessor::GetClassId(const File &panda_file, File::EntityId method_id)
51 {
52 auto sp = panda_file.GetSpanFromId(method_id);
53 auto class_idx = helpers::Read<IDX_SIZE>(&sp);
54 return File::EntityId(panda_file.ResolveClassIndex(method_id, class_idx).GetOffset());
55 }
56
GetName()57 inline panda_file::File::StringData MethodDataAccessor::GetName() const
58 {
59 return panda_file_.GetStringData(GetNameId());
60 }
61
SkipCode()62 inline void MethodDataAccessor::SkipCode()
63 {
64 GetCodeId();
65 }
66
SkipSourceLang()67 inline void MethodDataAccessor::SkipSourceLang()
68 {
69 GetSourceLang();
70 }
71
SkipRuntimeAnnotations()72 inline void MethodDataAccessor::SkipRuntimeAnnotations()
73 {
74 EnumerateRuntimeAnnotations([](File::EntityId /* unused */) {});
75 }
76
SkipRuntimeParamAnnotation()77 inline void MethodDataAccessor::SkipRuntimeParamAnnotation()
78 {
79 GetRuntimeParamAnnotationId();
80 }
81
SkipDebugInfo()82 inline void MethodDataAccessor::SkipDebugInfo()
83 {
84 GetDebugInfoId();
85 }
86
SkipAnnotations()87 inline void MethodDataAccessor::SkipAnnotations()
88 {
89 EnumerateAnnotations([](File::EntityId /* unused */) {});
90 }
91
SkipParamAnnotation()92 inline void MethodDataAccessor::SkipParamAnnotation()
93 {
94 GetParamAnnotationId();
95 }
96
SkipTypeAnnotation()97 inline void MethodDataAccessor::SkipTypeAnnotation()
98 {
99 EnumerateTypeAnnotations([](File::EntityId /* unused */) {});
100 }
101
SkipRuntimeTypeAnnotation()102 inline void MethodDataAccessor::SkipRuntimeTypeAnnotation()
103 {
104 EnumerateRuntimeTypeAnnotations([](File::EntityId /* unused */) {});
105 }
106
GetCodeId()107 inline std::optional<File::EntityId> MethodDataAccessor::GetCodeId()
108 {
109 if (is_external_) {
110 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
111 // which fails Release builds for GCC 8 and 9.
112 std::optional<File::EntityId> novalue;
113 return novalue;
114 }
115
116 return helpers::GetOptionalTaggedValue<File::EntityId>(tagged_values_sp_, MethodTag::CODE, &source_lang_sp_);
117 }
118
GetSourceLang()119 inline std::optional<SourceLang> MethodDataAccessor::GetSourceLang()
120 {
121 if (is_external_) {
122 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
123 // which fails Release builds for GCC 8 and 9.
124 std::optional<SourceLang> novalue;
125 return novalue;
126 }
127
128 if (source_lang_sp_.data() == nullptr) {
129 SkipCode();
130 }
131
132 return helpers::GetOptionalTaggedValue<SourceLang>(source_lang_sp_, MethodTag::SOURCE_LANG,
133 &runtime_annotations_sp_);
134 }
135
136 template <class Callback>
EnumerateRuntimeAnnotations(Callback cb)137 inline void MethodDataAccessor::EnumerateRuntimeAnnotations(Callback cb)
138 {
139 if (is_external_) {
140 return;
141 }
142
143 if (runtime_annotations_sp_.data() == nullptr) {
144 SkipSourceLang();
145 }
146
147 helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(
148 runtime_annotations_sp_, MethodTag::RUNTIME_ANNOTATION, cb, &runtime_param_annotation_sp_);
149 }
150
GetRuntimeParamAnnotationId()151 inline std::optional<File::EntityId> MethodDataAccessor::GetRuntimeParamAnnotationId()
152 {
153 if (is_external_) {
154 return {};
155 }
156
157 if (runtime_param_annotation_sp_.data() == nullptr) {
158 SkipRuntimeAnnotations();
159 }
160
161 return helpers::GetOptionalTaggedValue<File::EntityId>(runtime_param_annotation_sp_,
162 MethodTag::RUNTIME_PARAM_ANNOTATION, &debug_sp_);
163 }
164
GetDebugInfoId()165 inline std::optional<File::EntityId> MethodDataAccessor::GetDebugInfoId()
166 {
167 if (is_external_) {
168 return {};
169 }
170
171 if (debug_sp_.data() == nullptr) {
172 SkipRuntimeParamAnnotation();
173 }
174
175 return helpers::GetOptionalTaggedValue<File::EntityId>(debug_sp_, MethodTag::DEBUG_INFO, &annotations_sp_);
176 }
177
178 template <class Callback>
EnumerateAnnotations(Callback cb)179 inline void MethodDataAccessor::EnumerateAnnotations(Callback cb)
180 {
181 if (is_external_) {
182 return;
183 }
184
185 if (annotations_sp_.data() == nullptr) {
186 SkipDebugInfo();
187 }
188
189 helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(annotations_sp_, MethodTag::ANNOTATION, cb,
190 ¶m_annotation_sp_);
191 }
192
193 template <class Callback>
EnumerateRuntimeAnnotationsWithEarlyStop(Callback cb)194 inline bool MethodDataAccessor::EnumerateRuntimeAnnotationsWithEarlyStop(Callback cb)
195 {
196 if (is_external_) {
197 return false;
198 }
199
200 if (runtime_annotations_sp_.data() == nullptr) {
201 SkipSourceLang();
202 }
203
204 return helpers::EnumerateTaggedValuesWithEarlyStop<File::EntityId, MethodTag, Callback>(
205 runtime_annotations_sp_, MethodTag::RUNTIME_ANNOTATION, cb);
206 }
207
208 template <class Callback>
EnumerateAnnotationsWithEarlyStop(Callback cb)209 inline bool MethodDataAccessor::EnumerateAnnotationsWithEarlyStop(Callback cb)
210 {
211 if (is_external_) {
212 return false;
213 }
214
215 if (annotations_sp_.data() == nullptr) {
216 SkipDebugInfo();
217 }
218
219 return helpers::EnumerateTaggedValuesWithEarlyStop<File::EntityId, MethodTag, Callback>(annotations_sp_,
220 MethodTag::ANNOTATION, cb);
221 }
222
223 template <class Callback>
EnumerateTypeAnnotations(Callback cb)224 inline void MethodDataAccessor::EnumerateTypeAnnotations(Callback cb)
225 {
226 if (is_external_) {
227 return;
228 }
229
230 if (type_annotation_sp_.data() == nullptr) {
231 SkipParamAnnotation();
232 }
233
234 helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(type_annotation_sp_, MethodTag::TYPE_ANNOTATION,
235 cb, &runtime_type_annotation_sp_);
236 }
237
238 template <class Callback>
EnumerateRuntimeTypeAnnotations(Callback cb)239 inline void MethodDataAccessor::EnumerateRuntimeTypeAnnotations(Callback cb)
240 {
241 if (is_external_) {
242 return;
243 }
244
245 if (runtime_type_annotation_sp_.data() == nullptr) {
246 SkipTypeAnnotation();
247 }
248
249 Span<const uint8_t> sp {nullptr, nullptr};
250 size_ = panda_file_.GetIdFromPointer(runtime_type_annotation_sp_.data()).GetOffset() - method_id_.GetOffset() +
251 1; // + 1 for NOTHING tag
252 helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(runtime_type_annotation_sp_,
253 MethodTag::RUNTIME_TYPE_ANNOTATION, cb, &sp);
254 }
255
GetParamAnnotationId()256 inline std::optional<File::EntityId> MethodDataAccessor::GetParamAnnotationId()
257 {
258 if (is_external_) {
259 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
260 // which fails Release builds for GCC 8 and 9.
261 std::optional<File::EntityId> novalue;
262 return novalue;
263 }
264
265 if (param_annotation_sp_.data() == nullptr) {
266 SkipAnnotations();
267 }
268
269 auto v = helpers::GetOptionalTaggedValue<File::EntityId>(param_annotation_sp_, MethodTag::PARAM_ANNOTATION,
270 &type_annotation_sp_);
271
272 return v;
273 }
274
GetAnnotationsNumber()275 inline uint32_t MethodDataAccessor::GetAnnotationsNumber()
276 {
277 size_t n = 0;
278 EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
279 return n;
280 }
281
GetRuntimeAnnotationsNumber()282 inline uint32_t MethodDataAccessor::GetRuntimeAnnotationsNumber()
283 {
284 size_t n = 0;
285 EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
286 return n;
287 }
288
GetTypeAnnotationsNumber()289 inline uint32_t MethodDataAccessor::GetTypeAnnotationsNumber()
290 {
291 size_t n = 0;
292 EnumerateTypeAnnotations([&n](File::EntityId /* unused */) { n++; });
293 return n;
294 }
295
GetRuntimeTypeAnnotationsNumber()296 inline uint32_t MethodDataAccessor::GetRuntimeTypeAnnotationsNumber()
297 {
298 size_t n = 0;
299 EnumerateRuntimeTypeAnnotations([&n](File::EntityId /* unused */) { n++; });
300 return n;
301 }
302
303 template <typename Callback>
EnumerateTypesInProto(Callback cb,bool skip_this)304 void MethodDataAccessor::EnumerateTypesInProto(Callback cb, bool skip_this)
305 {
306 size_t ref_idx = 0;
307 panda_file::ProtoDataAccessor pda(GetPandaFile(), GetProtoId());
308
309 auto type = pda.GetReturnType();
310 panda_file::File::EntityId class_id;
311
312 if (!type.IsPrimitive()) {
313 class_id = pda.GetReferenceType(ref_idx++);
314 }
315
316 cb(type, class_id);
317
318 if (!IsStatic() && !skip_this) {
319 // first arg type is method class
320 cb(panda_file::Type {panda_file::Type::TypeId::REFERENCE}, GetClassId());
321 }
322
323 for (uint32_t idx = 0; idx < pda.GetNumArgs(); ++idx) {
324 auto arg_type = pda.GetArgType(idx);
325 panda_file::File::EntityId klass_id;
326 if (!arg_type.IsPrimitive()) {
327 klass_id = pda.GetReferenceType(ref_idx++);
328 }
329 cb(arg_type, klass_id);
330 }
331 }
332
GetNumericalAnnotation(uint32_t field_id)333 inline uint32_t MethodDataAccessor::GetNumericalAnnotation(uint32_t field_id)
334 {
335 static constexpr uint32_t NUM_ELEMENT = 3;
336 static std::array<const char *, NUM_ELEMENT> elem_name_table = {"icSize", "parameterLength", "funcName"};
337 uint32_t result = 0;
338 EnumerateAnnotations([&](File::EntityId annotation_id) {
339 AnnotationDataAccessor ada(panda_file_, annotation_id);
340 auto *annotation_name = reinterpret_cast<const char *>(panda_file_.GetStringData(ada.GetClassId()).data);
341 if (::strcmp("L_ESAnnotation;", annotation_name) == 0) {
342 uint32_t elem_count = ada.GetCount();
343 for (uint32_t i = 0; i < elem_count; i++) {
344 AnnotationDataAccessor::Elem adae = ada.GetElement(i);
345 auto *elem_name = reinterpret_cast<const char *>(panda_file_.GetStringData(adae.GetNameId()).data);
346 if (::strcmp(elem_name_table[field_id], elem_name) == 0) {
347 result = adae.GetScalarValue().GetValue();
348 }
349 }
350 }
351 });
352 return result;
353 }
354
355 } // namespace panda::panda_file
356
357 #endif // LIBPANDAFILE_METHOD_DATA_ACCESSOR_INL_H
358