1 /**
2 * Copyright (c) 2021 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 "cache.h"
17
18 #include "runtime/include/runtime.h"
19
20 #include "runtime/include/class.h"
21 #include "runtime/include/method.h"
22 #include "runtime/include/field.h"
23
24 #include "runtime/include/class_helper.h"
25 #include "runtime/include/language_context.h"
26
27 #include "libpandabase/utils/logger.h"
28 #include "libpandabase/utils/utf.h"
29 #include "libpandabase/utils/hash.h"
30
31 #include "libpandafile/method_data_accessor-inl.h"
32 #include "libpandafile/class_data_accessor.h"
33 #include "libpandafile/class_data_accessor-inl.h"
34 #include "libpandafile/code_data_accessor.h"
35 #include "libpandafile/code_data_accessor-inl.h"
36 #include "libpandafile/field_data_accessor-inl.h"
37 #include "libpandafile/proto_data_accessor.h"
38 #include "libpandafile/proto_data_accessor-inl.h"
39 #include "libpandafile/modifiers.h"
40
41 #include "verification/util/invalid_ref.h"
42
43 #include "macros.h"
44
45 namespace panda::verifier {
46
47 using FastAPIClassRW = CacheOfRuntimeThings::FastAPIClass<access::ReadWrite>;
48 using FastAPIClassRO = CacheOfRuntimeThings::FastAPIClass<access::ReadOnly>;
49
GetName(const CacheOfRuntimeThings::CachedClass & cached_class)50 PandaString CacheOfRuntimeThings::GetName(const CacheOfRuntimeThings::CachedClass &cached_class)
51 {
52 if (cached_class.type_id == panda_file::Type::TypeId::REFERENCE) {
53 return ClassHelper::GetName<PandaString>(cached_class.name);
54 }
55 return {ClassHelper::GetPrimitiveTypeStr(cached_class.type_id)};
56 }
57
GetName(const DescriptorString & descriptor)58 PandaString CacheOfRuntimeThings::GetName(const DescriptorString &descriptor)
59 {
60 return ClassHelper::GetName<PandaString>(descriptor);
61 }
62
GetName(const CacheOfRuntimeThings::CachedMethod & cached_method)63 PandaString CacheOfRuntimeThings::GetName(const CacheOfRuntimeThings::CachedMethod &cached_method)
64 {
65 PandaOStringStream out;
66 out << GetName(cached_method.klass);
67 out << "::";
68 out << utf::Mutf8AsCString(cached_method.name);
69 out << " : ";
70 size_t idx = 0;
71 for (const auto &arg : cached_method.signature) {
72 if (idx > 1) {
73 out << ", ";
74 }
75 if (IsDescriptor(arg)) {
76 out << GetName(GetDescriptor(arg));
77 } else if (IsRef(arg)) {
78 out << GetName(GetRef(arg));
79 } else {
80 UNREACHABLE();
81 }
82 if (idx == 0) {
83 out << " ( ";
84 }
85 ++idx;
86 }
87 out << " )";
88 return out.str();
89 }
90
GetName(const CacheOfRuntimeThings::CachedField & cached_field)91 PandaString CacheOfRuntimeThings::GetName(const CacheOfRuntimeThings::CachedField &cached_field)
92 {
93 auto str = GetName(cached_field.klass);
94 str += ".";
95 str += utf::Mutf8AsCString(cached_field.name);
96 str += " : ";
97 const auto &type = cached_field.type;
98 if (IsRef(type)) {
99 str += GetName(GetRef(type));
100 } else if (IsDescriptor(type)) {
101 str += GetName(GetDescriptor(type));
102 } else {
103 UNREACHABLE();
104 }
105 return str;
106 }
107
108 template <>
GetLanguageContextBase(panda_file::SourceLang src_lang) const109 const panda::LanguageContextBase &FastAPIClassRW::GetLanguageContextBase(panda_file::SourceLang src_lang) const
110 {
111 if (src_lang == panda_file::SourceLang::PANDA_ASSEMBLY) {
112 return core_lang_ctx;
113 }
114 UNREACHABLE();
115 return core_lang_ctx;
116 }
117
118 template <>
GetLanguageContextBase(panda_file::SourceLang src_lang) const119 const panda::LanguageContextBase &FastAPIClassRO::GetLanguageContextBase(panda_file::SourceLang src_lang) const
120 {
121 if (src_lang == panda_file::SourceLang::PANDA_ASSEMBLY) {
122 return core_lang_ctx;
123 }
124 UNREACHABLE();
125 return core_lang_ctx;
126 }
127
128 template <>
GetPrimitiveClass(panda_file::SourceLang src_lang,panda_file::Type::TypeId id) const129 const CacheOfRuntimeThings::CachedClass &FastAPIClassRO::GetPrimitiveClass(panda_file::SourceLang src_lang,
130 panda_file::Type::TypeId id) const
131 {
132 return GetContext(src_lang).primitive_classes[id];
133 }
134
135 template <>
GetPrimitiveClass(panda_file::SourceLang src_lang,panda_file::Type::TypeId id) const136 const CacheOfRuntimeThings::CachedClass &FastAPIClassRW::GetPrimitiveClass(panda_file::SourceLang src_lang,
137 panda_file::Type::TypeId id) const
138 {
139 return GetContext(src_lang).primitive_classes[id];
140 }
141
142 template <>
143 template <>
144 CacheOfRuntimeThings::CachedClass &FastAPIClassRW::Link<CacheOfRuntimeThings::CachedClass>(
145 CacheOfRuntimeThings::CachedClass &cached_class);
146
147 template <>
148 template <>
149 CacheOfRuntimeThings::CachedMethod &FastAPIClassRW::Link<CacheOfRuntimeThings::CachedMethod>(
150 CacheOfRuntimeThings::CachedMethod &cached_method);
151
152 template <>
153 template <>
154 CacheOfRuntimeThings::CachedField &FastAPIClassRW::Link<CacheOfRuntimeThings::CachedField>(
155 CacheOfRuntimeThings::CachedField &cached_field);
156
157 template <>
158 template <>
GetFromCache(panda_file::SourceLang src_lang,CacheOfRuntimeThings::Id id)159 CacheOfRuntimeThings::CachedClass &FastAPIClassRW::GetFromCache<CacheOfRuntimeThings::CachedClass>(
160 panda_file::SourceLang src_lang, CacheOfRuntimeThings::Id id)
161 {
162 auto &class_cache = GetContext(src_lang).class_cache;
163 auto it = class_cache.find(id);
164 if (it == class_cache.end()) {
165 return Invalid<CachedClass>();
166 }
167 return Link(it->second);
168 }
169
170 template <>
171 template <>
GetFromCache(panda_file::SourceLang src_lang,CacheOfRuntimeThings::Id id)172 CacheOfRuntimeThings::CachedMethod &FastAPIClassRW::GetFromCache<CacheOfRuntimeThings::CachedMethod>(
173 panda_file::SourceLang src_lang, CacheOfRuntimeThings::Id id)
174 {
175 auto &method_cache = GetContext(src_lang).method_cache;
176 auto it = method_cache.find(id);
177 if (it == method_cache.end()) {
178 return Invalid<CachedMethod>();
179 }
180 return Link(it->second);
181 }
182
183 template <>
184 template <>
GetFromCache(panda_file::SourceLang src_lang,CacheOfRuntimeThings::Id id)185 CacheOfRuntimeThings::CachedField &FastAPIClassRW::GetFromCache<CacheOfRuntimeThings::CachedField>(
186 panda_file::SourceLang src_lang, CacheOfRuntimeThings::Id id)
187 {
188 auto &field_cache = GetContext(src_lang).field_cache;
189 auto it = field_cache.find(id);
190 if (it == field_cache.end()) {
191 return Invalid<CachedField>();
192 }
193 return Link(it->second);
194 }
195
196 namespace {
197
GetClassFlags(uint32_t raw_flags)198 CacheOfRuntimeThings::CachedClass::FlagsValue GetClassFlags(uint32_t raw_flags)
199 {
200 CacheOfRuntimeThings::CachedClass::FlagsValue flags;
201 flags[CacheOfRuntimeThings::CachedClass::Flag::PUBLIC] = (raw_flags & ACC_PUBLIC) != 0;
202 flags[CacheOfRuntimeThings::CachedClass::Flag::FINAL] = (raw_flags & ACC_FINAL) != 0;
203 flags[CacheOfRuntimeThings::CachedClass::Flag::ANNOTATION] = (raw_flags & ACC_ANNOTATION) != 0;
204 flags[CacheOfRuntimeThings::CachedClass::Flag::ENUM] = (raw_flags & ACC_ENUM) != 0;
205
206 flags[CacheOfRuntimeThings::CachedClass::Flag::ABSTRACT] = (raw_flags & ACC_ABSTRACT) != 0;
207 flags[CacheOfRuntimeThings::CachedClass::Flag::INTERFACE] = (raw_flags & ACC_INTERFACE) != 0;
208
209 return flags;
210 }
211
GetMethodFlags(const panda_file::MethodDataAccessor & mda)212 CacheOfRuntimeThings::CachedMethod::FlagsValue GetMethodFlags(const panda_file::MethodDataAccessor &mda)
213 {
214 CacheOfRuntimeThings::CachedMethod::FlagsValue flags;
215
216 flags[CacheOfRuntimeThings::CachedMethod::Flag::STATIC] = mda.IsStatic();
217 flags[CacheOfRuntimeThings::CachedMethod::Flag::NATIVE] = mda.IsNative();
218 flags[CacheOfRuntimeThings::CachedMethod::Flag::PUBLIC] = mda.IsPublic();
219 flags[CacheOfRuntimeThings::CachedMethod::Flag::PRIVATE] = mda.IsPrivate();
220 flags[CacheOfRuntimeThings::CachedMethod::Flag::PROTECTED] = mda.IsProtected();
221 flags[CacheOfRuntimeThings::CachedMethod::Flag::SYNTHETIC] = mda.IsSynthetic();
222 flags[CacheOfRuntimeThings::CachedMethod::Flag::ABSTRACT] = mda.IsAbstract();
223 flags[CacheOfRuntimeThings::CachedMethod::Flag::FINAL] = mda.IsFinal();
224 return flags;
225 }
226
GetFieldFlags(const panda_file::FieldDataAccessor & fda)227 CacheOfRuntimeThings::CachedField::FlagsValue GetFieldFlags(const panda_file::FieldDataAccessor &fda)
228 {
229 CacheOfRuntimeThings::CachedField::FlagsValue flags;
230 flags[CacheOfRuntimeThings::CachedField::Flag::STATIC] = fda.IsStatic();
231 flags[CacheOfRuntimeThings::CachedField::Flag::VOLATILE] = fda.IsVolatile();
232 flags[CacheOfRuntimeThings::CachedField::Flag::PUBLIC] = fda.IsPublic();
233 flags[CacheOfRuntimeThings::CachedField::Flag::PROTECTED] = fda.IsProtected();
234 flags[CacheOfRuntimeThings::CachedField::Flag::FINAL] = fda.IsFinal();
235 flags[CacheOfRuntimeThings::CachedField::Flag::PRIVATE] = fda.IsPrivate();
236 return flags;
237 }
238
239 } // namespace
240
241 template <>
MakeSyntheticClass(panda_file::SourceLang src_lang,const uint8_t * descriptor,panda_file::Type::TypeId type_id,uint32_t flags)242 CacheOfRuntimeThings::CachedClass &FastAPIClassRW::MakeSyntheticClass(panda_file::SourceLang src_lang,
243 const uint8_t *descriptor,
244 panda_file::Type::TypeId type_id, uint32_t flags)
245 {
246 auto &data = GetContext(src_lang);
247
248 auto id = Class::CalcUniqId(descriptor);
249
250 CachedClass cached_class {id, descriptor, src_lang, type_id, {}, {}, GetClassFlags(flags),
251 {}, {}, false, nullptr, {}};
252
253 auto &result = data.class_cache.emplace(id, std::move(cached_class)).first->second;
254 data.descr_lookup.emplace(result.name, std::cref(result));
255 return result;
256 }
257
258 template <>
MakeSyntheticMethod(CacheOfRuntimeThings::CachedClass & cached_class,const uint8_t * name,const std::function<void (CacheOfRuntimeThings::CachedClass &,CacheOfRuntimeThings::CachedMethod &)> & sig_filler)259 CacheOfRuntimeThings::CachedMethod &FastAPIClassRW::MakeSyntheticMethod(
260 CacheOfRuntimeThings::CachedClass &cached_class, const uint8_t *name,
261 const std::function<void(CacheOfRuntimeThings::CachedClass &, CacheOfRuntimeThings::CachedMethod &)> &sig_filler)
262 {
263 auto id = Method::CalcUniqId(cached_class.name, name);
264
265 CacheOfRuntimeThings::CachedMethod cached_method {
266 id, {}, name, std::cref(cached_class), {}, {}, {}, {}, {}, 0, 0, {}, nullptr, 0, false, nullptr, {}};
267
268 auto &data = GetContext(cached_class.source_lang);
269 auto &result = data.method_cache.emplace(id, std::move(cached_method)).first->second;
270 sig_filler(cached_class, result);
271 CalcMethodHash(result);
272 cached_class.methods.insert_or_assign(result.hash, std::cref(result));
273 return result;
274 }
275
276 template <>
AddArrayCtor(CacheOfRuntimeThings::CachedClass & array)277 CacheOfRuntimeThings::CachedMethod &FastAPIClassRW::AddArrayCtor(CacheOfRuntimeThings::CachedClass &array)
278 {
279 auto &lang_ctx = GetLanguageContextBase(array.source_lang);
280 auto &&h = [&](CacheOfRuntimeThings::CachedClass &c, CacheOfRuntimeThings::CachedMethod &cm) {
281 // register in methods_cache by id
282 size_t dims = ClassHelper::GetDimensionality(c.name);
283 cm.num_args = dims;
284 // method return type first
285 cm.signature.push_back(std::cref(c));
286 while (dims-- != 0) {
287 cm.signature.push_back(
288 DescriptorString(ClassHelper::GetPrimitiveTypeDescriptorStr(panda_file::Type::TypeId::I32)));
289 }
290 };
291 return MakeSyntheticMethod(array, lang_ctx.GetCtorName(), h);
292 }
293
294 template <>
AddArray(panda_file::SourceLang src_lang,const uint8_t * descr)295 CacheOfRuntimeThings::CachedClass &FastAPIClassRW::AddArray(panda_file::SourceLang src_lang, const uint8_t *descr)
296 {
297 auto &data = GetContext(src_lang);
298 auto &array =
299 MakeSyntheticClass(src_lang, descr, panda_file::Type::TypeId::REFERENCE, ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
300 array.flags[CacheOfRuntimeThings::CachedClass::Flag::ARRAY_CLASS] = true;
301 array.ancestors.push_back(data.object_descr);
302 auto comp_descr = DescriptorString(ClassHelper::GetComponentDescriptor(descr));
303 array.array_component = comp_descr;
304 if (comp_descr.GetLength() > 1) {
305 array.flags[CacheOfRuntimeThings::CachedClass::Flag::OBJECT_ARRAY_CLASS] = true;
306 }
307 AddArrayCtor(array);
308 return array;
309 }
310
311 template <>
InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId type_id)312 void FastAPIClassRW::InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId type_id)
313 {
314 auto &data = GetContext(panda_file::SourceLang::PANDA_ASSEMBLY);
315 auto &prim_classes = data.primitive_classes;
316 auto &C =
317 MakeSyntheticClass(panda_file::SourceLang::PANDA_ASSEMBLY, ClassHelper::GetPrimitiveTypeDescriptorStr(type_id),
318 type_id, ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
319 C.flags[CacheOfRuntimeThings::CachedClass::Flag::PRIMITIVE] = true;
320 prim_classes[type_id] = std::cref(C);
321 }
322
323 template <>
InitializePandaAssemblyRootClasses()324 void FastAPIClassRW::InitializePandaAssemblyRootClasses()
325 {
326 DescriptorString obj_descriptor = core_lang_ctx.GetObjectClassDescriptor();
327
328 auto &data = GetContext(panda_file::SourceLang::PANDA_ASSEMBLY);
329
330 data.object_descr = obj_descriptor;
331 data.string_descr = core_lang_ctx.GetStringClassDescriptor();
332 data.string_array_descr = core_lang_ctx.GetStringArrayClassDescriptor();
333
334 // primitive
335 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::VOID);
336 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::U1);
337 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::I8);
338 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::U8);
339 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::I16);
340 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::U16);
341 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::I32);
342 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::U32);
343 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::I64);
344 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::U64);
345 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::F32);
346 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::F64);
347 InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId::TAGGED);
348
349 // object
350 MakeSyntheticClass(panda_file::SourceLang::PANDA_ASSEMBLY, data.object_descr, panda_file::Type::TypeId::REFERENCE,
351 ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
352
353 auto &Str = MakeSyntheticClass(panda_file::SourceLang::PANDA_ASSEMBLY, core_lang_ctx.GetStringClassDescriptor(),
354 panda_file::Type::TypeId::REFERENCE, ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
355 auto &Class = MakeSyntheticClass(panda_file::SourceLang::PANDA_ASSEMBLY, core_lang_ctx.GetClassClassDescriptor(),
356 panda_file::Type::TypeId::REFERENCE, ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
357
358 Str.ancestors.push_back(obj_descriptor);
359 Class.ancestors.push_back(obj_descriptor);
360
361 AddArray(panda_file::SourceLang::PANDA_ASSEMBLY, reinterpret_cast<const uint8_t *>("[Z"));
362 AddArray(panda_file::SourceLang::PANDA_ASSEMBLY, reinterpret_cast<const uint8_t *>("[B"));
363 AddArray(panda_file::SourceLang::PANDA_ASSEMBLY, reinterpret_cast<const uint8_t *>("[S"));
364 AddArray(panda_file::SourceLang::PANDA_ASSEMBLY, reinterpret_cast<const uint8_t *>("[C"));
365 AddArray(panda_file::SourceLang::PANDA_ASSEMBLY, reinterpret_cast<const uint8_t *>("[I"));
366 AddArray(panda_file::SourceLang::PANDA_ASSEMBLY, reinterpret_cast<const uint8_t *>("[J"));
367 AddArray(panda_file::SourceLang::PANDA_ASSEMBLY, reinterpret_cast<const uint8_t *>("[F"));
368 AddArray(panda_file::SourceLang::PANDA_ASSEMBLY, reinterpret_cast<const uint8_t *>("[D"));
369 AddArray(panda_file::SourceLang::PANDA_ASSEMBLY, core_lang_ctx.GetStringArrayClassDescriptor());
370 }
371
CalcMethodHash(const panda_file::File * pf,const panda_file::MethodDataAccessor & mda)372 CacheOfRuntimeThings::MethodHash CacheOfRuntimeThings::CalcMethodHash(const panda_file::File *pf,
373 const panda_file::MethodDataAccessor &mda)
374 {
375 return CalcMethodHash(pf->GetStringData(mda.GetNameId()).data, [&](auto hash_str) {
376 const_cast<panda_file::MethodDataAccessor &>(mda).EnumerateTypesInProto([&](auto type, auto class_file_id) {
377 if (type.GetId() == panda_file::Type::TypeId::REFERENCE) {
378 hash_str(pf->GetStringData(class_file_id).data);
379 } else {
380 hash_str(ClassHelper::GetPrimitiveTypeDescriptorStr(type.GetId()));
381 }
382 });
383 });
384 }
385
CalcMethodHash(CacheOfRuntimeThings::CachedMethod & cached_method)386 CacheOfRuntimeThings::CachedMethod &CacheOfRuntimeThings::CalcMethodHash(
387 CacheOfRuntimeThings::CachedMethod &cached_method)
388 {
389 cached_method.hash = CalcMethodHash(cached_method.name, [&](auto hash_str) {
390 for (const auto &arg : cached_method.signature) {
391 if (CacheOfRuntimeThings::IsDescriptor(arg)) {
392 hash_str(CacheOfRuntimeThings::GetDescriptor(arg));
393 } else {
394 hash_str(CacheOfRuntimeThings::GetRef(arg).name);
395 }
396 }
397 });
398 return cached_method;
399 }
400
CalcFieldNameAndTypeHash(const panda_file::File * pf,const panda_file::FieldDataAccessor & fda)401 CacheOfRuntimeThings::FieldHash CacheOfRuntimeThings::CalcFieldNameAndTypeHash(const panda_file::File *pf,
402 const panda_file::FieldDataAccessor &fda)
403 {
404 uint64_t hash;
405 uint64_t name_hash = PseudoFnvHashString(pf->GetStringData(fda.GetNameId()).data);
406
407 uint64_t type_hash;
408
409 auto type = panda_file::Type::GetTypeFromFieldEncoding(fda.GetType());
410
411 if (type.GetId() != panda_file::Type::TypeId::REFERENCE) {
412 type_hash = PseudoFnvHashItem(ClassHelper::GetPrimitiveTypeDescriptorChar(type.GetId()));
413 } else {
414 auto type_class_id = panda_file::File::EntityId(fda.GetType());
415 const auto *descr = pf->GetStringData(type_class_id).data;
416 type_hash = PseudoFnvHashString(descr);
417 }
418
419 auto constexpr SHIFT = 32U;
420
421 hash = (name_hash << SHIFT) | type_hash;
422
423 return hash;
424 }
425
426 template <>
427 CacheOfRuntimeThings::CachedClass &FastAPIClassRW::AddToCache(const panda_file::File *pf,
428 panda_file::File::EntityId entity_id);
429
430 template <>
431 CacheOfRuntimeThings::CachedMethod &FastAPIClassRW::AddToCache(const CacheOfRuntimeThings::CachedClass &cached_class,
432 const panda_file::File *pf,
433 const panda_file::MethodDataAccessor &mda);
434
435 template <>
436 CacheOfRuntimeThings::CachedField &FastAPIClassRW::AddToCache(const CacheOfRuntimeThings::CachedClass &cached_class,
437 const panda_file::File *pf,
438 const panda_file::FieldDataAccessor &fda);
439
AddAncestors(CacheOfRuntimeThings::CachedClass * cached_class,panda_file::ClassDataAccessor * cda,const CacheOfRuntimeThings::LangContext & data)440 static void AddAncestors(CacheOfRuntimeThings::CachedClass *cached_class, panda_file::ClassDataAccessor *cda,
441 const CacheOfRuntimeThings::LangContext &data)
442 {
443 auto *pf = &cda->GetPandaFile();
444
445 cda->EnumerateInterfaces([&](auto entity_id) {
446 DescriptorString descr;
447 if (entity_id.GetOffset() == 0) {
448 descr = data.object_descr;
449 } else {
450 descr = pf->GetStringData(entity_id).data;
451 }
452 if (descr != cached_class->name) {
453 cached_class->ancestors.emplace_back(descr);
454 }
455 });
456
457 auto super_class_id = cda->GetSuperClassId();
458
459 DescriptorString descr;
460
461 if (super_class_id.GetOffset() == 0) {
462 descr = data.object_descr;
463 } else {
464 descr = pf->GetStringData(super_class_id).data;
465 }
466
467 if (descr != cached_class->name) {
468 cached_class->ancestors.emplace_back(descr);
469 }
470 }
471
472 template <>
AddToCache(const panda_file::File * pf,panda_file::File::EntityId entity_id)473 CacheOfRuntimeThings::CachedClass &FastAPIClassRW::AddToCache(const panda_file::File *pf,
474 panda_file::File::EntityId entity_id)
475 {
476 auto id = Class::CalcUniqId(pf, entity_id);
477
478 panda_file::ClassDataAccessor cda {*pf, entity_id};
479
480 panda_file::SourceLang src_lang;
481
482 auto src_lang_opt = cda.GetSourceLang();
483 if (!src_lang_opt) {
484 src_lang = panda_file::SourceLang::PANDA_ASSEMBLY;
485 } else {
486 src_lang = *src_lang_opt;
487 }
488
489 auto &cached_class_ref = GetFromCache<CachedClass>(src_lang, id);
490 if (Valid(cached_class_ref)) {
491 return cached_class_ref;
492 }
493
494 CachedClass cached_class;
495
496 cached_class.flags = GetClassFlags(cda.GetAccessFlags());
497
498 cached_class.id = id;
499
500 cached_class.source_lang = src_lang;
501 cached_class.type_id = panda_file::Type::TypeId::REFERENCE;
502
503 cached_class.ancestors.reserve(cda.GetIfacesNumber() + 1);
504
505 auto descriptor = cda.GetDescriptor();
506
507 cached_class.name = descriptor;
508
509 auto &data = GetContext(src_lang);
510
511 AddAncestors(&cached_class, &cda, data);
512
513 cached_class.file = pf;
514 cached_class.file_id = entity_id;
515 cached_class.linked = false;
516
517 cached_class.methods.reserve(cda.GetMethodsNumber());
518 cached_class.fields.reserve(cda.GetFieldsNumber());
519
520 auto &stored_cached_class = data.class_cache.emplace(id, std::move(cached_class)).first->second;
521
522 cda.EnumerateMethods([&](const panda_file::MethodDataAccessor &mda) {
523 if (!pf->IsExternal(mda.GetMethodId())) {
524 auto &cached_method = AddToCache(stored_cached_class, pf, mda);
525 stored_cached_class.methods.insert_or_assign(cached_method.hash, std::cref(cached_method));
526 }
527 });
528
529 cda.EnumerateFields([&](const panda_file::FieldDataAccessor &fda) {
530 if (!pf->IsExternal(fda.GetFieldId())) {
531 auto &cached_field = AddToCache(stored_cached_class, pf, fda);
532 stored_cached_class.fields.insert_or_assign(cached_field.hash, std::cref(cached_field));
533 }
534 });
535
536 if (data.descr_lookup.count(stored_cached_class.name) == 0) {
537 data.descr_lookup.emplace(stored_cached_class.name, std::cref(stored_cached_class));
538 }
539
540 data.file_cache.AddToCache<CachedClass>(pf, entity_id.GetOffset(), stored_cached_class);
541
542 return stored_cached_class;
543 }
544
InitializeClassIndex(CacheOfRuntimeThings::CachedMethod * cached_method,CacheOfRuntimeThings::LangContext * data)545 static void InitializeClassIndex(CacheOfRuntimeThings::CachedMethod *cached_method,
546 CacheOfRuntimeThings::LangContext *data)
547 {
548 auto *pf = cached_method->file;
549 auto file_id = cached_method->file_id;
550
551 auto &&class_index_table = pf->GetClassIndex(file_id);
552
553 auto &class_index_table_ref =
554 data->index_table_cache.GetFromCache<CacheOfRuntimeThings::ClassIndex>(pf, class_index_table);
555 if (Valid(class_index_table_ref)) {
556 cached_method->class_index = std::ref(class_index_table_ref);
557 } else {
558 CacheOfRuntimeThings::ClassIndex class_index;
559 for (auto idx_class_id : class_index_table) {
560 DescriptorString descr;
561
562 auto type = panda_file::Type::GetTypeFromFieldEncoding(idx_class_id.GetOffset());
563
564 if (type.IsReference()) {
565 descr = pf->GetStringData(idx_class_id).data;
566 } else {
567 descr = CacheOfRuntimeThings::GetRef(data->primitive_classes[type.GetId()]).name;
568 }
569
570 class_index.emplace_back(descr);
571 }
572 class_index.shrink_to_fit();
573 auto &index_table_ref = data->index_table_cache.AddToCache(pf, class_index_table, std::move(class_index));
574 cached_method->class_index = std::ref(index_table_ref);
575 }
576 }
577
InitializeMethodIndex(CacheOfRuntimeThings::CachedMethod * cached_method,CacheOfRuntimeThings::LangContext * data)578 static void InitializeMethodIndex(CacheOfRuntimeThings::CachedMethod *cached_method,
579 CacheOfRuntimeThings::LangContext *data)
580 {
581 auto *pf = cached_method->file;
582 auto file_id = cached_method->file_id;
583
584 auto &&method_index_table = pf->GetMethodIndex(file_id);
585
586 auto &method_index_table_ref =
587 data->index_table_cache.GetFromCache<CacheOfRuntimeThings::MethodIndex>(pf, method_index_table);
588 if (Valid(method_index_table_ref)) {
589 cached_method->method_index = std::ref(method_index_table_ref);
590 } else {
591 CacheOfRuntimeThings::MethodIndex method_index;
592 for (auto idx_method_id : method_index_table) {
593 method_index.emplace_back(idx_method_id);
594 }
595 method_index.shrink_to_fit();
596 auto &index_table_ref = data->index_table_cache.AddToCache(pf, method_index_table, std::move(method_index));
597 cached_method->method_index = std::ref(index_table_ref);
598 }
599 }
600
InitializeFieldIndex(CacheOfRuntimeThings::CachedMethod * cached_method,CacheOfRuntimeThings::LangContext * data)601 static void InitializeFieldIndex(CacheOfRuntimeThings::CachedMethod *cached_method,
602 CacheOfRuntimeThings::LangContext *data)
603 {
604 auto *pf = cached_method->file;
605 auto file_id = cached_method->file_id;
606
607 auto &&field_index_table = pf->GetFieldIndex(file_id);
608
609 auto &field_index_table_ref =
610 data->index_table_cache.GetFromCache<CacheOfRuntimeThings::FieldIndex>(pf, field_index_table);
611 if (Valid(field_index_table_ref)) {
612 cached_method->field_index = std::ref(field_index_table_ref);
613 } else {
614 CacheOfRuntimeThings::FieldIndex field_index;
615 for (auto idx_field_id : field_index_table) {
616 field_index.emplace_back(idx_field_id);
617 }
618 field_index.shrink_to_fit();
619 auto &index_table_ref = data->index_table_cache.AddToCache(pf, field_index_table, std::move(field_index));
620 cached_method->field_index = std::ref(index_table_ref);
621 }
622 }
623
InitializeHash(CacheOfRuntimeThings::CachedMethod * cached_method,const panda_file::MethodDataAccessor & mda,const CacheOfRuntimeThings::LangContext & data)624 static void InitializeHash(CacheOfRuntimeThings::CachedMethod *cached_method, const panda_file::MethodDataAccessor &mda,
625 const CacheOfRuntimeThings::LangContext &data)
626 {
627 auto *pf = cached_method->file;
628
629 cached_method->hash = CacheOfRuntimeThings::CalcMethodHash(cached_method->name, [&](auto hash_str) {
630 const_cast<panda_file::MethodDataAccessor &>(mda).EnumerateTypesInProto([&](auto type, auto class_file_id) {
631 auto type_id = type.GetId();
632 if (type_id == panda_file::Type::TypeId::REFERENCE) {
633 const auto *descr = pf->GetStringData(class_file_id).data;
634 hash_str(descr);
635 cached_method->signature.push_back(DescriptorString {descr});
636 } else {
637 hash_str(ClassHelper::GetPrimitiveTypeDescriptorStr(type_id));
638 cached_method->signature.push_back(data.primitive_classes[type_id]);
639 }
640 });
641 });
642 }
643
InitializeCode(CacheOfRuntimeThings::CachedMethod * cached_method,const panda_file::MethodDataAccessor & mda)644 static void InitializeCode(CacheOfRuntimeThings::CachedMethod *cached_method, const panda_file::MethodDataAccessor &mda)
645 {
646 auto *pf = cached_method->file;
647
648 auto code_id = const_cast<panda_file::MethodDataAccessor &>(mda).GetCodeId();
649 if (code_id) {
650 panda_file::CodeDataAccessor cda {*pf, *code_id};
651 cached_method->num_vregs = cda.GetNumVregs();
652 cached_method->num_args = cda.GetNumArgs();
653 cached_method->bytecode = cda.GetInstructions();
654 cached_method->bytecode_size = cda.GetCodeSize();
655 cda.EnumerateTryBlocks([&](const auto &try_block) {
656 auto try_block_start = reinterpret_cast<const uint8_t *>(
657 reinterpret_cast<uintptr_t>(cached_method->bytecode) + static_cast<uintptr_t>(try_block.GetStartPc()));
658 auto try_block_end = reinterpret_cast<const uint8_t *>(reinterpret_cast<uintptr_t>(try_block_start) +
659 static_cast<uintptr_t>(try_block.GetLength()));
660 const_cast<panda_file::CodeDataAccessor::TryBlock &>(try_block).EnumerateCatchBlocks(
661 [&](const auto &catch_block) {
662 auto handler_pc_ptr =
663 reinterpret_cast<const uint8_t *>(reinterpret_cast<uintptr_t>(cached_method->bytecode) +
664 static_cast<uintptr_t>(catch_block.GetHandlerPc()));
665 CacheOfRuntimeThings::CachedCatchBlock cached_catch_block {
666 try_block_start, try_block_end, DescriptorString {}, handler_pc_ptr, catch_block.GetCodeSize()};
667 auto type_idx = catch_block.GetTypeIdx();
668 if (type_idx != panda_file::INVALID_INDEX) {
669 if (type_idx < cached_method->class_index.get().size()) {
670 auto cls_item = cached_method->class_index.get()[type_idx];
671 CacheOfRuntimeThings::DescriptorString descr;
672 if (CacheOfRuntimeThings::IsDescriptor(cls_item)) {
673 descr = CacheOfRuntimeThings::GetDescriptor(cls_item);
674 } else {
675 descr = CacheOfRuntimeThings::GetRef(cls_item).name;
676 }
677 cached_catch_block.exception_type = descr;
678 } else {
679 }
680 }
681 // NOLINTNEXTLINE(performance-move-const-arg)
682 cached_method->catch_blocks.emplace_back(std::move(cached_catch_block));
683 return true;
684 });
685 return true;
686 });
687 cached_method->catch_blocks.shrink_to_fit();
688 } else {
689 cached_method->num_vregs = 0;
690 cached_method->num_args = 0;
691 cached_method->bytecode = nullptr;
692 cached_method->bytecode_size = 0;
693 }
694 }
695
InitializeCachedMethod(CacheOfRuntimeThings::CachedMethod * cached_method,const panda_file::MethodDataAccessor & mda,CacheOfRuntimeThings::LangContext * data)696 static void InitializeCachedMethod(CacheOfRuntimeThings::CachedMethod *cached_method,
697 const panda_file::MethodDataAccessor &mda, CacheOfRuntimeThings::LangContext *data)
698 {
699 InitializeClassIndex(cached_method, data);
700 InitializeMethodIndex(cached_method, data);
701 InitializeFieldIndex(cached_method, data);
702 InitializeHash(cached_method, mda, *data);
703 InitializeCode(cached_method, mda);
704 }
705
706 template <>
AddToCache(const CacheOfRuntimeThings::CachedClass & cached_class,const panda_file::File * pf,const panda_file::MethodDataAccessor & mda)707 CacheOfRuntimeThings::CachedMethod &FastAPIClassRW::AddToCache(const CacheOfRuntimeThings::CachedClass &cached_class,
708 const panda_file::File *pf,
709 const panda_file::MethodDataAccessor &mda)
710 {
711 auto file_id = mda.GetMethodId();
712
713 auto id = Method::CalcUniqId(pf, file_id);
714
715 panda_file::SourceLang src_lang;
716
717 auto src_lang_opt = const_cast<panda_file::MethodDataAccessor &>(mda).GetSourceLang();
718 if (!src_lang_opt) {
719 src_lang = cached_class.source_lang;
720 } else {
721 src_lang = *src_lang_opt;
722 }
723
724 auto &cached_method_ref = GetFromCache<CachedMethod>(src_lang, id);
725 if (Valid(cached_method_ref)) {
726 return cached_method_ref;
727 }
728
729 CachedMethod cached_method {id,
730 {},
731 pf->GetStringData(mda.GetNameId()).data,
732 std::cref(cached_class),
733 {},
734 {},
735 {},
736 {},
737 {},
738 0,
739 0,
740 GetMethodFlags(mda),
741 nullptr,
742 0,
743 false,
744 pf,
745 file_id};
746
747 auto &data = GetContext(src_lang);
748
749 InitializeCachedMethod(&cached_method, mda, &data);
750
751 auto &result = data.method_cache.emplace(id, std::move(cached_method)).first->second;
752
753 data.file_cache.AddToCache<CachedMethod>(pf, file_id.GetOffset(), result);
754
755 return result;
756 }
757
758 template <>
AddToCache(const CacheOfRuntimeThings::CachedClass & cached_class,const panda_file::File * pf,const panda_file::FieldDataAccessor & fda)759 CacheOfRuntimeThings::CachedField &FastAPIClassRW::AddToCache(const CacheOfRuntimeThings::CachedClass &cached_class,
760 const panda_file::File *pf,
761 const panda_file::FieldDataAccessor &fda)
762 {
763 auto file_id = fda.GetFieldId();
764
765 auto id = Field::CalcUniqId(pf, file_id);
766
767 auto &cached_field_ref = GetFromCache<CachedField>(cached_class.source_lang, id);
768 if (Valid(cached_field_ref)) {
769 return cached_field_ref;
770 }
771
772 CachedField cached_field {id,
773 {},
774 pf->GetStringData(fda.GetNameId()).data,
775 std::cref(cached_class),
776 std::cref(Invalid<CachedClass>()),
777 GetFieldFlags(fda),
778 false,
779 pf,
780 file_id};
781
782 auto type = panda_file::Type::GetTypeFromFieldEncoding(fda.GetType());
783
784 // NB! keep hashing in sync with CalcFieldNameAndTypeHash
785 uint64_t name_hash = PseudoFnvHashString(cached_field.name);
786
787 uint64_t type_hash;
788
789 auto &data = GetContext(cached_class.source_lang);
790
791 if (type.GetId() != panda_file::Type::TypeId::REFERENCE) {
792 cached_field.type = std::cref(data.primitive_classes[type.GetId()]);
793 type_hash = PseudoFnvHashItem(ClassHelper::GetPrimitiveTypeDescriptorChar(type.GetId()));
794 } else {
795 auto type_class_id = panda_file::File::EntityId(fda.GetType());
796 const auto *descr = pf->GetStringData(type_class_id).data;
797 cached_field.type = DescriptorString(descr);
798 type_hash = PseudoFnvHashString(descr);
799 }
800
801 auto constexpr SHIFT = 32U;
802
803 cached_field.hash = (name_hash << SHIFT) | type_hash;
804
805 // NOLINTNEXTLINE(performance-move-const-arg)
806 auto &result = data.field_cache.emplace(id, std::move(cached_field)).first->second;
807
808 data.file_cache.AddToCache<CachedField>(pf, file_id.GetOffset(), result);
809
810 return result;
811 }
812
813 template <>
ResolveByDescriptor(panda_file::SourceLang src_lang,const DescriptorString & descr_string)814 CacheOfRuntimeThings::CachedClass &FastAPIClassRW::ResolveByDescriptor(panda_file::SourceLang src_lang,
815 const DescriptorString &descr_string)
816 {
817 auto &data = GetContext(src_lang);
818
819 const auto it = data.descr_lookup.find(descr_string);
820 if (it != data.descr_lookup.cend()) {
821 return const_cast<CachedClass &>(it->second.get());
822 }
823
824 // check if it is an array descr
825 if (!ClassHelper::IsArrayDescriptor(descr_string)) {
826 return Invalid<CachedClass>();
827 }
828
829 return AddArray(src_lang, descr_string);
830 }
831
832 template <>
LinkArrayClass(CacheOfRuntimeThings::CachedClass & cached_class)833 CacheOfRuntimeThings::CachedClass &FastAPIClassRW::LinkArrayClass(CacheOfRuntimeThings::CachedClass &cached_class)
834 {
835 auto &array_comp = cached_class.array_component;
836 if (!IsLinked(array_comp)) {
837 if (IsDescriptor(array_comp)) {
838 auto &resolved_comp = ResolveByDescriptor(cached_class.source_lang, GetDescriptor(array_comp));
839 if (Valid(resolved_comp)) {
840 array_comp = std::cref(resolved_comp);
841 }
842 }
843 if (IsRef(array_comp)) {
844 if (!IsLinked(array_comp)) {
845 auto &linked_comp = Link(GetRef(array_comp));
846 if (Valid(linked_comp)) {
847 array_comp = std::cref(linked_comp);
848 } else {
849 cached_class.linked = false;
850 }
851 }
852 } else {
853 cached_class.linked = false;
854 }
855 }
856
857 if (!IsLinked(cached_class)) {
858 return Invalid<CachedClass>();
859 }
860
861 return cached_class;
862 }
863
864 template <>
865 template <>
Link(CacheOfRuntimeThings::CachedClass & cached_class)866 CacheOfRuntimeThings::CachedClass &FastAPIClassRW::Link<CacheOfRuntimeThings::CachedClass>(
867 CacheOfRuntimeThings::CachedClass &cached_class)
868 {
869 if (IsLinked(cached_class)) {
870 return cached_class;
871 }
872
873 cached_class.linked = true;
874
875 for (auto &ancestor : cached_class.ancestors) {
876 if (IsLinked(ancestor)) {
877 continue;
878 }
879 if (IsDescriptor(ancestor)) {
880 auto &resolved_ancestor = ResolveByDescriptor(cached_class.source_lang, GetDescriptor(ancestor));
881 if (Valid(resolved_ancestor)) {
882 ancestor = std::cref(resolved_ancestor);
883 }
884 }
885 if (IsRef(ancestor)) {
886 auto &ancestor_ref = GetRef(ancestor);
887 auto &linked_ancestor = Link(ancestor_ref);
888 if (Valid(linked_ancestor)) {
889 ancestor = std::cref(linked_ancestor);
890 continue;
891 }
892 }
893 cached_class.linked = false;
894 }
895
896 if (cached_class.flags[CacheOfRuntimeThings::CachedClass::Flag::ARRAY_CLASS]) {
897 return LinkArrayClass(cached_class);
898 }
899
900 if (!IsLinked(cached_class)) {
901 return Invalid<CachedClass>();
902 }
903
904 return cached_class;
905 }
906
907 template <>
LinkCatchBlocks(CacheOfRuntimeThings::CachedMethod & cached_method)908 void FastAPIClassRW::LinkCatchBlocks(CacheOfRuntimeThings::CachedMethod &cached_method)
909 {
910 auto &cached_class = CacheOfRuntimeThings::GetRef(cached_method.klass);
911 auto src_lang = cached_class.source_lang;
912
913 for (auto &catch_block : cached_method.catch_blocks) {
914 auto &exc_type = catch_block.exception_type;
915 if (IsLinked(exc_type)) {
916 continue;
917 }
918 // special case: invalid descriptor indicates catch_all section
919 if (IsDescriptor(exc_type) && !GetDescriptor(exc_type).IsValid()) {
920 continue;
921 }
922 if (IsDescriptor(exc_type)) {
923 auto &resolved = ResolveByDescriptor(src_lang, GetDescriptor(exc_type));
924 if (Valid(resolved)) {
925 exc_type = std::cref(resolved);
926 }
927 }
928 if (IsRef(exc_type)) {
929 auto &linked = Link(GetRef(exc_type));
930 if (Valid(linked)) {
931 exc_type = std::cref(linked);
932 continue;
933 }
934 }
935 cached_method.linked = false;
936 }
937 }
938
939 template <>
940 template <>
Link(CacheOfRuntimeThings::CachedMethod & cached_method)941 CacheOfRuntimeThings::CachedMethod &FastAPIClassRW::Link<CacheOfRuntimeThings::CachedMethod>(
942 CacheOfRuntimeThings::CachedMethod &cached_method)
943 {
944 if (IsLinked(cached_method)) {
945 return cached_method;
946 }
947
948 if (!IsLinked(cached_method.klass)) {
949 auto &class_ref = GetRef(cached_method.klass);
950 auto &linked_ref = Link(class_ref);
951 if (Invalid(linked_ref)) {
952 return Invalid<CachedMethod>();
953 }
954 }
955
956 auto &cached_class = GetRef(cached_method.klass);
957
958 auto src_lang = cached_class.source_lang;
959
960 cached_method.linked = true;
961
962 auto resolve_arg = [&](CachedClass::RefOrDescriptor &arg) -> bool {
963 if (IsDescriptor(arg)) {
964 const auto &descr = GetDescriptor(arg);
965 auto &arg_class = ResolveByDescriptor(src_lang, descr);
966 if (Valid(arg_class)) {
967 arg = std::cref(arg_class);
968 } else {
969 return false;
970 }
971 }
972 ASSERT(IsRef(arg));
973 if (IsLinked(GetRef(arg))) {
974 return true;
975 }
976 return Valid(Link(GetRef(arg)));
977 };
978
979 for (auto &arg : cached_method.signature) {
980 cached_method.linked &= resolve_arg(arg);
981 }
982
983 LinkCatchBlocks(cached_method);
984
985 if (!IsLinked(cached_method)) {
986 return Invalid<CachedMethod>();
987 }
988
989 return cached_method;
990 }
991
992 template <>
993 template <>
Link(CacheOfRuntimeThings::CachedField & cached_field)994 CacheOfRuntimeThings::CachedField &FastAPIClassRW::Link<CacheOfRuntimeThings::CachedField>(
995 CacheOfRuntimeThings::CachedField &cached_field)
996 {
997 if (IsLinked(cached_field)) {
998 return cached_field;
999 }
1000
1001 if (!IsLinked(cached_field.klass)) {
1002 auto &class_ref = GetRef(cached_field.klass);
1003 auto &linked = Link(class_ref);
1004 if (Invalid(linked)) {
1005 return Invalid<CachedField>();
1006 }
1007 }
1008
1009 auto &class_ref = GetRef(cached_field.klass);
1010 auto src_lang = class_ref.source_lang;
1011
1012 if (IsDescriptor(cached_field.type)) {
1013 auto &type_class = ResolveByDescriptor(src_lang, GetDescriptor(cached_field.type));
1014 if (Invalid(type_class)) {
1015 return Invalid<CachedField>();
1016 }
1017 cached_field.type = std::cref(type_class);
1018 }
1019
1020 auto &type_ref = GetRef(cached_field.type);
1021
1022 auto &linked = Link(type_ref);
1023 if (Invalid(linked)) {
1024 return Invalid<CachedField>();
1025 }
1026
1027 cached_field.type = std::cref(linked);
1028
1029 cached_field.linked = true;
1030
1031 return cached_field;
1032 }
1033
1034 template <>
1035 template <>
GetFromCache(const CacheOfRuntimeThings::CachedMethod & cached_method_,uint16_t idx)1036 const CacheOfRuntimeThings::CachedClass &FastAPIClassRW::GetFromCache<CacheOfRuntimeThings::CachedClass>(
1037 const CacheOfRuntimeThings::CachedMethod &cached_method_, uint16_t idx)
1038 {
1039 auto &cached_method = const_cast<CachedMethod &>(cached_method_);
1040
1041 auto &index = cached_method.class_index.get();
1042 if (idx >= index.size()) {
1043 return Invalid<CachedClass>();
1044 }
1045 auto &item = index[idx];
1046 if (IsRef(item)) {
1047 return GetRef(item);
1048 }
1049 if (IsDescriptor(item)) {
1050 auto &descr = GetDescriptor(item);
1051
1052 auto src_lang = GetRef(cached_method.klass).source_lang;
1053
1054 auto &class_ref = ResolveByDescriptor(src_lang, descr);
1055 if (Invalid(class_ref)) {
1056 return Invalid<CachedClass>();
1057 }
1058
1059 auto &linked = Link(class_ref);
1060 if (Invalid(linked)) {
1061 return Invalid<CachedClass>();
1062 }
1063
1064 item = std::cref(linked);
1065
1066 return linked;
1067 }
1068 UNREACHABLE();
1069 return Invalid<CachedClass>();
1070 }
1071
1072 template <>
ResolveMethod(const CacheOfRuntimeThings::CachedMethod & cached_method,panda_file::File::EntityId id)1073 const CacheOfRuntimeThings::CachedMethod &FastAPIClassRW::ResolveMethod(
1074 const CacheOfRuntimeThings::CachedMethod &cached_method, panda_file::File::EntityId id)
1075 {
1076 panda_file::MethodDataAccessor mda {*cached_method.file, id};
1077
1078 DescriptorString descr {cached_method.file->GetStringData(mda.GetClassId()).data};
1079
1080 panda_file::SourceLang method_src_lang;
1081
1082 auto src_lang = GetRef(cached_method.klass).source_lang;
1083 auto &data = GetContext(src_lang);
1084
1085 auto src_lang_opt = mda.GetSourceLang();
1086 if (!src_lang_opt) {
1087 method_src_lang = src_lang;
1088 } else {
1089 method_src_lang = *src_lang_opt;
1090 }
1091
1092 auto &class_ref = ResolveByDescriptor(method_src_lang, descr);
1093 if (Invalid(class_ref)) {
1094 return Invalid<CachedMethod>();
1095 }
1096
1097 auto &methods_table = class_ref.methods;
1098
1099 MethodHash method_hash;
1100
1101 if (class_ref.flags[CachedClass::Flag::ARRAY_CLASS]) {
1102 // NB: current assumption, that array classes have the only
1103 // one method - constructor
1104 ASSERT(methods_table.size() == 1);
1105 method_hash = methods_table.begin()->second.get().hash;
1106 } else {
1107 method_hash = CalcMethodHash(cached_method.file, mda);
1108 }
1109
1110 auto it = methods_table.find(method_hash);
1111 if (it == methods_table.end()) {
1112 return Invalid<CachedMethod>();
1113 }
1114
1115 auto &resolved_method = GetRef(it->second);
1116 ASSERT(Valid(resolved_method));
1117
1118 auto &linked_method = Link(resolved_method);
1119 if (Invalid(linked_method)) {
1120 return Invalid<CachedMethod>();
1121 }
1122
1123 data.file_cache.AddToCache(cached_method.file, id.GetOffset(), linked_method);
1124 return linked_method;
1125 }
1126
1127 template <>
1128 template <>
GetFromCache(const CacheOfRuntimeThings::CachedMethod & cached_method_,uint16_t idx)1129 const CacheOfRuntimeThings::CachedMethod &FastAPIClassRW::GetFromCache<CacheOfRuntimeThings::CachedMethod>(
1130 const CacheOfRuntimeThings::CachedMethod &cached_method_, uint16_t idx)
1131 {
1132 auto &cached_method = const_cast<CachedMethod &>(cached_method_);
1133 auto &index = cached_method.method_index.get();
1134 if (idx >= index.size()) {
1135 return Invalid<CachedMethod>();
1136 }
1137 auto &item = index[idx];
1138 if (IsRef(item)) {
1139 return GetRef(item);
1140 }
1141 if (IsEntityId(item)) {
1142 auto id = GetEntityId(item);
1143
1144 auto src_lang = GetRef(cached_method.klass).source_lang;
1145
1146 auto &data = GetContext(src_lang);
1147
1148 auto &method_ref = data.file_cache.GetCached<CachedMethod>(cached_method.file, id.GetOffset());
1149 if (Valid(method_ref)) {
1150 if (IsLinked(method_ref)) {
1151 item = std::cref(method_ref);
1152 return method_ref;
1153 }
1154 auto &linked = Link(method_ref);
1155 if (Invalid(linked)) {
1156 return Invalid<CachedMethod>();
1157 }
1158 item = std::cref(linked);
1159 return linked;
1160 }
1161
1162 auto &res = ResolveMethod(cached_method, id);
1163 item = std::cref(res);
1164 return res;
1165 }
1166
1167 UNREACHABLE();
1168 return Invalid<CachedMethod>();
1169 }
1170
1171 template <>
1172 template <>
GetFromCache(const CacheOfRuntimeThings::CachedMethod & cached_method_,uint16_t idx)1173 const CacheOfRuntimeThings::CachedField &FastAPIClassRW::GetFromCache<CacheOfRuntimeThings::CachedField>(
1174 const CacheOfRuntimeThings::CachedMethod &cached_method_, uint16_t idx)
1175 {
1176 auto &cached_method = const_cast<CachedMethod &>(cached_method_);
1177 auto &index = cached_method.field_index.get();
1178 if (idx >= index.size()) {
1179 return Invalid<CachedField>();
1180 }
1181 auto &item = index[idx];
1182 if (IsRef(item)) {
1183 return GetRef(item);
1184 }
1185 if (IsEntityId(item)) {
1186 auto entity_id = GetEntityId(item);
1187
1188 auto src_lang = GetRef(cached_method.klass).source_lang;
1189
1190 auto &data = GetContext(src_lang);
1191
1192 auto &field_ref = data.file_cache.GetCached<CachedField>(cached_method.file, entity_id.GetOffset());
1193 if (Valid(field_ref)) {
1194 if (IsLinked(field_ref)) {
1195 item = std::cref(field_ref);
1196 return field_ref;
1197 }
1198 auto &linked = Link(field_ref);
1199 if (Invalid(linked)) {
1200 return Invalid<CachedField>();
1201 }
1202 item = std::cref(linked);
1203 return linked;
1204 }
1205
1206 panda_file::FieldDataAccessor fda {*cached_method.file, entity_id};
1207
1208 DescriptorString descr {cached_method.file->GetStringData(fda.GetClassId()).data};
1209
1210 auto &class_ref = ResolveByDescriptor(src_lang, descr);
1211 if (Invalid(class_ref)) {
1212 return Invalid<CachedField>();
1213 }
1214
1215 auto &fields_table = class_ref.fields;
1216
1217 FieldHash field_hash = CalcFieldNameAndTypeHash(cached_method.file, fda);
1218
1219 auto it = fields_table.find(field_hash);
1220 if (it == fields_table.end()) {
1221 return Invalid<CachedField>();
1222 }
1223
1224 auto &resolved_field = GetRef(it->second);
1225 ASSERT(Valid(resolved_field));
1226
1227 auto &linked_field = Link(resolved_field);
1228 if (Invalid(linked_field)) {
1229 return Invalid<CachedField>();
1230 }
1231
1232 data.file_cache.AddToCache(cached_method.file, entity_id.GetOffset(), linked_field);
1233 item = std::cref(linked_field);
1234 return linked_field;
1235 }
1236 UNREACHABLE();
1237 return Invalid<CachedField>();
1238 }
1239
1240 template <>
GetStringClass(const CacheOfRuntimeThings::CachedMethod & method)1241 const CacheOfRuntimeThings::CachedClass &FastAPIClassRW::GetStringClass(
1242 const CacheOfRuntimeThings::CachedMethod &method)
1243 {
1244 auto &klass = GetRef(method.klass);
1245 auto src_lang = klass.source_lang;
1246 auto &ctx = GetContext(src_lang);
1247 auto &str_ref = ResolveByDescriptor(src_lang, ctx.string_descr);
1248 if (Invalid(str_ref)) {
1249 return Invalid<CachedClass>();
1250 }
1251 return Link(str_ref);
1252 }
1253
1254 template <>
GetStringArrayClass(const CacheOfRuntimeThings::CachedMethod & method)1255 const CacheOfRuntimeThings::CachedClass &FastAPIClassRW::GetStringArrayClass(
1256 const CacheOfRuntimeThings::CachedMethod &method)
1257 {
1258 auto &klass = GetRef(method.klass);
1259 auto src_lang = klass.source_lang;
1260 auto &ctx = GetContext(src_lang);
1261 auto &str_array_ref = ResolveByDescriptor(src_lang, ctx.string_array_descr);
1262 if (Invalid(str_array_ref)) {
1263 return Invalid<CachedClass>();
1264 }
1265 return Link(str_array_ref);
1266 }
1267
1268 template <>
ProcessFile(const panda_file::File * pf)1269 void FastAPIClassRW::ProcessFile(const panda_file::File *pf)
1270 {
1271 auto classes_indices = pf->GetClasses();
1272 for (auto idx : classes_indices) {
1273 panda_file::File::EntityId entity_id {idx};
1274 if (!pf->IsExternal(entity_id)) {
1275 AddToCache(pf, entity_id);
1276 }
1277 }
1278 }
1279
1280 } // namespace panda::verifier
1281