#include "TransformContext.h" #include "utils/Il2CppHashMap.h" #include "utils/HashUtils.h" #include "utils/StringUtils.h" namespace hybridclr { namespace transform { struct NamespaceAndName { const char* namespaze; const char* name; }; struct NamespaceAndNameHash { size_t operator()(const NamespaceAndName& pair) const { size_t h = il2cpp::utils::StringUtils::Hash(pair.namespaze); h = il2cpp::utils::HashUtils::Combine(h, il2cpp::utils::StringUtils::Hash(pair.name)); return h; } }; struct NamespaceAndNameEquals { bool operator()(const NamespaceAndName& p1, const NamespaceAndName& p2) const { return !strcmp(p1.namespaze, p2.namespaze) && !strcmp(p1.name, p2.name); } }; struct NamespaceAndNameAndMethod { const char* namespaze; const char* name; const char* method; }; struct NamespaceAndNameAndMethodHash { size_t operator()(const NamespaceAndNameAndMethod& pair) const { size_t h = il2cpp::utils::StringUtils::Hash(pair.namespaze); h = il2cpp::utils::HashUtils::Combine(h, il2cpp::utils::StringUtils::Hash(pair.name)); h = il2cpp::utils::HashUtils::Combine(h, il2cpp::utils::StringUtils::Hash(pair.method)); return h; } }; struct NamespaceAndNameAndMethodEquals { bool operator()(const NamespaceAndNameAndMethod& p1, const NamespaceAndNameAndMethod& p2) const { return !strcmp(p1.namespaze, p2.namespaze) && !strcmp(p1.name, p2.name) && !strcmp(p1.method, p2.method); } }; typedef bool (*InstinctHandler)(TransformContext& ctx, const MethodInfo* method); typedef Il2CppHashMap InstinctHandlerMap; static InstinctHandlerMap s_instinctHandlerMap; typedef Il2CppHashMap CtorInstinctHandlerMap; static CtorInstinctHandlerMap s_ctorInstinctHandlerMap; #define IHCreateAddIR(varName, typeName) IR##typeName* varName = ctx.pool.AllocIR(); varName->type = HiOpcodeEnum::typeName; ctx.curbb->insts.push_back(varName); static bool IH_object_ctor(TransformContext& ctx, const MethodInfo* method) { ctx.PopStack(); return true; } static bool IH_Nullable_ctor(TransformContext& ctx, const MethodInfo* method) { if (method->parameters_count != 1) { return false; } Il2CppClass* klass = method->klass; il2cpp::vm::Class::SetupFields(klass); il2cpp::vm::Class::SetupFields(klass->castClass); IL2CPP_ASSERT(ctx.evalStackTop >= 2); IHCreateAddIR(ir, NullableCtorVarVar); ir->dst = ctx.GetEvalStackOffset_2(); ir->data = ctx.GetEvalStackOffset_1(); ir->klass = ctx.GetOrAddResolveDataIndex(klass); ctx.PopStackN(2); return true; } static bool IH_Nullable_GetValueOrDefault(TransformContext& ctx, const MethodInfo* method) { Il2CppClass* klass = method->klass; il2cpp::vm::Class::SetupFields(klass); il2cpp::vm::Class::SetupFields(klass->castClass); uint32_t classIndirectIndex = ctx.GetOrAddResolveDataIndex(klass); uint16_t topOffset = ctx.GetEvalStackTopOffset(); if (method->parameters_count == 0) { IL2CPP_ASSERT(ctx.evalStackTop >= 1); IHCreateAddIR(ir, NullableGetValueOrDefaultVarVar); ir->dst = topOffset; ir->obj = topOffset; ir->klass = classIndirectIndex; // pop this, push value ctx.PopStack(); ctx.PushStackByType(&klass->castClass->byval_arg); return true; } else if (method->parameters_count == 1) { IL2CPP_ASSERT(ctx.evalStackTop >= 2); IHCreateAddIR(ir, NullableGetValueOrDefaultVarVar_1); ir->dst = ir->obj = ctx.GetEvalStackOffset_2(); ir->defaultValue = topOffset; ir->klass = classIndirectIndex; // pop this, default value then push value ctx.PopStackN(2); ctx.PushStackByType(&klass->castClass->byval_arg); return true; } return false; } static bool IH_Nullable_get_HasValue(TransformContext& ctx, const MethodInfo* method) { IL2CPP_ASSERT(ctx.evalStackTop >= 1); Il2CppClass* klass = method->klass; il2cpp::vm::Class::SetupFields(klass); il2cpp::vm::Class::SetupFields(klass->castClass); uint32_t classIndirectIndex = ctx.GetOrAddResolveDataIndex(klass); uint16_t topOffset = ctx.GetEvalStackTopOffset(); IHCreateAddIR(ir, NullableHasValueVar); ir->result = topOffset; ir->obj = topOffset; ir->klass = classIndirectIndex; // pop this, push value ctx.PopStack(); ctx.PushStackByReduceType(EvalStackReduceDataType::I4); return true; } static bool IH_Nullable_get_Value(TransformContext& ctx, const MethodInfo* method) { IL2CPP_ASSERT(ctx.evalStackTop >= 1); Il2CppClass* klass = method->klass; il2cpp::vm::Class::SetupFields(klass); il2cpp::vm::Class::SetupFields(klass->castClass); uint32_t classIndirectIndex = ctx.GetOrAddResolveDataIndex(klass); uint16_t topOffset = ctx.GetEvalStackTopOffset(); IHCreateAddIR(ir, NullableGetValueVarVar); ir->dst = topOffset; ir->obj = topOffset; ir->klass = classIndirectIndex; // pop this, push value ctx.PopStack(); ctx.PushStackByType(&klass->castClass->byval_arg); return true; } static bool IH_Array_GetGenericValueImpl(TransformContext& ctx, const MethodInfo* method) { IL2CPP_ASSERT(ctx.evalStackTop >= 3); uint16_t topOffset = ctx.GetEvalStackTopOffset(); IHCreateAddIR(ir, ArrayGetGenericValueImpl); ir->arr = ctx.GetEvalStackOffset_3(); ir->index = ctx.GetEvalStackOffset_2(); ir->value = ctx.GetEvalStackOffset_1(); ctx.PopStackN(3); return true; } static bool IH_Array_SetGenericValueImpl(TransformContext& ctx, const MethodInfo* method) { IL2CPP_ASSERT(ctx.evalStackTop >= 3); uint16_t topOffset = ctx.GetEvalStackTopOffset(); IHCreateAddIR(ir, ArraySetGenericValueImpl); ir->arr = ctx.GetEvalStackOffset_3(); ir->index = ctx.GetEvalStackOffset_2(); ir->value = ctx.GetEvalStackOffset_1(); ctx.PopStackN(3); return true; } static bool IH_Interlocked_CompareExchange(TransformContext& ctx, const MethodInfo* method) { IL2CPP_ASSERT(ctx.evalStackTop >= 3); uint16_t retIdx = ctx.GetEvalStackOffset_3(); uint16_t locationIdx = retIdx; uint16_t valueIdx = ctx.GetEvalStackOffset_2(); uint16_t comparandIdx = ctx.GetEvalStackOffset_1(); IHCreateAddIR(ir, InterlockedCompareExchangeVarVarVarVar_pointer); ir->ret = retIdx; ir->location = locationIdx; ir->value = valueIdx; ir->comparand = comparandIdx; const Il2CppType* paramType = GET_METHOD_PARAMETER_TYPE(method->parameters[1]); if (!paramType->byref) { Il2CppClass* paramKlass = il2cpp::vm::Class::FromIl2CppType(paramType); if (IS_CLASS_VALUE_TYPE(paramKlass)) { uint32_t valueSize = GetTypeValueSize(paramKlass); if (valueSize == 4) { ir->type = HiOpcodeEnum::InterlockedCompareExchangeVarVarVarVar_i4; } else if (valueSize == 8) { ir->type = HiOpcodeEnum::InterlockedCompareExchangeVarVarVarVar_i8; } else { RaiseExecutionEngineException("not support System.Threading.Interlocked.CompareExchange"); } } } ctx.PopStackN(3); ctx.PushStackByType(paramType); return true; } static bool IH_Interlocked_Exchange(TransformContext& ctx, const MethodInfo* method) { IL2CPP_ASSERT(ctx.evalStackTop >= 2); uint16_t retIdx = ctx.GetEvalStackOffset_2(); uint16_t locationIdx = retIdx; uint16_t valueIdx = ctx.GetEvalStackOffset_1(); IHCreateAddIR(ir, InterlockedExchangeVarVarVar_pointer); ir->ret = retIdx; ir->location = locationIdx; ir->value = valueIdx; const Il2CppType* paramType = GET_METHOD_PARAMETER_TYPE(method->parameters[1]); if (!paramType->byref) { Il2CppClass* paramKlass = il2cpp::vm::Class::FromIl2CppType(paramType); if (IS_CLASS_VALUE_TYPE(paramKlass)) { uint32_t valueSize = GetTypeValueSize(paramKlass); if (valueSize == 4) { ir->type = HiOpcodeEnum::InterlockedExchangeVarVarVar_i4; } else if (valueSize == 8) { ir->type = HiOpcodeEnum::InterlockedExchangeVarVarVar_i8; } else { RaiseExecutionEngineException("not support System.Threading.Interlocked.Exchange"); } } } ctx.PopStackN(2); ctx.PushStackByType(paramType); return true; } static bool IH_JitHelpers_UnsafeEnumCast(TransformContext& ctx, const MethodInfo* method) { IL2CPP_ASSERT(ctx.evalStackTop >= 1); IHCreateAddIR(ir, UnsafeEnumCast); ir->dst = ctx.GetEvalStackTopOffset(); ir->src = ctx.GetEvalStackTopOffset(); const Il2CppType* srcType = method->genericMethod->context.method_inst->type_argv[0]; if (srcType->type == IL2CPP_TYPE_VALUETYPE || srcType->type == IL2CPP_TYPE_GENERICINST) { Il2CppClass* srcKlass = il2cpp::vm::Class::FromIl2CppType(srcType); if (!srcKlass->enumtype) { RaiseExecutionEngineException("not support UnsafeEnumCast src type"); } ir->srcType = (uint16_t)srcKlass->castClass->byval_arg.type; } else { ir->srcType = (uint16_t)srcType->type; } ctx.PopStack(); ctx.PushStackByReduceType(EvalStackReduceDataType::I4); return true; } static bool IH_JitHelpers_UnsafeCast(TransformContext& ctx, const MethodInfo* method) { return true; } static bool IH_JitHelpers_UnsafeEnumCastLong(TransformContext& ctx, const MethodInfo* method) { return true; } static bool IH_Assembly_GetExecutingAssembly(TransformContext& ctx, const MethodInfo* method) { IL2CPP_ASSERT(ctx.evalStackTop >= 0); IHCreateAddIR(ir, AssemblyGetExecutingAssembly); ir->ret = ctx.GetEvalStackNewTopOffset(); ctx.PushStackByReduceType(NATIVE_INT_REDUCE_TYPE); return true; } static bool IH_UnityEngine_Vector2_ctor(TransformContext& ctx, const MethodInfo* method) { if (method->parameters_count != 2) { return false; } IL2CPP_ASSERT(ctx.evalStackTop >= 3); IHCreateAddIR(ir, CtorVector2); ir->obj = ctx.GetEvalStackOffset_3(); ir->x = ctx.GetEvalStackOffset_2(); ir->y = ctx.GetEvalStackOffset_1(); ctx.PopStackN(3); return true; } static bool IH_UnityEngine_Vector3_ctor(TransformContext& ctx, const MethodInfo* method) { switch (method->parameters_count) { case 2: { IL2CPP_ASSERT(ctx.evalStackTop >= 3); IHCreateAddIR(ir, CtorVector3_2); ir->obj = ctx.GetEvalStackOffset_3(); ir->x = ctx.GetEvalStackOffset_2(); ir->y = ctx.GetEvalStackOffset_1(); ctx.PopStackN(3); return true; } case 3: { IL2CPP_ASSERT(ctx.evalStackTop >= 4); IHCreateAddIR(ir, CtorVector3_3); ir->obj = ctx.GetEvalStackOffset_4(); ir->x = ctx.GetEvalStackOffset_3(); ir->y = ctx.GetEvalStackOffset_2(); ir->z = ctx.GetEvalStackOffset_1(); ctx.PopStackN(4); return true; } default: return false; } } static bool IH_UnityEngine_Vector4_ctor(TransformContext& ctx, const MethodInfo* method) { switch (method->parameters_count) { case 2: { IL2CPP_ASSERT(ctx.evalStackTop >= 3); IHCreateAddIR(ir, CtorVector4_2); ir->obj = ctx.GetEvalStackOffset_3(); ir->x = ctx.GetEvalStackOffset_2(); ir->y = ctx.GetEvalStackOffset_1(); ctx.PopStackN(3); return true; } case 3: { IL2CPP_ASSERT(ctx.evalStackTop >= 4); IHCreateAddIR(ir, CtorVector4_3); ir->obj = ctx.GetEvalStackOffset_4(); ir->x = ctx.GetEvalStackOffset_3(); ir->y = ctx.GetEvalStackOffset_2(); ir->z = ctx.GetEvalStackOffset_1(); ctx.PopStackN(4); return true; } case 4: { IL2CPP_ASSERT(ctx.evalStackTop >= 5); IHCreateAddIR(ir, CtorVector4_4); ir->obj = ctx.GetEvalStackOffset_5(); ir->x = ctx.GetEvalStackOffset_4(); ir->y = ctx.GetEvalStackOffset_3(); ir->z = ctx.GetEvalStackOffset_2(); ir->w = ctx.GetEvalStackOffset_1(); ctx.PopStackN(5); return true; } default: return false; } } static bool IH_ByReference_get_Value(TransformContext& ctx, const MethodInfo* method) { // ByReference.Value equals to *this IL2CPP_ASSERT(ctx.evalStackTop >= 1); TemporaryMemoryArena& pool = ctx.pool; IRBasicBlock*& curbb = ctx.curbb; CreateAddIR(ir, LdindVarVar_i1); #if HYBRIDCLR_ARCH_64 ir->type = HiOpcodeEnum::LdindVarVar_i8; #else ir->type = HiOpcodeEnum::LdindVarVar_i4; #endif ir->dst = ir->src = ctx.GetEvalStackTopOffset(); ctx.PopStack(); ctx.PushStackByReduceType(NATIVE_INT_REDUCE_TYPE); return true; } struct InstinctHandlerInfo { const char* namespaze; const char* name; const char* method; InstinctHandler handler; }; static InstinctHandlerInfo s_instinctHandlerInfos[] = { {"System", "Object", ".ctor", IH_object_ctor}, {"System", "Nullable`1", ".ctor", IH_Nullable_ctor}, {"System", "Nullable`1", "GetValueOrDefault", IH_Nullable_GetValueOrDefault}, {"System", "Nullable`1", "get_HasValue", IH_Nullable_get_HasValue}, {"System", "Nullable`1", "get_Value", IH_Nullable_get_Value}, {"System", "Array", "GetGenericValueImpl", IH_Array_GetGenericValueImpl}, {"System", "Array", "SetGenericValueImpl", IH_Array_SetGenericValueImpl}, {"System.Threading", "Interlocked", "CompareExchange", IH_Interlocked_CompareExchange}, {"System.Threading", "Interlocked", "Exchange", IH_Interlocked_Exchange}, {"System.Runtime.CompilerServices", "JitHelpers", "UnsafeEnumCast", IH_JitHelpers_UnsafeEnumCast}, {"System.Runtime.CompilerServices", "JitHelpers", "UnsafeCast", IH_JitHelpers_UnsafeCast}, {"System.Runtime.CompilerServices", "JitHelpers", "UnsafeEnumCastLong", IH_JitHelpers_UnsafeEnumCastLong}, {"System.Reflection", "Assembly", "GetExecutingAssembly", IH_Assembly_GetExecutingAssembly}, {"UnityEngine", "Vector2", ".ctor", IH_UnityEngine_Vector2_ctor}, {"UnityEngine", "Vector3", ".ctor", IH_UnityEngine_Vector3_ctor}, {"UnityEngine", "Vector4", ".ctor", IH_UnityEngine_Vector4_ctor}, {"System", "ByReference`1", "get_Value", IH_ByReference_get_Value}, }; struct CtorInstinctHandlerInfo { const char* namespaze; const char* name; InstinctHandler handler; }; static bool CIH_Object(TransformContext& ctx, const MethodInfo* method) { Il2CppClass* klass = method->klass; IHCreateAddIR(ir, NewSystemObjectVar); ir->obj = ctx.GetEvalStackNewTopOffset(); ctx.PushStackByReduceType(NATIVE_INT_REDUCE_TYPE); return true; } static bool CIH_String(TransformContext& ctx, const MethodInfo* method) { switch (method->parameters_count) { case 1: { const Il2CppType* paramType = GET_METHOD_PARAMETER_TYPE(method->parameters[0]); if (paramType->type == IL2CPP_TYPE_SZARRAY && paramType->data.type->type == IL2CPP_TYPE_CHAR) { // new string(char[]) IHCreateAddIR(ir, NewString); ir->str = ctx.GetEvalStackTopOffset(); ir->chars = ctx.GetEvalStackTopOffset(); return true; } return false; } case 2: { const Il2CppType* paramType1 = GET_METHOD_PARAMETER_TYPE(method->parameters[0]); const Il2CppType* paramType2 = GET_METHOD_PARAMETER_TYPE(method->parameters[1]); if (paramType1->type == IL2CPP_TYPE_CHAR && paramType2->type == IL2CPP_TYPE_I4) { IHCreateAddIR(ir, NewString_3); ir->str = ctx.GetEvalStackOffset_2(); ir->c = ctx.GetEvalStackOffset_2(); ir->count = ctx.GetEvalStackOffset_1(); ctx.PopStack(); return true; } return false; } case 3: { // new string(char[] chars, int startIndex, int length) const Il2CppType* paramType1 = GET_METHOD_PARAMETER_TYPE(method->parameters[0]); const Il2CppType* paramType2 = GET_METHOD_PARAMETER_TYPE(method->parameters[1]); const Il2CppType* paramType3 = GET_METHOD_PARAMETER_TYPE(method->parameters[2]); if (paramType1->type == IL2CPP_TYPE_SZARRAY && paramType1->data.type->type == IL2CPP_TYPE_CHAR && paramType2->type == IL2CPP_TYPE_I4 && paramType3->type == IL2CPP_TYPE_I4) { IHCreateAddIR(ir, NewString_2); ir->str = ctx.GetEvalStackOffset_3(); ir->chars = ctx.GetEvalStackOffset_3(); ir->startIndex = ctx.GetEvalStackOffset_2(); ir->length = ctx.GetEvalStackOffset_1(); ctx.PopStackN(2); return true; } return false; } default: return false; } } static bool CIH_Nullable(TransformContext& ctx, const MethodInfo* method) { Il2CppClass* klass = method->klass; IL2CPP_ASSERT(IS_CLASS_VALUE_TYPE(klass)); IL2CPP_ASSERT(ctx.evalStackTop > 0); il2cpp::vm::Class::SetupFields(klass); il2cpp::vm::Class::SetupFields(klass->castClass); IHCreateAddIR(ir, NullableNewVarVar); ir->dst = ir->data = ctx.GetEvalStackTopOffset(); ir->klass = ctx.GetOrAddResolveDataIndex(klass); ctx.PopStack(); ctx.PushStackByType(&klass->byval_arg); return true; } static bool CIH_MdArray(TransformContext& ctx, const MethodInfo* method) { uint8_t paramCount = method->parameters_count; Il2CppClass* klass = method->klass; if (klass->rank == paramCount) { IHCreateAddIR(ir, NewMdArrVarVar_length); ir->lengthIdxs = ctx.GetEvalStackOffset(ctx.evalStackTop - paramCount); ctx.PopStackN(paramCount); ctx.PushStackByReduceType(NATIVE_INT_REDUCE_TYPE); ir->arr = ctx.GetEvalStackTopOffset(); ir->klass = ctx.GetOrAddResolveDataIndex(klass); } else if (klass->rank * 2 == paramCount) { IHCreateAddIR(ir, NewMdArrVarVar_length_bound); ir->lengthIdxs = ctx.GetEvalStackOffset(ctx.evalStackTop - paramCount); ir->lowerBoundIdxs = ctx.GetEvalStackOffset(ctx.evalStackTop - klass->rank); ctx.PopStackN(paramCount); ctx.PushStackByReduceType(NATIVE_INT_REDUCE_TYPE); ir->arr = ctx.GetEvalStackTopOffset(); ir->klass = ctx.GetOrAddResolveDataIndex(klass); } else { RaiseExecutionEngineException("not support array ctor"); } return true; } static bool CIH_Delegate(TransformContext& ctx, const MethodInfo* method) { uint8_t paramCount = method->parameters_count; Il2CppClass* klass = method->klass; IL2CPP_ASSERT(ctx.evalStackTop >= 2); #if HYBRIDCLR_UNITY_2021_OR_NEW const MethodInfo* ctor = il2cpp::vm::Class::GetMethodFromName(method->klass, ".ctor", 2); if (ctor && ctor->methodPointer && !ctor->isInterpterImpl) { IHCreateAddIR(ir, CtorDelegate); ir->dst = ir->obj = ctx.GetEvalStackOffset_2(); ir->ctor = ctx.GetOrAddResolveDataIndex(ctor); ir->method = ctx.GetEvalStackOffset_1(); } else { IHCreateAddIR(ir, NewDelegate); ir->dst = ir->obj = ctx.GetEvalStackOffset_2(); ir->klass = ctx.GetOrAddResolveDataIndex(klass); ir->method = ctx.GetEvalStackOffset_1(); } #else IHCreateAddIR(ir, NewDelegate); ir->dst = ir->obj = ctx.GetEvalStackOffset_2(); ir->klass = ctx.GetOrAddResolveDataIndex(klass); ir->method = ctx.GetEvalStackOffset_1(); #endif ctx.PopStackN(2); ctx.PushStackByReduceType(NATIVE_INT_REDUCE_TYPE); return true; } static bool CIH_UnityEngine_Vector2_ctor(TransformContext& ctx, const MethodInfo* method) { if (method->parameters_count != 2) { return false; } IL2CPP_ASSERT(ctx.evalStackTop >= 2); IHCreateAddIR(ir, NewVector2); ir->obj = ir->x = ctx.GetEvalStackOffset_2(); ir->y = ctx.GetEvalStackOffset_1(); ctx.PopStackN(2); ctx.PushStackByType(&method->klass->byval_arg); return true; } static bool CIH_UnityEngine_Vector3_ctor(TransformContext& ctx, const MethodInfo* method) { switch (method->parameters_count) { case 2: { IL2CPP_ASSERT(ctx.evalStackTop >= 2); IHCreateAddIR(ir, NewVector3_2); ir->obj = ir->x = ctx.GetEvalStackOffset_2(); ir->y = ctx.GetEvalStackOffset_1(); ctx.PopStackN(2); ctx.PushStackByType(&method->klass->byval_arg); return true; } case 3: { IL2CPP_ASSERT(ctx.evalStackTop >= 3); IHCreateAddIR(ir, NewVector3_3); ir->obj = ir->x = ctx.GetEvalStackOffset_3(); ir->y = ctx.GetEvalStackOffset_2(); ir->z = ctx.GetEvalStackOffset_1(); ctx.PopStackN(3); ctx.PushStackByType(&method->klass->byval_arg); return true; } default: return false; } } static bool CIH_UnityEngine_Vector4_ctor(TransformContext& ctx, const MethodInfo* method) { switch (method->parameters_count) { case 2: { IL2CPP_ASSERT(ctx.evalStackTop >= 2); IHCreateAddIR(ir, NewVector4_2); ir->obj = ir->x = ctx.GetEvalStackOffset_2(); ir->y = ctx.GetEvalStackOffset_1(); ctx.PopStackN(2); ctx.PushStackByType(&method->klass->byval_arg); return true; } case 3: { IL2CPP_ASSERT(ctx.evalStackTop >= 3); IHCreateAddIR(ir, NewVector4_3); ir->obj = ir->x = ctx.GetEvalStackOffset_3(); ir->y = ctx.GetEvalStackOffset_2(); ir->z = ctx.GetEvalStackOffset_1(); ctx.PopStackN(3); ctx.PushStackByType(&method->klass->byval_arg); return true; } case 4: { IL2CPP_ASSERT(ctx.evalStackTop >= 4); IHCreateAddIR(ir, NewVector4_4); ir->obj = ir->x = ctx.GetEvalStackOffset_4(); ir->y = ctx.GetEvalStackOffset_3(); ir->z = ctx.GetEvalStackOffset_2(); ir->w = ctx.GetEvalStackOffset_1(); ctx.PopStackN(4); ctx.PushStackByType(&method->klass->byval_arg); return true; } default: return false; } } static bool CIH_ByReference(TransformContext& ctx, const MethodInfo* method) { // new ByReference(ref T value) don't need to do anything Il2CppClass* klass = method->klass; IL2CPP_ASSERT(ctx.evalStackTop > 0); ctx.PopStack(); ctx.PushStackByReduceType(NATIVE_INT_REDUCE_TYPE); return true; } static CtorInstinctHandlerInfo s_ctorInstinctHandlerInfos[] = { {"System", "Object", CIH_Object}, {"System", "String", CIH_String}, {"System", "Nullable`1", CIH_Nullable}, {"UnityEngine", "Vector2", CIH_UnityEngine_Vector2_ctor}, {"UnityEngine", "Vector3", CIH_UnityEngine_Vector3_ctor}, {"UnityEngine", "Vector4", CIH_UnityEngine_Vector4_ctor}, {"System", "ByReference`1", CIH_ByReference}, }; void TransformContext::InitializeInstinctHandlers() { for (InstinctHandlerInfo& handler : s_instinctHandlerInfos) { NamespaceAndNameAndMethod nnm = { handler.namespaze, handler.name, handler.method }; s_instinctHandlerMap.add(nnm, handler.handler); } for (CtorInstinctHandlerInfo& handler : s_ctorInstinctHandlerInfos) { NamespaceAndName nnm = { handler.namespaze, handler.name }; s_ctorInstinctHandlerMap.add(nnm, handler.handler); } } bool TransformContext::TryAddInstinctCtorInstruments(const MethodInfo* method) { Il2CppClass* klass = method->klass; if (klass->byval_arg.type == IL2CPP_TYPE_ARRAY) { return CIH_MdArray(*this, method); } if (IsChildTypeOfMulticastDelegate(method->klass)) { return CIH_Delegate(*this, method); } NamespaceAndName key = { klass->namespaze, klass->name }; auto it = s_ctorInstinctHandlerMap.find(key); if (it != s_ctorInstinctHandlerMap.end()) { return (it->second)(*this, method); } return false; } bool TransformContext::TryAddInstinctInstrumentsByName(const MethodInfo* method) { Il2CppClass* klass = method->klass; const char* namespaceName = klass->namespaze; const char* klassName = klass->name; const char* methodName = method->name; uint32_t paramCount = method->parameters_count; NamespaceAndNameAndMethod key = { namespaceName, klassName, methodName }; auto it = s_instinctHandlerMap.find(key); if (it == s_instinctHandlerMap.end()) { return false; } return (it->second)(*this, method); } bool TransformContext::TryAddArrayInstinctInstruments(const MethodInfo* method) { Il2CppClass* klass = method->klass; // warn! can't change to else if. because namespace == system if (klass->byval_arg.type == IL2CPP_TYPE_ARRAY) { const char* methodName = method->name; uint8_t paramCount = method->parameters_count + 1; const Il2CppType* eleType = &klass->element_class->byval_arg; LocationDescInfo desc = ComputLocationDescInfo(eleType); if (strcmp(methodName, "Get") == 0) { CreateAddIR(ir, GetMdArrElementVarVar_n); ir->type = CalcGetMdArrElementVarVarOpcode(eleType); ir->arr = GetEvalStackOffset(evalStackTop - paramCount); ir->lengthIdxs = ir->arr + 1; PopStackN(paramCount); PushStackByType(eleType); ir->value = GetEvalStackTopOffset(); return true; } else if (strcmp(methodName, "Address") == 0) { CreateAddIR(ir, GetMdArrElementAddressVarVar); ir->arr = GetEvalStackOffset(evalStackTop - paramCount); ir->lengthIdxs = ir->arr + 1; PopStackN(paramCount); PushStackByReduceType(NATIVE_INT_REDUCE_TYPE); ir->addr = GetEvalStackTopOffset(); return true; } else if (strcmp(methodName, "Set") == 0) { CreateAddIR(ir, SetMdArrElementVarVar_n); switch (desc.type) { case LocationDescType::I1: ir->type = HiOpcodeEnum::SetMdArrElementVarVar_i1; break; case LocationDescType::U1: ir->type = HiOpcodeEnum::SetMdArrElementVarVar_u1; break; case LocationDescType::I2: ir->type = HiOpcodeEnum::SetMdArrElementVarVar_i2; break; case LocationDescType::U2: ir->type = HiOpcodeEnum::SetMdArrElementVarVar_u2; break; case LocationDescType::I4: ir->type = HiOpcodeEnum::SetMdArrElementVarVar_i4; break; case LocationDescType::I8: ir->type = HiOpcodeEnum::SetMdArrElementVarVar_i8; break; case LocationDescType::Ref: ir->type = HiOpcodeEnum::SetMdArrElementVarVar_ref; break; case LocationDescType::S: ir->type = HiOpcodeEnum::SetMdArrElementVarVar_n; break; case LocationDescType::StructContainsRef: ir->type = HiOpcodeEnum::SetMdArrElementVarVar_WriteBarrier_n; break; default: RaiseExecutionEngineException("not support array element type"); break; } ir->arr = GetEvalStackOffset(evalStackTop - paramCount); ir->lengthIdxs = ir->arr + 1; ir->ele = GetEvalStackTopOffset(); PopStackN(paramCount); return true; } } return false; } } }