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.
474 lines
16 KiB
474 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; |
|
} |
|
} |
|
} |
|
}
|
|
|