public bool Equals(MemberInfo x, MemberInfo y) { if (x == null) { return(y == null); } if (y == null) { return(false); } if (x.GetType() == y.GetType()) { if (x.MetadataToken == y.MetadataToken && x.Module == y.Module) { if (x is MethodBase xMethod && y is MethodBase yMethod) { return(LabelName.GetFullName(xMethod) == LabelName.GetFullName(yMethod)); } else if (x is Type xType && y is Type yType) { return(LabelName.GetFullName(xType) == LabelName.GetFullName(yType)); } else { return(true); } }
private static void __cyclesrdtsc(int *target) { /* * push eax * push ecx * push edx * lea esi, target * rdtsc * mov [esi+4], eax * mov [esi], edx * pop edx * pop ecx * pop eax * ret */ __cyclesrdtscptr = target; string intname = LabelName.GetFullName(typeof(CPUImpl).GetTypeInfo().GetField(nameof(__cyclesrdtscptr))); XS.Push(XSRegisters.EAX); XS.Push(XSRegisters.ECX); XS.Push(XSRegisters.EDX); XS.Lea(XSRegisters.ESI, intname); XS.Rdtsc(); XS.Set(XSRegisters.ESI, XSRegisters.EAX, destinationIsIndirect: true, destinationDisplacement: 4); XS.Set(XSRegisters.ESI, XSRegisters.EDX, destinationIsIndirect: true); XS.Push(XSRegisters.EDX); XS.Push(XSRegisters.ECX); XS.Push(XSRegisters.EAX); XS.Return(); }
private static void __raterdmsr(int *target) { /* * ; esi register layout: (mperf_hi, mperf_lo, aperf_hi, aperf_lo) * ; * ; int* ptr = new int[4]; * ; * lea esi, ptr ;equivalent with `mov esi, &ptr` * mov ecx, e7h * rdmsr * mov [esi + 4], eax * mov [esi], edx * mov ecx, e8h * rdmsr * mov [esi + 12], eax * mov [esi + 8], edx * xor eax, eax * ret */ __raterdmsrptr = target; string intname = LabelName.GetFullName(typeof(CPUImpl).GetTypeInfo().GetField(nameof(__raterdmsrptr))); XS.Lea(XSRegisters.ESI, intname); XS.Set(XSRegisters.ECX, 0xe7); XS.Rdmsr(); XS.Set(XSRegisters.EAX, XSRegisters.ESI, destinationIsIndirect: true, destinationDisplacement: 4); XS.Set(XSRegisters.EDX, XSRegisters.ESI, destinationIsIndirect: true, destinationDisplacement: 0); XS.Set(XSRegisters.ECX, 0xe8); XS.Rdmsr(); XS.Set(XSRegisters.EAX, XSRegisters.ESI, destinationIsIndirect: true, destinationDisplacement: 12); XS.Set(XSRegisters.EDX, XSRegisters.ESI, destinationIsIndirect: true, destinationDisplacement: 8); XS.Xor(XSRegisters.EAX, XSRegisters.EAX); // XS.Set(XSRegisters.EAX, 0); XS.Return(); }
public override void ExpandStatements(ExtendedWarrior warrior, IWarriorParser parser, ref int currentAddress, int coreSize, bool evaluate) { //set labels, except last which is EQU expression for (int l = 0; l < Labels.Count; l++) { LabelName label = Labels[l]; if (l == Labels.Count - 1) {//equ parser.Variables[label.GetFullName(parser, currentAddress)] = expression; } else {//labels parser.Variables[label.GetFullName(parser, currentAddress)] = new Address(currentAddress); } } return; }
public void TestGetTypeFullName() { Action a = () => { }; Action <int> a1 = (i) => test++; Assert.That(LabelName.GetFullName(a.GetType()) != LabelName.GetFullName(a1.GetType())); var c = new { i = 1, n = "Test" }; var d = new { i = 1, n = "Test" }; var e = new { n = "Test", i = 1 }; Assert.That(LabelName.GetFullName(c.GetType()) != null); Assert.That(LabelName.GetFullName(c.GetType()) == LabelName.GetFullName(d.GetType())); }
public override void ExpandStatements(ExtendedWarrior warrior, IWarriorParser parser, ref int currentAddress, int coreSize, bool evaluate) { //set labels, except last which is FOR expression for (int l = 0; l < Labels.Count - 1; l++) { LabelName label = Labels[l]; parser.Variables[label.GetFullName(parser, currentAddress)] = new Address(currentAddress); } string cnt = Labels[Labels.Count - 1].Name; int count = parser.Variables[LimitName].Evaluate(parser, currentAddress); for (int i = 1; i <= count; i++) { parser.Variables[cnt] = new Value(i); base.ExpandStatements(warrior, parser, ref currentAddress, coreSize, evaluate); } }
internal static void FetchCPUVendor(int *target) { /* * lea esi, target * xor eax, eax * cpuid * mov [esi], ebx * mov [esi + 4], edx * mov [esi + 8], ecx * ret */ __vendortargetptr = target; string intname = LabelName.GetFullName(typeof(CPUImpl).GetTypeInfo().GetField(nameof(__vendortargetptr))); XS.Lea(XSRegisters.ESI, intname); // new Lea { DestinationReg = RegistersEnum.ESI, SourceRef = ElementReference.New(intname) }; XS.Cpuid(); XS.Set(XSRegisters.ESI, XSRegisters.EBX, destinationIsIndirect: true); XS.Set(XSRegisters.ESI, XSRegisters.EDX, destinationIsIndirect: true, destinationDisplacement: 4); XS.Set(XSRegisters.ESI, XSRegisters.ECX, destinationIsIndirect: true, destinationDisplacement: 8); XS.Return(); }
private void LoadBootEntries() { mBootEntries = new Dictionary <MethodBase, int?>(); mForceIncludes = new List <MemberInfo>(); var xCheckedAssemblies = new List <string>(); foreach (string xRef in References) { LogMessage("Checking Reference: " + xRef); if (File.Exists(xRef)) { LogMessage(" Exists"); var xAssembly = AssemblyLoadContext.Default.LoadFromAssemblyCacheOrPath(xRef); CheckAssembly(xAssembly); } } void CheckAssembly(Assembly aAssembly) { // Just for debugging //LogMessage("Checking Assembly: " + aAssembly.Location); xCheckedAssemblies.Add(aAssembly.GetName().ToString()); foreach (var xType in aAssembly.GetTypes()) { var xForceIncludeAttribute = xType.GetCustomAttribute <ForceInclude>(); if (xForceIncludeAttribute != null) { ForceInclude(xType, xForceIncludeAttribute); } foreach (var xMethod in xType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) { xForceIncludeAttribute = xMethod.GetCustomAttribute <ForceInclude>(); if (xForceIncludeAttribute != null) { ForceInclude(xMethod, xForceIncludeAttribute); } var xBootEntryAttribute = xMethod.GetCustomAttribute <BootEntry>(); if (xBootEntryAttribute != null) { var xEntryIndex = xBootEntryAttribute.EntryIndex; LogMessage("Boot Entry found: Name: " + xMethod + ", Entry Index: " + (xEntryIndex.HasValue ? xEntryIndex.Value.ToString() : "null")); if (xMethod.ReturnType != typeof(void)) { throw new NotSupportedException("Boot Entry should return void! Method: " + LabelName.Get(xMethod)); } if (xMethod.GetParameters().Length != 0) { throw new NotSupportedException("Boot Entry shouldn't have parameters! Method: " + LabelName.Get(xMethod)); } mBootEntries.Add(xMethod, xEntryIndex); } } if (xType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(m => m.GetCustomAttribute <BootEntry>() != null).Any()) { throw new NotSupportedException("Boot Entry should be static! Type: " + LabelName.GetFullName(xType)); } } foreach (var xReference in aAssembly.GetReferencedAssemblies()) { try { if (!xCheckedAssemblies.Contains(xReference.ToString())) { var xAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(xReference); if (xAssembly != null) { CheckAssembly(xAssembly); } } } catch (FileNotFoundException) { if (xReference.Name.Contains("Cosmos")) { LogWarning("Cosmos Assembly not found!" + Environment.NewLine + "Assembly Name: " + xReference.FullName); } } } } if (mBootEntries.Count == 0) { throw new NotSupportedException("No boot entries found!"); } if (mBootEntries.Where(e => e.Value == null).Count() == 0) { throw new NotImplementedException("No default boot entries found!"); } mBootEntries = mBootEntries.OrderBy(e => e.Value) .OrderByDescending(e => e.Value.HasValue) .ToDictionary(e => e.Key, e => e.Value); if (mBootEntries.Count > 1) { var xLastEntryIndex = mBootEntries.Values.ElementAt(0); for (int i = 1; i < mBootEntries.Count; i++) { var xEntryIndex = mBootEntries.Values.ElementAt(i); if (xLastEntryIndex == xEntryIndex) { throw new NotSupportedException("Two boot entries with the same entry index were found! Methods: '" + LabelName.GetFullName(mBootEntries.Keys.ElementAt(i - 1)) + "' and '" + LabelName.GetFullName(mBootEntries.Keys.ElementAt(i)) + "'"); } xLastEntryIndex = xEntryIndex; } } }
public static string GetTypeIDLabel(Type aType) { return("VMT__TYPE_ID_HOLDER__" + DataMember.FilterStringForIncorrectChars(LabelName.GetFullName(aType) + " ASM_IS__" + aType.GetTypeInfo().Assembly.GetName().Name)); }
protected void ScanMethod(MethodBase aMethod, bool aIsPlug, string sourceItem) { CompilerHelpers.Debug($"ILScanner: ScanMethod"); CompilerHelpers.Debug($"Method = '{aMethod}'"); CompilerHelpers.Debug($"IsPlug = '{aIsPlug}'"); CompilerHelpers.Debug($"Source = '{sourceItem}'"); var xParams = aMethod.GetParameters(); var xParamTypes = new Type[xParams.Length]; // Dont use foreach, enum generaly keeps order but // isn't guaranteed. //string xMethodFullName = LabelName.GetFullName(aMethod); for (int i = 0; i < xParams.Length; i++) { xParamTypes[i] = xParams[i].ParameterType; Queue(xParamTypes[i], aMethod, "Parameter"); } var xIsDynamicMethod = aMethod.DeclaringType == null; // Queue Types directly related to method if (!aIsPlug) { // Don't queue declaring types of plugs if (!xIsDynamicMethod) { // dont queue declaring types of dynamic methods either, those dont have a declaring type Queue(aMethod.DeclaringType, aMethod, "Declaring Type"); } } if (aMethod is MethodInfo) { Queue(((MethodInfo)aMethod).ReturnType, aMethod, "Return Type"); } // Scan virtuals #region Virtuals scan if (!xIsDynamicMethod && aMethod.IsVirtual) { // For virtuals we need to climb up the type tree // and find the top base method. We then add that top // node to the mVirtuals list. We don't need to add the // types becuase adding DeclaringType will already cause // all ancestor types to be added. var xVirtMethod = aMethod; var xVirtType = aMethod.DeclaringType; MethodBase xNewVirtMethod; while (true) { xVirtType = xVirtType.BaseType; if (xVirtType == null) { // We've reached object, can't go farther xNewVirtMethod = null; } else { xNewVirtMethod = xVirtType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where(method => method.Name == aMethod.Name && method.GetParameters().Select(param => param.ParameterType) .SequenceEqual(xParamTypes)) .SingleOrDefault(); if (xNewVirtMethod != null) { if (!xNewVirtMethod.IsVirtual) { // This can happen if a virtual "replaces" a non virtual // above it that is not virtual. xNewVirtMethod = null; } } } // We dont bother to add these to Queue, because we have to do a // full downlevel scan if its a new base virtual anyways. if (xNewVirtMethod == null) { // If its already in the list, we mark it null // so we dont do a full downlevel scan. if (mVirtuals.Contains(xVirtMethod)) { xVirtMethod = null; } break; } xVirtMethod = xNewVirtMethod; } // New virtual base found, we need to downscan it // If it was already in mVirtuals, then ScanType will take // care of new additions. if (xVirtMethod != null) { Queue(xVirtMethod, aMethod, "Virtual Base"); mVirtuals.Add(xVirtMethod); // List changes as we go, cant be foreach for (int i = 0; i < mItemsList.Count; i++) { if (mItemsList[i] is Type xType && xType != xVirtMethod.DeclaringType && !xType.IsInterface) { if (xType.IsSubclassOf(xVirtMethod.DeclaringType)) { var xNewMethod = xType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where(method => method.Name == aMethod.Name && method.GetParameters().Select(param => param.ParameterType).SequenceEqual(xParamTypes)) .SingleOrDefault(); if (xNewMethod != null) { // We need to check IsVirtual, a non virtual could // "replace" a virtual above it? if (xNewMethod.IsVirtual) { Queue(xNewMethod, aMethod, "Virtual Downscan"); } } } else if (xVirtMethod.DeclaringType.IsInterface && xType.GetInterfaces().Contains(xVirtMethod.DeclaringType)) { var xInterfaceMap = xType.GetInterfaceMap(xVirtMethod.DeclaringType); var xMethodIndex = Array.IndexOf(xInterfaceMap.InterfaceMethods, xVirtMethod); if (xMethodIndex != -1) { var xMethod = xInterfaceMap.TargetMethods[xMethodIndex]; if (xMethod.DeclaringType == xType) { Queue(xInterfaceMap.TargetMethods[xMethodIndex], aMethod, "Virtual Downscan"); } } } } } } } #endregion Virtuals scan MethodBase xPlug = null; // Plugs may use plugs, but plugs won't be plugged over themself var inl = aMethod.GetCustomAttribute <InlineAttribute>(); if (!aIsPlug && !xIsDynamicMethod) { // Check to see if method is plugged, if it is we don't scan body xPlug = mPlugManager.ResolvePlug(aMethod, xParamTypes); if (xPlug != null) { //ScanMethod(xPlug, true, "Plug method"); if (inl == null) { Queue(xPlug, aMethod, "Plug method"); } } } if (xPlug == null) { bool xNeedsPlug = false; if ((aMethod.Attributes & MethodAttributes.PinvokeImpl) != 0) { // pinvoke methods dont have an embedded implementation xNeedsPlug = true; } else { var xImplFlags = aMethod.GetMethodImplementationFlags(); // todo: prob even more if (xImplFlags.HasFlag(MethodImplAttributes.Native) || xImplFlags.HasFlag(MethodImplAttributes.InternalCall)) { // native implementations cannot be compiled xNeedsPlug = true; } } if (xNeedsPlug) { throw new Exception(Environment.NewLine + "Native code encountered, plug required." + Environment.NewLine + " DO NOT REPORT THIS AS A BUG." + Environment.NewLine + " Please see http://www.gocosmos.org/docs/plugs/missing/" + Environment.NewLine + " Need plug for: " + LabelName.GetFullName(aMethod) + "." + Environment.NewLine + " Called from :" + Environment.NewLine + sourceItem + Environment.NewLine); } //TODO: As we scan each method, we could update or put in a new list // that has the resolved plug so we don't have to reresolve it again // later for compilation. // Scan the method body for more type and method refs //TODO: Dont queue new items if they are plugged // or do we need to queue them with a resolved ref in a new list? if (inl != null) { return; // cancel inline } List <ILOpCode> xOpCodes; xOpCodes = mReader.ProcessMethod(aMethod); if (xOpCodes != null) { ProcessInstructions(xOpCodes); foreach (var xOpCode in xOpCodes) { if (xOpCode is ILOpCodes.OpMethod) { Queue(((ILOpCodes.OpMethod)xOpCode).Value, aMethod, "Call", sourceItem); } else if (xOpCode is ILOpCodes.OpType) { Queue(((ILOpCodes.OpType)xOpCode).Value, aMethod, "OpCode Value"); } else if (xOpCode is ILOpCodes.OpField xOpField) { //TODO: Need to do this? Will we get a ILOpCodes.OpType as well? Queue(xOpField.Value.DeclaringType, aMethod, "OpCode Value"); if (xOpField.Value.IsStatic) { //TODO: Why do we add static fields, but not instance? // AW: instance fields are "added" always, as part of a type, but for static fields, we need to emit a datamember Queue(xOpField.Value, aMethod, "OpCode Value"); } } else if (xOpCode is ILOpCodes.OpToken xOpToken) { if (xOpToken.ValueIsType) { Queue(xOpToken.ValueType, aMethod, "OpCode Value"); } if (xOpToken.ValueIsField) { Queue(xOpToken.ValueField.DeclaringType, aMethod, "OpCode Value"); if (xOpToken.ValueField.IsStatic) { //TODO: Why do we add static fields, but not instance? // AW: instance fields are "added" always, as part of a type, but for static fields, we need to emit a datamember Queue(xOpToken.ValueField, aMethod, "OpCode Value"); } } } } } } }
private static string BuildMethodKeyName(MethodBase m) { return(LabelName.GetFullName(m)); }
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; } PlugMethod 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.GetTypeInfo().GetMethods() .Where(method => method.Name == aMethod.Name && method.GetParameters().Select(param => param.ParameterType) .SequenceEqual(xParamTypes)) .SingleOrDefault(); if (xResult == null && aMethod.Name == ".ctor") { xResult = xImpl.GetTypeInfo().GetMethod("Ctor", xParamTypes, null); } if (xResult == null && aMethod.Name == ".cctor") { xResult = xImpl.GetTypeInfo().GetMethod("CCtor", xParamTypes, null); } if (xResult == null) { // Search by signature foreach (var xSigMethod in xImpl.GetTypeInfo().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 (PlugMethod x in xSigMethod.GetCustomAttributes(typeof(PlugMethod), 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.GetTypeInfo().GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).SingleOrDefault(); } else { xTargetMethod = (from item in aTargetType.GetTypeInfo().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(FieldAccess), false).Any()) { 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(FieldType), false).ToList(); if (xReplaceType.Any()) { xTypesStatic[0] = Type.GetType(((FieldType)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(FieldAccess), false).Any()) { continue; } var xReplaceType = xParam.GetCustomAttributes(typeof(FieldType), false).ToList(); if (xReplaceType.Any()) { xTypesInst[xCurIdx] = Type.GetType(((FieldType)xReplaceType[0]).Name, true); } else { xTypesInst[xCurIdx] = xParam.ParameterType; } xCurIdx++; } xCurIdx = 0; foreach (var xParam in xParams) { if (xParam.GetCustomAttributes(typeof(FieldAccess), false).Any()) { xCurIdx++; continue; } if (xCurIdx >= xTypesStatic.Length) { break; } xTypesStatic[xCurIdx] = xParam.ParameterType; xCurIdx++; } } 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", StringComparison.OrdinalIgnoreCase) == 0) { xTargetMethod = aTargetType.GetTypeInfo().GetConstructor(xTypesInst); } else { xTargetMethod = aTargetType.GetTypeInfo().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(method => method.Name == xSigMethod.Name && method.GetParameters().Select(param => param.ParameterType) .SequenceEqual(xTypesInst)) .SingleOrDefault(); } } // Not an instance method, try static if (xTargetMethod == null) { if (string.Compare(xSigMethod.Name, "cctor", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(xSigMethod.Name, "ctor", StringComparison.OrdinalIgnoreCase) == 0) { xTargetMethod = aTargetType.GetTypeInfo().GetConstructor(xTypesStatic); } else { xTargetMethod = aTargetType.GetTypeInfo().GetMethods() .Where(method => method.Name == xSigMethod.Name && method.GetParameters().Select(param => param.ParameterType) .SequenceEqual(xTypesStatic)) .SingleOrDefault(); } } if (xTargetMethod == aMethod) { xResult = xSigMethod; break; } if (xAttrib?.Signature != null) { var xName = DataMember.FilterStringForIncorrectChars(LabelName.GetFullName(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 (PlugMethod x in xResult.GetCustomAttributes(typeof(PlugMethod), false)) { xAttrib = x; } } // See if we need to disable this plug if (xAttrib != null) { if (!xAttrib.Enabled) { //xResult = null; return(null); } //else if (xAttrib.Signature != null) { // var xName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GetFullName(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.GetFullName(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); }
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; } PlugMethod 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 (PlugMethod x in xSigMethod.GetCustomAttributes(typeof(PlugMethod), false)) { xAttrib = x; } if (xAttrib != null && (xAttrib.IsWildcard && !xAttrib.WildcardMatchParameters)) { MethodBase xTargetMethod = null; if (String.Equals(xSigMethod.Name, "Ctor", StringComparison.OrdinalIgnoreCase) || String.Equals(xSigMethod.Name, "Cctor", StringComparison.OrdinalIgnoreCase)) { 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(FieldAccess), false).Length != 0) { xActualParamCount--; } } var 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 = Array.Empty <Type>(); var xReplaceType = xParams[0].GetCustomAttributes(typeof(FieldType), false).ToList(); if (xReplaceType.Count != 0) { xTypesStatic[0] = _typeResolver.ResolveType(((FieldType)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(FieldAccess), false).Length != 0) { continue; } var xReplaceType = xParam.GetCustomAttributes(typeof(FieldType), false).ToList(); if (xReplaceType.Count != 0) { xTypesInst[xCurIdx] = _typeResolver.ResolveType(((FieldType)xReplaceType[0]).Name, true); } else { xTypesInst[xCurIdx] = xParam.ParameterType; } xCurIdx++; } xCurIdx = 0; foreach (var xParam in xParams) { if (xParam.GetCustomAttributes(typeof(FieldAccess), false).Length != 0) { xCurIdx++; continue; } if (xCurIdx >= xTypesStatic.Length) { break; } xTypesStatic[xCurIdx] = xParam.ParameterType; xCurIdx++; } } 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.Equals(xSigMethod.Name, "ctor", StringComparison.OrdinalIgnoreCase)) { 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.Equals(xSigMethod.Name, "cctor", StringComparison.OrdinalIgnoreCase) || String.Equals(xSigMethod.Name, "ctor", StringComparison.OrdinalIgnoreCase)) { 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 (xAttrib?.Signature != null) { var xName = DataMember.FilterStringForIncorrectChars(LabelName.GetFullName(aMethod)); if (String.Equals(xName.Replace("_", ""), xAttrib.Signature.Replace("_", ""), StringComparison.OrdinalIgnoreCase)) { 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 && xResPara[correctIndex].ParameterType.Name != "Object") // to cheat if we cant access the actual type { // Allow explicit overwriting of types by signature in case we have to hide internal enum behind uint etc if (xResult.GetCustomAttribute <PlugMethod>()?.Signature.Replace("_", "") == DataMember.FilterStringForIncorrectChars(LabelName.GetFullName(aMethod)).Replace("_", "")) { } else { 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 (PlugMethod x in xResult.GetCustomAttributes(typeof(PlugMethod), false)) { xAttrib = x; } } // See if we need to disable this plug if (xAttrib != null) { if (!xAttrib.Enabled) { //xResult = null; return(null); } //else if (xAttrib.Signature != null) { // var xName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GetFullName(xResult)); // if (string.Compare(xName, xAttrib.Signature, true) != 0) { // xResult = null; // } //} } if (xResult is MethodInfo aMethodInfo && aMethodInfo.IsGenericMethodDefinition) { var types = aMethod.GetGenericArguments(); xResult = aMethodInfo.MakeGenericMethod(types); } return(xResult); }