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