• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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