diff options
| author | Mark Rowe <mark@vector35.com> | 2025-08-15 13:49:17 -0700 |
|---|---|---|
| committer | Mark Rowe <mark@vector35.com> | 2025-08-19 20:53:59 -0400 |
| commit | a1249c8bd73ec4da0838b65f2e5180e386e606a9 (patch) | |
| tree | ae85d332a69a171539a93af0ccb2511a74e57fad | |
| parent | 1efada49ae5280dd9a0f68aedaf009c5a54f8c45 (diff) | |
[ObjC] Only define metadata types if they don't already exist on the view
This eliminates a significant amount of wasted work when loading
multiple images containing Objective-C from a shared cache. The time
taken to load 400 images from an iOS shared cache (with an analysis hold
enabled) drops from eight minutes to around six minutes.
| -rw-r--r-- | objectivec/objc.cpp | 63 |
1 files changed, 38 insertions, 25 deletions
diff --git a/objectivec/objc.cpp b/objectivec/objc.cpp index 9d35d5e9..4e36c9ed 100644 --- a/objectivec/objc.cpp +++ b/objectivec/objc.cpp @@ -1,6 +1,8 @@ #include "objc.h" #include "inttypes.h" #include <optional> +#include <string> +#include <type_traits> #define RELEASE_ASSERT(condition) ((condition) ? (void)0 : (std::abort(), (void)0)) @@ -1098,37 +1100,51 @@ void ObjCProcessor::ReadIvarList(ObjCReader* reader, ClassBase& cls, std::string } } +// Returns the type named `name`, creating it via `factory()` and +// defining it on the view if it does not already exist. +template <typename F> + requires (std::is_same_v<std::invoke_result_t<F>, Ref<Type>>) +std::pair<QualifiedName, Ref<Type>> DefineNamedType( + Ref<BinaryView> view, const QualifiedName& name, F&& factory) +{ + auto typeID = Type::GenerateAutoTypeId("objc", name); + if (auto type = view->GetTypeById(typeID)) + return {name, type}; + + auto type = factory(); + auto definedName = view->DefineType(typeID, name, type); + return {definedName, type}; +} std::pair<QualifiedName, Ref<Type>> finalizeStructureBuilder( - Ref<BinaryView> m_data, StructureBuilder sb, std::string name) + Ref<BinaryView> m_data, StructureBuilder sb, const QualifiedName& name) { - auto classTypeStruct = sb.Finalize(); - - QualifiedName classTypeName(name); - auto classTypeId = Type::GenerateAutoTypeId("objc", classTypeName); - auto classType = Type::StructureType(classTypeStruct); - auto classQualName = m_data->DefineType(classTypeId, classTypeName, classType); + return DefineNamedType(m_data, name, [&]() { + auto classTypeStruct = sb.Finalize(); + return Type::StructureType(classTypeStruct); + }); +} - return {classQualName, classType}; +std::pair<QualifiedName, Ref<Type>> finalizeStructureBuilder( + Ref<BinaryView> m_data, StructureBuilder sb, const std::string& name) +{ + return finalizeStructureBuilder(m_data, std::move(sb), QualifiedName(name)); } std::pair<QualifiedName, Ref<Type>> finalizeEnumerationBuilder( - Ref<BinaryView> m_data, EnumerationBuilder eb, uint64_t size, QualifiedName name) + Ref<BinaryView> m_data, EnumerationBuilder eb, uint64_t size, const QualifiedName& name) { - auto enumTypeStruct = eb.Finalize(); - - auto enumTypeId = Type::GenerateAutoTypeId("objc", name); - auto enumType = Type::EnumerationType(enumTypeStruct, size); - auto enumQualName = m_data->DefineType(enumTypeId, name, enumType); - - return {enumQualName, enumType}; + return DefineNamedType(m_data, name, [&]() { + auto enumTypeStruct = eb.Finalize(); + return Type::EnumerationType(enumTypeStruct, size); + }); } -inline QualifiedName defineTypedef(Ref<BinaryView> m_data, const QualifiedName name, Ref<Type> type) +inline QualifiedName defineTypedef(Ref<BinaryView> m_data, const QualifiedName& name, Ref<Type> type) { - auto typeID = Type::GenerateAutoTypeId("objc", name); - m_data->DefineType(typeID, name, type); - return m_data->GetTypeNameById(typeID); + return DefineNamedType(m_data, name, [&]() { + return type; + }).first; } void ObjCProcessor::GenerateClassTypes() @@ -1528,11 +1544,8 @@ void ObjCProcessor::ProcessObjCData() classBuilder.AddMember(Type::PointerType(addrSize, Type::VoidType()), "vtable"); classBuilder.AddMember(Type::PointerType(addrSize, Type::NamedType(m_data, m_typeNames.classRO)), "data"); - auto classTypeStruct = classBuilder.Finalize(); - auto classType = Type::StructureType(classTypeStruct); - auto classQualName = m_data->DefineType(classTypeId, classTypeName, classType); - - m_typeNames.cls = classQualName; + type = finalizeStructureBuilder(m_data, classBuilder, classTypeName); + m_typeNames.cls = type.first; StructureBuilder categoryBuilder; categoryBuilder.AddMember(Type::PointerType(addrSize, Type::IntegerType(1, true)), "category_name"); |
