From a1249c8bd73ec4da0838b65f2e5180e386e606a9 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Fri, 15 Aug 2025 13:49:17 -0700 Subject: [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. --- objectivec/objc.cpp | 63 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 25 deletions(-) (limited to 'objectivec/objc.cpp') 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 +#include +#include #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 + requires (std::is_same_v, Ref>) +std::pair> DefineNamedType( + Ref 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> finalizeStructureBuilder( - Ref m_data, StructureBuilder sb, std::string name) + Ref 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> finalizeStructureBuilder( + Ref m_data, StructureBuilder sb, const std::string& name) +{ + return finalizeStructureBuilder(m_data, std::move(sb), QualifiedName(name)); } std::pair> finalizeEnumerationBuilder( - Ref m_data, EnumerationBuilder eb, uint64_t size, QualifiedName name) + Ref 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 m_data, const QualifiedName name, Ref type) +inline QualifiedName defineTypedef(Ref m_data, const QualifiedName& name, Ref 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"); -- cgit v1.3.1