#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;
|
}
|
|
}
|
}
|