You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

475 lines
16 KiB

using ILRuntime.CLR.TypeSystem;
using ILRuntime.CLR.Utils;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.Runtime.Stack;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace ILRuntime.CLR.Method
{
public class CLRMethod : IMethod
{
MethodInfo def;
ConstructorInfo cDef;
List<IType> parameters;
ParameterInfo[] parametersCLR;
ILRuntime.Runtime.Enviorment.AppDomain appdomain;
CLRType declaringType;
bool isConstructor;
CLRRedirectionDelegate redirect;
IType[] genericArguments;
Type[] genericArgumentsCLR;
object[] invocationParam;
bool isDelegateInvoke, isDelegateDynamicInvoke;
int hashCode = -1;
static int instance_id = 0x20000000;
public IType DeclearingType
{
get
{
return declaringType;
}
}
public string Name
{
get
{
return def.Name;
}
}
public bool HasThis
{
get
{
return isConstructor ? !cDef.IsStatic : !def.IsStatic;
}
}
int _genericParameterCount = -1;
public int GenericParameterCount
{
get
{
if (_genericParameterCount == -1)
{
if (def.ContainsGenericParameters && def.IsGenericMethodDefinition)
_genericParameterCount = def.GetGenericArguments().Length;
else
_genericParameterCount = 0;
}
return _genericParameterCount;
}
}
public bool IsGenericInstance
{
get
{
return genericArguments != null;
}
}
public bool IsDelegateInvoke
{
get
{
return isDelegateInvoke;
}
}
public bool IsDelegateDynamicInvoke
{
get
{
return isDelegateDynamicInvoke;
}
}
public bool IsStatic
{
get
{
if (cDef != null)
return cDef.IsStatic;
else
return def.IsStatic;
}
}
public CLRRedirectionDelegate Redirection
{
get
{
if (redirect == null)
{
if (def != null)
{
if (def.IsGenericMethod && !def.IsGenericMethodDefinition)
{
//Redirection of Generic method Definition will be prioritized
if (!appdomain.RedirectMap.TryGetValue(def.GetGenericMethodDefinition(), out redirect))
appdomain.RedirectMap.TryGetValue(def, out redirect);
}
else
appdomain.RedirectMap.TryGetValue(def, out redirect);
}
else if (cDef != null)
{
appdomain.RedirectMap.TryGetValue(cDef, out redirect);
}
}
return redirect;
}
}
public MethodInfo MethodInfo { get { return def; } }
public ConstructorInfo ConstructorInfo { get { return cDef; } }
public IType[] GenericArguments { get { return genericArguments; } }
public Type[] GenericArgumentsCLR
{
get
{
if (genericArgumentsCLR == null)
{
if (cDef != null)
genericArgumentsCLR = cDef.GetGenericArguments();
else
genericArgumentsCLR = def.GetGenericArguments();
}
return genericArgumentsCLR;
}
}
internal CLRMethod(MethodInfo def, CLRType type, ILRuntime.Runtime.Enviorment.AppDomain domain)
{
this.def = def;
declaringType = type;
this.appdomain = domain;
if (!def.ContainsGenericParameters)
{
ReturnType = domain.GetType(def.ReturnType.FullName);
if (ReturnType == null)
{
ReturnType = domain.GetType(def.ReturnType.AssemblyQualifiedName);
}
}
if (type.IsDelegate)
{
if (def.Name == "Invoke")
isDelegateInvoke = true;
if (def.Name == "DynamicInvoke")
{
isDelegateInvoke = true;
isDelegateDynamicInvoke = true;
}
}
isConstructor = false;
}
internal CLRMethod(ConstructorInfo def, CLRType type, ILRuntime.Runtime.Enviorment.AppDomain domain)
{
this.cDef = def;
declaringType = type;
this.appdomain = domain;
if (!def.ContainsGenericParameters)
{
ReturnType = type;
}
isConstructor = true;
}
public int ParameterCount
{
get
{
return Parameters.Count;
}
}
public List<IType> Parameters
{
get
{
if (parameters == null)
{
InitParameters();
}
return parameters;
}
}
public ParameterInfo[] ParametersCLR
{
get
{
if (parametersCLR == null)
{
if (cDef != null)
parametersCLR = cDef.GetParameters();
else
parametersCLR = def.GetParameters();
}
return parametersCLR;
}
}
public IType ReturnType
{
get;
private set;
}
public bool IsConstructor
{
get
{
return cDef != null;
}
}
void InitParameters()
{
parameters = new List<IType>();
foreach (var i in ParametersCLR)
{
IType type = appdomain.GetType(i.ParameterType.FullName);
if (type == null)
type = appdomain.GetType(i.ParameterType.AssemblyQualifiedName);
if (i.ParameterType.IsGenericTypeDefinition)
{
if (type == null)
type = appdomain.GetType(i.ParameterType.GetGenericTypeDefinition().FullName);
if (type == null)
type = appdomain.GetType(i.ParameterType.GetGenericTypeDefinition().AssemblyQualifiedName);
}
if (i.ParameterType.ContainsGenericParameters)
{
var t = i.ParameterType;
if (t.HasElementType)
t = i.ParameterType.GetElementType();
else if (t.GetGenericArguments().Length > 0)
{
t = t.GetGenericArguments()[0];
}
type = new ILGenericParameterType(t.Name);
}
if (type == null)
throw new TypeLoadException();
parameters.Add(type);
}
}
unsafe StackObject* Minus(StackObject* a, int b)
{
return (StackObject*)((long)a - sizeof(StackObject) * b);
}
public unsafe object Invoke(Runtime.Intepreter.ILIntepreter intepreter, StackObject* esp, IList<object> mStack, bool isNewObj = false)
{
if (parameters == null)
{
InitParameters();
}
int paramCount = ParameterCount;
if (invocationParam == null)
invocationParam = new object[paramCount];
object[] param = invocationParam;
for (int i = paramCount; i >= 1; i--)
{
var p = Minus(esp, i);
var pt = this.ParametersCLR[paramCount - i].ParameterType;
var obj = pt.CheckCLRTypes(StackObject.ToObject(p, appdomain, mStack));
obj = ILIntepreter.CheckAndCloneValueType(obj, appdomain);
param[paramCount - i] = obj;
}
if (isConstructor)
{
if (!isNewObj)
{
if (!cDef.IsStatic)
{
object instance = declaringType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((Minus(esp, paramCount + 1)), appdomain, mStack));
if (instance == null)
throw new NullReferenceException();
if (instance is CrossBindingAdaptorType && paramCount == 0)//It makes no sense to call the Adaptor's default constructor
return null;
cDef.Invoke(instance, param);
Array.Clear(invocationParam, 0, invocationParam.Length);
return null;
}
else
{
throw new NotImplementedException();
}
}
else
{
var res = cDef.Invoke(param);
FixReference(paramCount, esp, param, mStack, null, false);
Array.Clear(invocationParam, 0, invocationParam.Length);
return res;
}
}
else
{
object instance = null;
if (!def.IsStatic)
{
instance = StackObject.ToObject((Minus(esp, paramCount + 1)), appdomain, mStack);
if (!(instance is Reflection.ILRuntimeWrapperType))
instance = declaringType.TypeForCLR.CheckCLRTypes(instance);
if (declaringType.IsValueType)
instance = ILIntepreter.CheckAndCloneValueType(instance, appdomain);
if (instance == null)
throw new NullReferenceException();
}
object res = null;
/*if (redirect != null)
res = redirect(new ILContext(appdomain, intepreter, esp, mStack, this), instance, param, genericArguments);
else*/
{
res = def.Invoke(instance, param);
}
FixReference(paramCount, esp, param, mStack, instance, !def.IsStatic);
Array.Clear(invocationParam, 0, invocationParam.Length);
return res;
}
}
unsafe void FixReference(int paramCount, StackObject* esp, object[] param, IList<object> mStack, object instance, bool hasThis)
{
var cnt = hasThis ? paramCount + 1 : paramCount;
for (int i = cnt; i >= 1; i--)
{
var p = Minus(esp, i);
var val = i <= paramCount ? param[paramCount - i] : instance;
switch (p->ObjectType)
{
case ObjectTypes.StackObjectReference:
{
var addr = *(long*)&p->Value;
var dst = (StackObject*)addr;
if (dst->ObjectType >= ObjectTypes.Object)
{
var obj = val;
if (obj is CrossBindingAdaptorType)
obj = ((CrossBindingAdaptorType)obj).ILInstance;
mStack[dst->Value] = obj;
}
else
{
ILIntepreter.UnboxObject(dst, val, mStack, appdomain);
}
}
break;
case ObjectTypes.FieldReference:
{
var obj = mStack[p->Value];
if (obj is ILTypeInstance)
{
((ILTypeInstance)obj)[p->ValueLow] = val;
}
else
{
var t = appdomain.GetType(obj.GetType()) as CLRType;
t.GetField(p->ValueLow).SetValue(obj, val);
}
}
break;
case ObjectTypes.StaticFieldReference:
{
var t = appdomain.GetType(p->Value);
if (t is ILType)
{
((ILType)t).StaticInstance[p->ValueLow] = val;
}
else
{
((CLRType)t).SetStaticFieldValue(p->ValueLow, val);
}
}
break;
case ObjectTypes.ArrayReference:
{
var arr = mStack[p->Value] as Array;
arr.SetValue(val, p->ValueLow);
}
break;
}
}
}
public IMethod MakeGenericMethod(IType[] genericArguments)
{
Type[] p = new Type[genericArguments.Length];
for (int i = 0; i < genericArguments.Length; i++)
{
p[i] = genericArguments[i].TypeForCLR;
}
MethodInfo t = null;
#if UNITY_EDITOR || (DEBUG && !DISABLE_ILRUNTIME_DEBUG)
try
{
#endif
t = def.MakeGenericMethod(p);
#if UNITY_EDITOR || (DEBUG && !DISABLE_ILRUNTIME_DEBUG)
}
catch (Exception e)
{
string argString = "";
for (int i = 0; i < genericArguments.Length; i++)
{
argString += genericArguments[i].TypeForCLR.FullName + ", ";
}
argString = argString.Substring(0, argString.Length - 2);
throw new Exception(string.Format("MakeGenericMethod failed : {0}.{1}<{2}>", def.DeclaringType.FullName, def.Name, argString));
}
#endif
var res = new CLRMethod(t, declaringType, appdomain);
res.genericArguments = genericArguments;
return res;
}
public override string ToString()
{
if (def != null)
return def.ToString();
else
return cDef.ToString();
}
public override int GetHashCode()
{
if (hashCode == -1)
hashCode = System.Threading.Interlocked.Add(ref instance_id, 1);
return hashCode;
}
bool? isExtend;
public bool IsExtend
{
get
{
if (isExtend == null)
{
isExtend = this.IsExtendMethod();
}
return isExtend.Value;
}
}
}
}