• 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 #ifndef PANDA_VERIFICATION_JOB_QUEUE_CACHE_H_
17 #define PANDA_VERIFICATION_JOB_QUEUE_CACHE_H_
18 
19 #include "verification/util/flags.h"
20 #include "verification/util/synchronized.h"
21 #include "verification/util/access.h"
22 #include "verification/util/descriptor_string.h"
23 #include "verification/cache/file_entity_cache.h"
24 #include "verification/util/enum_array.h"
25 #include "verification/util/ref_wrapper.h"
26 
27 #include "runtime/core/core_language_context.h"
28 #include "runtime/include/mem/panda_containers.h"
29 #include "runtime/include/mem/panda_string.h"
30 #include "runtime/include/language_context.h"
31 
32 #include "libpandafile/file_items.h"
33 #include "libpandafile/file.h"
34 #include "libpandafile/method_data_accessor.h"
35 #include "libpandafile/field_data_accessor.h"
36 
37 #include "libpandabase/utils/hash.h"
38 
39 #include "verification/job_queue/index_table_cache.h"
40 
41 #include <functional>
42 #include <cstdint>
43 #include <variant>
44 #include <optional>
45 
46 namespace panda::verifier {
47 class CacheOfRuntimeThings {
48 public:
49     using Id = uint64_t;
50 
51     struct CachedClass;
52     struct CachedMethod;
53     struct CachedField;
54 
55     using CachedClassRef = std::reference_wrapper<const CachedClass>;
56     using CachedMethodRef = std::reference_wrapper<const CachedMethod>;
57     using CachedFieldRef = std::reference_wrapper<const CachedField>;
58 
59     using DescriptorString = panda::verifier::DescriptorString<mode::ExactCmp>;
60 
61     using CachedClassRefOrDescriptor = std::variant<DescriptorString, CachedClassRef>;
62     using CachedMethodRefOrEntityId = std::variant<panda_file::File::EntityId, CachedMethodRef>;
63     using CachedFieldRefOrEntityId = std::variant<panda_file::File::EntityId, CachedFieldRef>;
64 
IsRef(const CachedClassRefOrDescriptor & item)65     static bool IsRef(const CachedClassRefOrDescriptor &item)
66     {
67         return std::holds_alternative<CachedClassRef>(item);
68     }
69 
IsRef(const CachedMethodRefOrEntityId & item)70     static bool IsRef(const CachedMethodRefOrEntityId &item)
71     {
72         return std::holds_alternative<CachedMethodRef>(item);
73     }
74 
IsRef(const CachedFieldRefOrEntityId & item)75     static bool IsRef(const CachedFieldRefOrEntityId &item)
76     {
77         return std::holds_alternative<CachedFieldRef>(item);
78     }
79 
GetRef(const CachedClassRefOrDescriptor & item)80     static CachedClass &GetRef(const CachedClassRefOrDescriptor &item)
81     {
82         return const_cast<CachedClass &>(std::get<CachedClassRef>(item).get());
83     }
84 
GetRef(const CachedMethodRefOrEntityId & item)85     static CachedMethod &GetRef(const CachedMethodRefOrEntityId &item)
86     {
87         return const_cast<CachedMethod &>(std::get<CachedMethodRef>(item).get());
88     }
89 
GetRef(const CachedFieldRefOrEntityId & item)90     static CachedField &GetRef(const CachedFieldRefOrEntityId &item)
91     {
92         return const_cast<CachedField &>(std::get<CachedFieldRef>(item).get());
93     }
94 
GetRef(const CachedClassRef & item)95     static CachedClass &GetRef(const CachedClassRef &item)
96     {
97         return const_cast<CachedClass &>(item.get());
98     }
99 
GetRef(const CachedMethodRef & item)100     static CachedMethod &GetRef(const CachedMethodRef &item)
101     {
102         return const_cast<CachedMethod &>(item.get());
103     }
104 
GetRef(const CachedFieldRef & item)105     static CachedField &GetRef(const CachedFieldRef &item)
106     {
107         return const_cast<CachedField &>(item.get());
108     }
109 
IsDescriptor(const CachedClassRefOrDescriptor & item)110     static bool IsDescriptor(const CachedClassRefOrDescriptor &item)
111     {
112         return std::holds_alternative<DescriptorString>(item);
113     }
114 
GetDescriptor(const CachedClassRefOrDescriptor & item)115     static const DescriptorString &GetDescriptor(const CachedClassRefOrDescriptor &item)
116     {
117         return std::get<DescriptorString>(item);
118     }
119 
120     template <typename T>
IsEntityId(const T & item)121     static bool IsEntityId(const T &item)
122     {
123         return std::holds_alternative<panda_file::File::EntityId>(item);
124     }
125 
126     template <typename T>
GetEntityId(const T & item)127     static panda_file::File::EntityId GetEntityId(const T &item)
128     {
129         return std::get<panda_file::File::EntityId>(item);
130     }
131 
IsLinked(const CachedClassRef & item)132     static bool IsLinked(const CachedClassRef &item)
133     {
134         return GetRef(item).linked;
135     }
136 
IsLinked(const CachedMethodRef & item)137     static bool IsLinked(const CachedMethodRef &item)
138     {
139         return GetRef(item).linked;
140     }
141 
IsLinked(const CachedFieldRef & item)142     static bool IsLinked(const CachedFieldRef &item)
143     {
144         return GetRef(item).linked;
145     }
146 
IsLinked(const CachedClassRefOrDescriptor & item)147     static bool IsLinked(const CachedClassRefOrDescriptor &item)
148     {
149         return IsRef(item) && GetRef(item).linked;
150     }
151 
IsLinked(const CachedMethodRefOrEntityId & item)152     static bool IsLinked(const CachedMethodRefOrEntityId &item)
153     {
154         return IsRef(item) && GetRef(item).linked;
155     }
156 
IsLinked(const CachedFieldRefOrEntityId & item)157     static bool IsLinked(const CachedFieldRefOrEntityId &item)
158     {
159         return IsRef(item) && GetRef(item).linked;
160     }
161 
IsLinked(const CachedClass & item)162     static bool IsLinked(const CachedClass &item)
163     {
164         return item.linked;
165     }
166 
IsLinked(const CachedMethod & item)167     static bool IsLinked(const CachedMethod &item)
168     {
169         return item.linked;
170     }
171 
IsLinked(const CachedField & item)172     static bool IsLinked(const CachedField &item)
173     {
174         return item.linked;
175     }
176 
177     using MethodHash = uint64_t;
178     using FieldHash = uint64_t;
179 
180     template <typename Handler>
CalcMethodHash(const uint8_t * name,Handler && handler)181     static MethodHash CalcMethodHash(const uint8_t *name, Handler &&handler)
182     {
183         uint64_t name_hash = std::hash<DescriptorString> {}(DescriptorString {name});
184         uint64_t sig_hash = FNV_INITIAL_SEED;
185         auto hash_str = [&sig_hash](const DescriptorString &descr) {
186             sig_hash = PseudoFnvHashItem(std::hash<DescriptorString> {}(descr), sig_hash);
187         };
188         handler(hash_str);
189         auto constexpr SHIFT = 32U;
190         return (name_hash << SHIFT) | sig_hash;
191     }
192 
193     static MethodHash CalcMethodHash(const panda_file::File *pf, const panda_file::MethodDataAccessor &mda);
194     static CachedMethod &CalcMethodHash(CachedMethod &);
195 
196     static FieldHash CalcFieldNameAndTypeHash(const panda_file::File *, const panda_file::FieldDataAccessor &);
197 
198     using PrimitiveClassesArray =
199         EnumArraySimple<Ref<const CachedClass>, panda_file::Type::TypeId, panda_file::Type::TypeId::VOID,
200                         panda_file::Type::TypeId::U1, panda_file::Type::TypeId::U8, panda_file::Type::TypeId::I8,
201                         panda_file::Type::TypeId::U16, panda_file::Type::TypeId::I16, panda_file::Type::TypeId::U32,
202                         panda_file::Type::TypeId::I32, panda_file::Type::TypeId::U64, panda_file::Type::TypeId::I64,
203                         panda_file::Type::TypeId::F32, panda_file::Type::TypeId::F64, panda_file::Type::TypeId::TAGGED>;
204 
205     static PandaString GetName(const CachedClass &);
206     static PandaString GetName(const CachedMethod &);
207     static PandaString GetName(const CachedField &);
208     static PandaString GetName(const DescriptorString &);
209 
GetName(const CachedClassRef & item)210     static PandaString GetName(const CachedClassRef &item)
211     {
212         return GetName(GetRef(item));
213     }
214 
GetName(const CachedMethodRef & item)215     static PandaString GetName(const CachedMethodRef &item)
216     {
217         return GetName(GetRef(item));
218     }
219 
GetName(const CachedFieldRef & item)220     static PandaString GetName(const CachedFieldRef &item)
221     {
222         return GetName(GetRef(item));
223     }
224 
225     struct CachedClass {
226         using Ref = CachedClassRef;
227         using RefOrDescriptor = CachedClassRefOrDescriptor;
228         enum class Flag {
229             DYNAMIC_CLASS,
230             PUBLIC,
231             FINAL,
232             ANNOTATION,
233             ENUM,
234             ARRAY_CLASS,
235             OBJECT_ARRAY_CLASS,
236             STRING_CLASS,
237             VARIABLESIZE,
238             PRIMITIVE,
239             ABSTRACT,
240             INTERFACE,
241             INSTANTIABLE,
242             OBJECT_CLASS,
243             CLASS_CLASS,
244             PROXY,
245             SUPER,
246             SYNTHETIC
247         };
248         using FlagsValue =
249             FlagsForEnum<unsigned int, Flag, Flag::DYNAMIC_CLASS, Flag::PUBLIC, Flag::FINAL, Flag::ANNOTATION,
250                          Flag::ENUM, Flag::ARRAY_CLASS, Flag::OBJECT_ARRAY_CLASS, Flag::STRING_CLASS,
251                          Flag::VARIABLESIZE, Flag::PRIMITIVE, Flag::ABSTRACT, Flag::INTERFACE, Flag::INSTANTIABLE,
252                          Flag::OBJECT_CLASS, Flag::CLASS_CLASS, Flag::PROXY, Flag::SUPER, Flag::SYNTHETIC>;
253         Id id;
254         DescriptorString name;
255         panda_file::SourceLang source_lang;
256         panda_file::Type::TypeId type_id;
257         PandaVector<RefOrDescriptor> ancestors;
258         RefOrDescriptor array_component;
259         FlagsValue flags;
260         PandaUnorderedMap<MethodHash, CachedMethodRef> methods;
261         PandaUnorderedMap<FieldHash, CachedFieldRef> fields;
262         bool linked;
263         const panda_file::File *file;
264         panda_file::File::EntityId file_id;
265 
GetNameCachedClass266         PandaString GetName() const
267         {
268             return CacheOfRuntimeThings::GetName(*this);
269         }
270 
GetArrayComponentCachedClass271         const CachedClass &GetArrayComponent() const
272         {
273             ASSERT(IsRef(array_component));
274             return GetRef(array_component);
275         }
276     };
277 
278     struct CachedCatchBlock {
279         const uint8_t *try_block_start;
280         const uint8_t *try_block_end;
281         CachedClass::RefOrDescriptor exception_type;
282         const uint8_t *handler_bytecode;
283         size_t handler_bytecode_size;
284     };
285 
286     using ClassIndex = PandaVector<CachedClassRefOrDescriptor>;
287     using MethodIndex = PandaVector<CachedMethodRefOrEntityId>;
288     using FieldIndex = PandaVector<CachedFieldRefOrEntityId>;
289 
290     using ClassIndexRef = Ref<ClassIndex>;
291     using MethodIndexRef = Ref<MethodIndex>;
292     using FieldIndexRef = Ref<FieldIndex>;
293 
294     struct CachedMethod {
295         using Ref = CachedMethodRef;
296         enum class Flag {
297             STATIC,
298             PUBLIC,
299             PRIVATE,
300             PROTECTED,
301             NATIVE,
302             INTRINSIC,
303             SYNTHETIC,
304             ABSTRACT,
305             FINAL,
306             SYNCHRONIZED,
307             HAS_SINGLE_IMPLEMENTATION,
308             DEFAULT_INTERFACE_METHOD,
309             CONSTRUCTOR,
310             INSTANCE_CONSTRUCTOR,
311             STATIC_CONSTRUCTOR,
312             ARRAY_CONSTRUCTOR
313         };
314         using FlagsValue =
315             FlagsForEnum<unsigned int, Flag, Flag::STATIC, Flag::PUBLIC, Flag::PRIVATE, Flag::PROTECTED, Flag::NATIVE,
316                          Flag::INTRINSIC, Flag::SYNTHETIC, Flag::ABSTRACT, Flag::FINAL, Flag::SYNCHRONIZED,
317                          Flag::HAS_SINGLE_IMPLEMENTATION, Flag::DEFAULT_INTERFACE_METHOD, Flag::CONSTRUCTOR,
318                          Flag::INSTANCE_CONSTRUCTOR, Flag::STATIC_CONSTRUCTOR, Flag::ARRAY_CONSTRUCTOR>;
319         Id id;
320         MethodHash hash;
321         DescriptorString name;
322         CachedClass::Ref klass;
323         PandaVector<CachedClass::RefOrDescriptor> signature;
324         PandaVector<CachedCatchBlock> catch_blocks;
325         ClassIndexRef class_index;
326         MethodIndexRef method_index;
327         FieldIndexRef field_index;
328         size_t num_vregs;
329         size_t num_args;
330         FlagsValue flags;
331         const uint8_t *bytecode;
332         size_t bytecode_size;
333         bool linked;
334         /*
335         Keep here extended verification result in debug mode:
336         in case of verification problems, save bitmap of instructions
337         that were successfully verified with contexts at the beginnings of
338         unverified blocks to debug them
339         */
340         const panda_file::File *file;
341         panda_file::File::EntityId file_id;
342 
GetNameCachedMethod343         PandaString GetName() const
344         {
345             return CacheOfRuntimeThings::GetName(*this);
346         }
347 
GetClassCachedMethod348         const CachedClass &GetClass() const
349         {
350             ASSERT(Valid(GetRef(klass)));
351             return GetRef(klass);
352         }
353 
IsStaticCachedMethod354         bool IsStatic() const
355         {
356             return flags[Flag::STATIC];
357         }
358     };
359 
360     struct CachedField {
361         using Ref = std::reference_wrapper<const CachedField>;
362         enum class Flag { PUBLIC, PRIVATE, PROTECTED, STATIC, VOLATILE, FINAL };
363         using FlagsValue = FlagsForEnum<unsigned int, Flag, Flag::PUBLIC, Flag::PRIVATE, Flag::PROTECTED, Flag::STATIC,
364                                         Flag::VOLATILE, Flag::FINAL>;
365         Id id;
366         FieldHash hash;
367         DescriptorString name;
368         CachedClass::Ref klass;
369         CachedClass::RefOrDescriptor type;
370         FlagsValue flags;
371         bool linked;
372         const panda_file::File *file;
373         panda_file::File::EntityId file_id;
374 
GetNameCachedField375         PandaString GetName() const
376         {
377             return CacheOfRuntimeThings::GetName(*this);
378         }
379 
GetClassCachedField380         const CachedClass &GetClass() const
381         {
382             ASSERT(Valid(GetRef(klass)));
383             return GetRef(klass);
384         }
385 
GetTypeCachedField386         const CachedClass &GetType() const
387         {
388             ASSERT(IsRef(type));
389             ASSERT(Valid(IsRef(type)));
390             return GetRef(type);
391         }
392     };
393 
394     CacheOfRuntimeThings() = default;
395     CacheOfRuntimeThings(const CacheOfRuntimeThings &) = delete;
396     CacheOfRuntimeThings(CacheOfRuntimeThings &&) = delete;
397     CacheOfRuntimeThings &operator=(const CacheOfRuntimeThings &) = delete;
398     CacheOfRuntimeThings &operator=(CacheOfRuntimeThings &&) = delete;
399     ~CacheOfRuntimeThings() = default;
400 
401     template <typename Access>
402     class FastAPIClass;
403 
404     using ClassCache = PandaUnorderedMap<Id, CachedClass>;
405     using MethodCache = PandaUnorderedMap<Id, CachedMethod>;
406     using FieldCache = PandaUnorderedMap<Id, CachedField>;
407     using DescriptorLookup = PandaUnorderedMap<DescriptorString, CachedClass::Ref>;
408     using FileCache = FileEntityCache<CachedClass, CachedMethod, CachedField>;
409     using FileIndexTableCache = IndexTableCache<ClassIndex, MethodIndex, FieldIndex>;
410 
411     struct LangContext {
412         ClassCache class_cache;
413         MethodCache method_cache;
414         FieldCache field_cache;
415         PrimitiveClassesArray primitive_classes;
416         DescriptorLookup descr_lookup;
417         FileCache file_cache;
418         FileIndexTableCache index_table_cache;
419         DescriptorString string_descr;
420         DescriptorString object_descr;
421         DescriptorString string_array_descr;
422     };
423 
424     using Data = EnumArraySimple<LangContext, panda_file::SourceLang, panda_file::SourceLang::ECMASCRIPT,
425                                  panda_file::SourceLang::PANDA_ASSEMBLY>;
426 
427     using SyncData = Synchronized<Data, FastAPIClass<access::ReadOnly>, FastAPIClass<access::ReadWrite>>;
428 
429     template <typename Access>
430     class FastAPIClass {
431         ACCESS_IS_READONLY_OR_READWRITE(Access);
432 
433         SyncData &data_;
434         const panda::CoreLanguageContext &core_lang_ctx;
435 
FastAPIClass(CacheOfRuntimeThings & cache)436         explicit FastAPIClass(CacheOfRuntimeThings &cache) : data_ {cache.data_}, core_lang_ctx {cache.core_lang_ctx}
437         {
438             if constexpr (access::if_readonly<Access>) {
439                 data_.ReadLock();
440             } else {
441                 data_.WriteLock();
442             }
443         }
444 
445         friend class CacheOfRuntimeThings;
446 
447     public:
~FastAPIClass()448         ~FastAPIClass()
449         {
450             data_.Unlock();
451         }
452 
453         const panda::LanguageContextBase &GetLanguageContextBase(panda_file::SourceLang) const;
454 
GetContext(panda_file::SourceLang src_lang)455         const LangContext &GetContext(panda_file::SourceLang src_lang) const
456         {
457             return data_.GetObj()[src_lang];
458         }
GetContext(panda_file::SourceLang src_lang)459         LangContext &GetContext(panda_file::SourceLang src_lang)
460         {
461             return data_.GetObj()[src_lang];
462         }
463 
464         const CachedClass &GetStringClass(const CachedMethod &method);
465         const CachedClass &GetStringArrayClass(const CachedMethod &method);
466 
467         CachedClass &MakeSyntheticClass(panda_file::SourceLang, const uint8_t *, panda_file::Type::TypeId, uint32_t);
468 
469         CachedMethod &MakeSyntheticMethod(CachedClass &, const uint8_t *name,
470                                           const std::function<void(CachedClass &, CachedMethod &)> &);
471 
472         CachedMethod &AddArrayCtor(CachedClass &array);
473         CachedClass &AddArray(panda_file::SourceLang, const uint8_t *);
474 
475         CachedClass &ResolveByDescriptor(panda_file::SourceLang, const DescriptorString &);
476 
477         void InitializePandaAssemblyRootClasses();
478 
479         void ProcessFile(const panda_file::File *pf);
480 
481         const CachedClass &GetPrimitiveClass(panda_file::SourceLang, panda_file::Type::TypeId) const;
482 
483         template <typename CachedEntity>
484         CachedEntity &GetFromCache(panda_file::SourceLang, Id id);
485 
486         template <typename CachedEntity>
487         const CachedEntity &GetFromCache(const CachedMethod &, uint16_t idx);
488 
489         template <typename CachedEntity>
490         CachedEntity &Link(CachedEntity &);
491 
492         CachedClass &AddToCache(const panda_file::File *, panda_file::File::EntityId);
493         CachedMethod &AddToCache(const CachedClass &, const panda_file::File *, const panda_file::MethodDataAccessor &);
494         CachedField &AddToCache(const CachedClass &, const panda_file::File *, const panda_file::FieldDataAccessor &);
495 
496     private:
497         void InitializePandaAssemblyPrimitiveRoot(panda_file::Type::TypeId type_id);
498 
499         CachedClass &LinkArrayClass(CachedClass &);
500 
501         void LinkCatchBlocks(CachedMethod &);
502 
503         const CachedMethod &ResolveMethod(const CachedMethod &, panda_file::File::EntityId id);
504     };
505 
FastAPI()506     FastAPIClass<access::ReadWrite> FastAPI()
507     {
508         return FastAPIClass<access::ReadWrite> {*this};
509     }
510 
FastAPI()511     const FastAPIClass<access::ReadOnly> FastAPI() const
512     {
513         return FastAPIClass<access::ReadOnly> {const_cast<CacheOfRuntimeThings &>(*this)};
514     }
515 
516     template <typename CachedEntity>
GetFromCache(panda_file::SourceLang src_lang,Id id)517     CachedEntity &GetFromCache(panda_file::SourceLang src_lang, Id id)
518     {
519         return FastAPI().GetFromCache<CachedEntity>(src_lang, id);
520     }
521 
522 private:
523     template <typename Access>
524     friend class FastAPIClass;
525     SyncData data_;
526 
527     const panda::CoreLanguageContext core_lang_ctx {};
528 };
529 }  // namespace panda::verifier
530 
531 #endif  // PANDA_VERIFICATION_JOB_QUEUE_CACHE_H_
532