source/FieldCache.cpp (81 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include <Walkers.h> #include <mariana-trench/Assert.h> #include <mariana-trench/FieldCache.h> namespace { /** * Returns all known DexTypes in the hierarchy of `type` (ancestors and * descendents). */ std::unordered_set<const DexType*> types_in_class_hierarchy( const DexType* type, const marianatrench::ClassHierarchies& class_hierarchies) { mt_assert(type != type::java_lang_Object()); const auto* klass = type_class(type); if (klass == nullptr) { // Not an object type, or class does not exist in the APK (might be in // the system jars). No class hierarchy. return std::unordered_set<const DexType*>{}; } // Include self + descendants. auto types = class_hierarchies.extends(type); types.insert(type); // Include inherited types. const auto* super_class_type = klass->get_super_class(); while (super_class_type) { klass = type_class(super_class_type); if (klass == nullptr) { // This can happen if the class does not exist in the APK (e.g. exists in // jar). Stop here. We do not have enough information about `klass`. break; } types.insert(super_class_type); super_class_type = klass->get_super_class(); } return types; } } // namespace namespace marianatrench { FieldCache::FieldCache( const ClassHierarchies& class_hierarchies, const DexStoresVector& stores) { using FieldNameToTypeMap = std::unordered_map<const DexString*, const DexType*>; // Compute map class_type -> field -> type. // Class hierarchy is ignored at this stage. ConcurrentMap<const DexType*, FieldNameToTypeMap> fields_in_class; for (const auto& scope : DexStoreClassesIterator(stores)) { walk::parallel::classes(scope, [&](const DexClass* klass) { FieldNameToTypeMap field_to_type; for (const auto* field : klass->get_all_fields()) { field_to_type.emplace(field->get_name(), field->get_type()); } if (!field_to_type.empty()) { fields_in_class.emplace(klass->get_type(), std::move(field_to_type)); } }); } // Use class hierarchy to compute // class_type -> derived/inherited fields -> type for (const auto& scope : DexStoreClassesIterator(stores)) { walk::parallel::classes(scope, [&](const DexClass* klass) { const auto* type = klass->get_type(); if (type == type::java_lang_Object()) { return; } auto class_types = types_in_class_hierarchy(type, class_hierarchies); FieldTypeMap all_field_types; for (const auto* class_type : class_types) { auto field_types = fields_in_class.find(class_type); if (field_types == fields_in_class.end()) { // No fields in this class. continue; } for (const auto& [field, field_type] : field_types->second) { all_field_types[field].insert(field_type); } } field_cache_.emplace( klass->get_type(), std::make_unique<FieldTypeMap>(std::move(all_field_types))); }); } } const FieldCache::Types& FieldCache::field_types( const DexType* klass, const DexString* field) const { const auto* field_name_to_type = field_cache_.get(klass, /* default */ nullptr); if (field_name_to_type != nullptr) { auto result = field_name_to_type->find(field); if (result != field_name_to_type->end()) { return result->second; } } return empty_types_; } } // namespace marianatrench