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)); }
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)); }
public void Execute(MethodBase aStartMethod, IEnumerable <Assembly> plugsAssemblies) { if (aStartMethod == null) { throw new ArgumentNullException(nameof(aStartMethod)); } // TODO: Investigate using MS CCI // Need to check license, as well as in profiler // http://cciast.codeplex.com/ #region Description // Methodology // // Ok - we've done the scanner enough times to know it needs to be // documented super well so that future changes won't inadvertently // break undocumented and unseen requirements. // // We've tried many approaches including recursive and additive scanning. // They typically end up being inefficient, overly complex, or both. // // -We would like to scan all types/methods so we can plug them. // -But we can't scan them until we plug them, because we will scan things // that plugs would remove/change the paths of. // -Plugs may also call methods which are also plugged. // -We cannot resolve plugs ahead of time but must do on the fly during // scanning. // -TODO: Because we do on the fly resolution, we need to add explicit // checking of plug classes and err when public methods are found that // do not resolve. Maybe we can make a list and mark, or rescan. Can be done // later or as an optional auditing step. // // This why in the past we had repetitive scans. // // Now we focus on more passes, but simpler execution. In the end it should // be eaiser to optmize and yield overall better performance. Most of the // passes should be low overhead versus an integrated system which often // would need to reiterate over items multiple times. So we do more loops on // with less repetitive analysis, instead of fewer loops but more repetition. // // -Locate all plug classes // -Scan from entry point collecting all types and methods while checking // for and following plugs // -For each type // -Include all ancestors // -Include all static constructors // -For each virtual method // -Scan overloads in descendants until IsFinal, IsSealed or end // -Scan base in ancestors until top or IsAbstract // -Go to scan types again, until no new ones found. // -Because the virtual method scanning will add to the list as it goes, maintain // 2 lists. // -Known Types and Methods // -Types and Methods in Queue - to be scanned // -Finally, do compilation #endregion Description mPlugManager.FindPlugImpls(plugsAssemblies); // Now that we found all plugs, scan them. // We have to scan them after we find all plugs, because // plugs can use other plugs mPlugManager.ScanFoundPlugs(); foreach (var xPlug in mPlugManager.PlugImpls) { CompilerHelpers.Debug($"Plug found: '{xPlug.Key.FullName}' in '{xPlug.Key.Assembly.FullName}'"); } ILOp.PlugManager = mPlugManager; // Pull in extra implementations, GC etc. Queue(RuntimeEngineRefs.InitializeApplicationRef, null, "Explicit Entry"); Queue(RuntimeEngineRefs.FinalizeApplicationRef, null, "Explicit Entry"); Queue(VTablesImplRefs.IsInstanceRef, null, "Explicit Entry"); Queue(VTablesImplRefs.SetTypeInfoRef, null, "Explicit Entry"); Queue(VTablesImplRefs.SetInterfaceInfoRef, null, "Explicit Entry"); Queue(VTablesImplRefs.SetMethodInfoRef, null, "Explicit Entry"); Queue(VTablesImplRefs.SetInterfaceMethodInfoRef, null, "Explicit Entry"); Queue(VTablesImplRefs.GetMethodAddressForTypeRef, null, "Explicit Entry"); Queue(VTablesImplRefs.GetMethodAddressForInterfaceTypeRef, null, "Explicit Entry"); Queue(GCImplementationRefs.IncRefCountRef, null, "Explicit Entry"); Queue(GCImplementationRefs.DecRefCountRef, null, "Explicit Entry"); Queue(GCImplementationRefs.AllocNewObjectRef, null, "Explicit Entry"); // for now, to ease runtime exception throwing Queue(typeof(ExceptionHelper).GetMethod("ThrowNotImplemented", new Type[] { typeof(string) }, null), null, "Explicit Entry"); Queue(typeof(ExceptionHelper).GetMethod("ThrowOverflow", Type.EmptyTypes, null), null, "Explicit Entry"); Queue(typeof(ExceptionHelper).GetMethod("ThrowInvalidOperation", new Type[] { typeof(string) }, null), null, "Explicit Entry"); Queue(typeof(ExceptionHelper).GetMethod("ThrowArgumentOutOfRange", new Type[] { typeof(string) }, null), null, "Explicit Entry"); // register system types: Queue(typeof(Array), null, "Explicit Entry"); Queue(typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).First(), null, "Explicit Entry"); Queue(typeof(MulticastDelegate).GetMethod("GetInvocationList"), null, "Explicit Entry"); Queue(ExceptionHelperRefs.CurrentExceptionRef, null, "Explicit Entry"); Queue(ExceptionHelperRefs.ThrowInvalidCastExceptionRef, null, "Explicit Entry"); Queue(ExceptionHelperRefs.ThrowNotFiniteNumberExceptionRef, null, "Explicit Entry"); mAsmblr.ProcessField(typeof(string).GetField("Empty", BindingFlags.Static | BindingFlags.Public)); // Start from entry point of this program Queue(aStartMethod, null, "Entry Point"); ScanQueue(); UpdateAssemblies(); Assemble(); mAsmblr.EmitEntrypoint(aStartMethod); }