using System; using System.Collections; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; namespace Flee.InternalTypes { /// /// 包含各种共享实用方法的工具类 /// internal class Utility { private Utility() { } public static void AssertNotNull(object o, string paramName) { if (o == null) { throw new ArgumentNullException(paramName); } } public static void EmitStoreLocal(FleeILGenerator ilg, int index) { if (index >= 0 & index <= 3) { switch (index) { case 0: ilg.Emit(OpCodes.Stloc_0); break; case 1: ilg.Emit(OpCodes.Stloc_1); break; case 2: ilg.Emit(OpCodes.Stloc_2); break; case 3: ilg.Emit(OpCodes.Stloc_3); break; } } else if (index < 256) { ilg.Emit(OpCodes.Stloc_S, Convert.ToByte(index)); } else { Debug.Assert(index < 65535, "local index too large"); ilg.Emit(OpCodes.Stloc, unchecked((short)Convert.ToUInt16(index))); } } public static void EmitLoadLocal(FleeILGenerator ilg, int index) { Debug.Assert(index >= 0, "Invalid index"); if (index >= 0 & index <= 3) { switch (index) { case 0: ilg.Emit(OpCodes.Ldloc_0); break; case 1: ilg.Emit(OpCodes.Ldloc_1); break; case 2: ilg.Emit(OpCodes.Ldloc_2); break; case 3: ilg.Emit(OpCodes.Ldloc_3); break; } } else if (index < 256) { ilg.Emit(OpCodes.Ldloc_S, Convert.ToByte(index)); } else { Debug.Assert(index < 65535, "local index too large"); ilg.Emit(OpCodes.Ldloc, unchecked((short)Convert.ToUInt16(index))); } } public static void EmitLoadLocalAddress(FleeILGenerator ilg, int index) { Debug.Assert(index >= 0, "Invalid index"); if (index <= byte.MaxValue) { ilg.Emit(OpCodes.Ldloca_S, Convert.ToByte(index)); } else { ilg.Emit(OpCodes.Ldloca, index); } } public static void EmitArrayLoad(FleeILGenerator ilg, Type elementType) { TypeCode tc = Type.GetTypeCode(elementType); switch (tc) { case TypeCode.Byte: ilg.Emit(OpCodes.Ldelem_U1); break; case TypeCode.SByte: case TypeCode.Boolean: ilg.Emit(OpCodes.Ldelem_I1); break; case TypeCode.Int16: ilg.Emit(OpCodes.Ldelem_I2); break; case TypeCode.UInt16: ilg.Emit(OpCodes.Ldelem_U2); break; case TypeCode.Int32: ilg.Emit(OpCodes.Ldelem_I4); break; case TypeCode.UInt32: ilg.Emit(OpCodes.Ldelem_U4); break; case TypeCode.Int64: case TypeCode.UInt64: ilg.Emit(OpCodes.Ldelem_I8); break; case TypeCode.Single: ilg.Emit(OpCodes.Ldelem_R4); break; case TypeCode.Double: ilg.Emit(OpCodes.Ldelem_R8); break; case TypeCode.Object: case TypeCode.String: ilg.Emit(OpCodes.Ldelem_Ref); break; default: // Must be a non-primitive value type ilg.Emit(OpCodes.Ldelema, elementType); ilg.Emit(OpCodes.Ldobj, elementType); return; } } public static void EmitArrayStore(FleeILGenerator ilg, Type elementType) { TypeCode tc = Type.GetTypeCode(elementType); switch (tc) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Boolean: ilg.Emit(OpCodes.Stelem_I1); break; case TypeCode.Int16: case TypeCode.UInt16: ilg.Emit(OpCodes.Stelem_I2); break; case TypeCode.Int32: case TypeCode.UInt32: ilg.Emit(OpCodes.Stelem_I4); break; case TypeCode.Int64: case TypeCode.UInt64: ilg.Emit(OpCodes.Stelem_I8); break; case TypeCode.Single: ilg.Emit(OpCodes.Stelem_R4); break; case TypeCode.Double: ilg.Emit(OpCodes.Stelem_R8); break; case TypeCode.Object: case TypeCode.String: ilg.Emit(OpCodes.Stelem_Ref); break; default: // Must be a non-primitive value type ilg.Emit(OpCodes.Stelem, elementType); break; } } public static bool IsIntegralType(Type t) { TypeCode tc = Type.GetTypeCode(t); switch (tc) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: return true; default: return false; } } public static Type GetBitwiseOpType(Type leftType, Type rightType) { if (IsIntegralType(leftType) == false || IsIntegralType(rightType) == false) { return null; } else { return ImplicitConverter.GetBinaryResultType(leftType, rightType); } } /// /// Find a simple (unary) overloaded operator /// /// The name of the operator /// The type to convert from /// The type to convert to (can be null if it's not known beforehand) /// The operator's method or null of no match is found public static MethodInfo GetSimpleOverloadedOperator(string name, Type sourceType, Type destType) { Hashtable data = new Hashtable(); data.Add("Name", string.Concat("op_", name)); data.Add("sourceType", sourceType); data.Add("destType", destType); const BindingFlags flags = BindingFlags.Public | BindingFlags.Static; // Look on the source type and its ancestors MemberInfo[] members = new MemberInfo[0]; do { members = sourceType.FindMembers(MemberTypes.Method, flags, SimpleOverloadedOperatorFilter, data); } while (members.Length == 0 && (sourceType = sourceType.BaseType) != null); if (members.Length == 0 && destType != null) { // Look on the dest type and its ancestors do { members = destType.FindMembers(MemberTypes.Method, flags, SimpleOverloadedOperatorFilter, data); } while (members.Length == 0 && (destType = destType.BaseType) != null); } Debug.Assert(members.Length < 2, "Multiple overloaded operators found"); if (members.Length == 0) { // No match return null; } else { return (MethodInfo)members[0]; } } /// /// Matches simple overloaded operators /// /// /// /// /// private static bool SimpleOverloadedOperatorFilter(MemberInfo member, object value) { IDictionary data = (IDictionary)value; MethodInfo method = (MethodInfo)member; bool nameMatch = method.IsSpecialName == true && method.Name.Equals((string)data["Name"], StringComparison.OrdinalIgnoreCase); if (nameMatch == false) { return false; } // destination type might not be known Type destType = (Type)data["destType"]; if (destType != null) { bool returnTypeMatch = object.ReferenceEquals(destType, method.ReturnType); if (returnTypeMatch == false) { return false; } } ParameterInfo[] parameters = method.GetParameters(); bool argumentMatch = parameters.Length > 0 && parameters[0].ParameterType.IsAssignableFrom((Type)data["sourceType"]); return argumentMatch; } public static MethodInfo GetOverloadedOperator(string name, Type sourceType, Binder binder, params Type[] argumentTypes) { name = string.Concat("op_", name); MethodInfo mi = null; do { mi = sourceType.GetMethod(name, BindingFlags.Public | BindingFlags.Static, binder, CallingConventions.Any, argumentTypes, null); if (mi != null && mi.IsSpecialName == true) { return mi; } } while ((sourceType = sourceType.BaseType) != null); return null; } public static int GetILGeneratorLength(ILGenerator ilg) { //System.Reflection.FieldInfo fi = typeof(ILGenerator).GetField("m_length", BindingFlags.Instance | BindingFlags.NonPublic); //return (int)fi.GetValue(ilg); return ilg.ILOffset; } public static bool IsLongBranch(int startPosition, int endPosition) { return (endPosition - startPosition) > sbyte.MaxValue; } public static string FormatList(string[] items) { string separator = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator + " "; return string.Join(separator, items); } public static string GetGeneralErrorMessage(string key, params object[] args) { string msg = $"{key}"; return $"[{msg}]{string.Join(',',args)}"; } public static string GetCompileErrorMessage(string key, params object[] args) { string msg = $"{key}"; return $"[{msg}]{string.Join(',', args)}"; } } }