Files
ft/Client/HybridCLRData/il2cpp_plus_repo/libil2cpp/hybridclr/interpreter/InterpreterModule.cpp
2026-06-29 21:18:33 +08:00

528 lines
18 KiB
C++

#include "InterpreterModule.h"
#include "Interpreter.h"
#include <unordered_map>
#include "vm/GlobalMetadata.h"
#include "vm/MetadataCache.h"
#include "vm/MetadataLock.h"
#include "vm/Class.h"
#include "vm/Object.h"
#include "vm/Method.h"
#include "../metadata/MetadataModule.h"
#include "../metadata/MetadataUtil.h"
#include "../metadata/InterpreterImage.h"
#include "../transform/Transform.h"
#include "MethodBridge.h"
#include "InterpreterUtil.h"
namespace hybridclr
{
namespace interpreter
{
il2cpp::os::ThreadLocalValue InterpreterModule::s_machineState;
static Il2CppHashMap<const char*, Managed2NativeCallMethod, CStringHash, CStringEqualTo> g_managed2natives;
static Il2CppHashMap<const char*, Il2CppMethodPointer, CStringHash, CStringEqualTo> g_native2manageds;
static Il2CppHashMap<const char*, Il2CppMethodPointer, CStringHash, CStringEqualTo> g_adjustThunks;
static Il2CppHashMap<const char*, const char*, CStringHash, CStringEqualTo> g_fullName2signature;
MachineState& InterpreterModule::GetCurrentThreadMachineState()
{
MachineState* state = nullptr;
s_machineState.GetValue((void**)&state);
if (!state)
{
state = new MachineState();
s_machineState.SetValue(state);
}
return *state;
}
void InterpreterModule::FreeThreadLocalMachineState()
{
MachineState* state = nullptr;
s_machineState.GetValue((void**)&state);
if (state)
{
delete state;
s_machineState.SetValue(nullptr);
}
}
void InterpreterModule::Initialize()
{
for (size_t i = 0; ; i++)
{
Managed2NativeMethodInfo& method = g_managed2nativeStub[i];
if (!method.signature)
{
break;
}
g_managed2natives.insert({ method.signature, method.method });
}
for (size_t i = 0; ; i++)
{
Native2ManagedMethodInfo& method = g_native2managedStub[i];
if (!method.signature)
{
break;
}
g_native2manageds.insert({ method.signature, method.method });
}
for (size_t i = 0; ; i++)
{
NativeAdjustThunkMethodInfo& method = g_adjustThunkStub[i];
if (!method.signature)
{
break;
}
g_adjustThunks.insert({ method.signature, method.method });
}
for (size_t i = 0 ; ; i++)
{
FullName2Signature& nameSig = g_fullName2SignatureStub[i];
if (!nameSig.fullName)
{
break;
}
g_fullName2signature.insert({ nameSig.fullName, nameSig.signature });
}
}
void InterpreterModule::NotSupportNative2Managed()
{
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException("NotSupportNative2Managed"));
}
void InterpreterModule::NotSupportAdjustorThunk()
{
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException("NotSupportAdjustorThunk"));
}
const char* InterpreterModule::GetValueTypeSignature(const char* fullName)
{
auto it = g_fullName2signature.find(fullName);
return it != g_fullName2signature.end() ? it->second : "$";
}
static void* NotSupportInvoke(Il2CppMethodPointer, const MethodInfo* method, void*, void**)
{
char sigName[1000];
ComputeSignature(method, true, sigName, sizeof(sigName) - 1);
TEMP_FORMAT(errMsg, "Invoke method missing. sinature:%s %s.%s::%s", sigName, method->klass->namespaze, method->klass->name, method->name);
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException(errMsg));
return nullptr;
}
template<typename T>
const Managed2NativeCallMethod GetManaged2NativeMethod(const T* method, bool forceStatic)
{
char sigName[1000];
ComputeSignature(method, !forceStatic, sigName, sizeof(sigName) - 1);
auto it = g_managed2natives.find(sigName);
return it != g_managed2natives.end() ? it->second : nullptr;
}
template<typename T>
const Il2CppMethodPointer GetNative2ManagedMethod(const T* method, bool forceStatic)
{
char sigName[1000];
ComputeSignature(method, !forceStatic, sigName, sizeof(sigName) - 1);
auto it = g_native2manageds.find(sigName);
return it != g_native2manageds.end() ? it->second : InterpreterModule::NotSupportNative2Managed;
}
template<typename T>
const Il2CppMethodPointer GetNativeAdjustMethodMethod(const T* method, bool forceStatic)
{
char sigName[1000];
ComputeSignature(method, !forceStatic, sigName, sizeof(sigName) - 1);
auto it = g_adjustThunks.find(sigName);
return it != g_adjustThunks.end() ? it->second : InterpreterModule::NotSupportAdjustorThunk;
}
static void RaiseMethodNotSupportException(const MethodInfo* method, const char* desc)
{
TEMP_FORMAT(errMsg, "%s. %s.%s::%s", desc, method->klass->namespaze, method->klass->name, method->name);
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException(errMsg));
}
static void RaiseMethodNotSupportException(const Il2CppMethodDefinition* method, const char* desc)
{
Il2CppClass* klass = il2cpp::vm::GlobalMetadata::GetTypeInfoFromTypeDefinitionIndex(method->declaringType);
TEMP_FORMAT(errMsg, "%s. %s.%s::%s", desc, klass->namespaze, klass->name, il2cpp::vm::GlobalMetadata::GetStringFromIndex(method->nameIndex));
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException(errMsg));
}
Il2CppMethodPointer InterpreterModule::GetMethodPointer(const Il2CppMethodDefinition* method)
{
Il2CppMethodPointer ncm = GetNative2ManagedMethod(method, false);
return ncm ? ncm : (Il2CppMethodPointer)NotSupportNative2Managed;
}
Il2CppMethodPointer InterpreterModule::GetMethodPointer(const MethodInfo* method)
{
Il2CppMethodPointer ncm = GetNative2ManagedMethod(method, false);
return ncm ? ncm : (Il2CppMethodPointer)NotSupportNative2Managed;
}
Il2CppMethodPointer InterpreterModule::GetAdjustThunkMethodPointer(const Il2CppMethodDefinition* method)
{
return GetNativeAdjustMethodMethod(method, false);
}
Il2CppMethodPointer InterpreterModule::GetAdjustThunkMethodPointer(const MethodInfo* method)
{
return GetNativeAdjustMethodMethod(method, false);
}
void InterpreterModule::Managed2NativeCallByReflectionInvoke(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
{
if (hybridclr::metadata::IsInterpreterImplement(method))
{
Interpreter::Execute(method, localVarBase + argVarIndexs[0], ret);
return;
}
if (method->invoker_method == nullptr)
{
char sigName[1000];
ComputeSignature(method, true, sigName, sizeof(sigName) - 1);
TEMP_FORMAT(errMsg, "GetManaged2NativeMethodPointer. sinature:%s not support.", sigName);
RaiseMethodNotSupportException(method, errMsg);
}
if (!InitAndGetInterpreterDirectlyCallMethodPointer(method))
{
RaiseAOTGenericMethodNotInstantiatedException(method);
}
void* thisPtr;
uint16_t* argVarIndexBase;
if (hybridclr::metadata::IsInstanceMethod(method))
{
thisPtr = localVarBase[argVarIndexs[0]].obj;
argVarIndexBase = argVarIndexs + 1;
}
else
{
thisPtr = nullptr;
argVarIndexBase = argVarIndexs;
}
void* invokeParams[256];
for (uint8_t i = 0; i < method->parameters_count; i++)
{
const Il2CppType* argType = GET_METHOD_PARAMETER_TYPE(method->parameters[i]);
StackObject* argValue = localVarBase + argVarIndexBase[i];
if (!argType->byref && hybridclr::metadata::IsValueType(argType))
{
invokeParams[i] = argValue;
}
else
{
invokeParams[i] = argValue->ptr;
}
}
#if HYBRIDCLR_UNITY_2021_OR_NEW
method->invoker_method(method->methodPointerCallByInterp, method, thisPtr, invokeParams, ret);
#else
void* retObj = method->invoker_method(method->methodPointerCallByInterp, method, thisPtr, invokeParams);
if (ret)
{
const Il2CppType* returnType = method->return_type;
if (hybridclr::metadata::IsValueType(returnType))
{
Il2CppClass* returnKlass = il2cpp::vm::Class::FromIl2CppType(returnType);
if (il2cpp::vm::Class::IsNullable(returnKlass))
{
il2cpp::vm::Object::UnboxNullable((Il2CppObject*)retObj, returnKlass->element_class, ret);
}
else
{
std::memcpy(ret, il2cpp::vm::Object::Unbox((Il2CppObject*)retObj), il2cpp::vm::Class::GetValueSize(returnKlass, nullptr));
}
}
else
{
*(void**)ret = retObj;
}
}
#endif
}
Managed2NativeCallMethod InterpreterModule::GetManaged2NativeMethodPointer(const MethodInfo* method, bool forceStatic)
{
if (method->methodPointerCallByInterp == NotSupportNative2Managed
#if HYBRIDCLR_UNITY_2021_OR_NEW
|| method->has_full_generic_sharing_signature
#endif
)
{
return Managed2NativeCallByReflectionInvoke;
}
char sigName[1000];
ComputeSignature(method, !forceStatic, sigName, sizeof(sigName) - 1);
auto it = g_managed2natives.find(sigName);
return it != g_managed2natives.end() ? it->second : Managed2NativeCallByReflectionInvoke;
}
Managed2NativeCallMethod InterpreterModule::GetManaged2NativeMethodPointer(const metadata::ResolveStandAloneMethodSig& method)
{
char sigName[1000];
ComputeSignature(&method.returnType, method.params, method.paramCount, metadata::IsPrologHasThis(method.flags), sigName, sizeof(sigName) - 1);
auto it = g_managed2natives.find(sigName);
return it != g_managed2natives.end() ? it->second : Managed2NativeCallByReflectionInvoke;
}
static void RaiseExecutionEngineExceptionMethodIsNotFound(const MethodInfo* method)
{
if (il2cpp::vm::Method::GetClass(method))
RaiseExecutionEngineException(il2cpp::vm::Method::GetFullName(method).c_str());
else
RaiseExecutionEngineException(il2cpp::vm::Method::GetNameWithGenericTypes(method).c_str());
}
#ifdef HYBRIDCLR_UNITY_2021_OR_NEW
static void InterpreterInvoke(Il2CppMethodPointer methodPointer, const MethodInfo* method, void* __this, void** __args, void* __ret)
{
InterpMethodInfo* imi = method->interpData ? (InterpMethodInfo*)method->interpData : InterpreterModule::GetInterpMethodInfo(method);
bool isInstanceMethod = metadata::IsInstanceMethod(method);
StackObject* args = (StackObject*)alloca(sizeof(StackObject) * imi->argStackObjectSize);
if (isInstanceMethod)
{
if (IS_CLASS_VALUE_TYPE(method->klass))
{
__this = (Il2CppObject*)__this + (methodPointer != method->methodPointerCallByInterp);
}
args[0].ptr = __this;
}
MethodArgDesc* argDescs = imi->args + isInstanceMethod;
ConvertInvokeArgs(args + isInstanceMethod, method, argDescs, __args);
Interpreter::Execute(method, args, __ret);
}
static void InterpreterDelegateInvoke(Il2CppMethodPointer, const MethodInfo* method, void* __this, void** __args, void* __ret)
{
Il2CppMulticastDelegate* del = (Il2CppMulticastDelegate*)__this;
Il2CppDelegate** firstSubDel;
int32_t subDelCount;
if (del->delegates)
{
firstSubDel = (Il2CppDelegate**)il2cpp::vm::Array::GetFirstElementAddress(del->delegates);
subDelCount = il2cpp::vm::Array::GetLength(del->delegates);
}
else
{
firstSubDel = (Il2CppDelegate**)&del;
subDelCount = 1;
}
for (int32_t i = 0; i < subDelCount; i++)
{
Il2CppDelegate* cur = firstSubDel[i];
const MethodInfo* curMethod = cur->method;
Il2CppObject* curTarget = cur->target;
if (curMethod->invoker_method == nullptr)
{
RaiseExecutionEngineExceptionMethodIsNotFound(curMethod);
}
switch ((int)(method->parameters_count - curMethod->parameters_count))
{
case 0:
{
if (metadata::IsInstanceMethod(curMethod) && !curTarget)
{
il2cpp::vm::Exception::RaiseNullReferenceException();
}
curTarget += (IS_CLASS_VALUE_TYPE(curMethod->klass));
curMethod->invoker_method(curMethod->methodPointerCallByInterp, curMethod, curTarget, __args, __ret);
break;
}
case -1:
{
IL2CPP_ASSERT(!hybridclr::metadata::IsInstanceMethod(curMethod));
void** newArgs = (void**)alloca(sizeof(void*) * (size_t)curMethod->parameters_count);
newArgs[0] = curTarget;
for (int k = 0, endK = curMethod->parameters_count; k < endK; k++)
{
newArgs[k + 1] = __args[k];
}
curMethod->invoker_method(curMethod->methodPointerCallByInterp, curMethod, nullptr, newArgs, __ret);
break;
}
case 1:
{
IL2CPP_ASSERT(hybridclr::metadata::IsInstanceMethod(curMethod) && curMethod->parameters_count);
curTarget = (Il2CppObject*)__args[0];
if (!curTarget)
{
il2cpp::vm::Exception::RaiseNullReferenceException();
}
curMethod->invoker_method(curMethod->methodPointerCallByInterp, curMethod, curTarget, __args + 1, __ret);
break;
}
default:
{
RaiseExecutionEngineException("bad delegate method");
break;
}
}
}
}
#else
static void* InterpreterInvoke(Il2CppMethodPointer methodPointer, const MethodInfo* method, void* __this, void** __args)
{
StackObject args[256];
bool isInstanceMethod = metadata::IsInstanceMethod(method);
if (isInstanceMethod)
{
if (IS_CLASS_VALUE_TYPE(method->klass))
{
__this = (Il2CppObject*)__this + (methodPointer != method->methodPointerCallByInterp);
}
args[0].ptr = __this;
}
InterpMethodInfo* imi = method->interpData ? (InterpMethodInfo*)method->interpData : InterpreterModule::GetInterpMethodInfo(method);
MethodArgDesc* argDescs = imi->args + isInstanceMethod;
ConvertInvokeArgs(args + isInstanceMethod, method, argDescs, __args);
if (method->return_type->type == IL2CPP_TYPE_VOID)
{
Interpreter::Execute(method, args, nullptr);
return nullptr;
}
else
{
IL2CPP_ASSERT(GetTypeArgDesc(method->return_type).stackObjectSize <= hybridclr::metadata::kMaxRetValueTypeStackObjectSize);
StackObject ret[hybridclr::metadata::kMaxRetValueTypeStackObjectSize];
Interpreter::Execute(method, args, ret);
return TranslateNativeValueToBoxValue(method->return_type, ret);
}
}
static void* InterpreterDelegateInvoke(Il2CppMethodPointer, const MethodInfo* method, void* __this, void** __args)
{
Il2CppMulticastDelegate* del = (Il2CppMulticastDelegate*)__this;
Il2CppDelegate** firstSubDel;
int32_t subDelCount;
if (del->delegates)
{
firstSubDel = (Il2CppDelegate**)il2cpp::vm::Array::GetFirstElementAddress(del->delegates);
subDelCount = il2cpp::vm::Array::GetLength(del->delegates);
}
else
{
firstSubDel = (Il2CppDelegate**)&del;
subDelCount = 1;
}
void* ret = nullptr;
for (int32_t i = 0; i < subDelCount; i++)
{
Il2CppDelegate* cur = firstSubDel[i];
const MethodInfo* curMethod = cur->method;
Il2CppObject* curTarget = cur->target;
if (curMethod->invoker_method == nullptr)
{
RaiseExecutionEngineExceptionMethodIsNotFound(curMethod);
}
switch ((int)(method->parameters_count - curMethod->parameters_count))
{
case 0:
{
if (metadata::IsInstanceMethod(curMethod) && !curTarget)
{
il2cpp::vm::Exception::RaiseNullReferenceException();
}
curTarget += (IS_CLASS_VALUE_TYPE(curMethod->klass));
ret = curMethod->invoker_method(curMethod->methodPointerCallByInterp, curMethod, curTarget, __args);
break;
}
case -1:
{
IL2CPP_ASSERT(!hybridclr::metadata::IsInstanceMethod(curMethod));
void** newArgs = (void**)alloca(sizeof(void*) * (size_t)curMethod->parameters_count);
newArgs[0] = curTarget;
for (int k = 0, endK = curMethod->parameters_count; k < endK; k++)
{
newArgs[k + 1] = __args[k];
}
ret = curMethod->invoker_method(curMethod->methodPointerCallByInterp, curMethod, nullptr, newArgs);
break;
}
case 1:
{
IL2CPP_ASSERT(hybridclr::metadata::IsInstanceMethod(curMethod) && curMethod->parameters_count);
curTarget = (Il2CppObject*)__args[0];
if (!curTarget)
{
il2cpp::vm::Exception::RaiseNullReferenceException();
}
ret = curMethod->invoker_method(curMethod->methodPointerCallByInterp, curMethod, curTarget, __args + 1);
break;
}
default:
{
RaiseExecutionEngineException("bad delegate method");
break;
}
}
}
return ret;
}
#endif
InvokerMethod InterpreterModule::GetMethodInvoker(const Il2CppMethodDefinition* method)
{
Il2CppClass* klass = il2cpp::vm::GlobalMetadata::GetTypeInfoFromTypeDefinitionIndex(method->declaringType);
const char* methodName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(method->nameIndex);
// special for Delegate::DynamicInvoke
return !klass || !metadata::IsChildTypeOfMulticastDelegate(klass) || strcmp(methodName, "Invoke") ? InterpreterInvoke : InterpreterDelegateInvoke;
}
InvokerMethod InterpreterModule::GetMethodInvoker(const MethodInfo* method)
{
Il2CppClass* klass = method->klass;
return !klass || !metadata::IsChildTypeOfMulticastDelegate(klass) || strcmp(method->name, "Invoke") ? InterpreterInvoke : InterpreterDelegateInvoke;
}
bool InterpreterModule::IsImplementsByInterpreter(const MethodInfo* method)
{
return method->invoker_method == InterpreterDelegateInvoke || method->invoker_method == InterpreterInvoke;
}
InterpMethodInfo* InterpreterModule::GetInterpMethodInfo(const MethodInfo* methodInfo)
{
RuntimeInitClassCCtor(methodInfo);
il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
if (methodInfo->interpData)
{
return (InterpMethodInfo*)methodInfo->interpData;
}
IL2CPP_ASSERT(methodInfo->isInterpterImpl);
metadata::Image* image = metadata::IsInterpreterMethod(methodInfo) ? hybridclr::metadata::MetadataModule::GetImage(methodInfo->klass)
: (metadata::Image*)hybridclr::metadata::AOTHomologousImage::FindImageByAssembly(
methodInfo->klass->rank ? il2cpp_defaults.corlib->assembly : methodInfo->klass->image->assembly);
IL2CPP_ASSERT(image);
metadata::MethodBody* methodBody = image->GetMethodBody(methodInfo->token);
if (methodBody == nullptr || methodBody->ilcodes == nullptr)
{
TEMP_FORMAT(errMsg, "Method body is null. %s.%s::%s", methodInfo->klass->namespaze, methodInfo->klass->name, methodInfo->name);
il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException(errMsg));
}
InterpMethodInfo* imi = new (HYBRIDCLR_MALLOC_ZERO(sizeof(InterpMethodInfo))) InterpMethodInfo;
transform::HiTransform::Transform(image, methodInfo, *methodBody, *imi);
il2cpp::os::Atomic::FullMemoryBarrier();
const_cast<MethodInfo*>(methodInfo)->interpData = imi;
return imi;
}
}
}