Files
RedHotRoast-ios/HybridCLRData/LocalIl2CppData-OSXEditor/il2cpp/libil2cpp/hybridclr/metadata/VTableSetup.cpp
T
2026-07-17 14:03:00 +08:00

743 lines
25 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "VTableSetup.h"
#include <algorithm>
#include "vm/GlobalMetadata.h"
#include "metadata/GenericMetadata.h"
#include "MetadataModule.h"
namespace hybridclr
{
namespace metadata
{
const Il2CppType* TryInflateIfNeed(const Il2CppType* containerType, const Il2CppType* genericType, const Il2CppType* selfType)
{
if (selfType->type == IL2CPP_TYPE_CLASS || selfType->type == IL2CPP_TYPE_VALUETYPE)
{
if (genericType->data.typeHandle == selfType->data.typeHandle)
{
return containerType;
}
}
return TryInflateIfNeed(containerType, selfType);
}
VTableSetUp* VTableSetUp::InflateVts(Il2CppType2TypeDeclaringTreeMap& cache, VTableSetUp* genericType, const Il2CppType* type)
{
IL2CPP_ASSERT(genericType->_type->data.typeHandle == type->data.generic_class->type->data.typeHandle);
VTableSetUp* tdt = new (HYBRIDCLR_MALLOC_ZERO(sizeof(VTableSetUp))) VTableSetUp();
tdt->_type = type;
tdt->_typeDef = genericType->_typeDef;
tdt->_parent = genericType->_parent ? BuildByType(cache, TryInflateIfNeed(type, genericType->_parent->_type)) : nullptr;
tdt->_name = genericType->_name;
for (VTableSetUp* gintf : genericType->_interfaces)
{
const Il2CppType* intType = TryInflateIfNeed(type, gintf->_type);
VTableSetUp* intf = BuildByType(cache, intType);
tdt->_interfaces.push_back(intf);
}
for (GenericClassMethod& gcm : genericType->_virtualMethods)
{
tdt->_virtualMethods.push_back({ TryInflateIfNeed(type, genericType->_type, gcm.type), gcm.method, gcm.name });
}
for (RawInterfaceOffsetInfo& roi : genericType->_interfaceOffsetInfos)
{
const Il2CppType* intType = TryInflateIfNeed(type, genericType->_type, roi.type);
VTableSetUp* intf = BuildByType(cache, intType);
tdt->_interfaceOffsetInfos.push_back({ intType, intf, roi.offset });
}
for (VirtualMethodImpl& vmi : genericType->_methodImpls)
{
const Il2CppType* declaringType = vmi.type ? TryInflateIfNeed(type, genericType->_type, vmi.type) : nullptr;
tdt->_methodImpls.push_back({ vmi.method, declaringType, vmi.slot /*, vmi.name*/});
}
return tdt;
}
VTableSetUp* VTableSetUp::BuildByType(Il2CppType2TypeDeclaringTreeMap& cache, const Il2CppType* type)
{
auto it = cache.find(type);
if (it != cache.end())
{
return it->second;
}
if (type->type == IL2CPP_TYPE_GENERICINST)
{
const Il2CppType* genericType = type->data.generic_class->type;
IL2CPP_ASSERT(genericType);
VTableSetUp* gdt = BuildByType(cache, genericType);
VTableSetUp* gidt = InflateVts(cache, gdt, type);
return cache[type] = gidt;
}
VTableSetUp* tdt = new (HYBRIDCLR_MALLOC_ZERO(sizeof(VTableSetUp))) VTableSetUp();
const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(type);
const char* ns = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->namespaceIndex);
const char* name = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->nameIndex);
const Il2CppType* parentType = nullptr;
if (typeDef->parentIndex != kInvalidIndex)
{
parentType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->parentIndex);
}
tdt->_type = type;
tdt->_typeDef = typeDef;
tdt->_parent = parentType ? BuildByType(cache, parentType) : nullptr;
tdt->_name = name;
for (uint32_t i = 0; i < typeDef->interfaces_count; i++)
{
const Il2CppType* intType = il2cpp::vm::GlobalMetadata::GetInterfaceFromOffset(typeDef, i);
VTableSetUp* intf = BuildByType(cache, intType);
tdt->_interfaces.push_back(intf);
}
for (uint32_t i = 0; i < typeDef->method_count; i++)
{
const Il2CppMethodDefinition* methodDef = il2cpp::vm::GlobalMetadata::GetMethodDefinitionFromIndex(typeDef->methodStart + i);
const char* methodName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(methodDef->nameIndex);
if (hybridclr::metadata::IsVirtualMethod(methodDef->flags))
{
tdt->_virtualMethods.push_back({ type, methodDef, methodName });
}
}
if (hybridclr::metadata::IsInterface(typeDef->flags))
{
tdt->ComputeInterfaceVtables(cache);
}
else
{
tdt->ComputeVtables(cache);
}
cache[type] = tdt;
return tdt;
}
inline bool IsOverrideMethod(const GenericClassMethod& m1, const GenericClassMethod& m2)
{
return hybridclr::metadata::IsOverrideMethod(m1.type, m1.method, m2.type, m2.method);
}
uint16_t FindLastSameMethod(std::vector<GenericClassMethod>& methods, uint32_t maxIdx, const GenericClassMethod& find, bool notSealed)
{
for (uint32_t i = std::min(maxIdx, (uint32_t)methods.size()); i > 0; i--)
{
uint32_t idx = i - 1;
if (methods[idx].method == nullptr)
{
continue;
}
if (IsOverrideMethod(methods[idx], find))
{
return idx;
}
}
return kInvalidIl2CppMethodSlot;
}
bool containeTdt(const std::vector<VTableSetUp*>& trees, VTableSetUp* findTree)
{
for (VTableSetUp* add : trees)
{
if (il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(add->GetType(), findTree->GetType()))
{
return true;
}
}
return false;
}
bool FindType(const std::vector<RawInterfaceOffsetInfo>& interfaceOffsetInfos, const Il2CppType* type, uint16_t& resultIdx)
{
uint16_t idx = 0;
for (auto& ioi : interfaceOffsetInfos)
{
if (il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(type, ioi.type))
{
resultIdx = idx;
return true;
}
++idx;
}
resultIdx = (uint16_t)-1;
return false;
}
void VTableSetUp::ComputeInterfaceVtables(Il2CppType2TypeDeclaringTreeMap& cache)
{
IL2CPP_ASSERT(hybridclr::metadata::IsInterface(_typeDef->flags));
if (IsInterType())
{
uint16_t slotIdx = 0;
for (auto& vm : _virtualMethods)
{
Il2CppMethodDefinition* methodDef = const_cast<Il2CppMethodDefinition*>(vm.method);
IL2CPP_ASSERT(methodDef->slot == slotIdx);
slotIdx++;
}
}
}
void VTableSetUp::ComputeVtables(Il2CppType2TypeDeclaringTreeMap& cache)
{
if (IsInterType())
{
ComputeInterpTypeVtables(cache);
}
else
{
ComputAotTypeVtables(cache);
}
uint16_t idx = 0;
for (auto& vmi : _methodImpls)
{
IL2CPP_ASSERT(vmi.slot == idx);
++idx;
}
}
const Il2CppType* VTableSetUp::FindImplType(const Il2CppMethodDefinition* methodDef)
{
Il2CppTypeDefinition* declarType = (Il2CppTypeDefinition*)il2cpp::vm::GlobalMetadata::GetTypeHandleFromIndex(methodDef->declaringType);
for (VTableSetUp* cur = this; cur; cur = cur->_parent)
{
if (declarType == cur->_typeDef)
{
return cur->_type;
}
for(VTableSetUp* itf : cur->_interfaces)
{
if (declarType == itf->_typeDef)
{
return itf->_type;
}
}
}
TEMP_FORMAT(errMsg, "VTableSetUp::FindImplType can't find impl type for method:%s.%s::%s",
il2cpp::vm::GlobalMetadata::GetStringFromIndex(declarType->namespaceIndex),
il2cpp::vm::GlobalMetadata::GetStringFromIndex(declarType->nameIndex),
il2cpp::vm::GlobalMetadata::GetStringFromIndex(methodDef->nameIndex)
);
RaiseExecutionEngineException(errMsg);
return nullptr;
}
const VTableSetUp* VTableSetUp::FindAncestorTypeTree(const Il2CppType* implType)
{
for (VTableSetUp* cur = this; cur; cur = cur->_parent)
{
if (il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(cur->_type, implType))
{
return cur;
}
}
return nullptr;
}
static void RaiseParentOverridedMethodNotFindException(const Il2CppType* type, const char* methodName)
{
if (!type)
{
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException("type not exists"));
}
const Il2CppTypeDefinition* typeDefinition = GetUnderlyingTypeDefinition(type);
TEMP_FORMAT(errMsg, "VTableSetUp fail. virtual method: %s::%s::%s can't be find in declaring type or parent. It may be stripped by il2cpp",
il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDefinition->namespaceIndex),
il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDefinition->nameIndex),
methodName);
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetMissingMethodException(errMsg));
}
const GenericClassMethod* VTableSetUp::FindImplMethod(const Il2CppType* containerType, const Il2CppMethodDefinition* methodDef, bool throwExceptionIfNotFind)
{
for (VTableSetUp* curTdt = this; curTdt; curTdt = curTdt->_parent)
{
for (int idx = (int)curTdt->_virtualMethods.size() - 1; idx >= 0; idx--)
{
GenericClassMethod& pvm = curTdt->_virtualMethods[idx];
if (hybridclr::metadata::IsOverrideMethod(containerType, methodDef, pvm.type, pvm.method))
{
return &pvm;
}
}
}
if (throwExceptionIfNotFind)
{
RaiseParentOverridedMethodNotFindException(this->_type, il2cpp::vm::GlobalMetadata::GetStringFromIndex(methodDef->nameIndex));
}
return nullptr;
}
void VTableSetUp::ComputAotTypeVtables(Il2CppType2TypeDeclaringTreeMap& cache)
{
for (uint16_t i = 0; i < _typeDef->interface_offsets_count; i++)
{
Il2CppInterfaceOffsetInfo ioi = il2cpp::vm::GlobalMetadata::GetInterfaceOffsetInfo(_typeDef, i);
_interfaceOffsetInfos.push_back({ ioi.interfaceType, BuildByType(cache, ioi.interfaceType), (uint16_t)ioi.offset });
}
int nullVtableSlotCount = 0;
for (uint16_t i = 0; i < _typeDef->vtable_count; i++)
{
const Il2CppMethodDefinition* overideMethodDef = il2cpp::vm::GlobalMetadata::GetMethodDefinitionFromVTableSlot(_typeDef, i);
if (overideMethodDef == nullptr)
{
if (_parent && i < _parent->_typeDef->vtable_count)
{
IL2CPP_ASSERT(_parent->_methodImpls[i].method);
_methodImpls.push_back(_parent->_methodImpls[i]);
}
else
{
_methodImpls.push_back({ nullptr, nullptr, i /*, nullptr*/});
++nullVtableSlotCount;
}
continue;
}
const Il2CppType* implType = FindImplType(overideMethodDef);
const char* methodName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(overideMethodDef->nameIndex);
uint16_t slot = i;
_methodImpls.push_back({ overideMethodDef, implType, slot /*, methodName*/});
}
// il2cpp set vtable slot to nullptr if method is abstract, so we fill correct type and method
if (nullVtableSlotCount > 0)
{
for (GenericClassMethod& gcm : _virtualMethods)
{
IL2CPP_ASSERT(gcm.method->slot != kInvalidIl2CppMethodSlot);
VirtualMethodImpl& vmi = _methodImpls[gcm.method->slot];
if (vmi.method == nullptr)
{
vmi.type = _type;
vmi.method = gcm.method;
//vmi.name = gcm.name;
--nullVtableSlotCount;
}
}
for (VTableSetUp* interf : _interfaces)
{
bool findInterf = false;
for (RawInterfaceOffsetInfo& rioi : _interfaceOffsetInfos)
{
if (IsTypeEqual(interf->_type, rioi.type))
{
for (size_t i = 0; i < interf->_virtualMethods.size(); i++)
{
VirtualMethodImpl& vmi = _methodImpls[rioi.offset + i];
if (vmi.method == nullptr)
{
GenericClassMethod& igcm = interf->_virtualMethods[i];
const GenericClassMethod* implVirtualMethod = FindImplMethod(interf->_type, igcm.method);
IL2CPP_ASSERT(implVirtualMethod);
//vmi.name = igcm.name;
vmi.type = implVirtualMethod->type;
vmi.method = implVirtualMethod->method;
--nullVtableSlotCount;
}
}
findInterf = true;
break;
}
}
IL2CPP_ASSERT(findInterf);
}
IL2CPP_ASSERT(nullVtableSlotCount == 0);
}
IL2CPP_ASSERT(_typeDef->vtable_count == (uint16_t)_methodImpls.size());
}
void VTableSetUp::ApplyOverrideMethod(const GenericClassMethod* overrideParentMethod, const Il2CppMethodDefinition* overrideMethodDef, uint16_t checkOverrideMaxIdx)
{
IL2CPP_ASSERT(overrideParentMethod);
if (overrideParentMethod)
{
IL2CPP_ASSERT(overrideParentMethod->method->slot != kInvalidIl2CppMethodSlot);
//const_cast<Il2CppMethodDefinition*>(vm.method)->slot = overrideParentMethod->method->slot;
uint16_t slotIdx = overrideParentMethod->method->slot;
const Il2CppMethodDefinition* overrideAncestorMethod = _parent->_methodImpls[slotIdx].method;
IL2CPP_ASSERT(overrideAncestorMethod);
VirtualMethodImpl& curImpl = _methodImpls[slotIdx];
curImpl.type = _type;
curImpl.method = overrideMethodDef;
// search hierarchy methods, find match method.
// check override parent virtual methods and
for (uint16_t idx = 0; idx < checkOverrideMaxIdx; idx++)
{
VirtualMethodImpl& vmi = _methodImpls[idx];
if (vmi.method == overrideAncestorMethod)
{
vmi.type = _type;
vmi.method = overrideMethodDef;
}
}
}
}
uint16_t VTableSetUp::FindDefaultOverrideExplicitInterfaceSlot(GenericClassMethod& gcm, const Uin16Set& explicitImplSlots, const std::vector<uint16_t>& implInterfaceOffsetIdxs)
{
uint16_t slot = kInvalidIl2CppMethodSlot;
for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
{
RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
for (uint16_t idx = rioi.offset, end = rioi.offset + (uint16_t)rioi.tree->_virtualMethods.size(); idx < end; idx++)
{
if (explicitImplSlots.find(idx) != explicitImplSlots.end())
{
continue;
}
VirtualMethodImpl& vmi = _methodImpls[idx];
if (IsOverrideMethod(_type, gcm.method, vmi.type, vmi.method))
{
//IL2CPP_ASSERT(impl.body.methodDef->slot == kInvalidIl2CppMethodSlot);
vmi.type = _type;
vmi.method = gcm.method;
slot = idx;
}
}
}
return slot;
}
uint16_t VTableSetUp::FindExplicitOverrideInterfaceSlot(GenericClassMethod& gcm, const Int32ToUin16Map& explicitImplSlots)
{
auto it = explicitImplSlots.find(gcm.method->token);
return it != explicitImplSlots.end() ? it->second : kInvalidIl2CppMethodSlot;
}
void VTableSetUp::InitInterfaceVTable(uint16_t& curOffset, std::vector<uint16_t>& implInterfaceOffsetIdxs)
{
for (VTableSetUp* intTree : _interfaces)
{
const Il2CppType* intType = intTree->_type;
uint16_t overrideIntIdx;
if (!FindType(_parent->_interfaceOffsetInfos, intType, overrideIntIdx))
{
implInterfaceOffsetIdxs.push_back((uint16_t)_interfaceOffsetInfos.size());
_interfaceOffsetInfos.push_back({ intType, intTree, curOffset });
// curOffset += (uint32_t)intTree->_virtualMethods.size();
for (auto& vm : intTree->_virtualMethods)
{
_methodImpls.push_back({ vm.method, intType, curOffset++ /*, vm.name*/});
}
}
else
{
implInterfaceOffsetIdxs.push_back(overrideIntIdx);
}
}
}
static bool IsExpliciteMethodNameMatch(const char* implMethodName, const Il2CppType* targetDeclaringType, const char* targetMethodName)
{
// end with .<methodName>
std::string fullName;
const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(targetDeclaringType);
if (typeDef->namespaceIndex != kStringLiteralIndexInvalid)
{
fullName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->namespaceIndex);
fullName += ".";
}
const char* typeName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->nameIndex);
const char* genericQualifier = strchr(typeName, '`');
if (genericQualifier)
{
fullName.append(typeName, genericQualifier);
}
else
{
fullName += typeName;
}
if (!std::strstr(implMethodName, fullName.c_str()))
{
return false;
}
size_t len1 = std::strlen(implMethodName);
size_t len2 = std::strlen(targetMethodName);
if (len1 < len2 + 1)
{
return false;
}
if (implMethodName[len1 - len2 - 1] != '.')
{
return false;
}
return strcmp(implMethodName + len1 - len2, targetMethodName) == 0;
}
void VTableSetUp::ApplyAOTInterfaceExplicitOverride(const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots,
const Il2CppType* intfType, const Il2CppType* implType, const Il2CppMethodDefinition* implMethod)
{
const char* name1 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(implMethod->nameIndex);
for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
{
RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
if (!il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(rioi.type, intfType))
{
continue;
}
for (uint16_t idx = 0, end = (uint16_t)rioi.tree->_virtualMethods.size(); idx < end; idx++)
{
GenericClassMethod& rvm = rioi.tree->_virtualMethods[idx];
const char* name2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(rvm.method->nameIndex);
if (!IsExpliciteMethodNameMatch(name1, intfType, name2))
{
continue;
}
if (IsOverrideMethodIgnoreName(implType, implMethod, rvm.type, rvm.method))
{
uint16_t slot = (uint16_t)(idx + rioi.offset);
VirtualMethodImpl& ivmi = _methodImpls[slot];
_explicitImplSlots.insert(slot);
explicitImplToken2Slots.insert({ implMethod->token, slot });
ivmi.type = implType;
ivmi.method = implMethod;
//ivmi.name = name1;
return;
}
}
}
}
void VTableSetUp::ApplyExplicitOverride(const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots,
const Il2CppType* declaringType, const Il2CppMethodDefinition* decalringMethod, const Il2CppType* implType, const Il2CppMethodDefinition* implMethod)
{
const char* name1 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(decalringMethod->nameIndex);
for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
{
RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
if (!il2cpp::metadata::Il2CppTypeEqualityComparer::AreEqual(rioi.type, declaringType))
{
continue;
}
for (uint16_t idx = 0, end = (uint16_t)rioi.tree->_virtualMethods.size(); idx < end; idx++)
{
GenericClassMethod& rvm = rioi.tree->_virtualMethods[idx];
const char* name2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(rvm.method->nameIndex);
if (std::strcmp(name1, name2))
{
continue;
}
if (IsOverrideMethodIgnoreName(declaringType, decalringMethod, rvm.type, rvm.method))
{
uint16_t slot = (uint16_t)(idx + rioi.offset);
VirtualMethodImpl& ivmi = _methodImpls[slot];
_explicitImplSlots.insert(slot);
explicitImplToken2Slots.insert({ implMethod->token, slot});
ivmi.type = implType;
ivmi.method = implMethod;
//ivmi.name = il2cpp::vm::GlobalMetadata::GetStringFromIndex(implMethod->nameIndex);
return;
}
}
}
const VTableSetUp* containerTs = FindAncestorTypeTree(declaringType);
if (containerTs)
{
for (int idx = (int)containerTs->_virtualMethods.size() - 1; idx >= 0; idx--)
{
const GenericClassMethod& rvm = containerTs->_virtualMethods[idx];
const char* name2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(rvm.method->nameIndex);
if (std::strcmp(name1, name2) != 0)
{
continue;
}
if (IsOverrideMethodIgnoreName(declaringType, decalringMethod, rvm.type, rvm.method))
{
VirtualMethodImpl& ivmi = _methodImpls[rvm.method->slot];
_explicitImplSlots.insert(rvm.method->slot);
explicitImplToken2Slots.insert({ implMethod->token, rvm.method->slot });
ivmi.type = implType;
ivmi.method = implMethod;
//ivmi.name = il2cpp::vm::GlobalMetadata::GetStringFromIndex(implMethod->nameIndex);
return;
}
}
}
const Il2CppTypeDefinition* typeDefinition = GetUnderlyingTypeDefinition(declaringType);
TEMP_FORMAT(errMsg, "VTableSetUp fail. explicit implemented method: %s::%s::%s can't be find in parent or any interface.",
il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDefinition->namespaceIndex),
il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDefinition->nameIndex),
name1);
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException(errMsg));
}
void VTableSetUp::ApplyTypeExplicitImpls(const Il2CppType* type, const VTableSetUp* tree, const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots)
{
const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(type);
if (IsInterpreterType(typeDef))
{
const il2cpp::utils::dynamic_array<MethodImpl> explicitImpls = MetadataModule::GetImage(typeDef)->GetTypeMethodImplByTypeDefinition(typeDef);
if (type->type != IL2CPP_TYPE_GENERICINST)
{
for (const MethodImpl& mi : explicitImpls)
{
ApplyExplicitOverride(implInterfaceOffsetIdxs, explicitImplToken2Slots, mi.declaration.containerType,
mi.declaration.methodDef, mi.body.containerType, mi.body.methodDef);
}
}
else
{
const Il2CppGenericClass* genericClass = type->data.generic_class;
for (const MethodImpl& mi : explicitImpls)
{
const Il2CppType* containerType = il2cpp::metadata::GenericMetadata::InflateIfNeeded(mi.declaration.containerType, &genericClass->context, true);
const Il2CppType* implType = TryInflateIfNeed(type, type->data.generic_class->type, mi.body.containerType);
ApplyExplicitOverride(implInterfaceOffsetIdxs, explicitImplToken2Slots, containerType,
mi.declaration.methodDef, implType, mi.body.methodDef);
}
}
}
else if (IsInterface(typeDef->flags))
{
// we only need process explicit impls in interface.
// il2cpp doesn't provider any ways to get explicit impls in class.
// so we can only try to find explicit impls by name matching.
for (const GenericClassMethod& gcm : tree->_virtualMethods)
{
// only try to find explicit impls in private methods
uint32_t flags = gcm.method->flags;
if (!IsPrivateMethod(flags) || IsAbstractMethod(flags))
{
continue;
}
for (VTableSetUp* subIntf : tree->_interfaces)
{
ApplyAOTInterfaceExplicitOverride(implInterfaceOffsetIdxs, explicitImplToken2Slots, subIntf->_type, tree->_type, gcm.method);
}
}
}
}
void VTableSetUp::ComputeExplicitImpls(const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots)
{
ApplyTypeExplicitImpls(_type, this, implInterfaceOffsetIdxs, explicitImplToken2Slots);
for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
{
RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
ApplyTypeExplicitImpls(rioi.type, rioi.tree, implInterfaceOffsetIdxs, explicitImplToken2Slots);
}
}
void VTableSetUp::ComputeOverrideParentVirtualMethod(uint16_t& curOffset, const std::vector<uint16_t>& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots)
{
const uint16_t startOffset = curOffset;
// override parent virtual methods and interfaces
for (auto& vm : _virtualMethods)
{
IL2CPP_ASSERT(vm.type == _type);
uint16_t mflags = vm.method->flags;
if (hybridclr::metadata::IsNewSlot(mflags))
{
uint16_t overrideSlotIdx = kInvalidIl2CppMethodSlot;
if (IsSealed(mflags))
{
overrideSlotIdx = FindExplicitOverrideInterfaceSlot(vm, explicitImplToken2Slots);
if (overrideSlotIdx == kInvalidIl2CppMethodSlot && IsPublicMethod(mflags))
{
overrideSlotIdx = FindDefaultOverrideExplicitInterfaceSlot(vm, _explicitImplSlots, implInterfaceOffsetIdxs);
}
}
if (overrideSlotIdx != kInvalidIl2CppMethodSlot)
{
const_cast<Il2CppMethodDefinition*>(vm.method)->slot = overrideSlotIdx;
}
else
{
_methodImpls.push_back({ vm.method, _type, curOffset /*, vm.name*/});
IL2CPP_ASSERT(vm.method->slot == kInvalidIl2CppMethodSlot || vm.method->slot == curOffset);
const_cast<Il2CppMethodDefinition*>(vm.method)->slot = curOffset;
++curOffset;
}
}
else
{
// It's impossible to define private virtual method in c#but it's possible in cli.
// so sometime can't find override in parent
const GenericClassMethod* overrideParentMethod = _parent->FindImplMethod(_type, vm.method, false);
if (overrideParentMethod)
{
IL2CPP_ASSERT(overrideParentMethod->method->slot != kInvalidIl2CppMethodSlot);
const_cast<Il2CppMethodDefinition*>(vm.method)->slot = overrideParentMethod->method->slot;
ApplyOverrideMethod(overrideParentMethod, vm.method, startOffset);
}
else
{
IL2CPP_ASSERT(metadata::IsPrivateMethod(mflags));
_methodImpls.push_back({ vm.method, _type, curOffset /*, vm.name*/});
IL2CPP_ASSERT(vm.method->slot == kInvalidIl2CppMethodSlot || vm.method->slot == curOffset);
const_cast<Il2CppMethodDefinition*>(vm.method)->slot = curOffset;
++curOffset;
}
}
}
}
void VTableSetUp::ComputeInterfaceOverrideByParentVirtualMethod(const std::vector<uint16_t>& implInterfaceOffsetIdxs)
{
for (uint16_t interfaceIdx : implInterfaceOffsetIdxs)
{
RawInterfaceOffsetInfo& rioi = _interfaceOffsetInfos[interfaceIdx];
auto& interfaceVirtualMethods = rioi.tree->_virtualMethods;
for (uint16_t idx = 0, end = (uint16_t)interfaceVirtualMethods.size(); idx < end; idx++)
{
uint16_t slotIdx = (uint16_t)(rioi.offset + idx);
if (isExplicitImplInterfaceSlot(slotIdx))
{
continue;
}
VirtualMethodImpl& vmi = _methodImpls[slotIdx];
// override by virtual method
const GenericClassMethod* implVm = FindImplMethod(rioi.type, interfaceVirtualMethods[idx].method, false);
if (implVm)
{
vmi.type = implVm->type;
vmi.method = implVm->method;
//vmi.name = implVm->name;
}
}
}
}
void VTableSetUp::ComputeInterpTypeVtables(Il2CppType2TypeDeclaringTreeMap& cache)
{
uint16_t curOffset = 0;
if (_parent)
{
curOffset = (uint16_t)_parent->_methodImpls.size();
_methodImpls = _parent->_methodImpls;
_interfaceOffsetInfos = _parent->_interfaceOffsetInfos;
}
std::vector<uint16_t> implInterfaceOffsetIdxs;
InitInterfaceVTable(curOffset, implInterfaceOffsetIdxs);
Int32ToUin16Map explicitImplToken2Slots;
ComputeExplicitImpls(implInterfaceOffsetIdxs, explicitImplToken2Slots);
ComputeOverrideParentVirtualMethod(curOffset, implInterfaceOffsetIdxs, explicitImplToken2Slots);
ComputeInterfaceOverrideByParentVirtualMethod(implInterfaceOffsetIdxs);
}
}
}