protected void Assemble() { foreach (var xItem in mItems) { if (xItem is MethodBase) { var xMethod = (MethodBase)xItem; var xParams = xMethod.GetParameters(); var xParamTypes = xParams.Select(q => q.ParameterType).ToArray(); var xPlug = mPlugManager.ResolvePlug(xMethod, xParamTypes); var xMethodType = MethodInfo.TypeEnum.Normal; Type xPlugAssembler = null; MethodInfo xPlugInfo = null; var xMethodInline = xMethod.GetCustomAttribute <InlineAttribute>(); if (xMethodInline != null) { // inline assembler, shouldn't come here.. continue; } var xMethodIdMethod = mItemsList.IndexOf(xMethod); if (xMethodIdMethod == -1) { throw new Exception("Method not in scanner list!"); } if (xPlug != null) { xMethodType = MethodInfo.TypeEnum.NeedsPlug; var xAttrib = xPlug.GetCustomAttribute <PlugMethodAttribute>(); var xInline = xPlug.GetCustomAttribute <InlineAttribute>(); var xMethodIdPlug = mItemsList.IndexOf(xPlug); if (xMethodIdPlug == -1 && xInline == null) { throw new Exception("Plug method not in scanner list!"); } if (xAttrib != null && xInline == null) { xPlugAssembler = xAttrib.Assembler; xPlugInfo = new MethodInfo(xPlug, (uint)xMethodIdPlug, MethodInfo.TypeEnum.Plug, null, xPlugAssembler); var xMethodInfo = new MethodInfo(xMethod, (uint)xMethodIdMethod, xMethodType, xPlugInfo /*, xPlugAssembler*/); if (xAttrib != null && xAttrib.IsWildcard) { xPlugInfo.PluggedMethod = xMethodInfo; var xInstructions = mReader.ProcessMethod(xPlug); if (xInstructions != null) { ProcessInstructions(xInstructions); mAsmblr.ProcessMethod(xPlugInfo, xInstructions); } } mAsmblr.GenerateMethodForward(xMethodInfo, xPlugInfo); } else { if (xInline != null) { var xMethodID = mItemsList.IndexOf(xItem); if (xMethodID == -1) { throw new Exception("Method not in list!"); } xPlugInfo = new MethodInfo(xPlug, (uint)xMethodID, MethodInfo.TypeEnum.Plug, null, true); var xMethodInfo = new MethodInfo(xMethod, (uint)xMethodIdMethod, xMethodType, xPlugInfo /*, xPlugAssembler*/); xPlugInfo.PluggedMethod = xMethodInfo; var xInstructions = mReader.ProcessMethod(xPlug); if (xInstructions != null) { ProcessInstructions(xInstructions); mAsmblr.ProcessMethod(xPlugInfo, xInstructions); } mAsmblr.GenerateMethodForward(xMethodInfo, xPlugInfo); } else { xPlugInfo = new MethodInfo(xPlug, (uint)xMethodIdPlug, MethodInfo.TypeEnum.Plug, null, xPlugAssembler); var xMethodInfo = new MethodInfo(xMethod, (uint)xMethodIdMethod, xMethodType, xPlugInfo /*, xPlugAssembler*/); mAsmblr.GenerateMethodForward(xMethodInfo, xPlugInfo); } } } else { PlugMethodAttribute xAttrib = null; foreach (PlugMethodAttribute attrib in xMethod.GetCustomAttributes(typeof(PlugMethodAttribute), true)) { xAttrib = attrib; } if (xAttrib != null) { if (xAttrib.IsWildcard) { continue; } else if (xAttrib.PlugRequired) { throw new Exception(string.Format("Method {0} requires a plug, but none is implemented", xMethod.Name)); } xPlugAssembler = xAttrib.Assembler; } var xMethodInfo = new MethodInfo(xMethod, (uint)xMethodIdMethod, xMethodType, xPlugInfo, xPlugAssembler); var xInstructions = mReader.ProcessMethod(xMethod); if (xInstructions != null) { ProcessInstructions(xInstructions); mAsmblr.ProcessMethod(xMethodInfo, xInstructions); } } } else if (xItem is FieldInfo) { mAsmblr.ProcessField((FieldInfo)xItem); } } var xTypes = new HashSet <Type>(); var xMethods = new HashSet <MethodBase>(); foreach (var xItem in mItems) { if (xItem is MethodBase) { xMethods.Add((MethodBase)xItem); } else if (xItem is Type) { xTypes.Add((Type)xItem); } } mAsmblr.GenerateVMTCode(xTypes, xMethods, GetTypeUID, x => GetMethodUID(x, false)); }
private MethodBase ResolvePlug(Type aTargetType, List <Type> aImpls, MethodBase aMethod, Type[] aParamTypes) { //TODO: This method is "reversed" from old - remember that when porting MethodBase xResult = null; // Setup param types for search Type[] xParamTypes; if (aMethod.IsStatic) { xParamTypes = aParamTypes; } else { // If its an instance method, we have to add this to the ParamTypes to search xParamTypes = new Type[aParamTypes.Length + 1]; if (aParamTypes.Length > 0) { aParamTypes.CopyTo(xParamTypes, 1); } xParamTypes[0] = aTargetType; } PlugMethodAttribute xAttrib = null; foreach (var xImpl in aImpls) { // TODO: cleanup this loop, next statement shouldnt be neccessary if (xResult != null) { break; } // Plugs methods must be static, and public // Search for non signature matches first since signature searches are slower xResult = xImpl.GetMethod(aMethod.Name, BindingFlags.Static | BindingFlags.Public , null, xParamTypes, null); if (xResult == null && aMethod.Name == ".ctor") { xResult = xImpl.GetMethod("Ctor", BindingFlags.Static | BindingFlags.Public , null, xParamTypes, null); } if (xResult == null && aMethod.Name == ".cctor") { xResult = xImpl.GetMethod("CCtor", BindingFlags.Static | BindingFlags.Public , null, xParamTypes, null); } if (xResult == null) { // Search by signature foreach (var xSigMethod in xImpl.GetMethods(BindingFlags.Static | BindingFlags.Public)) { // TODO: Only allow one, but this code for now takes the last one // if there is more than one xAttrib = null; foreach (PlugMethodAttribute x in xSigMethod.GetCustomAttributes(typeof(PlugMethodAttribute), false)) { xAttrib = x; } if (xAttrib != null && (xAttrib.IsWildcard && !xAttrib.WildcardMatchParameters)) { MethodBase xTargetMethod = null; if (String.Compare(xSigMethod.Name, "Ctor", true) == 0 || String.Compare(xSigMethod.Name, "Cctor", true) == 0) { xTargetMethod = aTargetType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).SingleOrDefault(); } else { xTargetMethod = (from item in aTargetType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) where item.Name == xSigMethod.Name select item).SingleOrDefault(); } if (xTargetMethod == aMethod) { xResult = xSigMethod; } } else { var xParams = xSigMethod.GetParameters(); //TODO: Static method plugs dont seem to be separated // from instance ones, so the only way seems to be to try // to match instance first, and if no match try static. // I really don't like this and feel we need to find // an explicit way to determine or mark the method // implementations. // // Plug implementations take "this" as first argument // so when matching we don't include it in the search Type[] xTypesInst = null; var xActualParamCount = xParams.Length; foreach (var xParam in xParams) { if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0) { xActualParamCount--; } } Type[] xTypesStatic = new Type[xActualParamCount]; // If 0 params, has to be a static plug so we skip // any copying and leave xTypesInst = null // If 1 params, xTypesInst must be converted to Type[0] if (xActualParamCount == 1) { xTypesInst = new Type[0]; var xReplaceType = xParams[0].GetCustomAttributes(typeof(FieldTypeAttribute), false); if (xReplaceType.Length == 1) { xTypesStatic[0] = Type.GetType(((FieldTypeAttribute)xReplaceType[0]).Name, true); } else { xTypesStatic[0] = xParams[0].ParameterType; } } else if (xActualParamCount > 1) { xTypesInst = new Type[xActualParamCount - 1]; var xCurIdx = 0; foreach (var xParam in xParams.Skip(1)) { if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0) { continue; } var xReplaceType = xParam.GetCustomAttributes(typeof(FieldTypeAttribute), false); if (xReplaceType.Length == 1) { xTypesInst[xCurIdx] = Type.GetType(((FieldTypeAttribute)xReplaceType[0]).Name, true); } else { xTypesInst[xCurIdx] = xParam.ParameterType; } xCurIdx++; } xCurIdx = 0; foreach (var xParam in xParams) { if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0) { xCurIdx++; continue; } if (xCurIdx >= xTypesStatic.Length) { break; } xTypesStatic[xCurIdx] = xParam.ParameterType; xCurIdx++; } } SysReflection.MethodBase xTargetMethod = null; // TODO: In future make rule that all ctor plugs are called // ctor by name, or use a new attrib //TODO: Document all the plug stuff in a document on website //TODO: To make inclusion of plugs easy, we can make a plugs master // that references the other default plugs so user exes only // need to reference that one. // TODO: Skip FieldAccessAttribute if in impl if (xTypesInst != null) { if (string.Compare(xSigMethod.Name, "ctor", true) == 0) { xTargetMethod = aTargetType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesInst, null); } else { xTargetMethod = aTargetType.GetMethod(xSigMethod.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesInst, null); } } // Not an instance method, try static if (xTargetMethod == null) { if (string.Compare(xSigMethod.Name, "cctor", true) == 0 || string.Compare(xSigMethod.Name, "ctor", true) == 0) { xTargetMethod = aTargetType.GetConstructor(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesStatic, null); } else { xTargetMethod = aTargetType.GetMethod(xSigMethod.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesStatic, null); } } if (xTargetMethod == aMethod) { xResult = xSigMethod; break; } //if (aMethod.DeclaringType.IsGenericTypeDefinition) //{ // if (xTargetMethod.GetF) //} if (xAttrib != null && xAttrib.Signature != null) { var xName = DataMember.FilterStringForIncorrectChars(LabelName.GenerateFullName(aMethod)); if (string.Compare(xName, xAttrib.Signature, true) == 0) { xResult = xSigMethod; break; } } xAttrib = null; } } } else { // check if signatur is equal var xResPara = xResult.GetParameters(); var xAMethodPara = aMethod.GetParameters(); if (aMethod.IsStatic) { if (xResPara.Length != xAMethodPara.Length) { return(null); } } else { if (xResPara.Length - 1 != xAMethodPara.Length) { return(null); } } for (int i = 0; i < xAMethodPara.Length; i++) { int correctIndex = aMethod.IsStatic ? i : i + 1; if (xResPara[correctIndex].ParameterType != xAMethodPara[i].ParameterType) { return(null); } } if (xResult.Name == "Ctor" && aMethod.Name == ".ctor") { } else if (xResult.Name == "CCtor" && aMethod.Name == ".cctor") { } else if (xResult.Name != aMethod.Name) { return(null); } } } if (xResult == null) { return(null); } // If we found a matching method, check for attributes // that might disable it. //TODO: For signature ones, we could cache the attrib. Thats // why we check for null here if (xAttrib == null) { // TODO: Only allow one, but this code for now takes the last one // if there is more than one foreach (PlugMethodAttribute x in xResult.GetCustomAttributes(typeof(PlugMethodAttribute), false)) { xAttrib = x; } } // See if we need to disable this plug if (xAttrib != null) { if (!xAttrib.Enabled) { //xResult = null; return(null); } else if (xAttrib.IsMonoOnly) { //TODO: Check this against build options //TODO: Two exclusive IsOnly's dont make sense // refactor these as a positive rather than negative // Same thing at type plug level //xResult = null; return(null); } //else if (xAttrib.Signature != null) { // var xName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GenerateFullName(xResult)); // if (string.Compare(xName, xAttrib.Signature, true) != 0) { // xResult = null; // } //} } //if (xAttrib != null && xAttrib.Signature != null) //{ // var xTargetMethods = aTargetType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); // //System_Void__Indy_IL2CPU_Assembler_Assembler__cctor__ // //If signature exists, the search is slow. Signatures // //are infrequent though, so for now we just go slow method // //and have not optimized or cached this info. When we // //redo the plugs, we can fix this. // bool xEnabled=true; // foreach (var xTargetMethod in xTargetMethods) // { // string sName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GenerateFullName(xTargetMethod)); // if (string.Compare(sName, xAttrib.Signature, true) == 0) // { // //uint xUID = QueueMethod(xPlugImpl.Plug, "Plug", xMethod, true); // //mMethodPlugs.Add(xTargetMethod, new PlugInfo(xUID, xAttrib.Assembler)); // // Mark as disabled, because we already handled it // xEnabled = false; // break; // } // } // // if still enabled, we didn't find our method // if (xEnabled) // { // // todo: more precise error: imagine having a 100K line project, and this error happens... // throw new Exception("Plug target method not found."); // } //} return(xResult); }
protected void Assemble() { foreach (var xItem in mItems) { if (xItem is MethodBase) { var xMethod = (MethodBase)xItem; var xParams = xMethod.GetParameters(); var xParamTypes = xParams.Select(q => q.ParameterType).ToArray(); var xPlug = mPlugManager.ResolvePlug(xMethod, xParamTypes); var xMethodType = MethodInfo.TypeEnum.Normal; Type xPlugAssembler = null; MethodInfo xPlugInfo = null; if (xPlug != null) { xMethodType = MethodInfo.TypeEnum.NeedsPlug; PlugMethodAttribute xAttrib = null; foreach (PlugMethodAttribute attrib in xPlug.GetCustomAttributes(typeof(PlugMethodAttribute), true)) { xAttrib = attrib; } if (xAttrib != null) { xPlugAssembler = xAttrib.Assembler; xPlugInfo = new MethodInfo(xPlug, (uint)mItemsList.IndexOf(xPlug), MethodInfo.TypeEnum.Plug, null, xPlugAssembler); var xMethodInfo = new MethodInfo(xMethod, (uint)mItemsList.IndexOf(xMethod), xMethodType, xPlugInfo /*, xPlugAssembler*/); if (xAttrib != null && xAttrib.IsWildcard) { xPlugInfo.PluggedMethod = xMethodInfo; var xInstructions = mReader.ProcessMethod(xPlug); if (xInstructions != null) { ProcessInstructions(xInstructions); mAsmblr.ProcessMethod(xPlugInfo, xInstructions); } } mAsmblr.GenerateMethodForward(xMethodInfo, xPlugInfo); } else { InlineAttribute inl = null; foreach (InlineAttribute inli in xPlug.GetCustomAttributes(typeof(InlineAttribute), false)) { inl = inli; } if (inl != null) { xPlugInfo = new MethodInfo(xPlug, (uint)mItemsList.IndexOf(xItem), MethodInfo.TypeEnum.Plug, null, true); var xMethodInfo = new MethodInfo(xMethod, (uint)mItemsList.IndexOf(xMethod), xMethodType, xPlugInfo /*, xPlugAssembler*/); xPlugInfo.PluggedMethod = xMethodInfo; var xInstructions = mReader.ProcessMethod(xPlug); if (xInstructions != null) { ProcessInstructions(xInstructions); mAsmblr.ProcessMethod(xPlugInfo, xInstructions); } mAsmblr.GenerateMethodForward(xMethodInfo, xPlugInfo); } else { xPlugInfo = new MethodInfo(xPlug, (uint)mItemsList.IndexOf(xPlug), MethodInfo.TypeEnum.Plug, null, xPlugAssembler); var xMethodInfo = new MethodInfo(xMethod, (uint)mItemsList.IndexOf(xMethod), xMethodType, xPlugInfo /*, xPlugAssembler*/); if (xAttrib != null && xAttrib.IsWildcard) { xPlugInfo.PluggedMethod = xMethodInfo; var xInstructions = mReader.ProcessMethod(xPlug); if (xInstructions != null) { ProcessInstructions(xInstructions); mAsmblr.ProcessMethod(xPlugInfo, xInstructions); } } mAsmblr.GenerateMethodForward(xMethodInfo, xPlugInfo); } } } else { PlugMethodAttribute xAttrib = null; foreach (PlugMethodAttribute attrib in xMethod.GetCustomAttributes(typeof(PlugMethodAttribute), true)) { xAttrib = attrib; } if (xAttrib != null) { if (xAttrib.IsWildcard) { continue; } xPlugAssembler = xAttrib.Assembler; } var xMethodInfo = new MethodInfo(xMethod, (uint)mItemsList.IndexOf(xMethod), xMethodType, xPlugInfo, xPlugAssembler); var xInstructions = mReader.ProcessMethod(xMethod); if (xInstructions != null) { ProcessInstructions(xInstructions); mAsmblr.ProcessMethod(xMethodInfo, xInstructions); } } } else if (xItem is FieldInfo) { mAsmblr.ProcessField((FieldInfo)xItem); } } var xTypes = new HashSet <Type>(); var xMethods = new HashSet <MethodBase>(); foreach (var xItem in mItems) { if (xItem is MethodBase) { xMethods.Add((MethodBase)xItem); } else if (xItem is Type) { xTypes.Add((Type)xItem); } } mAsmblr.GenerateVMTCode(xTypes, xMethods, GetTypeUID, x => GetMethodUID(x, false)); }
public void ScanPlugs(Dictionary <Type, List <Type> > aPlugs) { foreach (var xPlug in aPlugs) { var xImpls = xPlug.Value; foreach (var xImpl in xImpls) { #region PlugMethods scan foreach (var xMethod in xImpl.GetMethods(BindingFlags.Public | BindingFlags.Static)) { PlugMethodAttribute xAttrib = null; foreach (PlugMethodAttribute x in xMethod.GetCustomAttributes(typeof(PlugMethodAttribute), false)) { xAttrib = x; } if (xAttrib == null) { //At this point we need to check the plug method actually //matches a method that might need plugging. // x08 bug // We must check for a number of cases: // - Public, static and private/internal methods that need plugging // - Ctor or Cctor bool OK = false; if (xMethod.Name.ToLower() == "ctor" || xMethod.Name.ToLower() == "cctor") { OK = true; } else { // Skip checking methods related to fields because it's just too messy... // We also skip methods which do method access. if (xMethod.GetParameters().Where(x => { return(x.GetCustomAttributes(typeof(FieldAccessAttribute)).Count() > 0 || x.GetCustomAttributes(typeof(ObjectPointerAccessAttribute)).Count() > 0); }).Count() > 0) { OK = true; } else { var xParamTypes = xMethod.GetParameters().Select(delegate(ParameterInfo x) { var result = x.ParameterType; if (result.IsByRef) { result = result.GetElementType(); } else if (result.IsPointer) { result = null; } return(result); }).ToArray(); var posMethods = xPlug.Key.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public) .Where(x => x.Name == xMethod.Name); foreach (SysReflection.MethodInfo posInf in posMethods) { // If static, no this param // Otherwise, take into account first param is this param //This param is either of declaring type, or ref to declaring type or pointer var posMethParamTypes = posInf.GetParameters().Select(delegate(ParameterInfo x) { var result = x.ParameterType; if (result.IsByRef) { result = result.GetElementType(); } else if (result.IsPointer) { result = null; } return(result); }).ToArray(); if (posInf.IsStatic) { if (posMethParamTypes.Length != xParamTypes.Length) { continue; } OK = true; // Exact params match excl. pointers - there could be "null" types for statics since some could be pointers for (int i = 0; i < posMethParamTypes.Length; i++) { if ((posMethParamTypes[i] == null && xParamTypes[i] == null) || !posMethParamTypes[i].Equals(xParamTypes[i])) { OK = false; break; } } if (!OK) { continue; } else { break; } } else { // Exact match except possibly 1st param if (posMethParamTypes.Length != xParamTypes.Length && posMethParamTypes.Length != xParamTypes.Length - 1) { continue; } int offset = 0; OK = true; // Exact match except if first param doesn't match, we skip 1st param and restart matching for (int i = 0; i < posMethParamTypes.Length && (i + offset) < xParamTypes.Length; i++) { //Continue if current type is null i.e. was a pointer as that could be any type originally. if (xParamTypes[i + offset] != null && !posMethParamTypes[i].Equals(xParamTypes[i + offset])) { if (offset == 0) { offset = 1; i = -1; } else { OK = false; break; } } } if (posMethParamTypes.Length == 0 && xParamTypes.Length > 0) { //We use IsAssignableFrom here because _some_ plugs decide to use more generic types for the //this parameter OK = xParamTypes[0] == null || xParamTypes[0].IsAssignableFrom(posInf.DeclaringType); } if (!OK) { continue; } else { break; } } } } } if (!OK) { if (xAttrib == null || xAttrib.IsOptional) { if (LogWarning != null) { LogWarning("Invalid plug method! Target method not found. : " + xMethod.GetFullName()); } } } } else { if (xAttrib.IsWildcard && xAttrib.Assembler == null) { if (LogWarning != null) { LogWarning("Wildcard PlugMethods need to use an assembler for now."); } } } } #endregion #region PlugFields scan foreach (var xField in xImpl.GetCustomAttributes(typeof(PlugFieldAttribute), true).Cast <PlugFieldAttribute>()) { IDictionary <string, PlugFieldAttribute> xFields = null; if (!mPlugFields.TryGetValue(xPlug.Key, out xFields)) { xFields = new Dictionary <string, PlugFieldAttribute>(); mPlugFields.Add(xPlug.Key, xFields); } if (xFields.ContainsKey(xField.FieldId)) { throw new Exception("Duplicate PlugField found for field '" + xField.FieldId + "'!"); } xFields.Add(xField.FieldId, xField); } #endregion } } }