#include "MethodBridge.h" #include "vm/Object.h" #include "vm/Class.h" #include "metadata/GenericMetadata.h" #include "../metadata/MetadataModule.h" #include "../metadata/MetadataUtil.h" #include "Interpreter.h" #include "InterpreterModule.h" #include "MemoryUtil.h" namespace hybridclr { namespace interpreter { void ConvertInvokeArgs(StackObject* resultArgs, const MethodInfo* method, MethodArgDesc* argDescs, void** args) { int32_t dstIdx = 0; for (uint8_t i = 0; i < method->parameters_count; i++) { StackObject* dst = resultArgs + dstIdx; MethodArgDesc& argDesc = argDescs[i]; if (argDesc.passbyValWhenInvoke) { dst->ptr = args[i]; ++dstIdx; } else { #if SUPPORT_MEMORY_NOT_ALIGMENT_ACCESS CopyStackObject(dst, args[i], argDesc.stackObjectSize); #else std::memcpy(dst, args[i], argDesc.stackObjectSize * sizeof(StackObject)); #endif dstIdx += argDesc.stackObjectSize; } } } static void AppendString(char* sigBuf, size_t bufSize, size_t& pos, const char* str) { size_t len = std::strlen(str); if (pos + len < bufSize) { std::strcpy(sigBuf + pos, str); pos += len; } else { RaiseExecutionEngineException(""); } } inline void AppendSignatureObjOrRefOrPointer(char* sigBuf, size_t bufSize, size_t& pos) { AppendString(sigBuf, bufSize, pos, "u"); } inline void AppendSignatureInterpreterValueType(char* sigBuf, size_t bufSize, size_t& pos) { AppendString(sigBuf, bufSize, pos, "$"); } static void AppendSignature(const Il2CppType* type, char* sigBuf, size_t bufferSize, size_t& pos, bool convertTypeName2SigName = true); static bool IsSystemOrUnityAssembly(const Il2CppImage* image) { const char* assName = image->nameNoExt; if (std::strcmp(assName, "mscorlib") == 0) { return true; } if (std::strncmp(assName, "System.", 7) == 0) { return true; } if (std::strncmp(assName, "UnityEngine.", 12) == 0) { return true; } return false; } static void BuildValueTypeFullName(const Il2CppClass* klass, char* sigBuf, size_t bufferSize, size_t& pos) { if (klass->declaringType) { BuildValueTypeFullName(klass->declaringType, sigBuf, bufferSize, pos); AppendString(sigBuf, bufferSize, pos, "/"); AppendString(sigBuf, bufferSize, pos, klass->name); return; } if (!IsSystemOrUnityAssembly(klass->image)) { AppendString(sigBuf, bufferSize, pos, klass->image->nameNoExt); AppendString(sigBuf, bufferSize, pos, ":"); } if (klass->namespaze[0]) { AppendString(sigBuf, bufferSize, pos, klass->namespaze); AppendString(sigBuf, bufferSize, pos, "."); } AppendString(sigBuf, bufferSize, pos, klass->name); } static void BuildGenericValueTypeFullName(const Il2CppType* type, char* sigBuf, size_t bufferSize, size_t& pos) { const Il2CppType* underlyingGenericType = type->data.generic_class->type; const Il2CppClass* underlyingGenericClass = il2cpp::vm::Class::FromIl2CppType(underlyingGenericType); BuildValueTypeFullName(underlyingGenericClass, sigBuf, bufferSize, pos); AppendString(sigBuf, bufferSize, pos, "<"); const Il2CppGenericInst* classInst = type->data.generic_class->context.class_inst; for (uint32_t i = 0 ; i < classInst->type_argc; ++i) { if (i != 0) { AppendString(sigBuf, bufferSize, pos, ","); } AppendSignature(classInst->type_argv[i], sigBuf, bufferSize, pos, false); } AppendString(sigBuf, bufferSize, pos, ">"); } static void AppendSignature(const Il2CppType* type, char* sigBuf, size_t bufferSize, size_t& pos, bool convertTypeName2SigName) { if (type->byref) { AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); return; } switch (type->type) { case IL2CPP_TYPE_VOID: AppendString(sigBuf, bufferSize, pos, "v"); break; case IL2CPP_TYPE_BOOLEAN: AppendString(sigBuf, bufferSize, pos, "u1"); break; case IL2CPP_TYPE_I1: AppendString(sigBuf, bufferSize, pos, "i1"); break; case IL2CPP_TYPE_U1: AppendString(sigBuf, bufferSize, pos, "u1"); break; case IL2CPP_TYPE_I2: AppendString(sigBuf, bufferSize, pos, "i2"); break; case IL2CPP_TYPE_U2: case IL2CPP_TYPE_CHAR: AppendString(sigBuf, bufferSize, pos, "u2"); break; case IL2CPP_TYPE_I4: AppendString(sigBuf, bufferSize, pos, "i4"); break; case IL2CPP_TYPE_U4: AppendString(sigBuf, bufferSize, pos, "u4"); break; case IL2CPP_TYPE_R4: AppendString(sigBuf, bufferSize, pos, "r4"); break; case IL2CPP_TYPE_R8: AppendString(sigBuf, bufferSize, pos, "r8"); break; case IL2CPP_TYPE_I8: AppendString(sigBuf, bufferSize, pos, "i8"); break; case IL2CPP_TYPE_U8: AppendString(sigBuf, bufferSize, pos, "u8"); break; case IL2CPP_TYPE_I: AppendString(sigBuf, bufferSize, pos, "i"); break; case IL2CPP_TYPE_U: AppendString(sigBuf, bufferSize, pos, "u"); break; case IL2CPP_TYPE_TYPEDBYREF: { IL2CPP_ASSERT(sizeof(Il2CppTypedRef) == sizeof(void*) * 3); AppendString(sigBuf, bufferSize, pos, "typedbyref"); break; } case IL2CPP_TYPE_VALUETYPE: { const Il2CppTypeDefinition* typeDef = (const Il2CppTypeDefinition*)type->data.typeHandle; if (hybridclr::metadata::IsEnumType(typeDef)) { AppendSignature(il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->elementTypeIndex), sigBuf, bufferSize, pos); break; } if (hybridclr::metadata::IsInterpreterType(typeDef)) { AppendSignatureInterpreterValueType(sigBuf, bufferSize, pos); break; } char tempFullName[1024]; size_t fullNamePos = 0; Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type); BuildValueTypeFullName(klass, tempFullName, sizeof(tempFullName) - 1, fullNamePos); tempFullName[fullNamePos] = 0; AppendString(sigBuf, bufferSize, pos, convertTypeName2SigName ? InterpreterModule::GetValueTypeSignature(tempFullName) : tempFullName); break; } case IL2CPP_TYPE_GENERICINST: { const Il2CppType* underlyingGenericType = type->data.generic_class->type; if (underlyingGenericType->type == IL2CPP_TYPE_CLASS) { AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); break; } const Il2CppTypeDefinition* underlyingTypeDef = (const Il2CppTypeDefinition*)underlyingGenericType->data.typeHandle; if (hybridclr::metadata::IsEnumType(underlyingTypeDef)) { AppendSignature(il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(underlyingTypeDef->elementTypeIndex), sigBuf, bufferSize, pos); break; } IL2CPP_ASSERT(underlyingGenericType->type == IL2CPP_TYPE_VALUETYPE); if (hybridclr::metadata::IsInterpreterType(underlyingTypeDef)) { AppendSignatureInterpreterValueType(sigBuf, bufferSize, pos); break; } char tempFullName[1024]; size_t fullNamePos = 0; BuildGenericValueTypeFullName(type, tempFullName, sizeof(tempFullName) - 1, fullNamePos); tempFullName[fullNamePos] = 0; AppendString(sigBuf, bufferSize, pos, convertTypeName2SigName ? InterpreterModule::GetValueTypeSignature(tempFullName) : tempFullName); break; } case IL2CPP_TYPE_VAR: case IL2CPP_TYPE_MVAR: { AppendString(sigBuf, bufferSize, pos, "!"); break; } default: AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); break; } } bool ComputeSignature(const Il2CppType* ret, const Il2CppType* params, uint32_t paramCount, bool instanceCall, char* sigBuf, size_t bufferSize) { size_t pos = 0; AppendSignature(ret, sigBuf, bufferSize, pos); if (instanceCall) { AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); } for (uint32_t i = 0; i < paramCount; i++) { AppendSignature(params + i, sigBuf, bufferSize, pos); } sigBuf[pos] = 0; return true; } bool ComputeSignature(const Il2CppMethodDefinition* method, bool call, char* sigBuf, size_t bufferSize) { size_t pos = 0; if (method->genericContainerIndex != kGenericContainerIndexInvalid) { AppendString(sigBuf, bufferSize, pos, "!"); return true; } const Il2CppImage* image = hybridclr::metadata::MetadataModule::GetImage(method)->GetIl2CppImage(); AppendSignature(hybridclr::metadata::MetadataModule::GetIl2CppTypeFromEncodeIndex(method->returnType), sigBuf, bufferSize, pos); if (call && metadata::IsInstanceMethod(method)) { AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); } for (uint8_t i = 0; i < method->parameterCount; i++) { TypeIndex paramTypeIndex = hybridclr::metadata::MetadataModule::GetParameterDefinitionFromIndex(image, method->parameterStart + i)->typeIndex; AppendSignature(hybridclr::metadata::MetadataModule::GetIl2CppTypeFromEncodeIndex(paramTypeIndex), sigBuf, bufferSize, pos); } sigBuf[pos] = 0; return true; } inline bool ContainsGenericParameters(const MethodInfo* method) { IL2CPP_ASSERT(method->is_inflated); auto& ctx = method->genericMethod->context; if (ctx.class_inst && il2cpp::metadata::GenericMetadata::ContainsGenericParameters(ctx.class_inst)) { return true; } if (ctx.method_inst && il2cpp::metadata::GenericMetadata::ContainsGenericParameters(ctx.method_inst)) { return true; } return false; } bool ComputeSignature(const MethodInfo* method, bool call, char* sigBuf, size_t bufferSize) { size_t pos = 0; if (method->is_generic || (method->is_inflated && ContainsGenericParameters(method))) { AppendString(sigBuf, bufferSize, pos, "!"); return true; } AppendSignature(method->return_type, sigBuf, bufferSize, pos); if (call && metadata::IsInstanceMethod(method)) { AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); } for (uint8_t i = 0; i < method->parameters_count; i++) { AppendSignature(GET_METHOD_PARAMETER_TYPE(method->parameters[i]), sigBuf, bufferSize, pos); } sigBuf[pos] = 0; return true; } } }