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 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 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(); 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 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 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; } } } }