#include "TransformContext.h" #include "../interpreter/MethodBridge.h" namespace hybridclr { namespace transform { enum class ArgCommonType { VOID, I1, U1, I2, U2, I4, I8, R4, R8, I, U, STRUCT, NOT_SUPPORT, }; #if HYBRIDCLR_ARCH_64 #define NATIVE_INT_COMMON_TYPE ArgCommonType::I8 #else #define NATIVE_INT_COMMON_TYPE ArgCommonType::I4 #endif static ArgCommonType ComputValueTypeArgCommonType(const Il2CppClass* klass) { return ArgCommonType::STRUCT; } static ArgCommonType ComputArgCommonType(const Il2CppType* type) { if (type->byref) { return NATIVE_INT_COMMON_TYPE; } switch (type->type) { case IL2CPP_TYPE_VOID: return ArgCommonType::VOID; case IL2CPP_TYPE_BOOLEAN: case IL2CPP_TYPE_U1: return ArgCommonType::U1; case IL2CPP_TYPE_I1: return ArgCommonType::I1; case IL2CPP_TYPE_I2: return ArgCommonType::I2; case IL2CPP_TYPE_CHAR: case IL2CPP_TYPE_U2: return ArgCommonType::U2; case IL2CPP_TYPE_I4: case IL2CPP_TYPE_U4: return ArgCommonType::I4; case IL2CPP_TYPE_R4: return ArgCommonType::R4; case IL2CPP_TYPE_I8: case IL2CPP_TYPE_U8: return ArgCommonType::I8; case IL2CPP_TYPE_R8: return ArgCommonType::R8; case IL2CPP_TYPE_I: case IL2CPP_TYPE_U: case IL2CPP_TYPE_FNPTR: case IL2CPP_TYPE_PTR: case IL2CPP_TYPE_BYREF: case IL2CPP_TYPE_STRING: case IL2CPP_TYPE_ARRAY: case IL2CPP_TYPE_SZARRAY: case IL2CPP_TYPE_OBJECT: case IL2CPP_TYPE_CLASS: return NATIVE_INT_COMMON_TYPE; case IL2CPP_TYPE_TYPEDBYREF: return ArgCommonType::NOT_SUPPORT; case IL2CPP_TYPE_VALUETYPE: { Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type); IL2CPP_ASSERT(IS_CLASS_VALUE_TYPE(klass)); if (klass->enumtype) { return ComputArgCommonType(&klass->castClass->byval_arg); } return ComputValueTypeArgCommonType(klass); } case IL2CPP_TYPE_GENERICINST: { Il2CppGenericClass* genericClass = type->data.generic_class; if (genericClass->type->type == IL2CPP_TYPE_CLASS) { IL2CPP_ASSERT(!IS_CLASS_VALUE_TYPE(il2cpp::vm::Class::FromIl2CppType(type))); return NATIVE_INT_COMMON_TYPE; } else { Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type); IL2CPP_ASSERT(IS_CLASS_VALUE_TYPE(klass)); if (klass->enumtype) { return ComputArgCommonType(&klass->castClass->byval_arg); } return ComputValueTypeArgCommonType(klass); } } default: { RaiseExecutionEngineException("not support arg type"); return ArgCommonType::NOT_SUPPORT; } } } ArgCommonType ComputMethodArgHomoType(const MethodInfo* method) { ArgCommonType homoType = ComputArgCommonType(GET_METHOD_PARAMETER_TYPE(method->parameters[0])); if (homoType == ArgCommonType::NOT_SUPPORT) { return homoType; } for (uint8_t i = 1; i < method->parameters_count; i++) { ArgCommonType pt = ComputArgCommonType(GET_METHOD_PARAMETER_TYPE(method->parameters[i])); if (pt != homoType) { return ArgCommonType::NOT_SUPPORT; } } return homoType; } constexpr int MAX_COMMON_PARAM_NUM = 4; bool TransformContext::TryAddCallCommonInstanceInstruments(const MethodInfo* method, uint32_t methodDataIndex) { const Il2CppType* returnType = method->return_type; int32_t paramCount = shareMethod->parameters_count; int32_t resolvedTotalArgdNum = paramCount + 1; int32_t callArgEvalStackIdxBase = evalStackTop - resolvedTotalArgdNum; uint16_t argBaseOffset = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase); ArgCommonType actRet = ComputArgCommonType(returnType); if (actRet == ArgCommonType::NOT_SUPPORT || actRet == ArgCommonType::STRUCT) { return false; } if (paramCount == 0) { // (void,u1,i1,i2,u2,i4, i8, f4, f8, v2, v3, v4} func(object x); if (actRet == ArgCommonType::VOID) { CreateAddIR(ir, CallCommonNativeInstance_v_0); ir->method = methodDataIndex; ir->self = argBaseOffset; return true; } CreateAddIR(ir, CallCommonNativeInstance_i1_0); ir->method = methodDataIndex; ir->self = argBaseOffset; ir->ret = argBaseOffset; switch (actRet) { case ArgCommonType::I1: { ir->type = HiOpcodeEnum::CallCommonNativeInstance_i1_0; break; } case ArgCommonType::U1: { ir->type = HiOpcodeEnum::CallCommonNativeInstance_u1_0; break; } case ArgCommonType::I2: { ir->type = HiOpcodeEnum::CallCommonNativeInstance_i2_0; break; } case ArgCommonType::U2: { ir->type = HiOpcodeEnum::CallCommonNativeInstance_u2_0; break; } case ArgCommonType::I4: { ir->type = HiOpcodeEnum::CallCommonNativeInstance_i4_0; break; } case ArgCommonType::I8: { ir->type = HiOpcodeEnum::CallCommonNativeInstance_i8_0; break; } case ArgCommonType::R4: { ir->type = HiOpcodeEnum::CallCommonNativeInstance_f4_0; break; } case ArgCommonType::R8: { ir->type = HiOpcodeEnum::CallCommonNativeInstance_f8_0; break; } default: RaiseExecutionEngineException("TryAddCallCommonInstanceInstruments. unknown ArgCommonType "); break; } return true; } if (paramCount > MAX_COMMON_PARAM_NUM) { return false; } ArgCommonType actParam = ComputMethodArgHomoType(method); if (actParam == ArgCommonType::NOT_SUPPORT) { return false; } #define SWITCH_INSTANCE_VOID(argType, argNum) \ switch (argNum) \ {\ case 1:\ {\ CreateAddIR(ir, CallCommonNativeInstance_v_##argType##_1);\ ir->method = methodDataIndex;\ ir->self = argBaseOffset;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ return true;\ }\ case 2:\ {\ CreateAddIR(ir, CallCommonNativeInstance_v_##argType##_2);\ ir->method = methodDataIndex;\ ir->self = argBaseOffset;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ return true;\ }\ case 3:\ {\ CreateAddIR(ir, CallCommonNativeInstance_v_##argType##_3);\ ir->method = methodDataIndex;\ ir->self = argBaseOffset;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ ir->param2 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 3);\ return true;\ }\ case 4:\ {\ CreateAddIR(ir, CallCommonNativeInstance_v_##argType##_4);\ ir->method = methodDataIndex;\ ir->self = argBaseOffset;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ ir->param2 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 3);\ ir->param3 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 4);\ return true;\ }\ default: return false;\ } // (void, u1, i4, i8, f4, f8} func(object this, T x1, ,, T xN); T={i4,i8,f4,f8}, N =[1,4] if (actRet == ArgCommonType::VOID) { switch (actParam) { case hybridclr::transform::ArgCommonType::I4: { SWITCH_INSTANCE_VOID(i4, paramCount); break; } case hybridclr::transform::ArgCommonType::I8: { SWITCH_INSTANCE_VOID(i8, paramCount); break; } case hybridclr::transform::ArgCommonType::R4: { SWITCH_INSTANCE_VOID(f4, paramCount); break; } case hybridclr::transform::ArgCommonType::R8: { SWITCH_INSTANCE_VOID(f8, paramCount); break; } default: return false; } } #define SWITCH_INSTANCE_RET(retType, argType, argNum) \ switch (argNum) \ {\ case 1:\ {\ CreateAddIR(ir, CallCommonNativeInstance_##retType##_##argType##_1);\ ir->method = methodDataIndex;\ ir->self = argBaseOffset;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->ret = argBaseOffset;\ return true;\ }\ case 2:\ {\ CreateAddIR(ir, CallCommonNativeInstance_##retType##_##argType##_2);\ ir->method = methodDataIndex;\ ir->self = argBaseOffset;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ ir->ret = argBaseOffset;\ return true;\ }\ case 3:\ {\ CreateAddIR(ir, CallCommonNativeInstance_##retType##_##argType##_3);\ ir->method = methodDataIndex;\ ir->self = argBaseOffset;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ ir->param2 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 3);\ ir->ret = argBaseOffset;\ return true;\ }\ case 4:\ {\ CreateAddIR(ir, CallCommonNativeInstance_##retType##_##argType##_4);\ ir->method = methodDataIndex;\ ir->self = argBaseOffset;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ ir->param2 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 3);\ ir->param3 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 4);\ ir->ret = argBaseOffset;\ return true;\ }\ default: return false;\ } #define SWTCH_INSTANCE_RET2(retType) \ switch (actParam)\ {\ case hybridclr::transform::ArgCommonType::I4:\ {\ SWITCH_INSTANCE_RET(retType, i4, paramCount);\ break;\ }\ case hybridclr::transform::ArgCommonType::I8:\ {\ SWITCH_INSTANCE_RET(retType, i8, paramCount);\ break;\ }\ case hybridclr::transform::ArgCommonType::R4:\ {\ SWITCH_INSTANCE_RET(retType, f4, paramCount);\ break;\ }\ case hybridclr::transform::ArgCommonType::R8:\ {\ SWITCH_INSTANCE_RET(retType, f8, paramCount);\ break;\ }\ default:\ return false;\ } switch (actRet) { case ArgCommonType::U1: { SWTCH_INSTANCE_RET2(u1); break; } case ArgCommonType::I4: { SWTCH_INSTANCE_RET2(i4); break; } case ArgCommonType::I8: { SWTCH_INSTANCE_RET2(i8); break; } case ArgCommonType::R4: { SWTCH_INSTANCE_RET2(f4); break; } case ArgCommonType::R8: { SWTCH_INSTANCE_RET2(f8); break; } } return false; } bool TransformContext::TryAddCallCommonStaticInstruments(const MethodInfo* method, uint32_t methodDataIndex) { const Il2CppType* returnType = method->return_type; int32_t paramCount = shareMethod->parameters_count; int32_t resolvedTotalArgdNum = paramCount; int32_t callArgEvalStackIdxBase = evalStackTop - resolvedTotalArgdNum; uint16_t argBaseOffset = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase); ArgCommonType actRet = ComputArgCommonType(returnType); if (actRet == ArgCommonType::NOT_SUPPORT || actRet == ArgCommonType::STRUCT) { return false; } if (paramCount == 0) { // (void,u1,i1,i2,u2,i4, i8, f4, f8, v2, v3, v4} func(); if (actRet == ArgCommonType::VOID) { CreateAddIR(ir, CallCommonNativeStatic_v_0); ir->method = methodDataIndex; return true; } CreateAddIR(ir, CallCommonNativeStatic_i1_0); ir->method = methodDataIndex; ir->ret = argBaseOffset; switch (actRet) { case ArgCommonType::I1: { ir->type = HiOpcodeEnum::CallCommonNativeStatic_i1_0; break; } case ArgCommonType::U1: { ir->type = HiOpcodeEnum::CallCommonNativeStatic_u1_0; break; } case ArgCommonType::I2: { ir->type = HiOpcodeEnum::CallCommonNativeStatic_i2_0; break; } case ArgCommonType::U2: { ir->type = HiOpcodeEnum::CallCommonNativeStatic_u2_0; break; } case ArgCommonType::I4: { ir->type = HiOpcodeEnum::CallCommonNativeStatic_i4_0; break; } case ArgCommonType::I8: { ir->type = HiOpcodeEnum::CallCommonNativeStatic_i8_0; break; } case ArgCommonType::R4: { ir->type = HiOpcodeEnum::CallCommonNativeStatic_f4_0; break; } case ArgCommonType::R8: { ir->type = HiOpcodeEnum::CallCommonNativeStatic_f8_0; break; } default: RaiseExecutionEngineException("TryAddCallCommonStaticInstruments. unknown ArgCommonType "); break; } return true; } if (paramCount > MAX_COMMON_PARAM_NUM) { return false; } ArgCommonType actParam = ComputMethodArgHomoType(method); if (actParam == ArgCommonType::NOT_SUPPORT) { return false; } #define SWITCH_STATIC_VOID(argType, argNum) \ switch (argNum) \ {\ case 1:\ {\ CreateAddIR(ir, CallCommonNativeStatic_v_##argType##_1);\ ir->method = methodDataIndex;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase);\ return true;\ }\ case 2:\ {\ CreateAddIR(ir, CallCommonNativeStatic_v_##argType##_2);\ ir->method = methodDataIndex;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ return true;\ }\ case 3:\ {\ CreateAddIR(ir, CallCommonNativeStatic_v_##argType##_3);\ ir->method = methodDataIndex;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param2 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ return true;\ }\ case 4:\ {\ CreateAddIR(ir, CallCommonNativeStatic_v_##argType##_4);\ ir->method = methodDataIndex;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param2 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ ir->param3 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 3);\ return true;\ }\ default: return false;\ } // (void, u1, i4, i8, f4, f8} func(object this, T x1, ,, T xN); T={i4,i8,f4,f8}, N =[1,4] if (actRet == ArgCommonType::VOID) { switch (actParam) { case hybridclr::transform::ArgCommonType::I4: { SWITCH_STATIC_VOID(i4, paramCount); break; } case hybridclr::transform::ArgCommonType::I8: { SWITCH_STATIC_VOID(i8, paramCount); break; } case hybridclr::transform::ArgCommonType::R4: { SWITCH_STATIC_VOID(f4, paramCount); break; } case hybridclr::transform::ArgCommonType::R8: { SWITCH_STATIC_VOID(f8, paramCount); break; } default: return false; } } #define SWITCH_STATIC_RET(retType, argType, argNum) \ switch (argNum) \ {\ case 1:\ {\ CreateAddIR(ir, CallCommonNativeStatic_##retType##_##argType##_1);\ ir->method = methodDataIndex;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase);\ ir->ret = argBaseOffset;\ return true;\ }\ case 2:\ {\ CreateAddIR(ir, CallCommonNativeStatic_##retType##_##argType##_2);\ ir->method = methodDataIndex;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->ret = argBaseOffset;\ return true;\ }\ case 3:\ {\ CreateAddIR(ir, CallCommonNativeStatic_##retType##_##argType##_3);\ ir->method = methodDataIndex;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param2 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ ir->ret = argBaseOffset;\ return true;\ }\ case 4:\ {\ CreateAddIR(ir, CallCommonNativeStatic_##retType##_##argType##_4);\ ir->method = methodDataIndex;\ ir->param0 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase);\ ir->param1 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 1);\ ir->param2 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 2);\ ir->param3 = (uint16_t)GetEvalStackOffset(callArgEvalStackIdxBase + 3);\ ir->ret = argBaseOffset;\ return true;\ }\ default: return false;\ } #define SWTCH_STATIC_RET2(retType) \ switch (actParam)\ {\ case hybridclr::transform::ArgCommonType::I4:\ {\ SWITCH_STATIC_RET(retType, i4, paramCount);\ break;\ }\ case hybridclr::transform::ArgCommonType::I8:\ {\ SWITCH_STATIC_RET(retType, i8, paramCount);\ break;\ }\ case hybridclr::transform::ArgCommonType::R4:\ {\ SWITCH_STATIC_RET(retType, f4, paramCount);\ break;\ }\ case hybridclr::transform::ArgCommonType::R8:\ {\ SWITCH_STATIC_RET(retType, f8, paramCount);\ break;\ }\ default:\ return false;\ } switch (actRet) { case ArgCommonType::U1: { SWTCH_STATIC_RET2(u1); break; } case ArgCommonType::I4: { SWTCH_STATIC_RET2(i4); break; } case ArgCommonType::I8: { SWTCH_STATIC_RET2(i8); break; } case ArgCommonType::R4: { SWTCH_STATIC_RET2(f4); break; } case ArgCommonType::R8: { SWTCH_STATIC_RET2(f8); break; } } return false; } } }