Files
RedHotRoast-ios/HybridCLRData/LocalIl2CppData-OSXEditor/il2cpp/libil2cpp/hybridclr/metadata/MetadataPool.cpp
T

415 lines
9.6 KiB
C++
Raw Normal View History

2026-07-17 14:03:00 +08:00
#include "MetadataPool.h"
#include "utils/MemoryPool.h"
#include "vm/MetadataAlloc.h"
#include "vm/MetadataLock.h"
#include "vm/GlobalMetadata.h"
#include "MetadataModule.h"
namespace hybridclr
{
namespace metadata
{
using il2cpp::utils::HashUtils;
constexpr int kMaxPrimitiveType = (int)IL2CPP_TYPE_OBJECT;
static bool s_initializedMetadataPool = false;
static Il2CppType s_primitiveTypes[(int)kMaxPrimitiveType + 1];
static Il2CppType s_byRefPrimitiveTypes[(int)kMaxPrimitiveType + 1];
class Il2CppArrayTypeHash
{
public:
size_t operator()(const Il2CppArrayType* t1) const
{
return Hash(t1);
}
static size_t Hash(const Il2CppArrayType* t1);
};
class Il2CppTypeFullHash
{
public:
size_t operator()(const Il2CppType* t1) const
{
return Hash(t1);
}
static size_t Hash(const Il2CppType* t1)
{
size_t hash = t1->type;
hash = HashUtils::Combine(hash, t1->byref);
hash = il2cpp::utils::HashUtils::Combine(hash, t1->attrs);
//hash = il2cpp::utils::HashUtils::Combine(hash, t1->num_mods);
hash = il2cpp::utils::HashUtils::Combine(hash, t1->pinned);
//hash = il2cpp::utils::HashUtils::Combine(hash, t1->valuetype);
switch (t1->type)
{
case IL2CPP_TYPE_VALUETYPE:
case IL2CPP_TYPE_CLASS:
{
return HashUtils::Combine(hash, reinterpret_cast<size_t>(t1->data.typeHandle));
}
case IL2CPP_TYPE_SZARRAY:
case IL2CPP_TYPE_PTR:
{
return HashUtils::Combine(hash, Hash(t1->data.type));
}
case IL2CPP_TYPE_ARRAY:
{
const Il2CppArrayType* a = t1->data.array;
// dont' compute sizes and lobounds
hash = HashUtils::Combine(hash, Il2CppArrayTypeHash::Hash(a));
return hash;
}
case IL2CPP_TYPE_GENERICINST:
{
return HashUtils::Combine(hash, (size_t)t1->data.generic_class);
}
case IL2CPP_TYPE_VAR:
case IL2CPP_TYPE_MVAR:
return HashUtils::Combine(hash, reinterpret_cast<size_t>(t1->data.genericParameterHandle));
default:
return hash;
}
return hash;
}
};
size_t Il2CppArrayTypeHash::Hash(const Il2CppArrayType* t1)
{
size_t hash = t1->rank;
hash = HashUtils::Combine(hash, t1->numsizes);
hash = HashUtils::Combine(hash, t1->numlobounds);
hash = HashUtils::Combine(hash, Il2CppTypeFullHash::Hash(t1->etype));
for (uint8_t i = 0; i < t1->numsizes; ++i)
{
hash = HashUtils::Combine(hash, t1->sizes[i]);
}
for (uint8_t i = 0; i < t1->numlobounds; ++i)
{
hash = HashUtils::Combine(hash, t1->lobounds[i]);
}
return hash;
}
class Il2CppArrayTypeEqualityComparer
{
public:
bool operator()(const Il2CppArrayType* t1, const Il2CppArrayType* t2) const
{
return AreEqual(t1, t2);
}
static bool AreEqual(const Il2CppArrayType* t1, const Il2CppArrayType* t2);
};
class Il2CppTypeFullEqualityComparer
{
public:
bool operator()(const Il2CppType* t1, const Il2CppType* t2) const
{
return AreEqual(t1, t2);
}
static bool AreEqual(const Il2CppType* t1, const Il2CppType* t2)
{
if (t1->type != t2->type)
{
return false;
}
if (t1->byref != t2->byref
|| t1->attrs != t2->attrs
|| t1->pinned != t2->pinned)
{
return false;
}
switch (t1->type)
{
case IL2CPP_TYPE_VALUETYPE:
case IL2CPP_TYPE_CLASS:
return t1->data.typeHandle == t2->data.typeHandle;
case IL2CPP_TYPE_PTR:
case IL2CPP_TYPE_SZARRAY:
return AreEqual(t1->data.type, t2->data.type);
case IL2CPP_TYPE_ARRAY:
{
const Il2CppArrayType* a1 = t1->data.array;
const Il2CppArrayType* a2 = t2->data.array;
return Il2CppArrayTypeEqualityComparer::AreEqual(a1, a2);
}
case IL2CPP_TYPE_GENERICINST:
{
return t1->data.generic_class == t2->data.generic_class;
}
case IL2CPP_TYPE_VAR:
case IL2CPP_TYPE_MVAR:
return t1->data.genericParameterHandle == t2->data.genericParameterHandle;
default:
return true;
}
return true;
}
};
bool Il2CppArrayTypeEqualityComparer::AreEqual(const Il2CppArrayType* a1, const Il2CppArrayType* a2)
{
if (a1->rank != a2->rank || a1->numsizes != a2->numsizes || a1->numlobounds != a2->numlobounds)
{
return false;
}
for (uint8_t i = 0; i < a1->numsizes; ++i)
{
if (a1->sizes[i] != a2->sizes[i])
return false;
}
for (uint8_t i = 0; i < a1->numlobounds; ++i)
{
if (a1->lobounds[i] != a2->lobounds[i])
return false;
}
return Il2CppTypeFullEqualityComparer::AreEqual(a1->etype, a2->etype);
}
class Il2CppArrayTypeHash2
{
public:
size_t operator()(const Il2CppArrayType* t1) const
{
return Hash(t1);
}
static size_t Hash(const Il2CppArrayType* t1)
{
size_t hash = t1->rank;
hash = HashUtils::Combine(hash, Il2CppTypeFullHash::Hash(t1->etype));
return hash;
}
};
class Il2CppArrayTypeEqualityComparer2
{
public:
bool operator()(const Il2CppArrayType* t1, const Il2CppArrayType* t2) const
{
return AreEqual(t1, t2);
}
static bool AreEqual(const Il2CppArrayType* a1, const Il2CppArrayType* a2)
{
if (a1->rank != a2->rank)
{
return false;
}
return Il2CppTypeFullEqualityComparer::AreEqual(a1->etype, a2->etype);
}
};
typedef Il2CppHashSet<const Il2CppType*, Il2CppTypeFullHash, Il2CppTypeFullEqualityComparer> Il2CppTypeHashSet;
static Il2CppTypeHashSet* s_Il2CppTypePool = nullptr;
typedef Il2CppHashSet<const Il2CppArrayType*, Il2CppArrayTypeHash2, Il2CppArrayTypeEqualityComparer2> Il2CppArrayTypeHashSet;
Il2CppArrayTypeHashSet* s_Il2CppArrayTypePool = nullptr;
static void InitMetadataPool()
{
IL2CPP_ASSERT(!s_initializedMetadataPool);
s_initializedMetadataPool = true;
std::memset(s_primitiveTypes, 0, sizeof(s_primitiveTypes));
std::memset(s_byRefPrimitiveTypes, 0, sizeof(s_byRefPrimitiveTypes));
for (int i = 0; i <= kMaxPrimitiveType; i++)
{
Il2CppType& type = s_primitiveTypes[i];
type.type = (Il2CppTypeEnum)i;
bool isValueType = i != IL2CPP_TYPE_OBJECT && i != IL2CPP_TYPE_STRING && i != IL2CPP_TYPE_VOID;
SET_IL2CPPTYPE_VALUE_TYPE(type, isValueType);
Il2CppType& byRefType = s_byRefPrimitiveTypes[i];
byRefType.type = (Il2CppTypeEnum)i;
byRefType.byref = 1;
}
s_Il2CppTypePool = new Il2CppTypeHashSet();
s_Il2CppArrayTypePool = new Il2CppArrayTypeHashSet();
}
static const Il2CppType* TryGetPrimitiveType(const Il2CppType& originalType)
{
if (!s_initializedMetadataPool)
{
InitMetadataPool();
}
if (originalType.attrs || originalType.num_mods || originalType.pinned)
{
return nullptr;
}
Il2CppTypeEnum type = originalType.type;
switch (type)
{
case IL2CPP_TYPE_VOID:
case IL2CPP_TYPE_BOOLEAN:
case IL2CPP_TYPE_CHAR:
case IL2CPP_TYPE_I1:
case IL2CPP_TYPE_U1:
case IL2CPP_TYPE_I2:
case IL2CPP_TYPE_U2:
case IL2CPP_TYPE_I4:
case IL2CPP_TYPE_U4:
case IL2CPP_TYPE_I8:
case IL2CPP_TYPE_U8:
case IL2CPP_TYPE_R4:
case IL2CPP_TYPE_R8:
case IL2CPP_TYPE_STRING:
case IL2CPP_TYPE_I:
case IL2CPP_TYPE_U:
case IL2CPP_TYPE_OBJECT:
return originalType.byref ? s_byRefPrimitiveTypes + (int)type : s_primitiveTypes + (int)type;
case IL2CPP_TYPE_VALUETYPE:
case IL2CPP_TYPE_CLASS:
{
const Il2CppTypeDefinition* typeDef = (const Il2CppTypeDefinition*)originalType.data.typeHandle;
if (typeDef)
{
if (originalType.byref)
{
#if HYBRIDCLR_UNITY_2019
return il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->byrefTypeIndex);
#endif
}
else
{
return il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->byvalTypeIndex);
}
}
return nullptr;
}
default:
return nullptr;
}
}
void MetadataPool::Initialize()
{
//InitMetadataPool();
}
static bool NeedCache(const Il2CppType& originalType)
{
Il2CppTypeEnum type = originalType.type;
switch (type)
{
case IL2CPP_TYPE_VOID:
case IL2CPP_TYPE_BOOLEAN:
case IL2CPP_TYPE_CHAR:
case IL2CPP_TYPE_I1:
case IL2CPP_TYPE_U1:
case IL2CPP_TYPE_I2:
case IL2CPP_TYPE_U2:
case IL2CPP_TYPE_I4:
case IL2CPP_TYPE_U4:
case IL2CPP_TYPE_I8:
case IL2CPP_TYPE_U8:
case IL2CPP_TYPE_R4:
case IL2CPP_TYPE_R8:
case IL2CPP_TYPE_STRING:
case IL2CPP_TYPE_I:
case IL2CPP_TYPE_U:
case IL2CPP_TYPE_OBJECT:
return true;
case IL2CPP_TYPE_PTR:
case IL2CPP_TYPE_SZARRAY:
return NeedCache(*originalType.data.type);
case IL2CPP_TYPE_VALUETYPE:
case IL2CPP_TYPE_CLASS:
{
return originalType.data.typeHandle == nullptr;
}
default:
return false;
}
}
static Il2CppType* DeepCloneIl2CppType(const Il2CppType& type)
{
Il2CppType* newType = MetadataMallocT<Il2CppType>();
*newType = type;
return newType;
}
const Il2CppType* MetadataPool::GetPooledIl2CppType(const Il2CppType& type)
{
const Il2CppType* pooledType = TryGetPrimitiveType(type);
if (pooledType)
{
return pooledType;
}
bool needCache = NeedCache(type);
if (needCache)
{
auto it = s_Il2CppTypePool->find(&type);
if (it != s_Il2CppTypePool->end())
return *it;
}
Il2CppType* newType = DeepCloneIl2CppType(type);
if (needCache)
{
auto ret = s_Il2CppTypePool->insert(newType);
IL2CPP_ASSERT(ret.second);
}
return newType;
}
Il2CppType* MetadataPool::ShallowCloneIl2CppType(const Il2CppType* type)
{
Il2CppType* newType = MetadataMallocT<Il2CppType>();
*newType = *type;
return newType;
}
const Il2CppArrayType* MetadataPool::GetPooledIl2CppArrayType(const Il2CppType* elementType, uint32_t rank)
{
Il2CppArrayType type = {};
type.etype = elementType;
type.rank = rank;
bool needCache = NeedCache(*elementType);
if (needCache)
{
auto it = s_Il2CppArrayTypePool->find(&type);
if (it != s_Il2CppArrayTypePool->end())
return *it;
}
Il2CppArrayType* newType = MetadataMallocT<Il2CppArrayType>();
*newType = type;
if (needCache)
{
auto ret = s_Il2CppArrayTypePool->insert(newType);
IL2CPP_ASSERT(ret.second);
}
return newType;
}
}
}