123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using ILRuntime.CLR.Method;
- using ILRuntime.CLR.TypeSystem;
- using ILRuntime.Runtime.Intepreter;
- using System.Reflection;
- using System.Threading;
- namespace ILRuntime.Runtime.Enviorment
- {
- public class CrossBindingCodeGenerator
- {
- class PropertyGenerateInfo
- {
- public string Name;
- public Type ReturnType;
- public string GetterBody;
- public string SettingBody;
- public string Modifier;
- public string OverrideString;
- }
- public static string GenerateCrossBindingAdapterCode(Type baseType, string nameSpace)
- {
- StringBuilder sb = new StringBuilder();
- List<MethodInfo> virtMethods = new List<MethodInfo>();
- GetMethods(baseType, virtMethods);
- string clsName, realClsName;
- bool isByRef;
- baseType.GetClassName(out clsName, out realClsName, out isByRef, true);
- sb.Append(@"using System;
- using ILRuntime.CLR.Method;
- using ILRuntime.Runtime.Enviorment;
- using ILRuntime.Runtime.Intepreter;
- namespace ");
- sb.AppendLine(nameSpace);
- sb.Append(@"{
- public class ");
- sb.Append(clsName);
- sb.AppendLine(@"Adapter : CrossBindingAdaptor
- {");
-
- sb.Append(@" public override Type BaseCLRType
- {
- get
- {
- return typeof(");
- sb.Append(realClsName);
- sb.AppendLine(@");
- }
- }
- public override Type AdaptorType
- {
- get
- {
- return typeof(Adapter);
- }
- }
- public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
- {
- return new Adapter(appdomain, instance);
- }
- ");
- sb.AppendLine(string.Format(" public class Adapter : {0}, CrossBindingAdaptorType", realClsName));
- sb.AppendLine(" {");
- GenerateCrossBindingMethodInfo(sb, virtMethods);
- sb.AppendLine(@"
- bool isInvokingToString;
- ILTypeInstance instance;
- ILRuntime.Runtime.Enviorment.AppDomain appdomain;
- public Adapter()
- {
- }
- public Adapter(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
- {
- this.appdomain = appdomain;
- this.instance = instance;
- }
- public ILTypeInstance ILInstance { get { return instance; } }
- ");
- GenerateCrossBindingMethodBody(sb, virtMethods);
- sb.Append(@" public override string ToString()
- {
- IMethod m = appdomain.ObjectType.GetMethod("); sb.AppendLine("\"ToString\", 0);");
- sb.AppendLine(@" m = instance.Type.GetVirtualMethod(m);
- if (m == null || m is ILMethod)
- {
- if (!isInvokingToString)
- {
- isInvokingToString = true;
- string res = instance.ToString();
- isInvokingToString = false;
- return res;
- }
- else
- return instance.Type.FullName;
- }
- else
- return instance.Type.FullName;");
- sb.AppendLine(" }");
- sb.AppendLine(" }");
- sb.AppendLine(" }");
- sb.AppendLine("}");
- return sb.ToString();
- }
- static void GenerateCrossBindingMethodBody(StringBuilder sb, List<MethodInfo> virtMethods)
- {
- int index = 0;
- Dictionary<string, PropertyGenerateInfo> pendingProperties = new Dictionary<string, PropertyGenerateInfo>();
- foreach (var i in virtMethods)
- {
- if (ShouldSkip(i))
- continue;
- bool isProperty = i.IsSpecialName && (i.Name.StartsWith("get_") || i.Name.StartsWith("set_"));
- PropertyGenerateInfo pInfo = null;
- bool isGetter = false;
- bool isIndexFunc = false;
- bool isByRef;
- string clsName, realClsName;
- StringBuilder oriBuilder = null;
- if (isProperty)
- {
- string pName = i.Name.Substring(4);
- if (i.Name == "get_Item" || i.Name == "set_Item")
- {
- StringBuilder sBuilder = new StringBuilder();
- var p = i.GetParameters()[0];
- p.ParameterType.GetClassName(out clsName, out realClsName, out isByRef, true);
- pName = string.Format("this [{0}]", realClsName + " " + p.Name);
- isIndexFunc = true;
- }
- isGetter = i.Name.StartsWith("get_");
- oriBuilder = sb;
- sb = new StringBuilder();
- if (!pendingProperties.TryGetValue(pName, out pInfo))
- {
- pInfo = new PropertyGenerateInfo();
- pInfo.Name = pName;
- pendingProperties[pName] = pInfo;
- }
- if (pInfo.ReturnType == null)
- {
- if (isGetter)
- {
- pInfo.ReturnType = i.ReturnType;
- }
- else
- {
- pInfo.ReturnType = i.GetParameters()[0].ParameterType;
- }
- }
- }
- var param = i.GetParameters();
- string modifier = i.IsFamily ? "protected" : "public";
- string overrideStr = i.DeclaringType.IsInterface ? "" : (i.IsFinal ? "new " : "override ");
- string returnString = "";
- if (i.ReturnType != typeof(void))
- {
- i.ReturnType.GetClassName(out clsName, out realClsName, out isByRef, true);
- returnString = "return ";
- }
- else
- realClsName = "void";
- if (!isProperty)
- {
- sb.Append(string.Format(" {0} {3}{1} {2}(", modifier, realClsName, i.Name, overrideStr));
- GetParameterDefinition(sb, param, true);
- sb.AppendLine(@")
- {");
- }
- else
- {
- pInfo.Modifier = modifier;
- pInfo.OverrideString = overrideStr;
- }
- if (!i.IsAbstract)
- {
- sb.AppendLine(string.Format(" if (m{0}_{1}.CheckShouldInvokeBase(this.instance))", i.Name, index));
- if (isProperty)
- {
- string baseMethodName = isIndexFunc
- ? string.Format("base[{0}]", i.GetParameters()[0].Name)
- : string.Format("base.{0}", i.Name.Substring(4));
- if (isGetter)
- {
- sb.AppendLine(string.Format(" return {0};", baseMethodName));
- }
- else
- {
- sb.AppendLine(string.Format(" {0} = value;", baseMethodName));
- }
- }
- else
- sb.AppendLine(string.Format(" {2}base.{0}({1});", i.Name, GetParameterName(param, true), returnString));
- sb.AppendLine(" else");
- sb.AppendLine(string.Format(" {3}m{0}_{1}.Invoke(this.instance{2});", i.Name, index, GetParameterName(param, false), returnString));
- }
- else
- {
- sb.AppendLine(string.Format(" {3}m{0}_{1}.Invoke(this.instance{2});", i.Name, index, GetParameterName(param, false), returnString));
- }
- if (isProperty)
- {
- if (isGetter)
- {
- pInfo.GetterBody = sb.ToString();
- }
- else
- {
- pInfo.SettingBody = sb.ToString();
- }
- sb = oriBuilder;
- }
- else
- {
- sb.AppendLine(" }");
- sb.AppendLine();
- }
- index++;
- }
- foreach (var i in pendingProperties)
- {
- var pInfo = i.Value;
- string clsName, realClsName;
- bool isByRef;
- pInfo.ReturnType.GetClassName(out clsName, out realClsName, out isByRef, true);
- sb.AppendLine(string.Format(" {0} {3}{1} {2}", pInfo.Modifier, realClsName, pInfo.Name, pInfo.OverrideString));
- sb.AppendLine(" {");
- if (!string.IsNullOrEmpty(pInfo.GetterBody))
- {
- sb.AppendLine(" get");
- sb.AppendLine(" {");
- sb.AppendLine(pInfo.GetterBody);
- sb.AppendLine(" }");
- }
- if (!string.IsNullOrEmpty(pInfo.SettingBody))
- {
- sb.AppendLine(" set");
- sb.AppendLine(" {");
- sb.AppendLine(pInfo.SettingBody);
- sb.AppendLine(" }");
- }
- sb.AppendLine(" }");
- sb.AppendLine();
- }
- }
- static void GenerateCrossBindingMethodInfo(StringBuilder sb, List<MethodInfo> virtMethods)
- {
- int index = 0;
- foreach (var i in virtMethods)
- {
- if (ShouldSkip(i))
- continue;
- var param = i.GetParameters();
- if (NeedGenerateCrossBindingMethodClass(param))
- {
- GenerateCrossBindingMethodClass(sb, i.Name, index, param, i.ReturnType);
- sb.AppendLine(string.Format(" {0}_{1}Info m{0}_{1} = new {0}_{1}Info();", i.Name, index));
- }
- else
- {
- if (i.ReturnType != typeof(void))
- {
- sb.AppendLine(string.Format(" CrossBindingFunctionInfo<{0}> m{1}_{2} = new CrossBindingFunctionInfo<{0}>(\"{1}\");", GetParametersString(param, i.ReturnType), i.Name, index));
- }
- else
- {
- if (param.Length > 0)
- sb.AppendLine(string.Format(" CrossBindingMethodInfo<{0}> m{1}_{2} = new CrossBindingMethodInfo<{0}>(\"{1}\");", GetParametersString(param, i.ReturnType), i.Name, index));
- else
- sb.AppendLine(string.Format(" CrossBindingMethodInfo m{0}_{1} = new CrossBindingMethodInfo(\"{0}\");", i.Name, index));
- }
- }
- index++;
- }
- }
- static bool ShouldSkip(MethodInfo info)
- {
- var paramInfos = info.GetParameters();
- if (info.Name == "ToString" || info.Name == "GetHashCode" || info.Name == "Finalize")
- return paramInfos.Length == 0;
- if (info.Name == "Equals" && paramInfos.Length == 1 && paramInfos[0].ParameterType == typeof(object))
- return true;
- if (info.IsAssembly || info.IsFamilyOrAssembly || info.IsPrivate || info.IsFinal)
- return true;
- if (info.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length > 0)
- return true;
- for (int i = 0; i < paramInfos.Length; ++i)
- {
- var paramType = paramInfos[i].ParameterType;
- if (paramType.IsByRef)
- paramType = paramType.GetElementType();
- if (paramType.IsPointer || paramType.IsNotPublic || paramType.IsNested && !paramType.IsNestedPublic)
- {
- return true;
- }
- }
- var returnType = info.ReturnType;
- if (returnType.IsByRef)
- returnType = returnType.GetElementType();
- if (returnType.IsNotPublic || returnType.IsNested && !returnType.IsNestedPublic)
- return true;
- return false;
- }
- static string GetParametersString(ParameterInfo[] param, Type returnType)
- {
- StringBuilder sb = new StringBuilder();
- bool first = true;
- foreach (var i in param)
- {
- if (!first)
- sb.Append(", ");
- else
- first = false;
- string clsName, realClsName;
- bool isByRef;
- i.ParameterType.GetClassName(out clsName, out realClsName, out isByRef, true);
- sb.Append(realClsName);
- }
- if (returnType != typeof(void))
- {
- if (!first)
- sb.Append(", ");
- string clsName, realClsName;
- bool isByRef;
- returnType.GetClassName(out clsName, out realClsName, out isByRef, true);
- sb.Append(realClsName);
- }
- return sb.ToString();
- }
- static string GetParametersTypeString(ParameterInfo[] param, Type returnType)
- {
- StringBuilder sb = new StringBuilder();
- bool first = true;
- foreach (var i in param)
- {
- if (!first)
- sb.Append(", ");
- else
- first = false;
- string clsName, realClsName;
- bool isByRef;
- sb.Append("typeof(");
- i.ParameterType.GetClassName(out clsName, out realClsName, out isByRef, true);
- sb.Append(realClsName);
- sb.Append(")");
- if (isByRef)
- sb.Append(".MakeByRefType()");
- }
- if (returnType != typeof(void))
- {
- if (!first)
- sb.Append(", ");
- string clsName, realClsName;
- bool isByRef;
- returnType.GetClassName(out clsName, out realClsName, out isByRef, true);
- sb.Append(realClsName);
- }
- return sb.ToString();
- }
- static bool NeedGenerateCrossBindingMethodClass(ParameterInfo[] param)
- {
- if (param.Length > 5)
- return true;
- foreach (var i in param)
- {
- if (i.IsOut || i.ParameterType.IsByRef)
- return true;
- }
- return false;
- }
- static string GetParameterName(ParameterInfo[] param, bool first)
- {
- StringBuilder sb = new StringBuilder();
- foreach (var p in param)
- {
- if (!first)
- sb.Append(", ");
- else
- first = false;
- if (p.IsOut)
- sb.Append("out ");
- else if (p.ParameterType.IsByRef)
- sb.Append("ref ");
- sb.Append(p.Name);
- }
- return sb.ToString();
- }
- static void GetParameterDefinition(StringBuilder sb, ParameterInfo[] param, bool first)
- {
- string clsName, realClsName;
- bool isByRef;
- foreach (var p in param)
- {
- if (!first)
- sb.Append(", ");
- else
- first = false;
- p.ParameterType.GetClassName(out clsName, out realClsName, out isByRef, true);
- if (p.IsOut)
- sb.Append("out ");
- else if (isByRef)
- sb.Append("ref ");
- sb.Append(realClsName);
- sb.Append(" ");
- sb.Append(p.Name);
- }
- }
- static void GenerateCrossBindingMethodClass(StringBuilder sb, string funcName, int index, ParameterInfo[] param, Type returnType)
- {
- sb.AppendLine(string.Format(" class {0}_{1}Info : CrossBindingMethodInfo", funcName, index));
- sb.Append(@" {
- static Type[] pTypes = new Type[] {");
- sb.Append(GetParametersTypeString(param, returnType));
- sb.AppendLine("};");
- sb.AppendLine();
- sb.AppendLine(string.Format(" public {0}_{1}Info()", funcName, index));
- sb.AppendLine(string.Format(" : base(\"{0}\")", funcName));
- sb.Append(@" {
- }
- protected override Type ReturnType { get { return ");
- string clsName, realClsName;
- bool isByRef;
- returnType.GetClassName(out clsName, out realClsName, out isByRef, true);
- string rtRealName = realClsName;
- bool hasReturn = returnType != typeof(void);
- if (!hasReturn)
- sb.Append("null");
- else
- {
- sb.AppendFormat("typeof({0})", realClsName);
- }
- sb.AppendLine(@"; } }
- protected override Type[] Parameters { get { return pTypes; } }");
- sb.AppendFormat(" public {0} Invoke(ILTypeInstance instance", !hasReturn ? "void" : realClsName);
- GetParameterDefinition(sb, param, false);
- sb.AppendLine(@")
- {
- EnsureMethod(instance);");
- GenInitParams(sb, param);
- sb.AppendLine(@"
- if (method != null)
- {
- invoking = true;");
- if (hasReturn)
- sb.AppendLine(string.Format(" {0} __res = default({0});", rtRealName));
- sb.AppendLine(@" try
- {
- using (var ctx = domain.BeginInvoke(method))
- {");
- Dictionary<ParameterInfo, int> refIndex = new Dictionary<ParameterInfo, int>();
- int idx = 0;
- foreach (var p in param)
- {
- if (p.ParameterType.IsByRef)
- {
- sb.AppendLine(GetPushString(p.ParameterType.GetElementType(), p.Name));
- refIndex[p] = idx++;
- }
- }
- sb.AppendLine(" ctx.PushObject(instance);");
- foreach (var p in param)
- {
- if (p.ParameterType.IsByRef)
- {
- sb.AppendLine(string.Format(" ctx.PushReference({0});", refIndex[p]));
- }
- else
- {
- sb.AppendLine(GetPushString(p.ParameterType, p.Name));
- }
- }
- sb.AppendLine(" ctx.Invoke();");
- if (hasReturn)
- sb.AppendLine(GetReadString(returnType, rtRealName, "", "__res"));
- foreach (var p in param)
- {
- if (p.ParameterType.IsByRef)
- {
- p.ParameterType.GetClassName(out clsName, out realClsName, out isByRef, true);
- sb.AppendLine(GetReadString(p.ParameterType.GetElementType(), realClsName, refIndex[p].ToString(), p.Name));
- }
- }
- sb.AppendLine(" }");
- sb.AppendLine(@" }
- finally
- {
- invoking = false;
- }");
- if (hasReturn)
- sb.AppendLine(" return __res;");
- sb.AppendLine(" }");
- if (hasReturn)
- sb.AppendLine(@" else
- return default(TResult);");
- sb.AppendLine(@" }
- public override void Invoke(ILTypeInstance instance)
- {
- throw new NotSupportedException();
- }
- }");
- }
- static void GetMethods(Type type, List<MethodInfo> list)
- {
- if (type == null)
- return;
- MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
- foreach (var i in methods)
- {
- if ((i.IsVirtual || i.IsAbstract || type.IsInterface) && !i.ContainsGenericParameters)
- {
- if (list.Any(m => IsMethodEqual(m, i)))
- continue;
- list.Add(i);
- }
- }
- var interfaceArray = type.GetInterfaces();
- if (interfaceArray != null)
- {
- for (int i = 0; i < interfaceArray.Length; ++i)
- {
- GetMethods(interfaceArray[i], list);
- }
- }
- }
- static bool IsMethodEqual(MethodInfo left, MethodInfo right)
- {
- var leftParams = left.GetParameters();
- var rightParams = right.GetParameters();
- if (leftParams.Length != rightParams.Length)
- {
- return false;
- }
- // 有些继承了多个interface的类,且这几个interface的类有相同函数名的时候,子类实现的接口就会带上interfere的fullName
- string leftMethodName = left.Name.Replace(left.DeclaringType.FullName, "");
- string rightMethodName = right.Name.Replace(right.DeclaringType.FullName, "");
- if (leftMethodName != rightMethodName)
- {
- return false;
- }
- for (int i = 0; i < leftParams.Length; ++i)
- {
- if (leftParams[i].ParameterType != rightParams[i].ParameterType)
- {
- return false;
- }
- }
- return true;
- }
- static void GenInitParams(StringBuilder sb, ParameterInfo[] param)
- {
- foreach (var p in param)
- {
- if (p.IsOut)
- {
- sb.AppendLine(string.Format(" {0} = default({1});", p.Name, p.ParameterType.GetElementType().FullName));
- }
- }
- }
- static string GetPushString(Type type, string argName)
- {
- if (type.IsPrimitive)
- {
- if (type == typeof(int))
- {
- return string.Format(" ctx.PushInteger({0});", argName);
- }
- else if (type == typeof(long))
- {
- return string.Format(" ctx.PushLong({0});", argName);
- }
- else if (type == typeof(short))
- {
- return string.Format(" ctx.PushInteger({0});", argName);
- }
- else if (type == typeof(bool))
- {
- return string.Format(" ctx.PushBool({0});", argName);
- }
- else if (type == typeof(ushort))
- {
- return string.Format(" ctx.PushInteger({0});", argName);
- }
- else if (type == typeof(float))
- {
- return string.Format(" ctx.PushFloat({0});", argName);
- }
- else if (type == typeof(double))
- {
- return string.Format(" ctx.PushDouble({0});", argName);
- }
- else if (type == typeof(byte))
- {
- return string.Format(" ctx.PushInteger({0});", argName);
- }
- else if (type == typeof(sbyte))
- {
- return string.Format(" ctx.PushInteger({0});", argName);
- }
- else if (type == typeof(uint))
- {
- return string.Format(" ctx.PushInteger((int){0});", argName);
- }
- else if (type == typeof(char))
- {
- return string.Format(" ctx.PushInteger((int){0});", argName);
- }
- else if (type == typeof(ulong))
- {
- return string.Format(" ctx.PushLong((long){0});", argName);
- }
- else
- throw new NotImplementedException();
- }
- else
- {
- return string.Format(" ctx.PushObject({0});", argName);
- }
- }
- static string GetReadString(Type type, string realClsName, string argName, string valName)
- {
- if (type.IsPrimitive)
- {
- if (type == typeof(int))
- {
- return string.Format(" {1} = ctx.ReadInteger({0});", argName, valName);
- }
- else if (type == typeof(long))
- {
- return string.Format(" {1} = ctx.ReadLong({0});", argName, valName);
- }
- else if (type == typeof(short))
- {
- return string.Format(" {1} = (short)ctx.ReadInteger({0});", argName, valName);
- }
- else if (type == typeof(bool))
- {
- return string.Format(" {1} = ctx.ReadBool({0});", argName, valName);
- }
- else if (type == typeof(ushort))
- {
- return string.Format(" {1} = (ushort)ctx.ReadInteger({0});", argName, valName);
- }
- else if (type == typeof(float))
- {
- return string.Format(" {1} = ctx.ReadFloat({0});", argName, valName);
- }
- else if (type == typeof(double))
- {
- return string.Format(" {1} = ctx.ReadDouble({0});", argName, valName);
- }
- else if (type == typeof(byte))
- {
- return string.Format(" {1} = (byte)ctx.ReadInteger({0});", argName, valName);
- }
- else if (type == typeof(sbyte))
- {
- return string.Format(" {1} = (sbyte)ctx.ReadInteger({0});", argName, valName);
- }
- else if (type == typeof(uint))
- {
- return string.Format(" {1} = (uint)ctx.ReadInteger({0});", argName, valName);
- }
- else if (type == typeof(char))
- {
- return string.Format(" {1} = (char)ctx.ReadInteger({0});", argName, valName);
- }
- else if (type == typeof(ulong))
- {
- return string.Format(" {1} = (ulong)ctx.ReadLong({0});", argName, valName);
- }
- else
- throw new NotImplementedException();
- }
- else
- {
- return string.Format(" {2} = ctx.ReadObject<{1}>({0});", argName, realClsName, valName);
- }
- }
- }
- }
|