Skip to content

Commit

Permalink
[fix] 修复泛型类型循环依赖时, 虚表相关数据未正确初始化的bug
Browse files Browse the repository at this point in the history
  • Loading branch information
pirunxi committed May 8, 2022
1 parent 75bae98 commit e2bdc36
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 37 deletions.
26 changes: 18 additions & 8 deletions huatuo/metadata/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ namespace metadata

InitClass();

InitVtables();
InitVTables_1();
InitVTables_2();
}

void Image::InitTypeDefs_0()
Expand Down Expand Up @@ -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;
}
}
}

Expand Down Expand Up @@ -213,7 +229,6 @@ namespace metadata
}

cur.elementTypeIndex = kInvalidIndex;
cur.vtableStart = kInvalidIndex;
}
}

Expand Down Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion huatuo/metadata/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -626,6 +630,7 @@ namespace metadata

// runtime data
std::vector<Il2CppClass*> _classList;
Il2CppType2TypeDeclaringTreeMap _cacheTrees;

std::unordered_map<std::tuple<uint32_t, const Il2CppGenericContext*>, void*, TokenGenericContextTypeHash, TokenGenericContextTypeEqual> _token2ResolvedDataCache;
il2cpp::gc::AppendOnlyGCHashMap<uint32_t, Il2CppString*, std::hash<uint32_t>> _il2cppStringCache;
Expand Down
127 changes: 101 additions & 26 deletions huatuo/metadata/Image_Gneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}


Expand Down
4 changes: 2 additions & 2 deletions huatuo/metadata/VTableSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down

0 comments on commit e2bdc36

Please sign in to comment.