#include "Image.h"
|
|
#include "vm/ClassInlines.h"
|
#include "vm/Image.h"
|
#include "vm/GlobalMetadata.h"
|
#include "vm/Type.h"
|
#include "vm/Field.h"
|
#include "vm/Object.h"
|
#include "vm/Runtime.h"
|
#include "vm/Array.h"
|
#include "vm/Reflection.h"
|
#include "vm/MetadataLock.h"
|
#include "vm/String.h"
|
#include "metadata/GenericMetadata.h"
|
#include "icalls/mscorlib/System.Reflection/FieldInfo.h"
|
#ifdef HYBRIDCLR_UNITY_2021_OR_NEW
|
#include "icalls/mscorlib/System/RuntimeTypeHandle.h"
|
#else
|
#include "icalls/mscorlib/System.Reflection/PropertyInfo.h"
|
#endif
|
#include "icalls/mscorlib/System/Type.h"
|
#include "utils/StringUtils.h"
|
|
#include "MetadataUtil.h"
|
#include "BlobReader.h"
|
|
namespace hybridclr
|
{
|
namespace metadata
|
{
|
|
static const char* s_netstandardRefs[]
|
{
|
"mscorlib",
|
"System",
|
"System.Core",
|
"System.Numerics",
|
"System.Collections",
|
"System.Collections.Concurrent",
|
"System.Numerics.Vectors",
|
"System.Data",
|
"System.Configuration",
|
"System.IO.Compression",
|
"System.Net",
|
"System.Security",
|
"System.Xml",
|
"System.Xml.Linq",
|
"System.Xml.Serialization",
|
"System.Runtime.Serialization",
|
"System.Json",
|
"System.Diagnostics.Tracing",
|
"System.Net.Http",
|
nullptr,
|
};
|
|
bool Image::IsValueTypeFromToken(TableType tableType, uint32_t rowIndex)
|
{
|
switch (tableType)
|
{
|
case TableType::TYPEREF:
|
{
|
TbTypeRef r = _rawImage.ReadTypeRef(rowIndex);
|
const char* typeNamespace = _rawImage.GetStringFromRawIndex(r.typeNamespace);
|
if (std::strcmp(typeNamespace, "System"))
|
{
|
return false;
|
}
|
const char* typeName = _rawImage.GetStringFromRawIndex(r.typeName);
|
return std::strcmp(typeName, "ValueType") == 0 || std::strcmp(typeName, "Enum") == 0;
|
}
|
default:
|
{
|
return false;
|
}
|
}
|
}
|
|
bool Image::IsThreadStaticCtorToken(TableType tableType, uint32_t rowIndex)
|
{
|
if (tableType != TableType::MEMBERREF)
|
{
|
return false;
|
}
|
TbMemberRef data = _rawImage.ReadMemberRef(rowIndex);
|
TableType parentTableType = DecodeMemberRefParentType(data.classIdx);
|
if (parentTableType != TableType::TYPEREF)
|
{
|
return false;
|
}
|
Il2CppType type = {};
|
ReadTypeFromTypeRef(DecodeMemberRefParentRowIndex(data.classIdx), type);
|
const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(&type);
|
const char* strNamespace = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->namespaceIndex);
|
if (std::strcmp(strNamespace, "System"))
|
{
|
return false;
|
}
|
const char* strName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->nameIndex);
|
return std::strcmp(strName, "ThreadStaticAttribute") == 0;
|
}
|
|
void Image::ReadMemberRefParentFromToken(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex, ResolveMemberRefParent& ret)
|
{
|
ret.parentType = tableType;
|
switch (tableType)
|
{
|
case hybridclr::metadata::TableType::TYPEREF:
|
ReadTypeFromTypeRef(rowIndex, ret.type);
|
break;
|
case hybridclr::metadata::TableType::TYPEDEF:
|
ReadTypeFromTypeDef(rowIndex, ret.type);
|
break;
|
case hybridclr::metadata::TableType::METHOD:
|
RaiseNotSupportedException("ReadMemberRefParentFromToken. from METHOD");
|
break;
|
case hybridclr::metadata::TableType::MODULEREF:
|
RaiseNotSupportedException("ReadMemberRefParentFromToken. from MODULEREF");
|
break;
|
case hybridclr::metadata::TableType::TYPESPEC:
|
ReadTypeFromTypeSpec(klassGenericContainer, methodGenericContainer, rowIndex, ret.type);
|
break;
|
default:
|
{
|
RaiseExecutionEngineException("ReadMemberRefParentFromToken. invalid table type");
|
break;
|
}
|
}
|
}
|
|
#pragma region type
|
|
void Image::ReadArrayType(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, Il2CppArrayType& type)
|
{
|
// FIXME memory leak
|
Il2CppType* eleType = (Il2CppType*)HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppType));
|
ReadType(reader, klassGenericContainer, methodGenericContainer, *eleType);
|
type.etype = eleType;
|
type.rank = reader.ReadCompressedUint32();
|
type.numsizes = reader.ReadCompressedUint32();
|
if (type.numsizes > 0)
|
{
|
type.sizes = (int*)HYBRIDCLR_CALLOC(type.numsizes, sizeof(int));
|
for (uint8_t i = 0; i < type.numsizes; i++)
|
{
|
type.sizes[i] = reader.ReadCompressedUint32();
|
}
|
}
|
else
|
{
|
type.sizes = nullptr;
|
}
|
type.numlobounds = reader.ReadCompressedUint32();
|
if (type.numlobounds > 0)
|
{
|
type.lobounds = (int*)HYBRIDCLR_CALLOC(type.numlobounds, sizeof(int));
|
for (uint8_t i = 0; i < type.numlobounds; i++)
|
{
|
type.lobounds[i] = reader.ReadCompressedInt32();
|
}
|
}
|
else
|
{
|
type.lobounds = nullptr;
|
}
|
}
|
|
void Image::ReadGenericClass(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, Il2CppGenericClass& type)
|
{
|
Il2CppType* genericBase = (Il2CppType*)HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppType));
|
ReadType(reader, klassGenericContainer, methodGenericContainer, *genericBase);
|
IL2CPP_ASSERT(genericBase->type == IL2CPP_TYPE_CLASS || genericBase->type == IL2CPP_TYPE_VALUETYPE);
|
type.type = genericBase;
|
|
uint32_t argc = reader.ReadCompressedUint32();
|
IL2CPP_ASSERT(argc > 0);
|
const Il2CppType** argv = (const Il2CppType**)alloca(argc * sizeof(const Il2CppType*));
|
for (uint32_t i = 0; i < argc; i++)
|
{
|
Il2CppType* argType = (Il2CppType*)HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppType));
|
ReadType(reader, klassGenericContainer, methodGenericContainer, *argType);
|
argv[i] = argType;
|
}
|
const Il2CppGenericInst* genericInst = il2cpp::vm::MetadataCache::GetGenericInst(argv, argc);
|
type.context.class_inst = genericInst;
|
type.context.method_inst = nullptr;
|
}
|
|
void Image::ReadType(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, Il2CppType& type)
|
{
|
readAgain:
|
Il2CppTypeEnum etype = (Il2CppTypeEnum)reader.ReadByte();
|
type.type = etype;
|
switch (etype)
|
{
|
case IL2CPP_TYPE_VOID:
|
break;
|
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:
|
{
|
SET_IL2CPPTYPE_VALUE_TYPE(type, 1);
|
break;
|
}
|
case IL2CPP_TYPE_STRING:
|
break;
|
case IL2CPP_TYPE_PTR:
|
{
|
Il2CppType* ptrType = (Il2CppType*)HYBRIDCLR_MALLOC(sizeof(Il2CppType));
|
*ptrType = {};
|
ReadType(reader, klassGenericContainer, methodGenericContainer, *ptrType);
|
type.data.type = ptrType;
|
SET_IL2CPPTYPE_VALUE_TYPE(type, 1);
|
break;
|
}
|
case IL2CPP_TYPE_BYREF:
|
{
|
type.byref = 1;
|
ReadType(reader, klassGenericContainer, methodGenericContainer, type);
|
break;
|
}
|
case IL2CPP_TYPE_VALUETYPE:
|
case IL2CPP_TYPE_CLASS:
|
{
|
uint32_t codedIndex = reader.ReadCompressedUint32(); // 低2位为type, 高位为index
|
ReadTypeFromToken(klassGenericContainer, methodGenericContainer, DecodeTypeDefOrRefOrSpecCodedIndexTableType(codedIndex), DecodeTypeDefOrRefOrSpecCodedIndexRowIndex(codedIndex), type);
|
SET_IL2CPPTYPE_VALUE_TYPE(type, (etype == IL2CPP_TYPE_VALUETYPE));
|
break;
|
}
|
case IL2CPP_TYPE_ARRAY:
|
{
|
Il2CppArrayType* arrType = (Il2CppArrayType*)HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppArrayType));
|
ReadArrayType(reader, klassGenericContainer, methodGenericContainer, *arrType);
|
type.data.array = arrType;
|
break;
|
}
|
case IL2CPP_TYPE_GENERICINST:
|
{
|
Il2CppGenericClass* genericClass = (Il2CppGenericClass*)HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppGenericClass));
|
ReadGenericClass(reader, klassGenericContainer, methodGenericContainer, *genericClass);
|
type.data.generic_class = genericClass;
|
COPY_IL2CPPTYPE_VALUE_TYPE_FLAG(type, *genericClass->type);
|
break;
|
}
|
case IL2CPP_TYPE_TYPEDBYREF:
|
{
|
SET_IL2CPPTYPE_VALUE_TYPE(type, 1);
|
break;
|
}
|
case IL2CPP_TYPE_I:
|
case IL2CPP_TYPE_U:
|
{
|
SET_IL2CPPTYPE_VALUE_TYPE(type, 1);
|
break;
|
}
|
case IL2CPP_TYPE_FNPTR:
|
{
|
// il2cpp doesn't support FNPTR. il2cpp treats IL2CPP_TYPE_FNPTR as IL2CPP_TYPE_I.
|
// so we handle it as IL2CPP_TYPE_I.
|
//
|
//MethodRefSig* method = new (HYBRIDCLR_MALLOC(sizeof(MethodRefSig))) MethodRefSig();
|
//ReadMethodRefSig(reader, *method);
|
//type.data.method = method;
|
type.type = IL2CPP_TYPE_I;
|
MethodRefSig method = {};
|
ReadMethodRefSig(reader, method);
|
break;
|
}
|
case IL2CPP_TYPE_OBJECT:
|
break;
|
case IL2CPP_TYPE_SZARRAY:
|
{
|
Il2CppType* eleType = (Il2CppType*)HYBRIDCLR_MALLOC(sizeof(Il2CppType));
|
*eleType = {};
|
ReadType(reader, klassGenericContainer, methodGenericContainer, *eleType);
|
type.data.type = eleType;
|
break;
|
}
|
case IL2CPP_TYPE_VAR:
|
{
|
IL2CPP_ASSERT(!klassGenericContainer || !klassGenericContainer->is_method);
|
uint32_t number = reader.ReadCompressedUint32();
|
if (klassGenericContainer)
|
{
|
//IL2CPP_ASSERT(hybridclr::metadata::IsInterpreterIndex(klassGenericContainer->ownerIndex));
|
type.data.genericParameterHandle = il2cpp::vm::GlobalMetadata::GetGenericParameterFromIndex((Il2CppMetadataGenericContainerHandle)klassGenericContainer, number);
|
}
|
else
|
{
|
type.data.__genericParameterIndex = number;
|
}
|
/*Il2CppGenericParameter* gp = (Il2CppGenericParameter*)type.data.genericParameterHandle;
|
IL2CPP_ASSERT(hybridclr::metadata::IsInterpreterIndex(gp->ownerIndex));*/
|
break;
|
}
|
case IL2CPP_TYPE_MVAR:
|
{
|
IL2CPP_ASSERT(!methodGenericContainer || methodGenericContainer->is_method);
|
uint32_t number = reader.ReadCompressedUint32();
|
if (methodGenericContainer)
|
{
|
type.data.genericParameterHandle = il2cpp::vm::GlobalMetadata::GetGenericParameterFromIndex((Il2CppMetadataGenericContainerHandle)methodGenericContainer, number);
|
}
|
else
|
{
|
// method ref can't resolve at that time
|
type.data.__genericParameterIndex = number;
|
}
|
break;
|
}
|
case IL2CPP_TYPE_CMOD_REQD:
|
{
|
++type.num_mods;
|
uint32_t encodeToken = reader.ReadCompressedUint32();
|
Il2CppType modType = {};
|
ReadTypeFromToken(nullptr, nullptr, DecodeTypeDefOrRefOrSpecCodedIndexTableType(encodeToken), DecodeTypeDefOrRefOrSpecCodedIndexRowIndex(encodeToken), modType);
|
IL2CPP_ASSERT(modType.data.typeHandle);
|
const Il2CppTypeDefinition* modTypeDef = (const Il2CppTypeDefinition*)modType.data.typeHandle;
|
const char* modTypeName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(modTypeDef->nameIndex);
|
const char* modTypeNamespace = il2cpp::vm::GlobalMetadata::GetStringFromIndex(modTypeDef->namespaceIndex);
|
if (std::strcmp(modTypeNamespace, "System.Runtime.InteropServices") == 0)
|
{
|
if (std::strcmp(modTypeName, "InAttribute") == 0)
|
{
|
type.attrs |= PARAM_ATTRIBUTE_IN;
|
}
|
else if (std::strcmp(modTypeName, "OutAttribute") == 0)
|
{
|
type.attrs |= PARAM_ATTRIBUTE_OUT;
|
}
|
else if (std::strcmp(modTypeName, "OptionalAttribute") == 0)
|
{
|
type.attrs |= PARAM_ATTRIBUTE_OPTIONAL;
|
}
|
}
|
goto readAgain;
|
break;
|
}
|
case IL2CPP_TYPE_CMOD_OPT:
|
{
|
++type.num_mods;
|
uint32_t encodeToken = reader.ReadCompressedUint32();
|
goto readAgain;
|
break;
|
}
|
case IL2CPP_TYPE_INTERNAL:
|
{
|
RaiseNotSupportedException("Image::ReadType IL2CPP_TYPE_INTERNAL");
|
break;
|
}
|
case IL2CPP_TYPE_MODIFIER:
|
{
|
RaiseNotSupportedException("Image::ReadType IL2CPP_TYPE_MODIFIER");
|
break;
|
}
|
case IL2CPP_TYPE_SENTINEL:
|
{
|
break;
|
}
|
case IL2CPP_TYPE_PINNED:
|
{
|
type.pinned = true;
|
ReadType(reader, klassGenericContainer, methodGenericContainer, type);
|
break;
|
}
|
default:
|
{
|
RaiseBadImageException("Image::ReadType invalid type");
|
}
|
break;
|
}
|
}
|
|
void Image::ReadTypeFromResolutionScope(uint32_t scope, uint32_t typeNamespace, uint32_t typeName, Il2CppType& type)
|
{
|
TableType tokenType;
|
uint32_t rawIndex;
|
DecodeResolutionScopeCodedIndex(scope, tokenType, rawIndex);
|
switch (tokenType)
|
{
|
case TableType::MODULE:
|
{
|
GetModuleIl2CppType(type, rawIndex, typeNamespace, typeName, true);
|
break;
|
}
|
case TableType::MODULEREF:
|
{
|
RaiseNotSupportedException("Image::ReadTypeFromResolutionScope not support ResolutionScore.MODULEREF");
|
break;
|
}
|
case TableType::ASSEMBLYREF:
|
{
|
TbAssemblyRef assRef = _rawImage.ReadAssemblyRef(rawIndex);
|
const Il2CppType* refType = GetIl2CppType(rawIndex, typeNamespace, typeName, true);
|
type.type = refType->type;
|
type.data = refType->data;
|
break;
|
}
|
case TableType::TYPEREF:
|
{
|
Il2CppType enClosingType = {};
|
ReadTypeFromTypeRef(rawIndex, enClosingType);
|
IL2CPP_ASSERT(typeNamespace == 0);
|
const char* name = _rawImage.GetStringFromRawIndex(typeName);
|
|
void* iter = nullptr;
|
Il2CppMetadataTypeHandle enclosingTypeDef = enClosingType.data.typeHandle;
|
if (!enclosingTypeDef)
|
{
|
TEMP_FORMAT(errMsg, "Image::ReadTypeFromResolutionScope ReadTypeFromResolutionScope.TYPEREF enclosingType:%s", name);
|
RaiseExecutionEngineException(errMsg);
|
}
|
bool find = false;
|
for (const Il2CppTypeDefinition* nextTypeDef; (nextTypeDef = (const Il2CppTypeDefinition*)il2cpp::vm::GlobalMetadata::GetNestedTypes(enclosingTypeDef, &iter));)
|
{
|
const char* nestedTypeName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(nextTypeDef->nameIndex);
|
IL2CPP_ASSERT(nestedTypeName);
|
if (!std::strcmp(name, nestedTypeName))
|
{
|
GetIl2CppTypeFromTypeDefinition(nextTypeDef, type);
|
find = true;
|
break;
|
}
|
}
|
if (!find)
|
{
|
std::string enclosingTypeName = GetKlassCStringFullName(&enClosingType);
|
TEMP_FORMAT(errMsg, "Image::ReadTypeFromResolutionScope ReadTypeFromResolutionScope.TYPEREF fail. type:%s.%s", enclosingTypeName.c_str(), name);
|
RaiseExecutionEngineException(errMsg);
|
}
|
break;
|
}
|
default:
|
{
|
RaiseBadImageException("Image::ReadTypeFromResolutionScope invaild TableType");
|
break;
|
}
|
}
|
IL2CPP_ASSERT(type.data.typeHandle);
|
}
|
|
void Image::ReadTypeFromTypeDef(uint32_t rowIndex, Il2CppType& type)
|
{
|
const Il2CppType* typeDef = GetIl2CppTypeFromRawTypeDefIndex(rowIndex - 1);
|
type.type = typeDef->type;
|
type.data.typeHandle = typeDef->data.typeHandle;
|
}
|
|
void Image::ReadTypeFromTypeRef(uint32_t rowIndex, Il2CppType& type)
|
{
|
TbTypeRef r = _rawImage.ReadTypeRef(rowIndex);
|
ReadTypeFromResolutionScope(r.resolutionScope, r.typeNamespace, r.typeName, type);
|
}
|
|
void Image::ReadTypeFromTypeSpec(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, uint32_t rowIndex, Il2CppType& type)
|
{
|
TbTypeSpec r = _rawImage.ReadTypeSpec(rowIndex);
|
BlobReader reader = _rawImage.GetBlobReaderByRawIndex(r.signature);
|
ReadType(reader, klassGenericContainer, methodGenericContainer, type);
|
}
|
|
void Image::ReadTypeFromMemberRefParent(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex, Il2CppType& type)
|
{
|
ResolveMemberRefParent mrp = {};
|
ReadMemberRefParentFromToken(klassGenericContainer, methodGenericContainer, tableType, rowIndex, mrp);
|
type = mrp.type;
|
IL2CPP_ASSERT(mrp.parentType == TableType::TYPEDEF || mrp.parentType == TableType::TYPEREF || mrp.parentType == TableType::TYPESPEC);
|
}
|
|
void Image::ReadTypeFromToken(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex, Il2CppType& type)
|
{
|
switch (tableType)
|
{
|
case TableType::TYPEDEF:
|
{
|
ReadTypeFromTypeDef(rowIndex, type);
|
break;
|
}
|
case TableType::TYPEREF:
|
{
|
ReadTypeFromTypeRef(rowIndex, type);
|
break;
|
}
|
case TableType::TYPESPEC:
|
{
|
ReadTypeFromTypeSpec(klassGenericContainer, methodGenericContainer, rowIndex, type);
|
break;
|
}
|
default:
|
{
|
RaiseBadImageException("Image::ReadTypeFromToken invalid TableType");
|
break;
|
}
|
}
|
}
|
|
#pragma endregion
|
|
void Image::ReadFieldRefSig(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, FieldRefSig& field)
|
{
|
field = {};
|
uint8_t rawSigType = reader.ReadByte();
|
SigType sigType = DecodeSigType(rawSigType);
|
IL2CPP_ASSERT(sigType == SigType::FIELD);
|
ReadType(reader, klassGenericContainer, nullptr, field.type);
|
}
|
|
void Image::ReadMethodRefSig(BlobReader& reader, MethodRefSig& method)
|
{
|
method = {};
|
//BlobReader reader = _rawImage.GetBlobReaderByRawIndex(signature);
|
uint8_t rawSigFlags = reader.ReadByte();
|
method.flags = rawSigFlags;
|
if (rawSigFlags & (uint8_t)SigType::GENERIC)
|
{
|
method.genericParamCount = reader.ReadCompressedUint32();
|
}
|
uint32_t paramCount = reader.ReadCompressedUint32();
|
|
ReadType(reader, nullptr, nullptr, method.returnType);
|
|
bool sentinel = false;
|
for (uint32_t readParamNum = 0; readParamNum < paramCount; ++readParamNum)
|
{
|
Il2CppType paramType = {};
|
ReadType(reader, nullptr, nullptr, paramType);
|
if (paramType.type == IL2CPP_TYPE_SENTINEL)
|
{
|
IL2CPP_ASSERT(rawSigFlags & (uint8_t)SigType::VARARG);
|
sentinel = true;
|
continue;
|
}
|
method.params.push_back(paramType);
|
}
|
}
|
|
void Image::ReadMemberRefSig(const Il2CppGenericContainer* klassGenericContainer, TbMemberRef& data, ResolveMemberRefSig& signature)
|
{
|
BlobReader reader = _rawImage.GetBlobReaderByRawIndex(data.signature);
|
uint8_t rawSigFlags = reader.PeekByte();
|
SigType sigType = DecodeSigType(rawSigFlags);
|
if (sigType == SigType::FIELD)
|
{
|
signature.memberType = TableType::FIELD_POINTER;
|
ReadFieldRefSig(reader, klassGenericContainer, signature.field);
|
}
|
else
|
{
|
signature.memberType = TableType::METHOD_POINTER;
|
ReadMethodRefSig(reader, signature.method);
|
}
|
}
|
|
|
void Image::ReadMethodRefInfoFromToken(const Il2CppGenericContainer* klassGenericContainer,
|
const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex, MethodRefInfo& ret)
|
{
|
IL2CPP_ASSERT(rowIndex > 0);
|
switch (tableType)
|
{
|
case TableType::METHOD:
|
{
|
const Il2CppMethodDefinition* methodDef = GetMethodDefinitionFromRawIndex(rowIndex - 1);
|
const Il2CppTypeDefinition* typeDef = (const Il2CppTypeDefinition*)il2cpp::vm::GlobalMetadata::GetTypeHandleFromIndex(methodDef->declaringType);
|
const Il2CppType* type = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->byvalTypeIndex);
|
ret.containerType = *type;
|
ret.methodDef = methodDef;
|
IL2CPP_ASSERT(type);
|
IL2CPP_ASSERT(methodDef);
|
break;
|
}
|
case TableType::MEMBERREF:
|
{
|
ReadMethodRefInfoFromMemberRef(klassGenericContainer, methodGenericContainer, rowIndex, ret);
|
break;
|
}
|
case TableType::METHODSPEC:
|
{
|
TbMethodSpec methodSpec = _rawImage.ReadMethodSpec(rowIndex);
|
|
ReadMethodSpecInstantiation(methodSpec.instantiation, klassGenericContainer, methodGenericContainer, ret.instantiation);
|
//FIXME instantiation memory leak
|
|
TableType methodTableType = DecodeMethodDefOrRefCodedIndexTableType(methodSpec.method);
|
uint32_t methodRowIndex = DecodeMethodDefOrRefCodedIndexRowIndex(methodSpec.method);
|
switch (methodTableType)
|
{
|
case TableType::METHOD:
|
{
|
ReadMethodRefInfoFromToken(klassGenericContainer, methodGenericContainer, methodTableType, methodRowIndex, ret);
|
break;
|
}
|
case TableType::MEMBERREF:
|
{
|
ReadMethodRefInfoFromMemberRef(klassGenericContainer, methodGenericContainer, methodRowIndex, ret);
|
break;
|
}
|
default:
|
{
|
RaiseBadImageException("Image::ReadMethodRefInfoFromToken METHODSPEC invalid TableType");
|
break;
|
}
|
}
|
break;
|
}
|
default:
|
{
|
RaiseBadImageException("Image::ReadMethodRefInfoFromToken invalid TableType");
|
}
|
}
|
}
|
|
void Image::ReadResolveMemberRefFromMemberRef(const Il2CppGenericContainer* klassGenericContainer,
|
const Il2CppGenericContainer* methodGenericContainer, uint32_t rowIndex, ResolveMemberRef& ret)
|
{
|
TbMemberRef data = _rawImage.ReadMemberRef(rowIndex);
|
ret.name = _rawImage.GetStringFromRawIndex(data.name);
|
ReadMemberRefParentFromToken(klassGenericContainer, methodGenericContainer, DecodeMemberRefParentType(data.classIdx), DecodeMemberRefParentRowIndex(data.classIdx), ret.parent);
|
IL2CPP_ASSERT(ret.parent.parentType == TableType::TYPEDEF || ret.parent.parentType == TableType::TYPEREF || ret.parent.parentType == TableType::TYPESPEC);
|
Il2CppType& parentType = ret.parent.type;
|
ReadMemberRefSig(nullptr, data, ret.signature);
|
}
|
|
void Image::ReadMethodRefInfoFromMemberRef(const Il2CppGenericContainer* klassGenericContainer,
|
const Il2CppGenericContainer* methodGenericContainer, uint32_t rowIndex, MethodRefInfo& ret)
|
{
|
ResolveMemberRef rmr = {};
|
ReadResolveMemberRefFromMemberRef(klassGenericContainer, methodGenericContainer, rowIndex, rmr);
|
IL2CPP_ASSERT(rmr.parent.parentType == TableType::TYPEDEF || rmr.parent.parentType == TableType::TYPEREF || rmr.parent.parentType == TableType::TYPESPEC);
|
IL2CPP_ASSERT(rmr.signature.memberType == TableType::METHOD_POINTER);
|
ret.containerType = rmr.parent.type;
|
ret.methodDef = ResolveMethodDefinition(&rmr.parent.type, rmr.name, rmr.signature.method);
|
}
|
|
void Image::ReadMethodSpecInstantiation(uint32_t signature, const Il2CppGenericContainer* klassGenericContainer,
|
const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericInst*& genericInstantiation)
|
{
|
BlobReader reader = _rawImage.GetBlobReaderByRawIndex(signature);
|
uint8_t rawSigFlags = reader.ReadByte();
|
IL2CPP_ASSERT(rawSigFlags == 0xA);
|
uint32_t argCount = reader.ReadCompressedUint32();
|
IL2CPP_ASSERT(argCount >= 0 && argCount < 100);
|
if (argCount == 0)
|
{
|
genericInstantiation = nullptr;
|
return;
|
}
|
|
const Il2CppType** type_argv = (const Il2CppType**)alloca(argCount * sizeof(Il2CppType*));
|
for (uint32_t i = 0; i < argCount; i++)
|
{
|
Il2CppType* type = (Il2CppType*)HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppType));
|
ReadType(reader, klassGenericContainer, methodGenericContainer, *type);
|
type_argv[i] = type;
|
}
|
genericInstantiation = il2cpp::vm::MetadataCache::GetGenericInst(type_argv, argCount);
|
}
|
|
void Image::ReadFieldRefInfoFromMemberRef(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, uint32_t rowIndex, FieldRefInfo& ret)
|
{
|
ResolveMemberRef rmr = {};
|
ReadResolveMemberRefFromMemberRef(klassGenericContainer, methodGenericContainer, rowIndex, rmr);
|
IL2CPP_ASSERT(rmr.parent.parentType == TableType::TYPEDEF || rmr.parent.parentType == TableType::TYPEREF || rmr.parent.parentType == TableType::TYPESPEC);
|
IL2CPP_ASSERT(rmr.signature.memberType == TableType::FIELD_POINTER);
|
ret.containerType = rmr.parent.type;
|
ResolveFieldThrow(&rmr.parent.type, rmr.name, &rmr.signature.field.type, ret.field);
|
}
|
|
void Image::ReadLocalVarSig(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, Il2CppType*& vars, uint32_t& varCount)
|
{
|
uint8_t sig = reader.ReadByte();
|
IL2CPP_ASSERT(sig == 0x7);
|
varCount = reader.ReadCompressedUint32();
|
IL2CPP_ASSERT(varCount >= 1 && varCount <= 0xFFFE);
|
vars = (Il2CppType*)HYBRIDCLR_MALLOC_ZERO(varCount * sizeof(Il2CppType));
|
for (uint32_t i = 0; i < varCount; i++)
|
{
|
ReadType(reader, klassGenericContainer, methodGenericContainer, vars[i]);
|
}
|
}
|
|
void Image::ReadStandAloneSig(uint32_t signatureIdx, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, ResolveStandAloneMethodSig& methodSig)
|
{
|
BlobReader reader = _rawImage.GetBlobReaderByRawIndex(signatureIdx);
|
uint8_t sig = reader.ReadByte();
|
methodSig.flags = sig;
|
uint32_t paramCount = reader.ReadCompressedUint32();
|
if (paramCount > 0xFFFE)
|
{
|
RaiseBadImageException("ReadStandAloneSig exceed max param count");
|
}
|
methodSig.paramCount = paramCount;
|
ReadType(reader, klassGenericContainer, methodGenericContainer, methodSig.returnType);
|
if (paramCount > 0)
|
{
|
Il2CppType* params = (Il2CppType*)HYBRIDCLR_MALLOC_ZERO(paramCount * sizeof(Il2CppType));
|
for (uint32_t i = 0; i < paramCount; i++)
|
{
|
ReadType(reader, klassGenericContainer, methodGenericContainer, params[i]);
|
}
|
methodSig.params = params;
|
}
|
else
|
{
|
methodSig.params = nullptr;
|
}
|
if (reader.NonEmpty())
|
{
|
RaiseNotSupportedException("ReadStandAloneSig don't support sentinel params");
|
}
|
}
|
|
Il2CppClass* Image::FindNetStandardExportedType(const char* namespaceStr, const char* nameStr)
|
{
|
for (const char** ptrAssName = s_netstandardRefs; *ptrAssName; ptrAssName++)
|
{
|
const Il2CppAssembly* refAss = GetLoadedAssembly(*ptrAssName);
|
if (refAss)
|
{
|
const Il2CppImage* image2 = il2cpp::vm::Assembly::GetImage(refAss);
|
Il2CppClass* klass = il2cpp::vm::Class::FromName(image2, namespaceStr, nameStr);
|
if (klass)
|
{
|
return klass;
|
}
|
}
|
}
|
return nullptr;
|
}
|
|
const Il2CppType* Image::GetIl2CppType(uint32_t assemblyRefIndex, uint32_t typeNamespace, uint32_t typeName, bool raiseExceptionIfNotFound)
|
{
|
TbAssemblyRef data = _rawImage.ReadAssemblyRef(assemblyRefIndex);
|
const char* assName = _rawImage.GetStringFromRawIndex(data.name);
|
const char* typeNameStr = _rawImage.GetStringFromRawIndex(typeName);
|
const char* typeNamespaceStr = _rawImage.GetStringFromRawIndex(typeNamespace);
|
const Il2CppAssembly* refAss = GetLoadedAssembly(assName);
|
Il2CppClass* klass = nullptr;
|
if (refAss)
|
{
|
const Il2CppImage* image2 = il2cpp::vm::Assembly::GetImage(refAss);
|
klass = il2cpp::vm::Class::FromName(image2, typeNamespaceStr, typeNameStr);
|
}
|
else if (!refAss && std::strcmp(assName, "netstandard") == 0)
|
{
|
klass = FindNetStandardExportedType(typeNamespaceStr, typeNameStr);
|
}
|
if (!klass)
|
{
|
if (!raiseExceptionIfNotFound)
|
{
|
return nullptr;
|
}
|
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException(
|
CStringToStringView(typeNamespaceStr),
|
CStringToStringView(typeNameStr),
|
CStringToStringView(assName)));
|
}
|
return &klass->byval_arg;
|
}
|
|
void Image::ReadMethodBody(const Il2CppMethodDefinition& methodDef, const TbMethod& methodData, MethodBody& body)
|
{
|
uint32_t bodyRVA = methodData.rva;
|
if (bodyRVA > 0)
|
{
|
uint32_t methodImageOffset = 0;
|
bool ret = _rawImage.TranslateRVAToImageOffset(bodyRVA, methodImageOffset);
|
IL2CPP_ASSERT(ret);
|
const byte* bodyStart = _rawImage.GetDataPtrByImageOffset(methodImageOffset);
|
byte bodyFlags = *bodyStart;
|
byte smallFatFlags = bodyFlags & 0x3;
|
|
if (smallFatFlags == (uint8_t)CorILMethodFormat::Tiny)
|
{
|
body.flags = (uint32_t)(bodyFlags & 0x3);
|
body.ilcodes = bodyStart + 1;
|
body.codeSize = (uint8_t)bodyFlags >> 2;
|
body.maxStack = 8;
|
body.localVarCount = 0;
|
body.localVars = nullptr;
|
}
|
else
|
{
|
IL2CPP_ASSERT(smallFatFlags == (uint8_t)CorILMethodFormat::Fat);
|
const CorILMethodFatHeader* methodHeader = (const CorILMethodFatHeader*)GetAlignBorder<4>(bodyStart);
|
IL2CPP_ASSERT(methodHeader->size == 3);
|
body.flags = methodHeader->flags;
|
body.ilcodes = bodyStart + methodHeader->size * 4;
|
body.codeSize = methodHeader->codeSize;
|
body.maxStack = methodHeader->maxStack;
|
|
if (methodHeader->localVarSigToken)
|
{
|
TbStandAloneSig sigData = _rawImage.ReadStandAloneSig(DecodeTokenRowIndex(methodHeader->localVarSigToken));
|
|
BlobReader reader = _rawImage.GetBlobReaderByRawIndex(sigData.signature);
|
ReadLocalVarSig(reader,
|
GetGenericContainerByTypeDefRawIndex(DecodeMetadataIndex(methodDef.declaringType)),
|
GetGenericContainerByRawIndex(DecodeMetadataIndex(methodDef.genericContainerIndex)),
|
body.localVars, body.localVarCount);
|
}
|
}
|
if (body.flags & (uint8_t)CorILMethodFormat::MoreSects)
|
{
|
const byte* nextSection = (const byte*)GetAlignBorder<4>(body.ilcodes + body.codeSize);
|
while (true)
|
{
|
byte kind = *nextSection;
|
if (!(kind & (byte)CorILSecion::EHTable))
|
{
|
IL2CPP_ASSERT(false && "not support kind");
|
break;
|
}
|
if (kind & (byte)CorILSecion::FatFormat)
|
{
|
CorILEHSectionHeaderFat* ehSec = (CorILEHSectionHeaderFat*)nextSection;
|
uint32_t dataSize = (uint32_t)ehSec->dataSize0 | ((uint32_t)ehSec->dataSize1 << 8) | ((uint32_t)ehSec->dataSize2 << 16);
|
IL2CPP_ASSERT(dataSize % 24 == 4);
|
uint32_t ehCount = (dataSize - 4) / 24;
|
body.exceptionClauses.reserve(ehCount);
|
for (uint32_t i = 0; i < ehCount; i++)
|
{
|
CorILEHFat& eh = ehSec->clauses[i];
|
IL2CPP_ASSERT(eh.flags >= (uint32_t)CorILExceptionClauseType::Exception && eh.flags <= (uint32_t)CorILExceptionClauseType::Fault);
|
body.exceptionClauses.push_back({
|
(CorILExceptionClauseType)eh.flags,
|
eh.tryOffset,
|
eh.tryLength,
|
eh.handlerOffset,
|
eh.handlerLength,
|
eh.classTokenOrFilterOffset });
|
}
|
nextSection += dataSize;
|
}
|
else
|
{
|
CorILEHSectionHeaderSmall* ehSec = (CorILEHSectionHeaderSmall*)nextSection;
|
IL2CPP_ASSERT(ehSec->dataSize % 12 == 4);
|
uint32_t ehCount = (ehSec->dataSize - 4) / 12;
|
body.exceptionClauses.reserve(ehCount);
|
for (uint32_t i = 0; i < ehCount; i++)
|
{
|
CorILEHSmall& eh = ehSec->clauses[i];
|
IL2CPP_ASSERT(eh.flags >= 0 && eh.flags <= 4);
|
body.exceptionClauses.push_back({
|
(CorILExceptionClauseType)eh.flags,
|
eh.tryOffset,
|
eh.tryLength,
|
((uint32_t)eh.handlerOffset1 << 8) + eh.handlerOffset0,
|
eh.handlerLength,
|
eh.classTokenOrFilterOffset });
|
}
|
nextSection += ehSec->dataSize;
|
}
|
if (!(kind & (byte)CorILSecion::MoreSects))
|
{
|
break;
|
}
|
}
|
}
|
}
|
else
|
{
|
body.ilcodes = nullptr;
|
body.codeSize = 0;
|
}
|
}
|
|
const MethodInfo* Image::FindImplMethod(Il2CppClass* klass, const MethodInfo* method)
|
{
|
if (!IsVirtualMethod(method->flags))
|
{
|
return method;
|
}
|
il2cpp::vm::Class::Init(klass);
|
const MethodInfo* result;
|
if (hybridclr::metadata::IsInterface(method->klass->flags))
|
{
|
result = il2cpp::vm::ClassInlines::GetInterfaceInvokeDataFromVTable(klass, method->klass, method->slot)->method;
|
}
|
else
|
{
|
result = klass->vtable[method->slot].method;
|
}
|
IL2CPP_ASSERT(!method->genericMethod || method->is_inflated);
|
if (method->genericMethod && method->genericMethod->context.method_inst/* && method->genericMethod*/) // means it's genericInstance method 或generic method
|
{
|
result = GetGenericVirtualMethod(result, method);
|
}
|
return result;
|
}
|
|
|
Il2CppString* Image::GetIl2CppUserStringFromRawIndex(StringIndex index)
|
{
|
il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
|
Il2CppString* clrStr;
|
if (_il2cppStringCache.TryGetValue(index, &clrStr))
|
{
|
return clrStr;
|
}
|
else
|
{
|
const byte* str = _rawImage.GetUserStringBlogByIndex((uint32_t)index);
|
uint32_t lengthSize;
|
uint32_t stringLength = BlobReader::ReadCompressedUint32(str, lengthSize);
|
|
Il2CppString* clrStr;
|
if (stringLength == 0)
|
{
|
clrStr = il2cpp::vm::String::Empty();
|
}
|
else
|
{
|
str += lengthSize;
|
IL2CPP_ASSERT(stringLength % 2 == 1);
|
UserStringEncoding charEncoding = (UserStringEncoding)str[stringLength - 1];
|
clrStr = il2cpp::vm::String::NewUtf16((const Il2CppChar*)str, (stringLength - 1) / 2);
|
}
|
#if HYBRIDCLR_UNITY_2022_OR_NEW
|
_il2cppStringCache.GetOrAdd(index, clrStr);
|
#else
|
_il2cppStringCache.Add(index, clrStr);
|
#endif
|
return clrStr;
|
}
|
}
|
|
Il2CppClass* Image::GetClassFromToken(uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext)
|
{
|
auto key = std::tuple<uint32_t, const Il2CppGenericContext*>(token, genericContext);
|
{
|
il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
|
auto it = _token2ResolvedDataCache.find(key);
|
if (it != _token2ResolvedDataCache.end())
|
{
|
return (Il2CppClass*)it->second;
|
}
|
}
|
Il2CppType originType = {};
|
ReadTypeFromToken(klassGenericContainer, methodGenericContainer, DecodeTokenTableType(token), DecodeTokenRowIndex(token), originType);
|
const Il2CppType* resultType = genericContext != nullptr ? il2cpp::metadata::GenericMetadata::InflateIfNeeded(&originType, genericContext, true) : &originType;
|
Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(resultType);
|
if (!klass)
|
{
|
TEMP_FORMAT(errMsg, "InterpreterImage::GetClassFromToken token:%u class not exists", token);
|
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException(errMsg));
|
}
|
// FIXME free resultType
|
{
|
il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
|
_token2ResolvedDataCache.insert({ key, (void*)klass });
|
}
|
return klass;
|
}
|
|
const FieldInfo* Image::GetFieldInfoFromFieldRef(const Il2CppType& type, const Il2CppFieldDefinition* fieldDef)
|
{
|
Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(&type);
|
const char* name = il2cpp::vm::GlobalMetadata::GetStringFromIndex(fieldDef->nameIndex);
|
void* iter = nullptr;
|
for (const FieldInfo* cur = nullptr; (cur = il2cpp::vm::Class::GetFields(klass, &iter)) != nullptr; )
|
{
|
if (cur->token == fieldDef->token)
|
{
|
IL2CPP_ASSERT(std::strcmp(cur->name, name) == 0);
|
return cur;
|
}
|
}
|
RaiseMissingFieldException(&type, name);
|
return nullptr;
|
}
|
|
const MethodInfo* Image::ResolveMethodInfo(const Il2CppType* type, const char* resolveMethodName, const MethodRefSig& resolveSig, const Il2CppGenericInst* genericInstantiation, const Il2CppGenericContext* genericContext)
|
{
|
if (type->type != IL2CPP_TYPE_ARRAY)
|
{
|
const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(type);
|
const Il2CppGenericContainer* klassGenericContainer = GetGenericContainerFromIl2CppType(type);
|
const char* typeName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->nameIndex);
|
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);
|
IL2CPP_ASSERT((genericInstantiation ? genericInstantiation->type_argc : 0) == resolveSig.genericParamCount);
|
if (std::strcmp(resolveMethodName, methodName) == 0 && IsMatchMethodSig(methodDef, resolveSig, klassGenericContainer))
|
{
|
return GetMethodInfo(type, methodDef, genericInstantiation, genericContext);
|
}
|
}
|
}
|
else
|
{
|
IL2CPP_ASSERT(genericInstantiation == nullptr);
|
Il2CppClass* arrayKlass = il2cpp::vm::Class::FromIl2CppType(type);
|
il2cpp::vm::Class::SetupMethods(arrayKlass);
|
//const Il2CppType* genericClassInstArgv[] = { &arrayKlass->element_class->byval_arg };
|
const Il2CppType** genericClassInstArgv = genericContext && genericContext->class_inst ? genericContext->class_inst->type_argv : nullptr;
|
const Il2CppType** genericMethodInstArgv = genericContext && genericContext->method_inst ? genericContext->method_inst->type_argv : nullptr;
|
|
// FIXME MEMORY LEAK
|
for (uint16_t i = 0; i < arrayKlass->method_count; i++)
|
{
|
const MethodInfo* method = arrayKlass->methods[i];
|
if (std::strcmp(resolveMethodName, method->name) == 0 && IsMatchMethodSig(method, resolveSig, genericClassInstArgv, genericMethodInstArgv))
|
{
|
return method;
|
}
|
}
|
}
|
RaiseMethodNotFindException(type, resolveMethodName);
|
return nullptr;
|
}
|
|
const void* Image::ReadRuntimeHandleFromMemberRef(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext, uint32_t rowIndex)
|
{
|
|
ResolveMemberRef rmr = {};
|
ReadResolveMemberRefFromMemberRef(klassGenericContainer, methodGenericContainer, rowIndex, rmr);
|
if (rmr.signature.memberType == TableType::FIELD_POINTER)
|
{
|
const Il2CppFieldDefinition* fieldDef = nullptr;
|
ResolveFieldThrow(&rmr.parent.type, rmr.name, &rmr.signature.field.type, fieldDef);
|
if (!fieldDef)
|
{
|
RaiseMissingFieldException(&rmr.parent.type, rmr.name);
|
}
|
const FieldInfo* fieldInfo = GetFieldInfoFromFieldRef(rmr.parent.type, fieldDef);
|
return fieldInfo;
|
}
|
else if (rmr.signature.memberType == TableType::METHOD_POINTER)
|
{
|
if (genericContext)
|
{
|
rmr.parent.type = *TryInflateIfNeed(&rmr.parent.type, genericContext, true);
|
}
|
return ResolveMethodInfo(&rmr.parent.type, rmr.name, rmr.signature.method, nullptr, genericContext);
|
}
|
else
|
{
|
RaiseExecutionEngineException("GetRuntimeHandleFromToken invaild ParentType");
|
return nullptr;
|
}
|
}
|
|
const void* Image::GetRuntimeHandleFromToken(uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext)
|
{
|
TableType ttype = DecodeTokenTableType(token);
|
uint32_t rowIndex = DecodeTokenRowIndex(token);
|
switch (ttype)
|
{
|
case hybridclr::metadata::TableType::TYPEREF:
|
case hybridclr::metadata::TableType::TYPEDEF:
|
case hybridclr::metadata::TableType::TYPESPEC:
|
{
|
// TODO cache
|
Il2CppType* type = (Il2CppType*)HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppType));
|
ReadTypeFromToken(klassGenericContainer, methodGenericContainer, ttype, rowIndex, *type);
|
if (genericContext)
|
{
|
type = const_cast<Il2CppType*>(TryInflateIfNeed(type, genericContext, true));
|
}
|
return type;
|
}
|
case hybridclr::metadata::TableType::FIELD:
|
{
|
return GetFieldInfoFromToken(token, klassGenericContainer, methodGenericContainer, genericContext);
|
}
|
case hybridclr::metadata::TableType::METHOD:
|
case hybridclr::metadata::TableType::METHODSPEC:
|
{
|
return GetMethodInfoFromToken(token, klassGenericContainer, methodGenericContainer, genericContext);
|
}
|
case hybridclr::metadata::TableType::MEMBERREF:
|
{
|
const void* handle = ReadRuntimeHandleFromMemberRef(klassGenericContainer, methodGenericContainer, genericContext, rowIndex);
|
//_token2RuntimeHandleCache.insert({ key, (void*)handle });
|
return handle;
|
}
|
default:
|
{
|
RaiseExecutionEngineException("GetRuntimeHandleFromToken invaild TableType");
|
return nullptr;
|
}
|
}
|
}
|
|
const FieldInfo* Image::GetFieldInfoFromToken(uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext)
|
{
|
auto key = std::tuple<uint32_t, const Il2CppGenericContext*>(token, genericContext);
|
{
|
il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
|
auto it = _token2ResolvedDataCache.find(key);
|
if (it != _token2ResolvedDataCache.end())
|
{
|
return (const FieldInfo*)it->second;
|
}
|
}
|
|
FieldRefInfo fri;
|
ReadFieldRefInfoFromToken(klassGenericContainer, methodGenericContainer, DecodeTokenTableType(token), DecodeTokenRowIndex(token), fri);
|
if (!fri.field)
|
{
|
TEMP_FORMAT(errMsg, "token:%d", token);
|
RaiseMissingFieldException(&fri.containerType, errMsg);
|
}
|
const Il2CppType* resultType = genericContext != nullptr ? il2cpp::metadata::GenericMetadata::InflateIfNeeded(&fri.containerType, genericContext, true) : &fri.containerType;
|
const FieldInfo* fieldInfo = GetFieldInfoFromFieldRef(*resultType, fri.field);
|
il2cpp::vm::Class::Init(fieldInfo->parent);
|
{
|
il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
|
_token2ResolvedDataCache.insert({ key, (void*)fieldInfo });
|
}
|
return fieldInfo;
|
}
|
|
|
const MethodInfo* Image::ReadMethodInfoFromToken(const Il2CppGenericContainer* klassGenericContainer,
|
const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext, const Il2CppGenericInst* genericInst, TableType tableType, uint32_t rowIndex)
|
{
|
IL2CPP_ASSERT(rowIndex > 0);
|
switch (tableType)
|
{
|
case TableType::METHOD:
|
{
|
const Il2CppMethodDefinition* methodDef = GetMethodDefinitionFromRawIndex(rowIndex - 1);
|
const Il2CppTypeDefinition* declareType = (Il2CppTypeDefinition*)il2cpp::vm::GlobalMetadata::GetTypeHandleFromIndex(methodDef->declaringType);
|
const Il2CppType* type = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(declareType->byvalTypeIndex);
|
return GetMethodInfo(type, methodDef, genericInst, genericContext);
|
}
|
case TableType::MEMBERREF:
|
{
|
ResolveMemberRef rmr = {};
|
ReadResolveMemberRefFromMemberRef(klassGenericContainer, methodGenericContainer, rowIndex, rmr);
|
IL2CPP_ASSERT(rmr.parent.parentType == TableType::TYPEDEF || rmr.parent.parentType == TableType::TYPEREF || rmr.parent.parentType == TableType::TYPESPEC);
|
IL2CPP_ASSERT(rmr.signature.memberType == TableType::METHOD_POINTER);
|
if (genericContext)
|
{
|
rmr.parent.type = *TryInflateIfNeed(&rmr.parent.type, genericContext, true);
|
}
|
return ResolveMethodInfo(&rmr.parent.type, rmr.name, rmr.signature.method, genericInst, genericContext);
|
}
|
case TableType::METHODSPEC:
|
{
|
TbMethodSpec methodSpec = _rawImage.ReadMethodSpec(rowIndex);
|
const Il2CppGenericInst* genericInstantiation = nullptr;
|
// FIXME! genericInstantiation memory leak
|
ReadMethodSpecInstantiation(methodSpec.instantiation, klassGenericContainer, methodGenericContainer, genericInstantiation);
|
// FIXME memory leak
|
genericInstantiation = TryInflateGenericInst(genericInstantiation, genericContext);
|
|
TableType methodTableType = DecodeMethodDefOrRefCodedIndexTableType(methodSpec.method);
|
uint32_t methodRowIndex = DecodeMethodDefOrRefCodedIndexRowIndex(methodSpec.method);
|
switch (methodTableType)
|
{
|
case TableType::METHOD:
|
{
|
return ReadMethodInfoFromToken(klassGenericContainer, methodGenericContainer, genericContext, genericInstantiation, methodTableType, methodRowIndex);
|
}
|
case TableType::MEMBERREF:
|
{
|
return ReadMethodInfoFromToken(klassGenericContainer, methodGenericContainer, genericContext, genericInstantiation, methodTableType, methodRowIndex);
|
}
|
default:
|
{
|
RaiseBadImageException("ReadMethodSpec invaild TableType");
|
return nullptr;
|
}
|
}
|
break;
|
}
|
default:
|
{
|
RaiseBadImageException("ReadMethodInfoFromToken invaild TableType");
|
return nullptr;
|
}
|
}
|
}
|
|
const MethodInfo* Image::GetMethodInfoFromToken(uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext)
|
{
|
auto key = std::tuple<uint32_t, const Il2CppGenericContext*>(token, genericContext);
|
{
|
il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
|
auto it = _token2ResolvedDataCache.find(key);
|
if (it != _token2ResolvedDataCache.end())
|
{
|
return (const MethodInfo*)it->second;
|
}
|
}
|
|
const MethodInfo* method = ReadMethodInfoFromToken(klassGenericContainer, methodGenericContainer, genericContext,
|
nullptr, DecodeTokenTableType(token), DecodeTokenRowIndex(token));
|
|
IL2CPP_ASSERT(method);
|
il2cpp::vm::Class::Init(method->klass);
|
{
|
il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
|
_token2ResolvedDataCache.insert({ key, (void*)method });
|
}
|
return method;
|
}
|
|
const MethodInfo* Image::GetMethodInfo(const Il2CppType* containerType, const Il2CppMethodDefinition* methodDef, const Il2CppGenericInst* instantiation, const Il2CppGenericContext* genericContext)
|
{
|
const Il2CppType* finalContainerType = TryInflateIfNeed(containerType, genericContext, true);
|
const MethodInfo* method = GetMethodInfoFromMethodDef(containerType, methodDef);
|
IL2CPP_ASSERT(method);
|
// final genericContext = finalContainerType.class_inst + mri.instantiation
|
if (instantiation)
|
{
|
const Il2CppGenericInst* finalClassIns = finalContainerType->type == IL2CPP_TYPE_GENERICINST ? finalContainerType->data.generic_class->context.class_inst : nullptr;
|
const Il2CppGenericInst* finalMethodIns = instantiation;
|
Il2CppGenericContext finalGenericContext = { finalClassIns, finalMethodIns };
|
method = method->is_inflated ? method->genericMethod->methodDefinition : method;
|
method = il2cpp::metadata::GenericMetadata::Inflate(method, &finalGenericContext);
|
IL2CPP_ASSERT(method);
|
}
|
return method;
|
}
|
|
void Image::GetStandAloneMethodSigFromToken(uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext, ResolveStandAloneMethodSig& methodSig)
|
{
|
TbStandAloneSig sas = _rawImage.ReadStandAloneSig(DecodeTokenRowIndex(token));
|
ReadStandAloneSig(sas.signature, klassGenericContainer, methodGenericContainer, methodSig);
|
if (genericContext)
|
{
|
// FIXME. memory leak
|
methodSig.returnType = *TryInflateIfNeed(&methodSig.returnType, genericContext, true);
|
for (uint32_t i = 0; i < methodSig.paramCount; i++)
|
{
|
methodSig.params[i] = *TryInflateIfNeed(methodSig.params + i, genericContext, true);
|
}
|
}
|
}
|
|
void Image::ReadFieldRefInfoFromToken(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex, FieldRefInfo& ret)
|
{
|
IL2CPP_ASSERT(rowIndex > 0);
|
if (tableType == TableType::FIELD)
|
{
|
ReadFieldRefInfoFromFieldDefToken(rowIndex, ret);
|
}
|
else
|
{
|
IL2CPP_ASSERT(tableType == TableType::MEMBERREF);
|
ReadFieldRefInfoFromMemberRef(klassGenericContainer, methodGenericContainer, rowIndex, ret);
|
}
|
}
|
}
|
}
|