diff --git a/huatuo/metadata/Image.cpp b/huatuo/metadata/Image.cpp index 8ebe943..b7daeca 100644 --- a/huatuo/metadata/Image.cpp +++ b/huatuo/metadata/Image.cpp @@ -117,7 +117,8 @@ namespace metadata InitClass(); - InitVtables(); + InitVTables_1(); + InitVTables_2(); } void Image::InitTypeDefs_0() @@ -150,6 +151,21 @@ namespace metadata SET_IL2CPPTYPE_VALUE_TYPE(cppType, isValueType); cppType.data.typeHandle = (Il2CppMetadataTypeHandle)&cur; cur.byvalTypeIndex = AddIl2CppTypeCache(cppType); + + if (IsInterface(cur.flags)) + { + cur.interfaceOffsetsStart = EncodeWithIndex(0); + cur.interface_offsets_count = 0; + cur.vtableStart = EncodeWithIndex(0); + cur.vtable_count = 0; + } + else + { + cur.interfaceOffsetsStart = 0; + cur.interface_offsets_count = 0; + cur.vtableStart = 0; + cur.vtable_count = 0; + } } } @@ -213,7 +229,6 @@ namespace metadata } cur.elementTypeIndex = kInvalidIndex; - cur.vtableStart = kInvalidIndex; } } @@ -944,13 +959,8 @@ namespace metadata { return klass; } - klass = _classList[index]; - if (klass) - { - return klass; - } - klass = il2cpp::vm::GlobalMetadata::FromTypeDefinition(EncodeWithIndex(index)); + IL2CPP_ASSERT(klass->interfaces_count <= klass->interface_offsets_count || _typesDefines[index].interfaceOffsetsStart == 0); il2cpp::os::Atomic::FullMemoryBarrier(); _classList[index] = klass; return klass; diff --git a/huatuo/metadata/Image.h b/huatuo/metadata/Image.h index e06fa75..0ab6e49 100644 --- a/huatuo/metadata/Image.h +++ b/huatuo/metadata/Image.h @@ -474,7 +474,11 @@ namespace metadata void InitEvents(); void InitMethodSemantics(); void InitInterfaces(); - void InitVtables(); + void InitVTables_1(); + void InitVTables_2(); + + void ComputeVTable1(TypeDefinitionDetail* tdd); + void ComputeVTable2(TypeDefinitionDetail* tdd); void SetIl2CppImage(Il2CppImage* image) { @@ -626,6 +630,7 @@ namespace metadata // runtime data std::vector _classList; + Il2CppType2TypeDeclaringTreeMap _cacheTrees; std::unordered_map, void*, TokenGenericContextTypeHash, TokenGenericContextTypeEqual> _token2ResolvedDataCache; il2cpp::gc::AppendOnlyGCHashMap> _il2cppStringCache; diff --git a/huatuo/metadata/Image_Gneric.cpp b/huatuo/metadata/Image_Gneric.cpp index 34af2fa..6574969 100644 --- a/huatuo/metadata/Image_Gneric.cpp +++ b/huatuo/metadata/Image_Gneric.cpp @@ -147,51 +147,126 @@ namespace metadata } } + void Image::ComputeVTable1(TypeDefinitionDetail* tdd) + { + Il2CppTypeDefinition& typeDef = *tdd->typeDef; + if (IsInterface(typeDef.flags) || typeDef.vtableStart != 0) + { + return; + } + const Il2CppType* type = GetIl2CppTypeFromRawIndex(DecodeMetadataIndex(typeDef.byvalTypeIndex)); - void Image::InitVtables() - { - Table& typeDefTb = _tables[(int)TableType::TYPEDEF]; + int32_t vtableCount = 0; - Il2CppType2TypeDeclaringTreeMap cacheTrees; + if (typeDef.parentIndex != kInvalidIndex) + { + const Il2CppType* parentType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef.parentIndex); + const Il2CppTypeDefinition* parentTypeDef = GetUnderlyingTypeDefinition(parentType); + if (IsInterpreterType(parentTypeDef) && parentTypeDef->vtableStart == 0) + { + IL2CPP_ASSERT(DecodeImageIndex(parentTypeDef->byvalTypeIndex) == this->GetIndex()); + ComputeVTable1(&_typeDetails[DecodeMetadataIndex(parentTypeDef->byvalTypeIndex)]); + } + vtableCount += parentTypeDef->vtable_count; + } - for (TypeDefinitionDetail& td : _typeDetails) + for (uint32_t i = 0; i < typeDef.interfaces_count; i++) { - Il2CppTypeDefinition& typeDef = *td.typeDef; - const Il2CppType* type = GetIl2CppTypeFromRawIndex(DecodeMetadataIndex(typeDef.byvalTypeIndex)); - VTableSetUp* typeTree = VTableSetUp::BuildByType(cacheTrees, type); + const Il2CppType* intType = il2cpp::vm::GlobalMetadata::GetInterfaceFromOffset(&typeDef, i); + const Il2CppTypeDefinition* intTypeDef = GetUnderlyingTypeDefinition(intType); + vtableCount += intTypeDef->method_count; + } - if (IsInterface(typeDef.flags)) + for (uint32_t i = 0; i < typeDef.method_count; i++) + { + const Il2CppMethodDefinition* methodDef = il2cpp::vm::GlobalMetadata::GetMethodDefinitionFromIndex(typeDef.methodStart + i); + if (huatuo::metadata::IsVirtualMethod(methodDef->flags)) { - typeDef.interfaceOffsetsStart = EncodeWithIndex(0); - typeDef.interface_offsets_count = 0; - typeDef.vtableStart = EncodeWithIndex(0); - typeDef.vtable_count = 0; - continue; + ++vtableCount; } + } + + typeDef.vtableStart = EncodeWithIndex(0); + // 计算出的vtableCount是一个保守上界,并非准确值. + // 在ComputVTable2中会重新修正 + typeDef.vtable_count = vtableCount; + } - uint32_t offsetsStart = (uint32_t)_interfaceOffsets.size(); + void Image::InitVTables_1() + { + Table& typeDefTb = _tables[(int)TableType::TYPEDEF]; + + for (TypeDefinitionDetail& td : _typeDetails) + { + ComputeVTable1(&td); + } + } - auto& vms = typeTree->GetVirtualMethodImpls(); - IL2CPP_ASSERT(td.vtable.empty()); - td.vtable = vms; + void Image::ComputeVTable2(TypeDefinitionDetail* tdd) + { + Il2CppTypeDefinition& typeDef = *tdd->typeDef; + if (IsInterface(typeDef.flags) || typeDef.interfaceOffsetsStart != 0) + { + return; + } - auto& interfaceOffsetInfos = typeTree->GetInterfaceOffsetInfos(); - for (auto ioi : interfaceOffsetInfos) + if (typeDef.parentIndex != kInvalidIndex) + { + const Il2CppType* parentType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef.parentIndex); + const Il2CppTypeDefinition* parentTypeDef = GetUnderlyingTypeDefinition(parentType); + if (IsInterpreterType(parentTypeDef) && parentTypeDef->interfaceOffsetsStart == 0) { - _interfaceOffsets.push_back({ ioi.type, ioi.offset }); + IL2CPP_ASSERT(DecodeImageIndex(parentTypeDef->byvalTypeIndex) == this->GetIndex()); + ComputeVTable2(&_typeDetails[DecodeMetadataIndex(parentTypeDef->byvalTypeIndex)]); } + } + + const Il2CppType* type = GetIl2CppTypeFromRawIndex(DecodeMetadataIndex(typeDef.byvalTypeIndex)); + VTableSetUp* typeTree = VTableSetUp::BuildByType(_cacheTrees, type); + + uint32_t offsetsStart = (uint32_t)_interfaceOffsets.size(); + + auto& vms = typeTree->GetVirtualMethodImpls(); + IL2CPP_ASSERT(tdd->vtable.empty()); + tdd->vtable = vms; + + auto& interfaceOffsetInfos = typeTree->GetInterfaceOffsetInfos(); + for (auto ioi : interfaceOffsetInfos) + { + _interfaceOffsets.push_back({ ioi.type, ioi.offset }); + } - typeDef.vtableStart = EncodeWithIndex(0); - typeDef.interfaceOffsetsStart = EncodeWithIndex(offsetsStart); - typeDef.vtable_count = (uint16_t)td.vtable.size(); - typeDef.interface_offsets_count = (uint32_t)interfaceOffsetInfos.size(); + typeDef.vtable_count = (uint16_t)vms.size(); + typeDef.interfaceOffsetsStart = EncodeWithIndex(offsetsStart); + typeDef.interface_offsets_count = (uint32_t)interfaceOffsetInfos.size(); + + // klass may create by prev BuildTree + Il2CppClass* klass = _classList[tdd->index]; + if (klass) + { + IL2CPP_ASSERT(klass->vtable_count >= typeDef.vtable_count); + klass->vtable_count = typeDef.vtable_count; + IL2CPP_ASSERT(klass->interface_offsets_count == 0); + klass->interface_offsets_count = typeDef.interface_offsets_count; } - for (auto& e : cacheTrees) + } + + void Image::InitVTables_2() + { + Table& typeDefTb = _tables[(int)TableType::TYPEDEF]; + + for (TypeDefinitionDetail& td : _typeDetails) + { + ComputeVTable2(&td); + } + + for (auto& e : _cacheTrees) { e.second->~VTableSetUp(); IL2CPP_FREE(e.second); } + _cacheTrees.clear(); } diff --git a/huatuo/metadata/VTableSetup.cpp b/huatuo/metadata/VTableSetup.cpp index 658b29a..ffb97ae 100644 --- a/huatuo/metadata/VTableSetup.cpp +++ b/huatuo/metadata/VTableSetup.cpp @@ -84,7 +84,7 @@ namespace metadata // FIXME. cache if (typeDef->parentIndex != kInvalidIndex) { - parentType = TryInflateIfNeed(type, il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->parentIndex)); + parentType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->parentIndex); } tdt->_type = type; tdt->_typeDef = typeDef; @@ -93,7 +93,7 @@ namespace metadata for (uint32_t i = 0; i < typeDef->interfaces_count; i++) { - const Il2CppType* intType = TryInflateIfNeed(type, il2cpp::vm::GlobalMetadata::GetInterfaceFromOffset(typeDef, i)); + const Il2CppType* intType = il2cpp::vm::GlobalMetadata::GetInterfaceFromOffset(typeDef, i); VTableSetUp* intf = BuildByType(cache, intType); tdt->_interfaces.push_back(intf); }