#include "InterpreterImage.h"
|
|
#include <cstring>
|
#include <cmath>
|
#include <iostream>
|
#include <algorithm>
|
|
#include "il2cpp-class-internals.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/MetadataLock.h"
|
#include "vm/MetadataCache.h"
|
#include "vm/MetadataAlloc.h"
|
#include "vm/String.h"
|
#include "vm/Reflection.h"
|
#include "metadata/FieldLayout.h"
|
#include "metadata/Il2CppTypeCompare.h"
|
#include "metadata/GenericMetadata.h"
|
#if HYBRIDCLR_UNITY_2021_OR_NEW
|
#include "metadata/CustomAttributeCreator.h"
|
#endif
|
#include "os/Atomic.h"
|
#include "icalls/mscorlib/System/MonoCustomAttrs.h"
|
|
#include "MetadataModule.h"
|
#include "MetadataUtil.h"
|
#include "ClassFieldLayoutCalculator.h"
|
|
#include "../interpreter/Engine.h"
|
#include "../interpreter/InterpreterModule.h"
|
|
namespace hybridclr
|
{
|
namespace metadata
|
{
|
|
static uint32_t s_nextImageIndexByKind[4] = { (1u << kMetadataImageIndexExtraShiftBitsA), 0, 0, 0};
|
|
InterpreterImage* InterpreterImage::s_images[kMaxMetadataImageCount] = {};
|
|
static int32_t GetImageKindByDllLength(uint32_t dllLength)
|
{
|
uint32_t maxPossibleIndexValue = dllLength * 4;
|
for (int32_t i = 3; i >= 0; i--)
|
{
|
if (maxPossibleIndexValue <= kMetadataIndexMaskArr[i])
|
{
|
return i;
|
}
|
}
|
return -1;
|
}
|
|
void InterpreterImage::Initialize()
|
{
|
|
}
|
|
uint32_t InterpreterImage::AllocImageIndex(uint32_t dllLength)
|
{
|
int32_t kind = GetImageKindByDllLength(dllLength);
|
if (kind < 0)
|
{
|
return kInvalidImageIndex;
|
}
|
for (int32_t finalKind = kind; finalKind >= 0; finalKind--)
|
{
|
uint32_t newImageIndex = s_nextImageIndexByKind[finalKind];
|
// 255 is preserved for invalid image index when kind is 3
|
if (newImageIndex >= kMaxMetadataImageIndexWithoutKind - (finalKind == 3))
|
{
|
continue;
|
}
|
s_nextImageIndexByKind[finalKind] += (1u << kMetadataImageIndexExtraShiftBitsArr[finalKind]);
|
return newImageIndex | ((uint32_t)finalKind << (kMetadataImageIndexBits - kMetadataKindBits));
|
}
|
return kInvalidImageIndex;
|
}
|
|
void InterpreterImage::RegisterImage(InterpreterImage* image)
|
{
|
il2cpp::os::Atomic::FullMemoryBarrier();
|
IL2CPP_ASSERT(image->GetIndex() > 0);
|
s_images[image->GetIndex()] = image;
|
}
|
|
void InterpreterImage::InitBasic(Il2CppImage* image)
|
{
|
SetIl2CppImage(image);
|
RegisterImage(this);
|
}
|
|
void InterpreterImage::BuildIl2CppAssembly(Il2CppAssembly* ass)
|
{
|
ass->token = EncodeToken(TableType::ASSEMBLY, 1);
|
ass->referencedAssemblyStart = EncodeWithIndex(1);
|
ass->referencedAssemblyCount = _rawImage.GetTableRowNum(TableType::ASSEMBLYREF);
|
|
TbAssembly data = _rawImage.ReadAssembly(1);
|
auto& aname = ass->aname;
|
aname.hash_alg = data.hashAlgId;
|
aname.major = data.majorVersion;
|
aname.minor = data.minorVersion;
|
aname.build = data.buildNumber;
|
aname.revision = data.revisionNumber;
|
aname.flags = data.flags;
|
aname.public_key = _rawImage.GetBlobFromRawIndex(data.publicKey);
|
aname.name = _rawImage.GetStringFromRawIndex(data.name);
|
aname.culture = _rawImage.GetStringFromRawIndex(data.culture);
|
}
|
|
void InterpreterImage::BuildIl2CppImage(Il2CppImage* image2)
|
{
|
image2->typeCount = _rawImage.GetTableRowNum(TableType::TYPEDEF);
|
image2->exportedTypeCount = _rawImage.GetTableRowNum(TableType::EXPORTEDTYPE);
|
image2->customAttributeCount = _rawImage.GetTableRowNum(TableType::CUSTOMATTRIBUTE);
|
|
#if HYBRIDCLR_UNITY_2019
|
image2->typeStart = EncodeWithIndex(0);
|
image2->customAttributeStart = EncodeWithIndex(0);
|
image2->entryPointIndex = EncodeWithIndexExcept0(_rawImage.GetEntryPointToken());
|
image2->exportedTypeStart = EncodeWithIndex(0);
|
#else
|
Il2CppImageGlobalMetadata* metadataImage = (Il2CppImageGlobalMetadata*)HYBRIDCLR_METADATA_MALLOC(sizeof(Il2CppImageGlobalMetadata));
|
metadataImage->typeStart = EncodeWithIndex(0);
|
metadataImage->customAttributeStart = EncodeWithIndex(0);
|
metadataImage->entryPointIndex = EncodeWithIndexExcept0(_rawImage.GetEntryPointToken());
|
metadataImage->exportedTypeStart = EncodeWithIndex(0);
|
metadataImage->image = image2;
|
image2->metadataHandle = reinterpret_cast<Il2CppMetadataImageHandle>(metadataImage);
|
#endif
|
|
image2->nameToClassHashTable = nullptr;
|
image2->codeGenModule = nullptr;
|
|
image2->token = EncodeWithIndex(0); // TODO
|
image2->dynamic = 0;
|
}
|
|
void InterpreterImage::InitRuntimeMetadatas()
|
{
|
IL2CPP_ASSERT(_rawImage.GetTable(TableType::EXPORTEDTYPE).rowNum == 0);
|
|
InitGenericParamDefs0();
|
InitTypeDefs_0();
|
InitMethodDefs0();
|
InitGenericParamDefs();
|
InitNestedClass(); // must before typedefs1, because parent may be nested class
|
InitTypeDefs_1();
|
|
InitGenericParamConstraintDefs();
|
|
InitParamDefs();
|
InitMethodDefs();
|
InitFieldDefs();
|
InitFieldLayouts();
|
InitFieldRVAs();
|
InitBlittables();
|
InitMethodImpls0();
|
InitProperties();
|
InitEvents();
|
InitMethodSemantics();
|
InitConsts();
|
InitCustomAttributes();
|
InitTypeDefs_2();
|
InitClassLayouts();
|
InitInterfaces();
|
InitClass();
|
InitVTables();
|
}
|
|
void InterpreterImage::InitTypeDefs_0()
|
{
|
const Table& typeDefTb = _rawImage.GetTable(TableType::TYPEDEF);
|
_typesDefines.resize(typeDefTb.rowNum);
|
_typeDetails.resize(typeDefTb.rowNum);
|
for (uint32_t i = 0, n = typeDefTb.rowNum; i < n; i++)
|
{
|
Il2CppTypeDefinition& cur = _typesDefines[i];
|
TypeDefinitionDetail& typeDetail = _typeDetails[i];
|
typeDetail.index = i;
|
typeDetail.typeDef = &cur;
|
typeDetail.typeSizes = {};
|
|
uint32_t rowIndex = i + 1;
|
TbTypeDef data = _rawImage.ReadTypeDef(rowIndex);
|
|
cur = {};
|
|
cur.genericContainerIndex = kGenericContainerIndexInvalid;
|
cur.declaringTypeIndex = kTypeDefinitionIndexInvalid;
|
cur.elementTypeIndex = kTypeDefinitionIndexInvalid;
|
|
cur.token = EncodeToken(TableType::TYPEDEF, rowIndex);
|
|
bool isValueType = data.extends && IsValueTypeFromToken(DecodeTypeDefOrRefOrSpecCodedIndexTableType(data.extends), DecodeTypeDefOrRefOrSpecCodedIndexRowIndex(data.extends));
|
Il2CppType cppType = {};
|
cppType.type = isValueType ? IL2CPP_TYPE_VALUETYPE : IL2CPP_TYPE_CLASS;
|
SET_IL2CPPTYPE_VALUE_TYPE(cppType, isValueType);
|
cppType.data.typeHandle = (Il2CppMetadataTypeHandle)&cur;
|
cur.byvalTypeIndex = AddIl2CppTypeCache(cppType);
|
#if HYBRIDCLR_UNITY_2019
|
Il2CppType byRefType = cppType;
|
byRefType.byref = 1;
|
cur.byrefTypeIndex = AddIl2CppTypeCache(byRefType);
|
#endif
|
|
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;
|
}
|
}
|
}
|
|
void InterpreterImage::InitTypeDefs_1()
|
{
|
const Table& typeDefTb = _rawImage.GetTable(TableType::TYPEDEF);
|
for (uint32_t i = 0, n = typeDefTb.rowNum; i < n; i++)
|
{
|
Il2CppTypeDefinition& last = _typesDefines[i > 0 ? i - 1 : 0];
|
Il2CppTypeDefinition& cur = _typesDefines[i];
|
uint32_t rowIndex = i + 1;
|
TbTypeDef data = _rawImage.ReadTypeDef(rowIndex); // token from 1
|
|
cur.flags = data.flags;
|
cur.nameIndex = EncodeWithIndex(data.typeName);
|
cur.namespaceIndex = EncodeWithIndex(data.typeNamespace);
|
|
cur.fieldStart = EncodeWithIndex(data.fieldList - 1);
|
cur.methodStart = EncodeWithIndex(data.methodList - 1);
|
|
if (i > 0)
|
{
|
last.field_count = (uint16_t)(cur.fieldStart - last.fieldStart);
|
last.method_count = (uint16_t)(cur.methodStart - last.methodStart);
|
}
|
if (i == n - 1)
|
{
|
cur.field_count = (uint16_t)(_rawImage.GetTableRowNum(TableType::FIELD) - DecodeMetadataIndex(cur.fieldStart));
|
cur.method_count = (uint16_t)(_rawImage.GetTableRowNum(TableType::METHOD) - DecodeMetadataIndex(cur.methodStart));
|
}
|
|
if (data.extends != 0)
|
{
|
Il2CppType parentType = {};
|
ReadTypeFromToken(GetGenericContainerByTypeDefinition(&cur), nullptr, DecodeTypeDefOrRefOrSpecCodedIndexTableType(data.extends), DecodeTypeDefOrRefOrSpecCodedIndexRowIndex(data.extends), parentType);
|
|
if (parentType.type == IL2CPP_TYPE_CLASS || parentType.type == IL2CPP_TYPE_VALUETYPE)
|
{
|
Il2CppTypeDefinition* parentDef = (Il2CppTypeDefinition*)parentType.data.typeHandle;
|
// FIXE ME . check mscorelib
|
const char* parentNs = il2cpp::vm::GlobalMetadata::GetStringFromIndex(parentDef->namespaceIndex);
|
if (std::strcmp(parentNs, "System") == 0)
|
{
|
const char* parentName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(parentDef->nameIndex);
|
if (std::strcmp(parentName, "Enum") == 0)
|
{
|
cur.bitfield |= (1 << (il2cpp::vm::kBitIsValueType - 1));
|
cur.bitfield |= (1 << (il2cpp::vm::kBitIsEnum - 1));
|
}
|
else if (std::strcmp(parentName, "ValueType") == 0)
|
{
|
cur.bitfield |= (1 << (il2cpp::vm::kBitIsValueType - 1));
|
}
|
}
|
}
|
cur.parentIndex = AddIl2CppTypeCache(parentType);
|
}
|
else
|
{
|
cur.parentIndex = kInvalidIndex;
|
}
|
|
cur.elementTypeIndex = kInvalidIndex;
|
}
|
}
|
|
void InterpreterImage::InitTypeDefs_2()
|
{
|
const Table& typeDefTb = _rawImage.GetTable(TableType::TYPEDEF);
|
|
for (uint32_t i = 0, n = typeDefTb.rowNum; i < n; i++)
|
{
|
TbTypeDef data = _rawImage.ReadTypeDef(i + 1); // token from 1
|
|
Il2CppTypeDefinition& last = _typesDefines[i > 0 ? i - 1 : 0];
|
Il2CppTypeDefinition& cur = _typesDefines[i];
|
uint32_t typeIndex = i; // type index start from 0, diff with field index ...
|
|
// enum element_type ==
|
if (IsEnumType(&cur))
|
{
|
cur.elementTypeIndex = _fieldDetails[DecodeMetadataIndex(cur.fieldStart)].fieldDef.typeIndex;
|
}
|
|
auto classLayoutRow = _classLayouts.find(typeIndex);
|
uint16_t packingSize = 0;
|
if (classLayoutRow != _classLayouts.end())
|
{
|
auto& layoutData = classLayoutRow->second;
|
packingSize = layoutData.packingSize;
|
}
|
else
|
{
|
cur.bitfield |= (1 << (il2cpp::vm::kClassSizeIsDefault - 1));
|
}
|
if (packingSize != 0)
|
{
|
cur.bitfield |= ((uint32_t)il2cpp::vm::GlobalMetadata::ConvertPackingSizeToEnum((uint8_t)packingSize) << (il2cpp::vm::kPackingSize - 1));
|
}
|
else
|
{
|
cur.bitfield |= (1 << (il2cpp::vm::kPackingSizeIsDefault - 1));
|
}
|
}
|
}
|
|
void InterpreterImage::InitParamDefs()
|
{
|
const Table& tb = _rawImage.GetTable(TableType::PARAM);
|
|
// extra 16 for not name params
|
_params.reserve(tb.rowNum + 16);
|
_paramRawIndex2ActualParamIndex.resize(tb.rowNum);
|
//for (uint32_t i = 0; i < tb.rowNum; i++)
|
//{
|
// uint32_t rowIndex = i + 1;
|
// Il2CppParameterDefinition& pd = _params[i].paramDef;
|
// TbParam data = _rawImage.ReadParam(rowIndex);
|
|
// pd.nameIndex = EncodeWithIndex(data.name);
|
// pd.token = EncodeToken(TableType::PARAM, rowIndex);
|
// // pd.typeIndex 在InitMethodDefs中解析signature后填充。
|
//}
|
}
|
|
|
void InterpreterImage::InitFieldDefs()
|
{
|
const Table& fieldTb = _rawImage.GetTable(TableType::FIELD);
|
_fieldDetails.resize(fieldTb.rowNum);
|
|
for (size_t i = 0; i < _typesDefines.size(); i++)
|
{
|
Il2CppTypeDefinition& typeDef = _typesDefines[i];
|
uint32_t start = DecodeMetadataIndex(typeDef.fieldStart);
|
for (uint32_t k = 0; k < typeDef.field_count; k++)
|
{
|
FieldDetail& fd = _fieldDetails[start + k];
|
fd.typeDefIndex = (uint32_t)i;
|
}
|
}
|
|
for (uint32_t i = 0, n = fieldTb.rowNum; i < n; i++)
|
{
|
FieldDetail& fd = _fieldDetails[i];
|
Il2CppFieldDefinition& cur = fd.fieldDef;
|
|
fd.offset = 0;
|
fd.defaultValueIndex = kDefaultValueIndexNull;
|
|
uint32_t rowIndex = i + 1;
|
TbField data = _rawImage.ReadField(rowIndex);
|
|
BlobReader br = _rawImage.GetBlobReaderByRawIndex(data.signature);
|
FieldRefSig frs;
|
ReadFieldRefSig(br, GetGenericContainerByTypeDefRawIndex(DecodeMetadataIndex(fd.typeDefIndex)), frs);
|
frs.type.attrs = data.flags;
|
|
//cur = {};
|
cur.nameIndex = EncodeWithIndex(data.name);
|
cur.token = EncodeToken(TableType::FIELD, rowIndex);
|
cur.typeIndex = AddIl2CppTypeCache(frs.type);
|
}
|
}
|
|
void InterpreterImage::InitFieldLayouts()
|
{
|
const Table& tb = _rawImage.GetTable(TableType::FIELDLAYOUT);
|
for (uint32_t i = 0; i < tb.rowNum; i++)
|
{
|
TbFieldLayout data = _rawImage.ReadFieldLayout(i + 1);
|
_fieldDetails[data.field - 1].offset = sizeof(Il2CppObject) + data.offset;
|
}
|
}
|
|
void InterpreterImage::InitFieldRVAs()
|
{
|
const Table& tb = _rawImage.GetTable(TableType::FIELDRVA);
|
for (uint32_t i = 0; i < tb.rowNum; i++)
|
{
|
TbFieldRVA data = _rawImage.ReadFieldRVA(i + 1);
|
FieldDetail& fd = _fieldDetails[data.field - 1];
|
fd.defaultValueIndex = (uint32_t)_fieldDefaultValues.size();
|
|
Il2CppFieldDefaultValue fdv = {};
|
fdv.fieldIndex = data.field - 1;
|
fdv.typeIndex = fd.fieldDef.typeIndex;
|
|
uint32_t dataImageOffset = (uint32_t)-1;
|
bool ret = _rawImage.TranslateRVAToImageOffset(data.rva, dataImageOffset);
|
IL2CPP_ASSERT(ret);
|
#if HYBRIDCLR_UNITY_2021_OR_NEW
|
fdv.dataIndex = (DefaultValueDataIndex)EncodeWithIndex(EncodeWithBlobSource(dataImageOffset, BlobSource::RAW_IMAGE));
|
#else
|
fdv.dataIndex = (DefaultValueDataIndex)EncodeWithIndex(dataImageOffset);
|
#endif
|
_fieldDefaultValues.push_back(fdv);
|
}
|
}
|
|
void InterpreterImage::InitBlittables()
|
{
|
const Table& typeDefTb = _rawImage.GetTable(TableType::TYPEDEF);
|
|
std::vector<bool> computFlags(typeDefTb.rowNum, false);
|
|
for (uint32_t i = 0, n = typeDefTb.rowNum; i < n; i++)
|
{
|
ComputeBlittable(&_typesDefines[i], computFlags);
|
}
|
}
|
|
void InterpreterImage::ComputeBlittable(Il2CppTypeDefinition* def, std::vector<bool>& computFlags)
|
{
|
if (DecodeImageIndex(def->byvalTypeIndex) != GetIndex())
|
{
|
return;
|
}
|
uint32_t typeIndex = GetTypeRawIndex(def);
|
if (computFlags[typeIndex])
|
{
|
return;
|
}
|
computFlags[typeIndex] = true;
|
|
const Il2CppType* type = GetIl2CppTypeFromRawIndex(DecodeMetadataIndex(def->byvalTypeIndex));
|
|
const char* typeName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(def->nameIndex);
|
|
|
bool blittable = false;
|
if (type->type == IL2CPP_TYPE_VALUETYPE)
|
{
|
blittable = true;
|
for (int i = 0; i < def->field_count; i++)
|
{
|
const Il2CppFieldDefinition* field = GetFieldDefinitionFromRawIndex(DecodeMetadataIndex(def->fieldStart + i));
|
const Il2CppType* fieldType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(field->typeIndex);
|
if (!hybridclr::metadata::IsInstanceField(fieldType))
|
{
|
continue;
|
}
|
|
switch (fieldType->type)
|
{
|
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_I:
|
case IL2CPP_TYPE_U:
|
case IL2CPP_TYPE_I8:
|
case IL2CPP_TYPE_U8:
|
case IL2CPP_TYPE_R4:
|
case IL2CPP_TYPE_R8:
|
case IL2CPP_TYPE_PTR:
|
case IL2CPP_TYPE_FNPTR:
|
{
|
break;
|
}
|
case IL2CPP_TYPE_VALUETYPE:
|
{
|
Il2CppTypeDefinition* fieldDef = (Il2CppTypeDefinition*)fieldType->data.typeHandle;
|
ComputeBlittable(fieldDef, computFlags);
|
blittable = fieldDef->bitfield & (1 << (il2cpp::vm::kBitIsBlittable - 1));
|
break;
|
}
|
default:
|
{
|
blittable = false;
|
}
|
}
|
if (!blittable)
|
{
|
break;
|
}
|
}
|
}
|
if (blittable)
|
{
|
def->bitfield |= (1 << (il2cpp::vm::kBitIsBlittable - 1));
|
}
|
}
|
|
#if HYBRIDCLR_UNITY_2021_OR_NEW
|
DefaultValueDataIndex InterpreterImage::ConvertConstValue(CustomAttributeDataWriter& writer, uint32_t blobIndex, const Il2CppType* type)
|
{
|
Il2CppTypeEnum ttype = type->type;
|
if (ttype == IL2CPP_TYPE_CLASS)
|
{
|
return kDefaultValueIndexNull;
|
}
|
|
DefaultValueIndex retIndex = EncodeWithIndex(EncodeWithBlobSource((DefaultValueIndex)writer.Size(), BlobSource::CONVERTED_IL2CPP_FORMAT));
|
|
BlobReader reader = _rawImage.GetBlobReaderByRawIndex(blobIndex);
|
switch (type->type)
|
{
|
case IL2CPP_TYPE_BOOLEAN:
|
case IL2CPP_TYPE_I1:
|
case IL2CPP_TYPE_U1:
|
{
|
writer.Write(reader, 1);
|
break;
|
}
|
case IL2CPP_TYPE_CHAR:
|
case IL2CPP_TYPE_I2:
|
case IL2CPP_TYPE_U2:
|
{
|
writer.Write(reader, 2);
|
break;
|
}
|
case IL2CPP_TYPE_I4:
|
{
|
writer.WriteCompressedInt32((int32_t)reader.Read32());
|
break;
|
}
|
case IL2CPP_TYPE_U4:
|
{
|
writer.WriteCompressedUint32(reader.Read32());
|
break;
|
}
|
case IL2CPP_TYPE_R4:
|
{
|
writer.Write(reader, 4);
|
break;
|
}
|
case IL2CPP_TYPE_I8:
|
case IL2CPP_TYPE_U8:
|
case IL2CPP_TYPE_R8:
|
{
|
writer.Write(reader, 8);
|
break;
|
}
|
case IL2CPP_TYPE_STRING:
|
{
|
std::string str = il2cpp::utils::StringUtils::Utf16ToUtf8((const Il2CppChar*)reader.GetData(), reader.GetLength() / 2);
|
writer.WriteCompressedInt32((int32_t)str.length());
|
writer.WriteBytes((const uint8_t*)str.c_str(), (int32_t)str.length());
|
break;
|
}
|
default:
|
{
|
RaiseExecutionEngineException("not supported const type");
|
}
|
}
|
|
return retIndex;
|
}
|
#endif
|
|
void InterpreterImage::InitConsts()
|
{
|
const Table& tb = _rawImage.GetTable(TableType::CONSTANT);
|
for (uint32_t i = 0; i < tb.rowNum; i++)
|
{
|
TbConstant data = _rawImage.ReadConstant(i + 1);
|
TableType parentType = DecodeHasConstantType(data.parent);
|
uint32_t rowIndex = DecodeHashConstantIndex(data.parent);
|
|
Il2CppType type = {};
|
type.type = (Il2CppTypeEnum)data.type;
|
TypeIndex dataTypeIndex = AddIl2CppTypeCache(type);
|
#if !HYBRIDCLR_UNITY_2021_OR_NEW
|
bool isNullValue = type.type == IL2CPP_TYPE_CLASS;
|
#endif
|
switch (parentType)
|
{
|
case TableType::FIELD:
|
{
|
FieldDetail& fd = _fieldDetails[rowIndex - 1];
|
fd.defaultValueIndex = (uint32_t)_fieldDefaultValues.size();
|
|
Il2CppFieldDefaultValue fdv = {};
|
fdv.fieldIndex = rowIndex - 1;
|
fdv.typeIndex = dataTypeIndex;
|
#if HYBRIDCLR_UNITY_2021_OR_NEW
|
fdv.dataIndex = ConvertConstValue(_constValues, data.value, &type);
|
#else
|
uint32_t dataImageOffset = _rawImage.GetImageOffsetOfBlob(type.type, data.value);
|
fdv.dataIndex = isNullValue ? kDefaultValueIndexNull : (DefaultValueDataIndex)EncodeWithIndex(dataImageOffset);
|
#endif
|
_fieldDefaultValues.push_back(fdv);
|
break;
|
}
|
case TableType::PARAM:
|
{
|
int32_t actualIndex = _paramRawIndex2ActualParamIndex[rowIndex - 1];
|
ParamDetail& fd = _params[actualIndex];
|
fd.defaultValueIndex = (uint32_t)_paramDefaultValues.size();
|
|
Il2CppParameterDefaultValue pdv = {};
|
pdv.typeIndex = dataTypeIndex;
|
pdv.parameterIndex = fd.parameterIndex;
|
#if HYBRIDCLR_UNITY_2021_OR_NEW
|
pdv.dataIndex = ConvertConstValue(_constValues, data.value, &type);
|
#else
|
uint32_t dataImageOffset = _rawImage.GetImageOffsetOfBlob(type.type, data.value);
|
pdv.dataIndex = isNullValue ? kDefaultValueIndexNull : (DefaultValueDataIndex)EncodeWithIndex(dataImageOffset);
|
#endif
|
_paramDefaultValues.push_back(pdv);
|
break;
|
}
|
case TableType::PROPERTY:
|
{
|
RaiseNotSupportedException("not support property const");
|
break;
|
}
|
default:
|
{
|
RaiseExecutionEngineException("not support const TableType");
|
break;
|
}
|
}
|
}
|
}
|
|
void InterpreterImage::InitCustomAttributes()
|
{
|
const Table& tb = _rawImage.GetTable(TableType::CUSTOMATTRIBUTE);
|
_tokenCustomAttributes.reserve(tb.rowNum);
|
|
|
uint32_t threadStaticMethodToken = 0;
|
Il2CppCustomAttributeTypeRange* curTypeRange = nullptr;
|
for (uint32_t rowIndex = 1; rowIndex <= tb.rowNum; rowIndex++)
|
{
|
TbCustomAttribute data = _rawImage.ReadCustomAttribute(rowIndex);
|
TableType parentType = DecodeHasCustomAttributeCodedIndexTableType(data.parent);
|
uint32_t parentRowIndex = DecodeHasCustomAttributeCodedIndexRowIndex(data.parent);
|
uint32_t token = EncodeToken(parentType, parentRowIndex);
|
if (curTypeRange == nullptr || curTypeRange->token != token)
|
{
|
IL2CPP_ASSERT(_tokenCustomAttributes.find(token) == _tokenCustomAttributes.end());
|
int32_t attributeStartIndex = EncodeWithIndex((int32_t)_customAttribues.size());
|
int32_t handleIndex = (int32_t)_customAttributeHandles.size();
|
_tokenCustomAttributes[token] = { (int32_t)EncodeWithIndex(handleIndex), false, nullptr, nullptr };
|
#ifdef HYBRIDCLR_UNITY_2021_OR_NEW
|
_customAttributeHandles.push_back({ token, (uint32_t)attributeStartIndex });
|
#else
|
_customAttributeHandles.push_back({ token, attributeStartIndex, 0 });
|
#endif
|
curTypeRange = &_customAttributeHandles[handleIndex];
|
}
|
#if !HYBRIDCLR_UNITY_2021_OR_NEW
|
++curTypeRange->count;
|
#endif
|
TableType ctorMethodTableType = DecodeCustomAttributeTypeCodedIndexTableType(data.type);
|
uint32_t ctorMethodRowIndex = DecodeCustomAttributeTypeCodedIndexRowIndex(data.type);
|
uint32_t ctorMethodToken = EncodeToken(ctorMethodTableType, ctorMethodRowIndex);
|
//CustomAttribute ca = { ctorMethodToken, data.value };
|
//ca.value = data.value;
|
//ReadMethodRefInfoFromToken(nullptr, nullptr, , ca.attrCtorMethod);
|
_customAttribues.push_back({ ctorMethodToken, data.value });
|
|
if (parentType == TableType::FIELD)
|
{
|
// try set thread static flags
|
if (threadStaticMethodToken == 0)
|
{
|
if (IsThreadStaticCtorToken(ctorMethodTableType, ctorMethodRowIndex))
|
{
|
threadStaticMethodToken = ctorMethodToken;
|
}
|
}
|
if (ctorMethodToken == threadStaticMethodToken)
|
{
|
IL2CPP_ASSERT(threadStaticMethodToken != 0);
|
_fieldDetails[parentRowIndex - 1].offset = THREAD_LOCAL_STATIC_MASK;
|
}
|
}
|
|
}
|
IL2CPP_ASSERT(_tokenCustomAttributes.size() == _customAttributeHandles.size());
|
#ifdef HYBRIDCLR_UNITY_2021_OR_NEW
|
// add extra Il2CppCustomAttributeTypeRange for compute count
|
_customAttributeHandles.push_back({ 0, EncodeWithIndex((int32_t)_customAttribues.size()) });
|
#endif
|
#if !HYBRIDCLR_UNITY_2022_OR_NEW
|
_customAttribtesCaches.resize(_tokenCustomAttributes.size());
|
#endif
|
}
|
|
#ifdef HYBRIDCLR_UNITY_2021_OR_NEW
|
|
void InterpreterImage::InitCustomAttributeData(CustomAttributesInfo& cai, const Il2CppCustomAttributeTypeRange& dataRange)
|
{
|
il2cpp::os::FastAutoLock metaLock(&il2cpp::vm::g_MetadataLock);
|
if (cai.inited)
|
{
|
return;
|
}
|
BuildCustomAttributesData(cai, dataRange);
|
il2cpp::os::Atomic::FullMemoryBarrier();
|
cai.inited = true;
|
}
|
|
void InterpreterImage::BuildCustomAttributesData(CustomAttributesInfo& cai, const Il2CppCustomAttributeTypeRange& curTypeRange)
|
{
|
hybridclr::interpreter::ExecutingInterpImageScope scope(hybridclr::interpreter::InterpreterModule::GetCurrentThreadMachineState(), this->_il2cppImage);
|
_il2cppFormatCustomDataBlob.Reset();
|
const Il2CppCustomAttributeDataRange& nextTypeRange = *(&curTypeRange + 1);
|
uint32_t attrCount = nextTypeRange.startOffset - curTypeRange.startOffset;
|
IL2CPP_ASSERT(attrCount > 0 && attrCount < 1024);
|
_il2cppFormatCustomDataBlob.WriteAttributeCount(attrCount);
|
int32_t attrStartOffset = DecodeMetadataIndex(curTypeRange.startOffset);
|
int32_t methodIndexDataOffset = _il2cppFormatCustomDataBlob.Size();
|
_il2cppFormatCustomDataBlob.Skip(attrCount * sizeof(int32_t));
|
for (uint32_t i = 0; i < attrCount; i++)
|
{
|
const CustomAttribute& ca = _customAttribues[attrStartOffset + (int32_t)i];
|
MethodRefInfo mri = {};
|
ReadMethodRefInfoFromToken(nullptr, nullptr, DecodeTokenTableType(ca.ctorMethodToken), DecodeTokenRowIndex(ca.ctorMethodToken), mri);
|
const MethodInfo* ctorMethod = GetMethodInfoFromMethodDef(&mri.containerType, mri.methodDef);
|
MethodIndex ctorIndex = il2cpp::vm::GlobalMetadata::GetMethodIndexFromDefinition(mri.methodDef);
|
_il2cppFormatCustomDataBlob.WriteMethodIndex(methodIndexDataOffset, ctorIndex);
|
methodIndexDataOffset += sizeof(int32_t);
|
if (ca.value != 0)
|
{
|
BlobReader reader = _rawImage.GetBlobReaderByRawIndex(ca.value);
|
ConvertILCustomAttributeData2Il2CppFormat(ctorMethod, reader);
|
}
|
else
|
{
|
IL2CPP_ASSERT(mri.methodDef->parameterCount == 0);
|
_il2cppFormatCustomDataBlob.WriteCompressedUint32(0);
|
_il2cppFormatCustomDataBlob.WriteCompressedUint32(0);
|
_il2cppFormatCustomDataBlob.WriteCompressedUint32(0);
|
}
|
}
|
void* resultData = HYBRIDCLR_MALLOC(_il2cppFormatCustomDataBlob.Size());
|
std::memcpy(resultData, _il2cppFormatCustomDataBlob.Data(), _il2cppFormatCustomDataBlob.Size());
|
cai.dataStartPtr = resultData;
|
cai.dataEndPtr = (uint8_t*)resultData + _il2cppFormatCustomDataBlob.Size();
|
}
|
|
void InterpreterImage::WriteEncodeTypeEnum(CustomAttributeDataWriter& writer, const Il2CppType* type)
|
{
|
Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type);
|
if (type->type == IL2CPP_TYPE_ENUM || klass->enumtype)
|
{
|
writer.WriteByte((byte)IL2CPP_TYPE_ENUM);
|
int32_t typeIndex = type->type == IL2CPP_TYPE_CLASS || type->type == IL2CPP_TYPE_VALUETYPE ? ((Il2CppTypeDefinition*)type->data.typeHandle)->byvalTypeIndex : AddIl2CppTypeCache(*type);
|
writer.WriteCompressedInt32(typeIndex);
|
}
|
else if (klass == il2cpp_defaults.systemtype_class)
|
{
|
writer.WriteByte((byte)IL2CPP_TYPE_IL2CPP_TYPE_INDEX);
|
}
|
else
|
{
|
writer.WriteByte((uint8_t)type->type);
|
}
|
}
|
|
void InterpreterImage::ConvertBoxedValue(CustomAttributeDataWriter& writer, BlobReader& reader, bool writeType)
|
{
|
uint64_t obj = 0;
|
Il2CppType kind = {};
|
ReadCustomAttributeFieldOrPropType(reader, kind);
|
ConvertFixedArg(writer, reader, &kind, true);
|
}
|
|
void InterpreterImage::ConvertSystemType(CustomAttributeDataWriter& writer, BlobReader& reader, bool writeType)
|
{
|
if (writeType)
|
{
|
writer.WriteByte((byte)IL2CPP_TYPE_IL2CPP_TYPE_INDEX);
|
}
|
Il2CppString* fullName = ReadSerString(reader);
|
if (!fullName)
|
{
|
writer.WriteCompressedInt32(-1);
|
return;
|
}
|
Il2CppReflectionType* type = GetReflectionTypeFromName(fullName);
|
if (!type)
|
{
|
std::string stdTypeName = il2cpp::utils::StringUtils::Utf16ToUtf8(fullName->chars);
|
TEMP_FORMAT(errMsg, "CustomAttribute fixed arg type:System.Type fullName:'%s' not find", stdTypeName.c_str());
|
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException(errMsg));
|
}
|
Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type->type);
|
if (!klass->generic_class)
|
{
|
writer.WriteCompressedInt32(((Il2CppTypeDefinition*)klass->typeMetadataHandle)->byvalTypeIndex);
|
}
|
else
|
{
|
writer.WriteCompressedInt32(AddIl2CppTypeCache(*(type->type)));
|
}
|
}
|
|
void InterpreterImage::ConvertFixedArg(CustomAttributeDataWriter& writer, BlobReader& reader, const Il2CppType* type, bool writeType)
|
{
|
switch (type->type)
|
{
|
case IL2CPP_TYPE_BOOLEAN:
|
case IL2CPP_TYPE_I1:
|
case IL2CPP_TYPE_U1:
|
{
|
if (writeType)
|
{
|
writer.WriteByte((uint8_t)type->type);
|
}
|
writer.Write(reader, 1);
|
break;
|
}
|
case IL2CPP_TYPE_CHAR:
|
case IL2CPP_TYPE_I2:
|
case IL2CPP_TYPE_U2:
|
{
|
if (writeType)
|
{
|
writer.WriteByte((uint8_t)type->type);
|
}
|
writer.Write(reader, 2);
|
break;
|
}
|
case IL2CPP_TYPE_I4:
|
{
|
if (writeType)
|
{
|
writer.WriteByte((uint8_t)type->type);
|
}
|
writer.WriteCompressedInt32((int32_t)reader.Read32());
|
break;
|
}
|
case IL2CPP_TYPE_U4:
|
{
|
if (writeType)
|
{
|
writer.WriteByte((uint8_t)type->type);
|
}
|
writer.WriteCompressedUint32(reader.Read32());
|
break;
|
}
|
case IL2CPP_TYPE_R4:
|
{
|
if (writeType)
|
{
|
writer.WriteByte((uint8_t)type->type);
|
}
|
writer.Write(reader, 4);
|
break;
|
}
|
case IL2CPP_TYPE_I8:
|
case IL2CPP_TYPE_U8:
|
case IL2CPP_TYPE_R8:
|
{
|
if (writeType)
|
{
|
writer.WriteByte((uint8_t)type->type);
|
}
|
writer.Write(reader, 8);
|
break;
|
}
|
case IL2CPP_TYPE_SZARRAY:
|
{
|
if (writeType)
|
{
|
writer.WriteByte((uint8_t)type->type);
|
}
|
int32_t numElem = (int32_t)reader.Read32();
|
writer.WriteCompressedInt32(numElem);
|
if (numElem != -1)
|
{
|
//Il2CppType kind = {};
|
//ReadCustomAttributeFieldOrPropType(reader, kind);
|
const Il2CppType* eleType = type->data.type;
|
WriteEncodeTypeEnum(writer, eleType);
|
if (eleType->type == IL2CPP_TYPE_OBJECT)
|
{
|
// kArrayTypeWithDifferentElements
|
writer.WriteByte(1);
|
for (uint16_t i = 0; i < numElem; i++)
|
{
|
ConvertBoxedValue(writer, reader, false);
|
}
|
}
|
else
|
{
|
// all element type is same.
|
writer.WriteByte(0);
|
for (uint16_t i = 0; i < numElem; i++)
|
{
|
ConvertFixedArg(writer, reader, eleType, false);
|
}
|
}
|
|
}
|
break;
|
}
|
case IL2CPP_TYPE_STRING:
|
{
|
if (writeType)
|
{
|
writer.WriteByte((uint8_t)type->type);
|
}
|
byte b = reader.PeekByte();
|
if (b == 0xFF)
|
{
|
reader.SkipByte();
|
writer.WriteCompressedInt32(-1);
|
}
|
else if (b == 0)
|
{
|
reader.SkipByte();
|
writer.WriteCompressedInt32(0);
|
}
|
else
|
{
|
const byte* beginDataPtr = reader.GetDataOfReadPosition();
|
uint32_t len = reader.ReadCompressedUint32();
|
writer.WriteCompressedInt32((int32_t)len);
|
writer.WriteBytes(reader.GetDataOfReadPosition(), len);
|
reader.SkipBytes(len);
|
}
|
break;
|
}
|
case IL2CPP_TYPE_OBJECT:
|
{
|
ConvertBoxedValue(writer, reader, writeType);
|
//*(Il2CppObject**)data = ReadBoxedValue(reader);
|
// FIXME memory barrier
|
break;
|
}
|
case IL2CPP_TYPE_CLASS:
|
{
|
Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type);
|
if (!klass)
|
{
|
RaiseExecutionEngineException("type not find");
|
}
|
if (klass == il2cpp_defaults.object_class)
|
{
|
ConvertBoxedValue(writer, reader, writeType);
|
}
|
else if (klass == il2cpp_defaults.systemtype_class)
|
{
|
ConvertSystemType(writer, reader, writeType);
|
}
|
else
|
{
|
TEMP_FORMAT(errMsg, "fixed arg type:%s.%s not support", klass->namespaze, klass->name);
|
RaiseNotSupportedException(errMsg);
|
}
|
break;
|
}
|
case IL2CPP_TYPE_VALUETYPE:
|
{
|
Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type);
|
if (writeType)
|
{
|
writer.WriteByte((byte)IL2CPP_TYPE_ENUM);
|
IL2CPP_ASSERT(klass->enumtype);
|
int32_t typeIndex = klass->generic_class ? AddIl2CppTypeCache(*type) : ((Il2CppTypeDefinition*)type->data.typeHandle)->byvalTypeIndex;
|
writer.WriteCompressedInt32(typeIndex);
|
}
|
ConvertFixedArg(writer, reader, &klass->element_class->byval_arg, false);
|
break;
|
}
|
case IL2CPP_TYPE_SYSTEM_TYPE:
|
{
|
ConvertSystemType(writer, reader, true);
|
break;
|
}
|
case IL2CPP_TYPE_BOXED_OBJECT:
|
{
|
uint8_t fieldOrPropType = reader.ReadByte();
|
IL2CPP_ASSERT(fieldOrPropType == 0x51);
|
ConvertBoxedValue(writer, reader, writeType);
|
break;
|
}
|
case IL2CPP_TYPE_ENUM:
|
{
|
Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type);
|
IL2CPP_ASSERT(klass->enumtype);
|
if (writeType)
|
{
|
int32_t typeIndex = klass->generic_class ? AddIl2CppTypeCache(*type) : ((Il2CppTypeDefinition*)type->data.typeHandle)->byvalTypeIndex;
|
writer.WriteCompressedInt32(typeIndex);
|
}
|
ConvertFixedArg(writer, reader, &klass->element_class->byval_arg, false);
|
break;
|
}
|
default:
|
{
|
RaiseExecutionEngineException("not support fixed argument type");
|
}
|
}
|
}
|
|
void InterpreterImage::GetFieldDeclaringTypeIndexAndFieldIndexByName(const Il2CppTypeDefinition* declaringType, const char* name, int32_t& typeIndex, int32_t& fieldIndex)
|
{
|
Il2CppClass* klass = il2cpp::vm::GlobalMetadata::GetTypeInfoFromHandle((Il2CppMetadataTypeHandle)declaringType);
|
FieldInfo* field = il2cpp::vm::Class::GetFieldFromName(klass, name);
|
if (!field)
|
{
|
RaiseExecutionEngineException("GetFieldDeclaringTypeIndexAndFieldIndexByName can't find field");
|
}
|
if (field->parent == klass)
|
{
|
typeIndex = kTypeDefinitionIndexInvalid;
|
}
|
else
|
{
|
klass = field->parent;
|
if (klass->generic_class)
|
{
|
RaiseExecutionEngineException("GetFieldDeclaringTypeIndexAndFieldIndexByName doesn't support field of generic CustomAttribute");
|
}
|
typeIndex = il2cpp::vm::GlobalMetadata::GetIndexForTypeDefinition(klass);
|
}
|
fieldIndex = (int32_t)(field - klass->fields);
|
}
|
|
void InterpreterImage::GetPropertyDeclaringTypeIndexAndPropertyIndexByName(const Il2CppTypeDefinition* declaringType, const char* name, int32_t& typeIndex, int32_t& fieldIndex)
|
{
|
Il2CppClass* klass = il2cpp::vm::GlobalMetadata::GetTypeInfoFromHandle((Il2CppMetadataTypeHandle)declaringType);
|
const PropertyInfo* propertyInfo = il2cpp::vm::Class::GetPropertyFromName(klass, name);
|
if (!propertyInfo)
|
{
|
RaiseExecutionEngineException("GetFieldDeclaringTypeIndexAndFieldIndexByName can't find field");
|
}
|
if (propertyInfo->parent == klass)
|
{
|
typeIndex = kTypeDefinitionIndexInvalid;
|
}
|
else
|
{
|
klass = propertyInfo->parent;
|
if (klass->generic_class)
|
{
|
RaiseExecutionEngineException("GetPropertyDeclaringTypeIndexAndPropertyIndexByName doesn't support field of generic CustomAttribute");
|
}
|
typeIndex = il2cpp::vm::GlobalMetadata::GetIndexForTypeDefinition(klass);
|
}
|
#if UNITY_ENGINE_TUANJIE
|
fieldIndex = -1;
|
for (int32_t i = 0; i < klass->property_count; i++)
|
{
|
if (klass->properties[i] == propertyInfo)
|
{
|
fieldIndex = i;
|
break;;
|
}
|
}
|
IL2CPP_ASSERT(fieldIndex != -1);
|
#else
|
fieldIndex = (int32_t)(propertyInfo - klass->properties);
|
#endif
|
}
|
|
void InterpreterImage::ConvertILCustomAttributeData2Il2CppFormat(const MethodInfo* ctorMethod, BlobReader& reader)
|
{
|
uint16_t prolog = reader.Read16();
|
IL2CPP_ASSERT(prolog == 0x0001);
|
IL2CPP_ASSERT(!ctorMethod->is_generic);
|
|
_tempCtorArgBlob.Reset();
|
for (uint16_t i = 0; i < ctorMethod->parameters_count; i++)
|
{
|
const Il2CppType* paramType = GET_METHOD_PARAMETER_TYPE(ctorMethod->parameters[i]);
|
ConvertFixedArg(_tempCtorArgBlob, reader, paramType, true);
|
}
|
|
uint16_t numNamed = reader.Read16();
|
|
uint32_t fieldCount = 0;
|
uint32_t propertyCount = 0;
|
_tempFieldBlob.Reset();
|
_tempPropertyBlob.Reset();
|
const Il2CppTypeDefinition* declaringType = GetUnderlyingTypeDefinition(&ctorMethod->klass->byval_arg);
|
for (uint16_t idx = 0; idx < numNamed; idx++)
|
{
|
byte fieldOrPropTypeTag = reader.ReadByte();
|
IL2CPP_ASSERT(fieldOrPropTypeTag == 0x53 || fieldOrPropTypeTag == 0x54);
|
Il2CppType fieldOrPropType = {};
|
ReadCustomAttributeFieldOrPropType(reader, fieldOrPropType);
|
Il2CppString* fieldOrPropName = ReadSerString(reader);
|
std::string stdStrName = il2cpp::utils::StringUtils::Utf16ToUtf8(fieldOrPropName->chars);
|
const char* cstrName = stdStrName.c_str();
|
int32_t fieldOrPropertyDeclaringTypeIndex = kTypeIndexInvalid;
|
int32_t fieldOrPropertyIndex = 0;
|
if (fieldOrPropTypeTag == 0x53)
|
{
|
++fieldCount;
|
ConvertFixedArg(_tempFieldBlob, reader, &fieldOrPropType, true);
|
GetFieldDeclaringTypeIndexAndFieldIndexByName(declaringType, cstrName, fieldOrPropertyDeclaringTypeIndex, fieldOrPropertyIndex);
|
if (fieldOrPropertyDeclaringTypeIndex == kTypeDefinitionIndexInvalid)
|
{
|
_tempFieldBlob.WriteCompressedInt32(fieldOrPropertyIndex);
|
}
|
else
|
{
|
_tempFieldBlob.WriteCompressedInt32(-fieldOrPropertyIndex - 1);
|
_tempFieldBlob.WriteCompressedUint32(fieldOrPropertyDeclaringTypeIndex);
|
}
|
}
|
else
|
{
|
++propertyCount;
|
ConvertFixedArg(_tempPropertyBlob, reader, &fieldOrPropType, true);
|
GetPropertyDeclaringTypeIndexAndPropertyIndexByName(declaringType, cstrName, fieldOrPropertyDeclaringTypeIndex, fieldOrPropertyIndex);
|
if (fieldOrPropertyDeclaringTypeIndex == kTypeDefinitionIndexInvalid)
|
{
|
_tempPropertyBlob.WriteCompressedInt32(fieldOrPropertyIndex);
|
}
|
else
|
{
|
_tempPropertyBlob.WriteCompressedInt32(-fieldOrPropertyIndex - 1);
|
_tempPropertyBlob.WriteCompressedUint32(fieldOrPropertyDeclaringTypeIndex);
|
}
|
}
|
}
|
_il2cppFormatCustomDataBlob.WriteCompressedUint32(ctorMethod->parameters_count);
|
_il2cppFormatCustomDataBlob.WriteCompressedUint32(fieldCount);
|
_il2cppFormatCustomDataBlob.WriteCompressedUint32(propertyCount);
|
_il2cppFormatCustomDataBlob.Write(_tempCtorArgBlob);
|
_il2cppFormatCustomDataBlob.Write(_tempFieldBlob);
|
_il2cppFormatCustomDataBlob.Write(_tempPropertyBlob);
|
}
|
#endif
|
|
#if !HYBRIDCLR_UNITY_2021_OR_NEW
|
|
void InterpreterImage::ConstructCustomAttribute(BlobReader& reader, Il2CppObject* obj, const MethodInfo* ctorMethod)
|
{
|
uint16_t prolog = reader.Read16();
|
IL2CPP_ASSERT(prolog == 0x0001);
|
if (ctorMethod->parameters_count == 0)
|
{
|
il2cpp::vm::Runtime::Invoke(ctorMethod, obj, nullptr, nullptr);
|
}
|
else
|
{
|
int32_t argSize = sizeof(uint64_t) * ctorMethod->parameters_count;
|
uint64_t* argDatas = (uint64_t*)alloca(argSize);
|
std::memset(argDatas, 0, argSize);
|
void** argPtrs = (void**)alloca(sizeof(void*) * ctorMethod->parameters_count); // same with argDatas
|
for (uint8_t i = 0; i < ctorMethod->parameters_count; i++)
|
{
|
argPtrs[i] = argDatas + i;
|
const Il2CppType* paramType = GET_METHOD_PARAMETER_TYPE(ctorMethod->parameters[i]);
|
ReadFixedArg(reader, paramType, argDatas + i);
|
Il2CppClass* paramKlass = il2cpp::vm::Class::FromIl2CppType(paramType);
|
if (!IS_CLASS_VALUE_TYPE(paramKlass))
|
{
|
argPtrs[i] = (void*)argDatas[i];
|
}
|
}
|
il2cpp::vm::Runtime::Invoke(ctorMethod, obj, argPtrs, nullptr);
|
// clear ref. may not need. gc memory barrier
|
std::memset(argDatas, 0, argSize);
|
}
|
uint16_t numNamed = reader.Read16();
|
Il2CppClass* klass = obj->klass;
|
for (uint16_t idx = 0; idx < numNamed; idx++)
|
{
|
byte fieldOrPropTypeTag = reader.ReadByte();
|
IL2CPP_ASSERT(fieldOrPropTypeTag == 0x53 || fieldOrPropTypeTag == 0x54);
|
Il2CppType fieldOrPropType = {};
|
ReadCustomAttributeFieldOrPropType(reader, fieldOrPropType);
|
Il2CppString* fieldOrPropName = ReadSerString(reader);
|
std::string stdStrName = il2cpp::utils::StringUtils::Utf16ToUtf8(fieldOrPropName->chars);
|
const char* cstrName = stdStrName.c_str();
|
uint64_t value = 0;
|
ReadFixedArg(reader, &fieldOrPropType, &value);
|
if (fieldOrPropTypeTag == 0x53)
|
{
|
FieldInfo* field = il2cpp::vm::Class::GetFieldFromName(klass, cstrName);
|
if (!field)
|
{
|
TEMP_FORMAT(errMsg, "CustomAttribute field missing. klass:%s.%s field:%s", klass->namespaze, klass->name, cstrName);
|
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeInitializationException(errMsg, nullptr));
|
}
|
Il2CppReflectionField* refField = il2cpp::vm::Reflection::GetFieldObject(klass, field);
|
IL2CPP_ASSERT(IsTypeEqual(&fieldOrPropType, field->type));
|
uint32_t fieldSize = GetTypeValueSize(&fieldOrPropType);
|
std::memcpy((byte*)obj + field->offset, &value, fieldSize);
|
//fixme MEMORY BARRIER
|
IL2CPP_ASSERT(refField);
|
}
|
else
|
{
|
const PropertyInfo* prop = il2cpp::vm::Class::GetPropertyFromName(klass, cstrName);
|
if (!prop)
|
{
|
TEMP_FORMAT(errMsg, "CustomAttribute property missing. klass:%s property:%s", klass->name, cstrName);
|
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeInitializationException(errMsg, nullptr));
|
}
|
IL2CPP_ASSERT(IsTypeEqual(&fieldOrPropType, GET_METHOD_PARAMETER_TYPE(prop->set->parameters[0])));
|
Il2CppException* ex = nullptr;
|
Il2CppClass* propKlass = il2cpp::vm::Class::FromIl2CppType(&fieldOrPropType);
|
IL2CPP_ASSERT(propKlass);
|
void* args[] = { (IS_CLASS_VALUE_TYPE(propKlass) ? &value : (void*)value) };
|
il2cpp::vm::Runtime::Invoke(prop->set, obj, args, &ex);
|
if (ex)
|
{
|
il2cpp::vm::Exception::Raise(ex);
|
}
|
}
|
}
|
}
|
|
CustomAttributesCache* InterpreterImage::GenerateCustomAttributesCacheInternal(CustomAttributeIndex index)
|
{
|
IL2CPP_ASSERT(index != kCustomAttributeIndexInvalid);
|
CustomAttributesCache* cache = _customAttribtesCaches[index];
|
if (cache)
|
{
|
return cache;
|
}
|
IL2CPP_ASSERT(index < (CustomAttributeIndex)_customAttributeHandles.size());
|
|
Il2CppCustomAttributeTypeRange& typeRange = _customAttributeHandles[index];
|
|
il2cpp::os::FastAutoLock metaLock(&il2cpp::vm::g_MetadataLock);
|
cache = _customAttribtesCaches[index];
|
if (cache)
|
{
|
return cache;
|
}
|
|
hybridclr::interpreter::ExecutingInterpImageScope scope(hybridclr::interpreter::InterpreterModule::GetCurrentThreadMachineState(), this->_il2cppImage);
|
|
cache = (CustomAttributesCache*)IL2CPP_CALLOC(1, sizeof(CustomAttributesCache));
|
int32_t count;
|
#ifdef HYBRIDCLR_UNITY_2021_OR_NEW
|
count = (int32_t)(_customAttributeHandles[index + 1].startOffset - typeRange.startOffset);
|
#else
|
count = (int32_t)typeRange.count;
|
#endif
|
cache->count = count;
|
cache->attributes = (Il2CppObject**)il2cpp::gc::GarbageCollector::AllocateFixed(sizeof(Il2CppObject*) * count, 0);
|
|
int32_t start = DecodeMetadataIndex(GET_CUSTOM_ATTRIBUTE_TYPE_RANGE_START(typeRange));
|
for (int32_t i = 0; i < count; i++)
|
{
|
int32_t attrIndex = start + i;
|
IL2CPP_ASSERT(attrIndex >= 0 && attrIndex < (int32_t)_customAttribues.size());
|
CustomAttribute& ca = _customAttribues[attrIndex];
|
MethodRefInfo mri = {};
|
ReadMethodRefInfoFromToken(nullptr, nullptr, DecodeTokenTableType(ca.ctorMethodToken), DecodeTokenRowIndex(ca.ctorMethodToken), mri);
|
const MethodInfo* ctorMethod = GetMethodInfoFromMethodDef(&mri.containerType, mri.methodDef);
|
IL2CPP_ASSERT(ctorMethod);
|
Il2CppClass* klass = ctorMethod->klass;
|
Il2CppObject* attr = il2cpp::vm::Object::New(klass);
|
Il2CppArray* paramArr = nullptr;
|
if (ca.value != 0)
|
{
|
BlobReader reader = _rawImage.GetBlobReaderByRawIndex(ca.value);
|
ConstructCustomAttribute(reader, attr, ctorMethod);
|
}
|
else
|
{
|
IL2CPP_ASSERT(ctorMethod->parameters_count == 0);
|
il2cpp::vm::Runtime::Invoke(ctorMethod, attr, nullptr, nullptr);
|
}
|
|
cache->attributes[i] = attr;
|
HYBRIDCLR_SET_WRITE_BARRIER((void**)cache->attributes + i);
|
}
|
|
il2cpp::os::Atomic::FullMemoryBarrier();
|
_customAttribtesCaches[index] = cache;
|
return cache;
|
}
|
#elif HYBRIDCLR_UNITY_2021
|
CustomAttributesCache* InterpreterImage::GenerateCustomAttributesCacheInternal(CustomAttributeIndex index)
|
{
|
IL2CPP_ASSERT(index != kCustomAttributeIndexInvalid);
|
CustomAttributesCache* cache = _customAttribtesCaches[index];
|
if (cache)
|
{
|
return cache;
|
}
|
IL2CPP_ASSERT(index < (CustomAttributeIndex)_customAttributeHandles.size());
|
|
Il2CppCustomAttributeTypeRange& typeRange = _customAttributeHandles[index];
|
|
cache = _customAttribtesCaches[index];
|
if (cache)
|
{
|
return cache;
|
}
|
|
hybridclr::interpreter::ExecutingInterpImageScope scope(hybridclr::interpreter::InterpreterModule::GetCurrentThreadMachineState(), this->_il2cppImage);
|
|
void* start;
|
void* end;
|
std::tie(start, end) = CreateCustomAttributeDataTuple(&typeRange);
|
IL2CPP_ASSERT(start && end);
|
|
il2cpp::metadata::CustomAttributeDataReader reader(start, end);
|
|
cache = (CustomAttributesCache*)IL2CPP_CALLOC(1, sizeof(CustomAttributesCache));
|
cache->count = (int)reader.GetCount();
|
cache->attributes = (Il2CppObject**)il2cpp::gc::GarbageCollector::AllocateFixed(sizeof(Il2CppObject*) * cache->count, 0);
|
|
il2cpp::metadata::CustomAttributeDataIterator iter = reader.GetDataIterator();
|
for (int i = 0; i < cache->count; i++)
|
{
|
Il2CppException* exc = NULL;
|
il2cpp::metadata::CustomAttributeCreator creator;
|
if (reader.VisitCustomAttributeData(_il2cppImage, &iter, &creator, &exc))
|
{
|
cache->attributes[i] = creator.GetAttribute(&exc);
|
HYBRIDCLR_SET_WRITE_BARRIER((void**)&cache->attributes[i]);
|
}
|
|
if (exc != NULL)
|
{
|
il2cpp::gc::GarbageCollector::FreeFixed(cache->attributes);
|
IL2CPP_FREE(cache);
|
il2cpp::vm::Exception::Raise(exc);
|
}
|
}
|
|
|
il2cpp::os::FastAutoLock metaLock(&il2cpp::vm::g_MetadataLock);
|
CustomAttributesCache* original = _customAttribtesCaches[index];
|
if (original)
|
{
|
// A non-NULL return value indicates some other thread already generated this cache.
|
// We need to cleanup the resources we allocated
|
il2cpp::gc::GarbageCollector::FreeFixed(cache->attributes);
|
IL2CPP_FREE(cache);
|
return original;
|
}
|
il2cpp::os::Atomic::FullMemoryBarrier();
|
_customAttribtesCaches[index] = cache;
|
return cache;
|
}
|
#endif
|
|
void InterpreterImage::InitMethodDefs0()
|
{
|
const Table& typeDefTb = _rawImage.GetTable(TableType::TYPEDEF);
|
const Table& methodTb = _rawImage.GetTable(TableType::METHOD);
|
|
_methodDefines.resize(methodTb.rowNum);
|
for (Il2CppMethodDefinition& md : _methodDefines)
|
{
|
md.genericContainerIndex = kGenericContainerIndexInvalid;
|
}
|
}
|
|
void InterpreterImage::InitMethodDefs()
|
{
|
const Table& typeDefTb = _rawImage.GetTable(TableType::TYPEDEF);
|
const Table& methodTb = _rawImage.GetTable(TableType::METHOD);
|
|
for (uint32_t i = 0, n = typeDefTb.rowNum; i < n; i++)
|
{
|
Il2CppTypeDefinition& typeDef = _typesDefines[i];
|
uint32_t rawMethodStart = DecodeMetadataIndex(typeDef.methodStart);
|
|
for (int m = 0; m < typeDef.method_count; m++)
|
{
|
Il2CppMethodDefinition& md = _methodDefines[rawMethodStart + m];
|
md.declaringType = EncodeWithIndex(i);
|
}
|
}
|
|
|
_methodDefine2InfoCaches.resize(methodTb.rowNum);
|
_methodBodies.resize(methodTb.rowNum);
|
|
int32_t paramTableRowNum = _rawImage.GetTable(TableType::PARAM).rowNum;
|
for (uint32_t index = 0; index < methodTb.rowNum; index++)
|
{
|
Il2CppMethodDefinition& md = _methodDefines[index];
|
uint32_t rowIndex = index + 1;
|
TbMethod methodData = _rawImage.ReadMethod(rowIndex);
|
|
md.nameIndex = EncodeWithIndex(methodData.name);
|
md.parameterStart = methodData.paramList - 1;
|
//md.genericContainerIndex = kGenericContainerIndexInvalid;
|
md.token = EncodeToken(TableType::METHOD, rowIndex);
|
md.flags = methodData.flags;
|
md.iflags = methodData.implFlags;
|
md.slot = kInvalidIl2CppMethodSlot;
|
if (index > 0)
|
{
|
auto& last = _methodDefines[index - 1];
|
last.parameterCount = md.parameterStart - last.parameterStart;
|
}
|
if (index == methodTb.rowNum - 1)
|
{
|
md.parameterCount = (int)paramTableRowNum - (int32_t)md.parameterStart;
|
}
|
|
//MethodBody& body = _methodBodies[index];
|
//ReadMethodBody(md, methodData, body);
|
}
|
|
for (uint32_t i = 0, n = typeDefTb.rowNum; i < n; i++)
|
{
|
Il2CppTypeDefinition& typeDef = _typesDefines[i];
|
uint32_t rawMethodStart = DecodeMetadataIndex(typeDef.methodStart);
|
bool isInterface = IsInterface(typeDef.flags);
|
uint16_t slotIdx = 0;
|
for (int m = 0; m < typeDef.method_count; m++)
|
{
|
Il2CppMethodDefinition& md = _methodDefines[rawMethodStart + m];
|
const char* methodName = _rawImage.GetStringFromRawIndex(DecodeMetadataIndex(md.nameIndex));
|
if (!std::strcmp(methodName, ".cctor"))
|
{
|
typeDef.bitfield |= (1 << (il2cpp::vm::kBitHasStaticConstructor - 1));
|
}
|
if (!std::strcmp(methodName, "Finalize"))
|
{
|
typeDef.bitfield |= (1 << (il2cpp::vm::kBitHasFinalizer - 1));
|
}
|
if (isInterface && IsInstanceMethod(&md) && IsVirtualMethod(md.flags))
|
{
|
md.slot = slotIdx++;
|
}
|
// TODO 可以考虑优化一下,将 signature在前一步存到暂时不用的 returnType里
|
TbMethod methodData = _rawImage.ReadMethod(rawMethodStart + m + 1);
|
|
BlobReader methodSigReader = _rawImage.GetBlobReaderByRawIndex(methodData.signature);
|
uint32_t namedParamStart = md.parameterStart;
|
uint32_t namedParamCount = md.parameterCount;
|
|
uint32_t actualParamStart = (uint32_t)_params.size();
|
ReadMethodDefSig(
|
methodSigReader,
|
GetGenericContainerByTypeDefinition(&typeDef),
|
GetGenericContainerByRawIndex(DecodeMetadataIndex(md.genericContainerIndex)),
|
md,
|
_params);
|
uint32_t actualParamCount = (uint32_t)_params.size() - actualParamStart;
|
md.parameterStart = actualParamStart;
|
md.parameterCount = actualParamCount;
|
for (uint32_t paramRowIndex = namedParamStart + 1; paramRowIndex <= namedParamStart + namedParamCount; paramRowIndex++)
|
{
|
TbParam data = _rawImage.ReadParam(paramRowIndex);
|
if (data.sequence > 0)
|
{
|
int32_t actualParamIndex = actualParamStart + data.sequence - 1;
|
ParamDetail& paramDetail = _params[actualParamIndex];
|
Il2CppParameterDefinition& pd = paramDetail.paramDef;
|
IL2CPP_ASSERT(paramDetail.parameterIndex == data.sequence - 1);
|
pd.nameIndex = EncodeWithIndex(data.name);
|
pd.token = EncodeToken(TableType::PARAM, paramRowIndex);
|
_paramRawIndex2ActualParamIndex[paramRowIndex - 1] = actualParamIndex;
|
if (data.flags)
|
{
|
paramDetail.type.attrs = data.flags;
|
pd.typeIndex = AddIl2CppTypeCache(paramDetail.type);
|
}
|
}
|
else
|
{
|
// data.sequence == 0 is for returnType.
|
// used for parent of CustomeAttributes of ReturnType
|
// il2cpp not support ReturnType CustomAttributes. so we just ignore it.
|
}
|
}
|
}
|
}
|
}
|
|
std::vector<MethodImpl> s_emptyMethodImpls;
|
|
const std::vector<MethodImpl>& InterpreterImage::GetTypeMethodImplByTypeDefinition(const Il2CppTypeDefinition* typeDef)
|
{
|
uint32_t index = (uint32_t)(typeDef - &_typesDefines[0]);
|
IL2CPP_ASSERT(index < (uint32_t)_typeDetails.size());
|
TypeDefinitionDetail& tdd = _typeDetails[index];
|
std::vector<MethodImpl>* methodImpls = tdd.methodImpls;
|
if (methodImpls == nullptr)
|
{
|
if (tdd.methodImplCount == 0)
|
{
|
methodImpls = &s_emptyMethodImpls;
|
}
|
else
|
{
|
methodImpls = new std::vector<MethodImpl>(tdd.methodImplCount);
|
for (uint32_t i = 0; i < tdd.methodImplCount; i++)
|
{
|
uint32_t index = tdd.methodImplStart + i;
|
TbMethodImpl data = _rawImage.ReadMethodImpl(index + 1);
|
TypeDefinitionDetail& tdd = _typeDetails[data.classIdx - 1];
|
Il2CppGenericContainer* gc = GetGenericContainerByTypeDefinition(tdd.typeDef);
|
MethodImpl& impl = (*methodImpls)[i];
|
ReadMethodRefInfoFromToken(gc, nullptr, DecodeMethodDefOrRefCodedIndexTableType(data.methodBody), DecodeMethodDefOrRefCodedIndexRowIndex(data.methodBody), impl.body);
|
ReadMethodRefInfoFromToken(gc, nullptr, DecodeMethodDefOrRefCodedIndexTableType(data.methodDeclaration), DecodeMethodDefOrRefCodedIndexRowIndex(data.methodDeclaration), impl.declaration);
|
}
|
}
|
|
|
tdd.methodImpls = methodImpls;
|
}
|
return *methodImpls;
|
}
|
|
void InterpreterImage::InitMethodImpls0()
|
{
|
const Table& miTb = _rawImage.GetTable(TableType::METHODIMPL);
|
for (uint32_t i = 0; i < miTb.rowNum; i++)
|
{
|
TbMethodImpl data = _rawImage.ReadMethodImpl(i + 1);
|
TypeDefinitionDetail& tdd = _typeDetails[data.classIdx - 1];
|
Il2CppGenericContainer* gc = GetGenericContainerByTypeDefinition(tdd.typeDef);
|
if (tdd.methodImplCount == 0)
|
{
|
tdd.methodImplStart = i;
|
}
|
++tdd.methodImplCount;
|
//MethodImpl impl;
|
//ReadMethodRefInfoFromToken(gc, nullptr, DecodeMethodDefOrRefCodedIndexTableType(data.methodBody), DecodeMethodDefOrRefCodedIndexRowIndex(data.methodBody), impl.body);
|
//ReadMethodRefInfoFromToken(gc, nullptr, DecodeMethodDefOrRefCodedIndexTableType(data.methodDeclaration), DecodeMethodDefOrRefCodedIndexRowIndex(data.methodDeclaration), impl.declaration);
|
//tdd.methodImpls.push_back(impl);
|
}
|
}
|
|
void InterpreterImage::InitProperties()
|
{
|
const Table& propertyMapTb = _rawImage.GetTable(TableType::PROPERTYMAP);
|
const Table& propertyTb = _rawImage.GetTable(TableType::PROPERTY);
|
_propeties.reserve(propertyTb.rowNum);
|
|
for (uint32_t rowIndex = 1; rowIndex <= propertyTb.rowNum; rowIndex++)
|
{
|
TbProperty data = _rawImage.ReadProperty(rowIndex);
|
_propeties.push_back({ _rawImage.GetStringFromRawIndex(data.name), data.flags, data.type, 0, 0
|
, nullptr
|
, { (StringIndex)EncodeWithIndex(data.name), kMethodIndexInvalid, kMethodIndexInvalid, (uint32_t)data.flags, EncodeToken(TableType::PROPERTY, rowIndex)}
|
});
|
}
|
|
Il2CppTypeDefinition* last = nullptr;
|
for (uint32_t rowIndex = 1; rowIndex <= propertyMapTb.rowNum; rowIndex++)
|
{
|
TbPropertyMap data = _rawImage.ReadPropertyMap(rowIndex);
|
TypeDefinitionDetail& cur = _typeDetails[data.parent - 1];
|
cur.typeDef->propertyStart = EncodeWithIndex(data.propertyList); // start from 1
|
if (last != nullptr)
|
{
|
last->property_count = data.propertyList - DecodeMetadataIndex(last->propertyStart);
|
}
|
last = cur.typeDef;
|
}
|
if (last)
|
{
|
last->property_count = propertyTb.rowNum - DecodeMetadataIndex(last->propertyStart) + 1;
|
}
|
#if HYBRIDCLR_UNITY_2019
|
for (const TypeDefinitionDetail& tdd : _typeDetails)
|
{
|
const Il2CppTypeDefinition* typeDef = tdd.typeDef;
|
if (typeDef->property_count == 0)
|
{
|
continue;
|
}
|
for (int32_t start = DecodeMetadataIndex(typeDef->propertyStart), i = 0; i < typeDef->property_count; i++)
|
{
|
_propeties[start + i - 1].declaringType = typeDef;
|
}
|
}
|
#endif
|
}
|
|
void InterpreterImage::InitEvents()
|
{
|
const Table& eventMapTb = _rawImage.GetTable(TableType::EVENTMAP);
|
const Table& eventTb = _rawImage.GetTable(TableType::EVENT);
|
_events.reserve(eventTb.rowNum);
|
|
for (uint32_t rowIndex = 1; rowIndex <= eventTb.rowNum; rowIndex++)
|
{
|
TbEvent data = _rawImage.ReadEvent(rowIndex);
|
_events.push_back({ _rawImage.GetStringFromRawIndex(data.name), data.eventFlags, data.eventType, 0, 0, 0
|
#if HYBRIDCLR_UNITY_2019
|
, nullptr
|
, { (StringIndex)EncodeWithIndex(data.name), kTypeIndexInvalid, kMethodIndexInvalid, kMethodIndexInvalid, kMethodIndexInvalid, EncodeToken(TableType::EVENT, rowIndex)}
|
#endif
|
});
|
}
|
|
Il2CppTypeDefinition* last = nullptr;
|
for (uint32_t rowIndex = 1; rowIndex <= eventMapTb.rowNum; rowIndex++)
|
{
|
TbEventMap data = _rawImage.ReadEventMap(rowIndex);
|
TypeDefinitionDetail& cur = _typeDetails[data.parent - 1];
|
cur.typeDef->eventStart = EncodeWithIndex(data.eventList); // start from 1
|
if (last != nullptr)
|
{
|
last->event_count = data.eventList - DecodeMetadataIndex(last->eventStart);
|
}
|
last = cur.typeDef;
|
}
|
if (last)
|
{
|
last->event_count = eventTb.rowNum - DecodeMetadataIndex(last->eventStart) + 1;
|
}
|
#if HYBRIDCLR_UNITY_2019
|
for (const TypeDefinitionDetail& tdd : _typeDetails)
|
{
|
const Il2CppTypeDefinition* typeDef = tdd.typeDef;
|
if (typeDef->event_count == 0)
|
{
|
continue;
|
}
|
for (int32_t start = DecodeMetadataIndex(typeDef->eventStart), i = 0; i < typeDef->event_count; i++)
|
{
|
EventDetail& ed = _events[start + i - 1];
|
ed.declaringType = typeDef;
|
ed.il2cppDefinition.typeIndex = typeDef->byvalTypeIndex;
|
}
|
}
|
#endif
|
}
|
|
|
void InterpreterImage::InitMethodSemantics()
|
{
|
const Table& msTb = _rawImage.GetTable(TableType::METHODSEMANTICS);
|
for (uint32_t rowIndex = 1; rowIndex <= msTb.rowNum; rowIndex++)
|
{
|
TbMethodSemantics data = _rawImage.ReadMethodSemantics(rowIndex);
|
uint32_t method = data.method;
|
uint16_t semantics = data.semantics;
|
TableType tableType = DecodeHasSemanticsCodedIndexTableType(data.association);
|
uint32_t propertyOrEventIndex = DecodeHasSemanticsCodedIndexRowIndex(data.association) - 1;
|
if (semantics & (uint16_t)MethodSemanticsAttributes::Getter)
|
{
|
IL2CPP_ASSERT(tableType == TableType::PROPERTY);
|
PropertyDetail& pd = _propeties[propertyOrEventIndex];
|
pd.getterMethodIndex = method;
|
#if HYBRIDCLR_UNITY_2019
|
pd.il2cppDefinition.get = method - DecodeMetadataIndex(pd.declaringType->methodStart) - 1;
|
#endif
|
}
|
if (semantics & (uint16_t)MethodSemanticsAttributes::Setter)
|
{
|
IL2CPP_ASSERT(tableType == TableType::PROPERTY);
|
PropertyDetail& pd = _propeties[propertyOrEventIndex];
|
pd.setterMethodIndex = method;
|
#if HYBRIDCLR_UNITY_2019
|
pd.il2cppDefinition.set = method - DecodeMetadataIndex(pd.declaringType->methodStart) - 1;
|
#endif
|
}
|
if (semantics & (uint16_t)MethodSemanticsAttributes::AddOn)
|
{
|
IL2CPP_ASSERT(tableType == TableType::EVENT);
|
EventDetail& ed = _events[propertyOrEventIndex];
|
ed.addMethodIndex = method;
|
#if HYBRIDCLR_UNITY_2019
|
ed.il2cppDefinition.add = method - DecodeMetadataIndex(ed.declaringType->methodStart) - 1;
|
#endif
|
}
|
if (semantics & (uint16_t)MethodSemanticsAttributes::RemoveOn)
|
{
|
IL2CPP_ASSERT(tableType == TableType::EVENT);
|
EventDetail& ed = _events[propertyOrEventIndex];
|
ed.removeMethodIndex = method;
|
#if HYBRIDCLR_UNITY_2019
|
ed.il2cppDefinition.remove = method - DecodeMetadataIndex(ed.declaringType->methodStart) - 1;
|
#endif
|
}
|
if (semantics & (uint16_t)MethodSemanticsAttributes::Fire)
|
{
|
IL2CPP_ASSERT(tableType == TableType::EVENT);
|
EventDetail& ed = _events[propertyOrEventIndex];
|
ed.fireMethodIndex = method;
|
#if HYBRIDCLR_UNITY_2019
|
ed.il2cppDefinition.raise = method - DecodeMetadataIndex(ed.declaringType->methodStart) - 1;
|
#endif
|
}
|
}
|
}
|
|
struct EnclosingClassInfo
|
{
|
uint32_t enclosingTypeIndex; // rowIndex - 1
|
std::vector<uint32_t> nestedTypeIndexs;
|
};
|
|
void InterpreterImage::InitNestedClass()
|
{
|
const Table& nestedClassTb = _rawImage.GetTable(TableType::NESTEDCLASS);
|
_nestedTypeDefineIndexs.reserve(nestedClassTb.rowNum);
|
std::vector<EnclosingClassInfo> enclosingTypes;
|
|
for (uint32_t i = 0; i < nestedClassTb.rowNum; i++)
|
{
|
TbNestedClass data = _rawImage.ReadNestedClass(i + 1);
|
Il2CppTypeDefinition& nestedType = _typesDefines[data.nestedClass - 1];
|
Il2CppTypeDefinition& enclosingType = _typesDefines[data.enclosingClass - 1];
|
if (enclosingType.nested_type_count == 0)
|
{
|
// 此行代码不能删,用于标识 enclosingTypes的index
|
enclosingType.nestedTypesStart = (uint32_t)enclosingTypes.size();
|
enclosingTypes.push_back({ data.enclosingClass - 1 });
|
}
|
++enclosingType.nested_type_count;
|
enclosingTypes[enclosingType.nestedTypesStart].nestedTypeIndexs.push_back(data.nestedClass - 1);
|
//_nestedTypeDefineIndexs.push_back(data.nestedClass - 1);
|
nestedType.declaringTypeIndex = enclosingType.byvalTypeIndex;
|
}
|
|
for (auto& enclosingType : enclosingTypes)
|
{
|
Il2CppTypeDefinition& enclosingTypeDef = _typesDefines[enclosingType.enclosingTypeIndex];
|
IL2CPP_ASSERT(enclosingType.nestedTypeIndexs.size() == (size_t)enclosingTypeDef.nested_type_count);
|
enclosingTypeDef.nestedTypesStart = (NestedTypeIndex)_nestedTypeDefineIndexs.size();
|
enclosingTypeDef.nested_type_count = (uint16_t)enclosingType.nestedTypeIndexs.size();
|
_nestedTypeDefineIndexs.insert(_nestedTypeDefineIndexs.end(), enclosingType.nestedTypeIndexs.begin(), enclosingType.nestedTypeIndexs.end());
|
}
|
}
|
|
void InterpreterImage::InitClassLayouts()
|
{
|
const Table& classLayoutTb = _rawImage.GetTable(TableType::CLASSLAYOUT);
|
for (uint32_t i = 0; i < classLayoutTb.rowNum; i++)
|
{
|
TbClassLayout data = _rawImage.ReadClassLayout(i + 1);
|
_classLayouts[data.parent - 1] = data;
|
if (data.classSize > 0)
|
{
|
Il2CppTypeDefinitionSizes& typeSizes = _typeDetails[data.parent - 1].typeSizes;
|
typeSizes.instance_size = data.classSize + sizeof(Il2CppObject);
|
}
|
}
|
|
ClassFieldLayoutCalculator calculator(this);
|
for (TypeDefinitionDetail& type : _typeDetails)
|
{
|
const Il2CppType* il2cppType = GetIl2CppTypeFromRawTypeDefIndex(type.index);
|
calculator.CalcClassNotStaticFields(il2cppType);
|
}
|
|
for (TypeDefinitionDetail& type : _typeDetails)
|
{
|
const Il2CppType* il2cppType = GetIl2CppTypeFromRawTypeDefIndex(type.index);
|
calculator.CalcClassStaticFields(il2cppType);
|
ClassLayoutInfo* layout = calculator.GetClassLayoutInfo(il2cppType);
|
Il2CppTypeDefinition* typeDef = type.typeDef;
|
|
auto& sizes = type.typeSizes;
|
sizes.native_size = layout->nativeSize;
|
if (typeDef->genericContainerIndex == kGenericContainerIndexInvalid)
|
{
|
sizes.static_fields_size = layout->staticFieldsSize;
|
sizes.thread_static_fields_size = layout->threadStaticFieldsSize;
|
}
|
else
|
{
|
sizes.static_fields_size = 0;
|
sizes.thread_static_fields_size = 0;
|
}
|
if (sizes.instance_size == 0)
|
{
|
sizes.instance_size = layout->instanceSize;
|
}
|
int32_t fieldStart = DecodeMetadataIndex(typeDef->fieldStart);
|
for (int32_t i = 0, end = typeDef->field_count; i < end ; i++)
|
{
|
FieldDetail& fd = _fieldDetails[fieldStart + i];
|
FieldLayout& fieldLayout = layout->fields[i];
|
if (fd.offset == 0)
|
{
|
fd.offset = fieldLayout.offset;
|
}
|
else if (fd.offset == THREAD_LOCAL_STATIC_MASK)
|
{
|
fd.offset = fieldLayout.offset;
|
}
|
else
|
{
|
IL2CPP_ASSERT(fd.offset == fieldLayout.offset);
|
int a = 0;
|
}
|
}
|
}
|
}
|
|
uint32_t InterpreterImage::AddIl2CppTypeCache(const Il2CppType& type)
|
{
|
auto it = _type2Indexs.find(&type);
|
if (it != _type2Indexs.end())
|
{
|
return it->second;
|
}
|
uint32_t encodeIndex = EncodeWithIndex((uint32_t)_types.size());
|
Il2CppType* newType = (Il2CppType*)HYBRIDCLR_METADATA_MALLOC(sizeof(Il2CppType));
|
*newType = type;
|
_types.push_back(newType);
|
_type2Indexs.insert({ newType, encodeIndex });
|
return encodeIndex;
|
}
|
|
uint32_t InterpreterImage::AddIl2CppGenericContainers(Il2CppGenericContainer& geneContainer)
|
{
|
uint32_t index = (uint32_t)_genericContainers.size();
|
_genericContainers.push_back(geneContainer);
|
return EncodeWithIndex(index);
|
}
|
|
void InterpreterImage::InitClass()
|
{
|
const Table& typeDefTb = _rawImage.GetTable(TableType::TYPEDEF);
|
_classList.resize(typeDefTb.rowNum);
|
}
|
|
Il2CppClass* InterpreterImage::GetTypeInfoFromTypeDefinitionRawIndex(uint32_t index)
|
{
|
IL2CPP_ASSERT(index < _classList.size());
|
Il2CppClass* klass = _classList[index];
|
if (klass)
|
{
|
return klass;
|
}
|
il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
|
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;
|
}
|
|
const Il2CppType* InterpreterImage::GetInterfaceFromGlobalOffset(TypeInterfaceIndex globalOffset)
|
{
|
IL2CPP_ASSERT((uint32_t)globalOffset < (uint32_t)_interfaceDefines.size());
|
|
TypeIndex typeIndex = _interfaceDefines[globalOffset];
|
if (typeIndex == kTypeIndexInvalid)
|
{
|
uint32_t rowIndex = globalOffset + 1;
|
TbInterfaceImpl data = _rawImage.ReadInterfaceImpl(rowIndex);
|
Il2CppTypeDefinition& typeDef = _typesDefines[data.classIdx - 1];
|
Il2CppType intType = {};
|
ReadTypeFromToken(GetGenericContainerByTypeDefinition(&typeDef), nullptr,
|
DecodeTypeDefOrRefOrSpecCodedIndexTableType(data.interfaceIdx), DecodeTypeDefOrRefOrSpecCodedIndexRowIndex(data.interfaceIdx), intType);
|
_interfaceDefines[globalOffset] = typeIndex = DecodeMetadataIndex(AddIl2CppTypeCache(intType));
|
}
|
|
return _types[typeIndex];
|
}
|
|
const Il2CppType* InterpreterImage::GetInterfaceFromIndex(const Il2CppClass* klass, TypeInterfaceIndex globalOffset)
|
{
|
return GetInterfaceFromGlobalOffset(globalOffset);
|
}
|
|
const Il2CppType* InterpreterImage::GetInterfaceFromOffset(const Il2CppClass* klass, TypeInterfaceIndex offset)
|
{
|
const Il2CppTypeDefinition* typeDef = (const Il2CppTypeDefinition*)(klass->typeMetadataHandle);
|
IL2CPP_ASSERT(typeDef);
|
return GetInterfaceFromOffset(typeDef, offset);
|
}
|
|
const Il2CppType* InterpreterImage::GetInterfaceFromOffset(const Il2CppTypeDefinition* typeDef, TypeInterfaceIndex offset)
|
{
|
uint32_t globalOffset = typeDef->interfacesStart + offset;
|
return GetInterfaceFromGlobalOffset(globalOffset);
|
}
|
|
Il2CppInterfaceOffsetInfo InterpreterImage::GetInterfaceOffsetInfo(const Il2CppTypeDefinition* typeDefine, TypeInterfaceOffsetIndex index)
|
{
|
uint32_t globalIndex = DecodeMetadataIndex((uint32_t)(typeDefine->interfaceOffsetsStart + index));
|
IL2CPP_ASSERT(globalIndex < (uint32_t)_interfaceOffsets.size());
|
|
InterfaceOffsetInfo& offsetPair = _interfaceOffsets[globalIndex];
|
return { offsetPair.type, (int32_t)offsetPair.offset };
|
}
|
|
Il2CppClass* InterpreterImage::GetNestedTypeFromOffset(const Il2CppTypeDefinition* typeDefine, TypeNestedTypeIndex offset)
|
{
|
uint32_t globalIndex = typeDefine->nestedTypesStart + offset;
|
IL2CPP_ASSERT(globalIndex < (uint32_t)_nestedTypeDefineIndexs.size());
|
uint32_t typeDefIndex = _nestedTypeDefineIndexs[globalIndex];
|
IL2CPP_ASSERT(typeDefIndex < (uint32_t)_typesDefines.size());
|
return il2cpp::vm::GlobalMetadata::GetTypeInfoFromHandle((Il2CppMetadataTypeHandle)&_typesDefines[typeDefIndex]);
|
}
|
|
Il2CppClass* InterpreterImage::GetNestedTypeFromOffset(const Il2CppClass* klass, TypeNestedTypeIndex offset)
|
{
|
return GetNestedTypeFromOffset((Il2CppTypeDefinition*)klass->typeMetadataHandle, offset);
|
}
|
|
Il2CppTypeDefinition* InterpreterImage::GetNestedTypes(Il2CppTypeDefinition* typeDefinition, void** iter)
|
{
|
if (_nestedTypeDefineIndexs.empty())
|
{
|
return nullptr;
|
}
|
const TypeDefinitionIndex* nestedTypeIndices = (const TypeDefinitionIndex*)(&_nestedTypeDefineIndexs[typeDefinition->nestedTypesStart]);
|
|
if (!*iter)
|
{
|
if (typeDefinition->nested_type_count == 0)
|
return NULL;
|
|
*iter = (void*)(nestedTypeIndices);
|
return &_typesDefines[nestedTypeIndices[0]];
|
}
|
|
TypeDefinitionIndex* nestedTypeAddress = (TypeDefinitionIndex*)*iter;
|
nestedTypeAddress++;
|
ptrdiff_t index = nestedTypeAddress - nestedTypeIndices;
|
|
if (index < typeDefinition->nested_type_count)
|
{
|
*iter = nestedTypeAddress;
|
return &_typesDefines[*nestedTypeAddress];
|
}
|
|
return NULL;
|
}
|
|
const Il2CppAssembly* InterpreterImage::GetReferencedAssembly(int32_t referencedAssemblyTableIndex, const Il2CppAssembly assembliesTable[], int assembliesCount)
|
{
|
auto& table = _rawImage.GetTable(TableType::ASSEMBLYREF);
|
IL2CPP_ASSERT((uint32_t)referencedAssemblyTableIndex < table.rowNum);
|
|
TbAssemblyRef assRef = _rawImage.ReadAssemblyRef(referencedAssemblyTableIndex + 1);
|
const char* refAssName = _rawImage.GetStringFromRawIndex(assRef.name);
|
const Il2CppAssembly* il2cppAssRef = il2cpp::vm::Assembly::GetLoadedAssembly(refAssName);
|
if (!il2cppAssRef)
|
{
|
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetDllNotFoundException(refAssName));
|
}
|
return il2cppAssRef;
|
}
|
|
void InterpreterImage::ReadFieldRefInfoFromFieldDefToken(uint32_t rowIndex, FieldRefInfo& ret)
|
{
|
IL2CPP_ASSERT(rowIndex > 0);
|
const FieldDetail& fd = GetFieldDetailFromRawIndex(rowIndex - 1);
|
ret.containerType = *GetIl2CppTypeFromRawTypeDefIndex(DecodeMetadataIndex(fd.typeDefIndex));
|
ret.field = &fd.fieldDef;
|
}
|
|
void InterpreterImage::GetClassAndMethodGenericContainerFromGenericContainerIndex(GenericContainerIndex idx, const Il2CppGenericContainer*& klassGc, const Il2CppGenericContainer*& methodGc)
|
{
|
Il2CppGenericContainer* gc = GetGenericContainerByRawIndex(DecodeMetadataIndex(idx));
|
IL2CPP_ASSERT(gc);
|
if (gc->is_method)
|
{
|
const Il2CppMethodDefinition* methodDef = GetMethodDefinitionFromRawIndex(DecodeMetadataIndex(gc->ownerIndex));
|
klassGc = GetGenericContainerByTypeDefRawIndex(DecodeMetadataIndex(methodDef->declaringType));
|
methodGc = GetGenericContainerByRawIndex(DecodeMetadataIndex(methodDef->genericContainerIndex));
|
}
|
else
|
{
|
klassGc = gc;
|
methodGc = nullptr;
|
}
|
}
|
|
void InterpreterImage::InitGenericParamConstraintDefs()
|
{
|
const Table& tb = _rawImage.GetTable(TableType::GENERICPARAMCONSTRAINT);
|
_genericConstraints.resize(tb.rowNum, kTypeIndexInvalid);
|
for (uint32_t i = 0; i < tb.rowNum; i++)
|
{
|
uint32_t rowIndex = i + 1;
|
TbGenericParamConstraint data = _rawImage.ReadGenericParamConstraint(rowIndex);
|
Il2CppGenericParameter& genericParam = _genericParams[data.owner - 1];
|
|
if (genericParam.constraintsCount == 0)
|
{
|
genericParam.constraintsStart = EncodeWithIndex(i);
|
}
|
++genericParam.constraintsCount;
|
//_genericConstraints[i] == kTypeIndexInvalid;
|
|
//Il2CppType paramCons = {};
|
|
//const Il2CppGenericContainer* klassGc;
|
//const Il2CppGenericContainer* methodGc;
|
//GetClassAndMethodGenericContainerFromGenericContainerIndex(genericParam.ownerIndex, klassGc, methodGc);
|
|
//ReadTypeFromToken(klassGc, methodGc, DecodeTypeDefOrRefOrSpecCodedIndexTableType(data.constraint), DecodeTypeDefOrRefOrSpecCodedIndexRowIndex(data.constraint), paramCons);
|
//_genericConstraints[i] = DecodeMetadataIndex(AddIl2CppTypeCache(paramCons));
|
}
|
}
|
|
void InterpreterImage::InitGenericParamDefs0()
|
{
|
const Table& tb = _rawImage.GetTable(TableType::GENERICPARAM);
|
_genericParams.resize(tb.rowNum);
|
}
|
|
void InterpreterImage::InitGenericParamDefs()
|
{
|
const Table& tb = _rawImage.GetTable(TableType::GENERICPARAM);
|
for (uint32_t i = 0; i < tb.rowNum; i++)
|
{
|
uint32_t rowIndex = i + 1;
|
TbGenericParam data = _rawImage.ReadGenericParam(rowIndex);
|
Il2CppGenericParameter& paramDef = _genericParams[i];
|
paramDef.num = data.number;
|
paramDef.flags = data.flags;
|
paramDef.nameIndex = EncodeWithIndex(data.name);
|
// constraintsStart 和 constrantsCount init at InitGenericParamConstrains() latter
|
|
TableType ownerType = DecodeTypeOrMethodDefCodedIndexTableType(data.owner);
|
uint32_t ownerIndex = DecodeTypeOrMethodDefCodedIndexRowIndex(data.owner);
|
IL2CPP_ASSERT(ownerIndex > 0);
|
Il2CppGenericContainer* geneContainer;
|
int32_t interIndex = ownerIndex - 1;
|
if (ownerType == TableType::TYPEDEF)
|
{
|
Il2CppTypeDefinition& typeDef = _typesDefines[interIndex];
|
if (typeDef.genericContainerIndex == kGenericContainerIndexInvalid)
|
{
|
Il2CppGenericContainer c = {};
|
c.ownerIndex = EncodeWithIndex(interIndex);
|
c.is_method = false;
|
typeDef.genericContainerIndex = AddIl2CppGenericContainers(c);
|
}
|
geneContainer = &_genericContainers[DecodeMetadataIndex(typeDef.genericContainerIndex)];
|
paramDef.ownerIndex = typeDef.genericContainerIndex;
|
}
|
else
|
{
|
Il2CppMethodDefinition& methodDef = _methodDefines[interIndex];
|
if (methodDef.genericContainerIndex == kGenericContainerIndexInvalid)
|
{
|
Il2CppGenericContainer c = {};
|
c.ownerIndex = EncodeWithIndex(interIndex);
|
c.is_method = true;
|
methodDef.genericContainerIndex = AddIl2CppGenericContainers(c);
|
}
|
geneContainer = &_genericContainers[DecodeMetadataIndex(methodDef.genericContainerIndex)];
|
paramDef.ownerIndex = methodDef.genericContainerIndex;
|
}
|
if (geneContainer->type_argc == 0)
|
{
|
geneContainer->genericParameterStart = EncodeWithIndex(i);
|
}
|
++geneContainer->type_argc;
|
}
|
}
|
|
|
void InterpreterImage::InitInterfaces()
|
{
|
const Table& table = _rawImage.GetTable(TableType::INTERFACEIMPL);
|
|
// interface中只包含直接继承的interface,不包括来自父类的
|
// 此interface只在CastClass及Type.GetInterfaces()反射函数中
|
// 发挥作用,不在callvir中发挥作用。
|
// interfaceOffsets中包含了水平展开的所有interface(包括父类的)
|
_interfaceDefines.resize(table.rowNum, kTypeIndexInvalid);
|
uint32_t lastClassIdx = 0;
|
for (uint32_t i = 0; i < table.rowNum; i++)
|
{
|
uint32_t rowIndex = i + 1;
|
TbInterfaceImpl data = _rawImage.ReadInterfaceImpl(rowIndex);
|
|
Il2CppTypeDefinition& typeDef = _typesDefines[data.classIdx - 1];
|
//Il2CppType intType = {};
|
//ReadTypeFromToken(GetGenericContainerByTypeDefinition(&typeDef), nullptr,
|
// DecodeTypeDefOrRefOrSpecCodedIndexTableType(data.interfaceIdx), DecodeTypeDefOrRefOrSpecCodedIndexRowIndex(data.interfaceIdx), intType);
|
//_interfaceDefines[i] = DecodeMetadataIndex(AddIl2CppTypeCache(intType));
|
if (typeDef.interfaces_count == 0)
|
{
|
typeDef.interfacesStart = (InterfacesIndex)i;
|
}
|
else
|
{
|
// 必须连续
|
IL2CPP_ASSERT(data.classIdx == lastClassIdx);
|
}
|
++typeDef.interfaces_count;
|
lastClassIdx = data.classIdx;
|
}
|
}
|
|
void InterpreterImage::ComputeVTable(TypeDefinitionDetail* tdd)
|
{
|
Il2CppTypeDefinition& typeDef = *tdd->typeDef;
|
if (IsInterface(typeDef.flags) || typeDef.interfaceOffsetsStart != 0)
|
{
|
return;
|
}
|
|
if (typeDef.parentIndex != kInvalidIndex)
|
{
|
const Il2CppType* parentType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef.parentIndex);
|
const Il2CppTypeDefinition* parentTypeDef = GetUnderlyingTypeDefinition(parentType);
|
if (IsInterpreterType(parentTypeDef) && parentTypeDef->interfaceOffsetsStart == 0)
|
{
|
IL2CPP_ASSERT(DecodeImageIndex(parentTypeDef->byvalTypeIndex) == this->GetIndex());
|
int32_t typeDefIndex = GetTypeRawIndexByEncodedIl2CppTypeIndex(parentTypeDef->byvalTypeIndex);
|
ComputeVTable(&_typeDetails[typeDefIndex]);
|
}
|
}
|
|
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.vtable_count = (uint16_t)vms.size();
|
typeDef.interfaceOffsetsStart = EncodeWithIndex(offsetsStart);
|
typeDef.interface_offsets_count = (uint16_t)interfaceOffsetInfos.size();
|
|
Il2CppClass* klass = _classList[tdd->index];
|
IL2CPP_ASSERT(!klass);
|
}
|
|
void InterpreterImage::InitVTables()
|
{
|
const Table& typeDefTb = _rawImage.GetTable(TableType::TYPEDEF);
|
|
for (TypeDefinitionDetail& td : _typeDetails)
|
{
|
ComputeVTable(&td);
|
}
|
|
for (auto& e : _cacheTrees)
|
{
|
e.second->~VTableSetUp();
|
HYBRIDCLR_FREE(e.second);
|
}
|
Il2CppType2TypeDeclaringTreeMap temp;
|
_cacheTrees.swap(temp);
|
}
|
|
// index => MethodDefinition -> DeclaringClass -> index - klass->methodStart -> MethodInfo*
|
const MethodInfo* InterpreterImage::GetMethodInfoFromMethodDefinitionRawIndex(uint32_t index)
|
{
|
IL2CPP_ASSERT((size_t)index <= _methodDefine2InfoCaches.size());
|
if (_methodDefine2InfoCaches[index])
|
{
|
return _methodDefine2InfoCaches[index];
|
}
|
const Il2CppMethodDefinition* methodDefinition = GetMethodDefinitionFromRawIndex(index);
|
const Il2CppTypeDefinition* typeDefinition = (const Il2CppTypeDefinition*)il2cpp::vm::GlobalMetadata::GetTypeHandleFromIndex(methodDefinition->declaringType);
|
int32_t indexInClass = index - DecodeMetadataIndex(typeDefinition->methodStart);
|
IL2CPP_ASSERT(indexInClass >= 0 && indexInClass < typeDefinition->method_count);
|
Il2CppClass* klass = il2cpp::vm::GlobalMetadata::GetTypeInfoFromHandle((Il2CppMetadataTypeHandle)typeDefinition);
|
il2cpp::vm::Class::SetupMethods(klass);
|
// il2cpp::vm::Class::Init(klass);
|
return _methodDefine2InfoCaches[index] = klass->methods[indexInClass];
|
}
|
|
const MethodInfo* InterpreterImage::GetMethodInfoFromMethodDefinition(const Il2CppMethodDefinition* methodDef)
|
{
|
uint32_t rawIndex = (uint32_t)(methodDef - &_methodDefines[0]);
|
IL2CPP_ASSERT(rawIndex < (uint32_t)_methodDefines.size());
|
return GetMethodInfoFromMethodDefinitionRawIndex(rawIndex);
|
}
|
|
// typeDef vTableSlot -> type virtual method index -> MethodDefinition*
|
const Il2CppMethodDefinition* InterpreterImage::GetMethodDefinitionFromVTableSlot(const Il2CppTypeDefinition* typeDef, int32_t vTableSlot)
|
{
|
uint32_t typeDefIndex = GetTypeRawIndex(typeDef);
|
IL2CPP_ASSERT(typeDefIndex < (uint32_t)_typeDetails.size());
|
TypeDefinitionDetail& td = _typeDetails[typeDefIndex];
|
|
IL2CPP_ASSERT(vTableSlot >= 0 && vTableSlot < (int32_t)td.vtable.size());
|
VirtualMethodImpl& vmi = td.vtable[vTableSlot];
|
return vmi.method;
|
}
|
|
const MethodInfo* InterpreterImage::GetMethodInfoFromVTableSlot(const Il2CppClass* klass, int32_t vTableSlot)
|
{
|
IL2CPP_ASSERT(!klass->generic_class);
|
const Il2CppTypeDefinition* typeDef = (Il2CppTypeDefinition*)klass->typeMetadataHandle;
|
//const Il2CppMethodDefinition* methodDef = GetMethodDefinitionFromVTableSlot((Il2CppTypeDefinition*)klass->typeMetadataHandle, vTableSlot);
|
// FIX ME. why return null?
|
//IL2CPP_ASSERT(methodDef);
|
|
uint32_t typeDefIndex = GetTypeRawIndex(typeDef);
|
IL2CPP_ASSERT(typeDefIndex < (uint32_t)_typeDetails.size());
|
TypeDefinitionDetail& td = _typeDetails[typeDefIndex];
|
|
IL2CPP_ASSERT(vTableSlot >= 0 && vTableSlot < (int32_t)td.vtable.size());
|
VirtualMethodImpl& vmi = td.vtable[vTableSlot];
|
if (vmi.method)
|
{
|
if (vmi.method->declaringType == EncodeWithIndex(typeDefIndex))
|
{
|
return il2cpp::vm::GlobalMetadata::GetMethodInfoFromMethodHandle((Il2CppMetadataMethodDefinitionHandle)vmi.method);
|
}
|
else
|
{
|
Il2CppClass* implClass = il2cpp::vm::Class::FromIl2CppType(vmi.type);
|
IL2CPP_ASSERT(implClass != klass);
|
il2cpp::vm::Class::SetupMethods(implClass);
|
for (uint32_t i = 0; i < implClass->method_count; i++)
|
{
|
const MethodInfo* implMethod = implClass->methods[i];
|
if (implMethod->token == vmi.method->token)
|
{
|
return implMethod;
|
}
|
}
|
RaiseExecutionEngineException("not find vtable method");
|
}
|
}
|
return nullptr;
|
}
|
|
Il2CppMethodPointer InterpreterImage::GetAdjustorThunk(uint32_t token)
|
{
|
uint32_t methodIndex = DecodeTokenRowIndex(token) - 1;
|
IL2CPP_ASSERT(methodIndex < (uint32_t)_methodDefines.size());
|
const Il2CppMethodDefinition* methodDef = &_methodDefines[methodIndex];
|
return IsInstanceMethod(methodDef) ? hybridclr::interpreter::InterpreterModule::GetAdjustThunkMethodPointer(methodDef) : nullptr;
|
}
|
|
Il2CppMethodPointer InterpreterImage::GetMethodPointer(uint32_t token)
|
{
|
uint32_t methodIndex = DecodeTokenRowIndex(token) - 1;
|
IL2CPP_ASSERT(methodIndex < (uint32_t)_methodDefines.size());
|
const Il2CppMethodDefinition* methodDef = &_methodDefines[methodIndex];
|
return hybridclr::interpreter::InterpreterModule::GetMethodPointer(methodDef);
|
}
|
|
InvokerMethod InterpreterImage::GetMethodInvoker(uint32_t token)
|
{
|
uint32_t methodIndex = DecodeTokenRowIndex(token) - 1;
|
IL2CPP_ASSERT(methodIndex < (uint32_t)_methodDefines.size());
|
const Il2CppMethodDefinition* methodDef = &_methodDefines[methodIndex];
|
return hybridclr::interpreter::InterpreterModule::GetMethodInvoker(methodDef);
|
}
|
|
|
Il2CppString* InterpreterImage::ReadSerString(BlobReader& reader)
|
{
|
byte b = reader.PeekByte();
|
if (b == 0xFF)
|
{
|
reader.SkipByte();
|
return nullptr;
|
}
|
else if (b == 0)
|
{
|
reader.SkipByte();
|
return il2cpp::vm::String::Empty();
|
}
|
else
|
{
|
uint32_t len = reader.ReadCompressedUint32();
|
#if !HYBRIDCLR_UNITY_2021_OR_NEW
|
return il2cpp::vm::String::NewLen((char*)reader.GetAndSkipCurBytes(len), len);
|
#else
|
char* chars = (char*)reader.GetDataOfReadPosition();
|
reader.SkipBytes(len);
|
return il2cpp::vm::String::NewLen(chars, len);
|
#endif
|
}
|
}
|
|
#if HYBRIDCLR_UNITY_2021_OR_NEW
|
bool InterpreterImage::ReadUTF8SerString(BlobReader& reader, std::string& s)
|
{
|
byte b = reader.PeekByte();
|
if (b == 0xFF)
|
{
|
reader.SkipByte();
|
return false;
|
}
|
else if (b == 0)
|
{
|
reader.SkipByte();
|
s.clear();
|
return true;
|
}
|
else
|
{
|
uint32_t len = reader.ReadCompressedUint32();
|
char* chars = (char*)reader.GetDataOfReadPosition();
|
reader.SkipBytes(len);
|
s.assign(chars, len);
|
return true;
|
}
|
}
|
#endif
|
|
Il2CppReflectionType* InterpreterImage::ReadSystemType(BlobReader& reader)
|
{
|
Il2CppString* fullName = ReadSerString(reader);
|
if (!fullName)
|
{
|
return nullptr;
|
}
|
Il2CppReflectionType* type = GetReflectionTypeFromName(fullName);
|
if (!type)
|
{
|
std::string stdTypeName = il2cpp::utils::StringUtils::Utf16ToUtf8(fullName->chars);
|
TEMP_FORMAT(errMsg, "CustomAttribute fixed arg type:System.Type fullName:'%s' not find", stdTypeName.c_str());
|
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException(errMsg));
|
}
|
return type;
|
}
|
|
|
Il2CppObject* InterpreterImage::ReadBoxedValue(BlobReader& reader)
|
{
|
uint64_t obj = 0;
|
Il2CppType kind = {};
|
ReadCustomAttributeFieldOrPropType(reader, kind);
|
ReadFixedArg(reader, &kind, &obj);
|
Il2CppClass* valueType = il2cpp::vm::Class::FromIl2CppType(&kind);
|
return il2cpp::vm::Object::Box(valueType, &obj);
|
}
|
|
void InterpreterImage::ReadFixedArg(BlobReader& reader, const Il2CppType* argType, void* data)
|
{
|
switch (argType->type)
|
{
|
case IL2CPP_TYPE_BOOLEAN:
|
{
|
*(byte*)data = reader.ReadByte();
|
break;
|
}
|
case IL2CPP_TYPE_CHAR:
|
{
|
*(uint16_t*)data = reader.Read16();
|
break;
|
}
|
case IL2CPP_TYPE_I1:
|
case IL2CPP_TYPE_U1:
|
{
|
*(byte*)data = reader.ReadByte();
|
break;
|
}
|
case IL2CPP_TYPE_I2:
|
case IL2CPP_TYPE_U2:
|
{
|
*(uint16_t*)data = reader.Read16();
|
break;
|
}
|
case IL2CPP_TYPE_I4:
|
case IL2CPP_TYPE_U4:
|
{
|
*(uint32_t*)data = reader.Read32();
|
break;
|
}
|
case IL2CPP_TYPE_I8:
|
case IL2CPP_TYPE_U8:
|
{
|
*(uint64_t*)data = reader.Read64();
|
break;
|
}
|
case IL2CPP_TYPE_R4:
|
{
|
*(float*)data = reader.ReadFloat();
|
break;
|
}
|
case IL2CPP_TYPE_R8:
|
{
|
*(double*)data = reader.ReadDouble();
|
break;
|
}
|
case IL2CPP_TYPE_SZARRAY:
|
{
|
uint32_t numElem = reader.Read32();
|
if (numElem != (uint32_t)-1)
|
{
|
Il2CppClass* arrKlass = il2cpp::vm::Class::FromIl2CppType(argType);
|
Il2CppArray* arr = il2cpp::vm::Array::New(il2cpp::vm::Class::GetElementClass(arrKlass), numElem);
|
for (uint16_t i = 0; i < numElem; i++)
|
{
|
ReadFixedArg(reader, argType->data.type, GET_ARRAY_ELEMENT_ADDRESS(arr, i, arr->klass->element_size));
|
}
|
*(void**)data = arr;
|
}
|
else
|
{
|
*(void**)data = nullptr;
|
}
|
HYBRIDCLR_SET_WRITE_BARRIER((void**)data);
|
break;
|
}
|
case IL2CPP_TYPE_STRING:
|
{
|
*(Il2CppString**)data = ReadSerString(reader);
|
HYBRIDCLR_SET_WRITE_BARRIER((void**)data);
|
break;
|
}
|
case IL2CPP_TYPE_OBJECT:
|
{
|
*(Il2CppObject**)data = ReadBoxedValue(reader);
|
HYBRIDCLR_SET_WRITE_BARRIER((void**)data);
|
break;
|
}
|
case IL2CPP_TYPE_CLASS:
|
{
|
Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(argType);
|
if (!klass)
|
{
|
RaiseExecutionEngineException("type not find");
|
}
|
if (klass == il2cpp_defaults.object_class)
|
{
|
*(Il2CppObject**)data = ReadBoxedValue(reader);
|
}
|
else if (klass == il2cpp_defaults.systemtype_class)
|
{
|
*(Il2CppReflectionType**)data = ReadSystemType(reader);
|
}
|
else
|
{
|
TEMP_FORMAT(errMsg, "fixed arg type:%s.%s not support", klass->namespaze, klass->name);
|
RaiseNotSupportedException(errMsg);
|
}
|
HYBRIDCLR_SET_WRITE_BARRIER((void**)data);
|
break;
|
}
|
case IL2CPP_TYPE_VALUETYPE:
|
{
|
Il2CppClass* valueType = il2cpp::vm::Class::FromIl2CppType(argType);
|
IL2CPP_ASSERT(valueType->enumtype);
|
ReadFixedArg(reader, &valueType->element_class->byval_arg, data);
|
break;
|
}
|
case IL2CPP_TYPE_SYSTEM_TYPE:
|
{
|
*(Il2CppReflectionType**)data = ReadSystemType(reader);
|
HYBRIDCLR_SET_WRITE_BARRIER((void**)data);
|
break;
|
}
|
case IL2CPP_TYPE_BOXED_OBJECT:
|
{
|
uint8_t fieldOrPropType = reader.ReadByte();
|
IL2CPP_ASSERT(fieldOrPropType == 0x51);
|
*(Il2CppObject**)data = ReadBoxedValue(reader);
|
HYBRIDCLR_SET_WRITE_BARRIER((void**)data);
|
break;
|
}
|
case IL2CPP_TYPE_ENUM:
|
{
|
Il2CppClass* valueType = il2cpp::vm::Class::FromIl2CppType(argType);
|
IL2CPP_ASSERT(valueType->enumtype);
|
ReadFixedArg(reader, &valueType->element_class->byval_arg, data);
|
break;
|
}
|
default:
|
{
|
RaiseExecutionEngineException("not support fixed argument type");
|
}
|
}
|
}
|
|
void InterpreterImage::ReadCustomAttributeFieldOrPropType(BlobReader& reader, Il2CppType& type)
|
{
|
type.type = (Il2CppTypeEnum)reader.ReadByte();
|
|
switch (type.type)
|
{
|
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:
|
{
|
break;
|
}
|
case IL2CPP_TYPE_SZARRAY:
|
{
|
// FIXME MEMORY LEAK
|
Il2CppType* eleType = (Il2CppType*)HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppType));
|
ReadCustomAttributeFieldOrPropType(reader, *eleType);
|
type.data.type = eleType;
|
break;
|
}
|
case IL2CPP_TYPE_ENUM:
|
{
|
Il2CppString* enumTypeName = ReadSerString(reader);
|
|
Il2CppReflectionType* enumType = GetReflectionTypeFromName(enumTypeName);
|
if (!enumType)
|
{
|
std::string stdStrName = il2cpp::utils::StringUtils::Utf16ToUtf8(enumTypeName->chars);
|
TEMP_FORMAT(errMsg, "ReadCustomAttributeFieldOrPropType enum:'%s' not exists", stdStrName.c_str());
|
RaiseExecutionEngineException(errMsg);
|
}
|
type = *enumType->type;
|
break;
|
}
|
case IL2CPP_TYPE_SYSTEM_TYPE:
|
{
|
type = il2cpp_defaults.systemtype_class->byval_arg;
|
break;
|
}
|
case IL2CPP_TYPE_BOXED_OBJECT:
|
{
|
type = il2cpp_defaults.object_class->byval_arg;
|
break;
|
}
|
default:
|
{
|
TEMP_FORMAT(errMsg, "ReadCustomAttributeFieldOrPropType. image:%s unknown type:%d", GetIl2CppImage()->name, (int)type.type);
|
RaiseBadImageException(errMsg);
|
}
|
}
|
}
|
|
void InterpreterImage::ReadMethodDefSig(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, Il2CppMethodDefinition& methodDef, std::vector<ParamDetail>& paramArr)
|
{
|
uint8_t rawSigFlags = reader.ReadByte();
|
|
if (rawSigFlags & (uint8_t)MethodSigFlags::GENERIC)
|
{
|
//IL2CPP_ASSERT(false);
|
uint32_t genParamCount = reader.ReadCompressedUint32();
|
Il2CppGenericContainer* gc = GetGenericContainerByRawIndex(DecodeMetadataIndex(methodDef.genericContainerIndex));
|
IL2CPP_ASSERT(gc->type_argc == genParamCount);
|
}
|
uint32_t paramCount = reader.ReadCompressedUint32();
|
//IL2CPP_ASSERT(paramCount >= methodDef.parameterCount);
|
|
Il2CppType returnType = {};
|
ReadType(reader, klassGenericContainer, methodGenericContainer, returnType);
|
methodDef.returnType = AddIl2CppTypeCache(returnType);
|
|
int readParamNum = 0;
|
for (; reader.NonEmpty(); )
|
{
|
ParamDetail curParam = {};
|
curParam.type = {};
|
ReadType(reader, klassGenericContainer, methodGenericContainer, curParam.type);
|
curParam.parameterIndex = readParamNum++;
|
curParam.methodDef = &methodDef;
|
curParam.paramDef.typeIndex = AddIl2CppTypeCache(curParam.type);
|
paramArr.push_back(curParam);
|
}
|
IL2CPP_ASSERT(readParamNum == (int)paramCount);
|
}
|
|
bool InterpreterImage::GetModuleIl2CppType(Il2CppType& resultType, uint32_t moduleRowIndex, uint32_t typeNamespace, uint32_t typeName, bool raiseExceptionIfNotFound)
|
{
|
IL2CPP_ASSERT(moduleRowIndex == 1);
|
uint32_t encodedNamespaceIndex = EncodeWithIndex(typeNamespace);
|
uint32_t encodedNameIndex = EncodeWithIndex(typeName);
|
for (TypeDefinitionDetail& type : _typeDetails)
|
{
|
if (type.typeDef->namespaceIndex == encodedNamespaceIndex && type.typeDef->nameIndex == encodedNameIndex)
|
{
|
GetIl2CppTypeFromTypeDefinition(type.typeDef, resultType);
|
return true;
|
}
|
}
|
resultType = {};
|
if (!raiseExceptionIfNotFound)
|
{
|
return false;
|
}
|
const char* typeNameStr = _rawImage.GetStringFromRawIndex(typeName);
|
const char* typeNamespaceStr = _rawImage.GetStringFromRawIndex(typeNamespace);
|
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException(
|
CStringToStringView(typeNamespaceStr),
|
CStringToStringView(typeNameStr),
|
CStringToStringView(_il2cppImage->nameNoExt)));
|
return false;
|
}
|
}
|
}
|