/// <summary> /// Process an unplugged method. /// </summary> /// <param name="aMethod">The method to process.</param> /// <param name="staticConstructorDependencyRoot">Null if method scanning is not a static constructor. Otherwise, the root node that represents the static constructor being scanned.</param> /// <returns>A new ILChunk with ILOpInfos and common attribites loaded. Null if any errors occur.</returns> /// <exception cref="System.Exception"> /// Thrown when an unrecognised operand type is read. Can occur if MSBuild has been /// updated/extended from when the kernel compiler was last updated. /// </exception> public ILChunk ProcessUnpluggedMethod(MethodBase aMethod, StaticConstructorDependency staticConstructorDependencyRoot = null) { ILChunk result = new ILChunk() { Plugged = false, Method = aMethod }; //Pre-process common method attributes so we get information such as //whether to apply GC or not etc. ProcessCommonMethodAttributes(aMethod, result); //Get the method body which can then be used to get locals info and //IL bytes that are the IL code. MethodBody theMethodBody = aMethod.GetMethodBody(); //Method body for something like [DelegateType].Invoke() // is null if (theMethodBody == null) { //Just return empty method return result; } //For each local variable in this method foreach (LocalVariableInfo aLocal in theMethodBody.LocalVariables) { //Add it to our list of locals with some common information pre-worked out LocalVariable localItem = new LocalVariable() { sizeOnStackInBytes = Utils.GetNumBytesForType(aLocal.LocalType), isFloat = Utils.IsFloat(aLocal.LocalType), TheType = aLocal.LocalType, isGCManaged = Utils.IsGCManaged(aLocal.LocalType) }; result.LocalVariables.Add(localItem); } //Used later to store location and length of the cleanup try-finally block int CleanUpBlock_TryOffset = 0; int CleanUpBlock_TryLength = 0; int CleanUpBlock_FinallyOffset = 0; int CleanUpBlock_FinallyLength = 0; //The "cleanup" block is the finally handler created by the IL reader that //calls GC.DecrementRefCount of locals and arguments as-required so that //memory managed by the GC through objects gets freed correctly. //The try-section of the cleanup block surrounds all of the main code of the method //excluding the final "ret" instruction. In this way, even if an exception occurs, //locals and args still get "cleaned up". //The IL bytes are the IL code. byte[] ILBytes = theMethodBody.GetILAsByteArray(); //Note: IL offsets are usually calculated as the number of bytes offset from the // start of the method. //Note: IL line numbers are IL offsets. //The current position in the IL bytes. //This will change throughout the loop below so it always points past //all the bytes processed so far. int ILBytesPos = 0; //The previous position in the IL bytes. //This will only change in the loop below after a new IL op is created. In this way, //it actually points to the IL bytes position just before the new op is created. //That is to say, it points to the IL bytes pos of the start of the new op. int PrevILBytesPos = 0; //The previous IL op info that was created. //This is the latest one that was created as opposed the the one before that. //I.e. this is the last ILOpInfo added to the final list of IL op infos. ILOpInfo prevInfo = null; //Loop through all the IL bytes for this method... while (ILBytesPos < ILBytes.Length) { //The current System.Reflection.Emit.OpCode being processed OpCode currOpCode; //The unique number that identifies the op code. //This number is also deliberately equivalent to Kernel.Compiler.ILOps.IlOp.OpCodes! ushort currOpCodeID = 0; //MSIL is saved such that OpIds that only require 1 byte, only use 1 byte! //ILBytes encoded as big-endian(?) so high bytes of the op code value (ID) come first //So if high byte is set to 0xFE then we need to load the next byte as low byte if (ILBytes[ILBytesPos] == 0xFE) { currOpCodeID = (ushort)(0xFE00 + (short)ILBytes[ILBytesPos + 1]); ILBytesPos += 2; } else { currOpCodeID = (ushort)ILBytes[ILBytesPos]; ILBytesPos++; } //Load the op code from our pre-constructed list of all op codes currOpCode = AllOpCodes[currOpCodeID]; int operandSize = 0; //Operand type tells us the operand size //We must: // a) Skip over the operand bytes so that we read the next IL op correctly // b) Store the operand bytes in the ILOpInfo for later use switch(currOpCode.OperandType) { case OperandType.InlineBrTarget: operandSize = 4; break; case OperandType.InlineField: operandSize = 4; break; case OperandType.InlineI: operandSize = 4; break; case OperandType.InlineI8: operandSize = 8; break; case OperandType.InlineMethod: operandSize = 4; break; case OperandType.InlineNone: //No operands = no op size break; case OperandType.InlineR: operandSize = 8; break; case OperandType.InlineSig: operandSize = 4; break; case OperandType.InlineString: operandSize = 4; break; case OperandType.InlineSwitch: { int count = Utils.ReadInt32(ILBytes, ILBytesPos); ILBytesPos += 4; operandSize = count * 4; } break; case OperandType.InlineTok: operandSize = 4; break; case OperandType.InlineType: operandSize = 4; break; case OperandType.InlineVar: operandSize = 2; break; case OperandType.ShortInlineBrTarget: operandSize = 1; break; case OperandType.ShortInlineI: operandSize = 1; break; case OperandType.ShortInlineR: operandSize = 4; break; case OperandType.ShortInlineVar: operandSize = 1; break; default: throw new Exception("Unrecognised operand type!"); } //Update the previous op with next position now that we // know what that is... if (prevInfo != null) { prevInfo.NextPosition = PrevILBytesPos; } //The IL reader pre-loads any methods that should be called by, for example, a call op //This was added so that the MethodToCall could be set by the IL reader to inject call ops // - It was going to be a lot harder to try and get the "metadata token bytes" for the // method to call than to simply "pre-load" the method to call. MethodBase methodToCall = null; //Value bytes generally contain a constant value to be loaded or the bytes of a metadata token. //Metadata tokens can be used to retrieve information such as string literals or method infos //from the calling assembly. byte[] valueBytes = new byte[operandSize]; //Don't bother copying 0 bytes... if (operandSize > 0) { //Copy the bytes... Array.Copy(ILBytes, ILBytesPos, valueBytes, 0, operandSize); //If the op is one where the valueBytes are a metadata token pointing to a method: if ((ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Call || (ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Calli || (ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Callvirt || (ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Ldftn || (ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Newobj) { //Pre-load the method for reasons described above. //The metadata token that identifies the method to call in the DLL //It is used to retrieve more information about the method from the DLL int MethodMetadataToken = Utils.ReadInt32(valueBytes, 0); //The method to call retrieved using the metasdata token methodToCall = aMethod.Module.ResolveMethod(MethodMetadataToken); } } //If the op being processed is a Return op and this method has GC applied: if ((ILOps.ILOp.OpCodes)currOpCode.Value == ILOps.ILOp.OpCodes.Ret && result.ApplyGC) { //We must insert the cleanup block code. //Insert try-finally block around the entire method but just before Ret //The finally block can then do clean-up of local variables and args //1. Insert IL ops for doing locals / args cleanup //2. Add the try/finally block (or just finally block if try block already exists) //We must also consider the fact that just before a "ret" op, the return value is loaded. //Since this cleanup block will wrap that load op, we must add code to store the return value //at the end of the try block and then re-load the return value after the finally block (but //before the ret op.) //Get a list of all the params to the current method List<Type> allParams = result.Method.GetParameters() .Select(x => x.ParameterType) .ToList(); //If it isn't a static method: if (!result.Method.IsStatic) { //The first param is the current instance reference. allParams.Insert(0, result.Method.DeclaringType); } //Only insert the cleanup block if there are some params or locals to clean up. //This is the first of two checks of this condition. if (result.LocalVariables.Count > 0 || allParams.Count > 0) { //As per above we need to check for return value LocalVariable returnValVariable = null; //Return type of constructor is void, so only check proper methods if(result.Method is MethodInfo) { Type returnType = ((MethodInfo)result.Method).ReturnType; //Void return type = no return value if(returnType != typeof(void)) { //Add a new local variable for storing the return value returnValVariable = new LocalVariable() { isFloat = Utils.IsFloat(returnType), sizeOnStackInBytes = Utils.GetNumBytesForType(returnType), TheType = returnType, isGCManaged = Utils.IsGCManaged(returnType) }; result.LocalVariables.Add(returnValVariable); //This will become the penultimate IL op of the try-block //It will immediately follow the op just before ret which // will have loaded the return value or, at the very least, // the top-most item on the stack is the return value //This op stores that return value in our new local variable // for reload after the finally block has completed. result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Stloc, Position = PrevILBytesPos++, NextPosition = PrevILBytesPos, ValueBytes = BitConverter.GetBytes(result.LocalVariables.IndexOf(returnValVariable)) }); } } //This becomes the last op of the try-block (and is required to be // the last op of a try block) result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Leave_S, Position = PrevILBytesPos++, NextPosition = PrevILBytesPos, ValueBytes = new byte[4] }); //Try block length is now the length in IL bytes from start // (i.e. offset) to start of the current IL op. See above for // why we use PrevIlBytesPos. CleanUpBlock_TryLength = PrevILBytesPos - CleanUpBlock_TryOffset; //Finally offset is offset to first op of finally block i.e. // current IL op position. CleanUpBlock_FinallyOffset = PrevILBytesPos; //Finally length is currently 0 - gets increased later. CleanUpBlock_FinallyLength = 0; //Add cleanup code for each local for (int i = 0; i < result.LocalVariables.Count; i++) { //Clean-up local variables //If the local variable is GC handled: //1. Load the the local //2. Call GC Dec Ref count LocalVariable aVar = result.LocalVariables[i]; //Only add cleanup code if the local is actually GC managed. if (Utils.IsGCManaged(aVar.TheType)) { if (prevInfo != null) { prevInfo.NextPosition = PrevILBytesPos; } //Load the local result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Ldloc, Position = PrevILBytesPos++, NextPosition = -1, ValueBytes = BitConverter.GetBytes(i) }); prevInfo.NextPosition = PrevILBytesPos; //Decrement the ref count of the local result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Call, Position = PrevILBytesPos++, NextPosition = -1, SetToGCDecRefCountMethod = true }); CleanUpBlock_FinallyLength += 2; } } //Add cleanup code for each arg //Dec ref count of all args passed to the method for (int i = 0; i < allParams.Count; i++) { Type aVarType = allParams[i]; //Only add cleanup code if the arg is actually GC managed. if (Utils.IsGCManaged(aVarType)) { if (prevInfo != null) { prevInfo.NextPosition = PrevILBytesPos; } result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Ldarg, Position = PrevILBytesPos++, NextPosition = -1, ValueBytes = BitConverter.GetBytes(i) }); prevInfo.NextPosition = PrevILBytesPos; result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Call, Position = PrevILBytesPos++, NextPosition = -1, SetToGCDecRefCountMethod = true }); CleanUpBlock_FinallyLength += 2; } } //Locals and args not necessarily of GC managed type // so we could potentially have cleaned up nothing //This is the second of the two checks to make sure we // only add cleanup code if there is something to cleanup if (CleanUpBlock_FinallyLength > 0) { //If there is cleanup code, add the end of the finally block and // reload the return value if necessary. prevInfo.NextPosition = PrevILBytesPos; result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Endfinally, Position = PrevILBytesPos++, NextPosition = -1 }); CleanUpBlock_FinallyLength += 1; if (returnValVariable != null) { result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = OpCodes.Ldloc, Position = PrevILBytesPos++, NextPosition = PrevILBytesPos, ValueBytes = BitConverter.GetBytes(result.LocalVariables.IndexOf(returnValVariable)) }); } } else { //If there was nothing to cleanup, we need to remove // the ops and locals etc. that got added earlier. result.ILOpInfos.RemoveAt(result.ILOpInfos.Count - 1); PrevILBytesPos--; if(returnValVariable != null) { result.LocalVariables.Remove(returnValVariable); result.ILOpInfos.RemoveAt(result.ILOpInfos.Count - 1); PrevILBytesPos--; } } } } if (staticConstructorDependencyRoot != null) { //Create our static constructor dependency tree //Each of these ops could try to access a static method or field switch((ILOps.ILOp.OpCodes)currOpCode.Value) { case ILOps.ILOp.OpCodes.Call: //Check if the method to call is static and not a constructor itself //If so, we must add the declaring type's static constructors to the tree { int metadataToken = Utils.ReadInt32(valueBytes, 0); MethodBase methodBaseInf = aMethod.Module.ResolveMethod(metadataToken); if(!(methodBaseInf.IsConstructor || methodBaseInf is ConstructorInfo)) { MethodInfo methodInf = (MethodInfo)methodBaseInf; ConstructorInfo[] staticConstructors = methodInf.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.Public) .Concat(methodInf.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)) .ToArray(); if (staticConstructors.Length > 0) { ConstructorInfo TheConstructor = staticConstructors[0]; if (staticConstructorDependencyRoot[TheConstructor] == null) { staticConstructorDependencyRoot.Children.Add(new StaticConstructorDependency() { TheConstructor = TheConstructor }); } } } } break; case ILOps.ILOp.OpCodes.Ldsfld: case ILOps.ILOp.OpCodes.Ldsflda: case ILOps.ILOp.OpCodes.Stsfld: { int metadataToken = Utils.ReadInt32(valueBytes, 0); FieldInfo fieldInf = aMethod.Module.ResolveField(metadataToken); ConstructorInfo[] staticConstructors = fieldInf.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.Public) .Concat(fieldInf.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)) .ToArray(); if(staticConstructors.Length > 0) { ConstructorInfo TheConstructor = staticConstructors[0]; if (staticConstructorDependencyRoot[TheConstructor] == null) { staticConstructorDependencyRoot.Children.Add(new StaticConstructorDependency() { TheConstructor = TheConstructor }); } } } break; } } //Add the IL op result.ILOpInfos.Add(prevInfo = new ILOpInfo() { opCode = currOpCode, Position = PrevILBytesPos, // Next position set to -1 indicates no next op NextPosition = -1, ValueBytes = valueBytes, MethodToCall = methodToCall }); ILBytesPos += operandSize; PrevILBytesPos = ILBytesPos; } prevInfo.NextPosition = PrevILBytesPos; //Add the exception handlers (excluding Cleanup try-finally block - see below) foreach (ExceptionHandlingClause aClause in theMethodBody.ExceptionHandlingClauses) { ExceptionHandledBlock exBlock = result.GetExactExceptionHandledBlock(aClause.TryOffset); if (exBlock == null) { exBlock = new ExceptionHandledBlock(); exBlock.Offset = aClause.TryOffset; exBlock.Length = aClause.TryLength; result.ExceptionHandledBlocks.Add(exBlock); } switch (aClause.Flags) { case ExceptionHandlingClauseOptions.Fault: case ExceptionHandlingClauseOptions.Clause: { CatchBlock catchBlock = new CatchBlock() { Offset = aClause.HandlerOffset, Length = aClause.HandlerLength, //Though not used, we may as well set it anyway FilterType = aClause.CatchType }; exBlock.CatchBlocks.Add(catchBlock); } break; case ExceptionHandlingClauseOptions.Finally: { FinallyBlock finallyBlock = new FinallyBlock() { Offset = aClause.HandlerOffset, Length = aClause.HandlerLength }; exBlock.FinallyBlocks.Add(finallyBlock); } break; default: OutputError(new NotSupportedException("Exception handling clause not supported! Type: " + aClause.Flags.ToString())); break; } } //Add the cleanup try-finally block //Only add the block if try-section has non-zero length and // if the finally block has more than just the endfinally op if (CleanUpBlock_TryLength != 0 && CleanUpBlock_FinallyLength > 1) { ExceptionHandledBlock cleanUpTryBlock = new ExceptionHandledBlock() { Offset = CleanUpBlock_TryOffset, Length = CleanUpBlock_TryLength }; FinallyBlock cleanupFinallyBlock = new FinallyBlock() { Offset = CleanUpBlock_FinallyOffset, Length = CleanUpBlock_FinallyLength, }; cleanUpTryBlock.FinallyBlocks.Add(cleanupFinallyBlock); result.ExceptionHandledBlocks.Add(cleanUpTryBlock); } return result; }
/// <summary> /// Executes the IL scanner on the specified IL chunks. Loads plug ASM for target architecture and converts unplugged IL to ASM. /// </summary> /// <param name="ILChunks">The IL chunks to scan.</param> /// <param name="Types">The types to scan.</param> /// <param name="TheStaticConstructorDependencyTree">The static constructor dependency tree (generated by the IL reader) to use.</param> /// <returns>True if scanning completed successfully. Otherwise false.</returns> /// <exception cref="System.Exception"> /// Thrown if: /// <list type="bullet"> /// <item> /// <term>Multiple kernel main methods found.</term> /// </item> /// <item> /// <term>No kernel main method found.</term> /// </item> /// </list> /// </exception> public bool Execute(List<Type> Types, List<ILChunk> ILChunks, StaticConstructorDependency TheStaticConstructorDependencyTree) { bool OK = true; AllTypes = Types; OK = LoadTargetArchitectureAssembly(); if (OK) { LoadIlOpTypes(); TheScannerState = new ILScannerState(TheSettings.DebugBuild); ASMChunks.Add(TheScannerState.StringLiteralsDataBlock); ASMChunks.Add(TheScannerState.StaticFieldsDataBlock); ASMChunks.Add(TheScannerState.TypesTableDataBlock); //Pre-process all types // - Do NOT change to foreach or you get a collection modified exception // because processing a type may cause a change to AllTypes and thus to Types for (int i = 0; i < Types.Count; i++) { ProcessType(Types[i]); } if (string.IsNullOrEmpty(TheSettings[Settings.KernelMainMethodKey])) { List<ILChunk> potChunks = (from chunks in ILChunks where (chunks.IsMainMethod) select chunks).ToList(); if (potChunks.Count > 0) { if (potChunks.Count == 1) { string kernelMainMethodID = TheScannerState.GetMethodID(potChunks[0].Method); TheSettings[Settings.KernelMainMethodKey] = kernelMainMethodID; } else { throw new Exception("Multiple kernel main methods found!"); } } else { throw new Exception("No kernel main method found!"); } } ILChunk CallStaticConstructorsChunk = (from chunks in ILChunks where (chunks.IsCallStaticConstructorsMethod) select chunks).First(); List<ConstructorInfo> staticConstructorsToCall = TheStaticConstructorDependencyTree.Flatten(); int position = CallStaticConstructorsChunk.ILOpInfos.Count; foreach (ConstructorInfo anInfo in staticConstructorsToCall) { CallStaticConstructorsChunk.ILOpInfos.Insert(CallStaticConstructorsChunk.ILOpInfos.Count - 1, new ILOpInfo() { opCode = System.Reflection.Emit.OpCodes.Call, Position = position, NextPosition = ++position, ValueBytes = null, MethodToCall = anInfo } ); } if (string.IsNullOrEmpty(TheSettings[Settings.CallStaticConstructorsMethodKey])) { TheSettings[Settings.CallStaticConstructorsMethodKey] = TheScannerState.GetMethodID(CallStaticConstructorsChunk.Method); } TheScannerState.AddExceptionHandlerInfoMethod = (from chunks in ILChunks where (chunks.IsAddExceptionHandlerInfoMethod) select chunks).First().Method; TheScannerState.ExceptionsHandleLeaveMethod = (from chunks in ILChunks where (chunks.IsExceptionsHandleLeaveMethod) select chunks).First().Method; TheScannerState.ExceptionsHandleEndFinallyMethod = (from chunks in ILChunks where (chunks.IsExceptionsHandleEndFinallyMethod) select chunks).First().Method; TheScannerState.ThrowNullReferenceExceptionMethod = (from chunks in ILChunks where (chunks.IsExceptionsThrowNullReferenceMethod) select chunks).First().Method; TheScannerState.ThrowArrayTypeMismatchExceptionMethod = (from chunks in ILChunks where (chunks.IsExceptionsThrowArrayTypeMismatchMethod) select chunks).First().Method; TheScannerState.ThrowIndexOutOfRangeExceptionMethod = (from chunks in ILChunks where (chunks.IsExceptionsThrowIndexOutOfRangeMethod) select chunks).First().Method; TheScannerState.NewObjMethod = (from chunks in ILChunks where (chunks.IsNewObjMethod) select chunks).First().Method; TheScannerState.NewArrMethod = (from chunks in ILChunks where (chunks.IsNewArrMethod) select chunks).First().Method; TheScannerState.IncrementRefCountMethod = (from chunks in ILChunks where (chunks.IsIncrementRefCountMethod) select chunks).First().Method; TheScannerState.DecrementRefCountMethod = (from chunks in ILChunks where (chunks.IsDecrementRefCountMethod) select chunks).First().Method; TheScannerState.HaltMethod = (from chunks in ILChunks where (chunks.IsHaltMethod) select chunks).First().Method; foreach (ILChunk aChunk in ILChunks) { //We don't want to break the loop if one chunk fails //So that if there are more errors, they all get outputted //to the developer so the developer can fix all of them before //their next re-compile try { ASMChunk resultChunk = ProcessILChunk(aChunk); if (resultChunk != null) { ASMChunks.Add(resultChunk); } else { throw new Exception("Failed to process IL chunk!"); } } catch (Exception ex) { OK = false; OutputError(ex); } } TheScannerState.Finalise(); foreach (ASMChunk aChunk in TheScannerState.MethodTablesDataBlock) { ASMChunks.Add(aChunk); } foreach (ASMChunk aChunk in TheScannerState.FieldTablesDataBlock) { ASMChunks.Add(aChunk); } ASMChunk endChunk = new ASMChunk(); endChunk.ASM.AppendLine("_end_code:"); endChunk.SequencePriority = long.MaxValue; ASMChunks.Add(endChunk); } return OK; }
/// <summary> /// Executes the ILReader. /// </summary> /// <returns>True if execution completed successfully. Otherwise false.</returns> public bool Execute() { bool OK = true; TheStaticConstructorDependencyTree = new StaticConstructorDependency() { TheConstructor = null }; //In these loops, we do not abort as soon as one method fails to process. //This is because if we did, debugging code would be slow as only one error //would be caught at a time. By continuing, we can output all the reading //errors so the developer can fix all of them before recompiling. //Go through plugged types foreach (Type aType in TheAssemblyManager.PluggedTypes.Values) { //Check to make sure this isn't an mscorlib type e.g. System.Object if (aType.AssemblyQualifiedName.Contains("mscorlib")) { continue; } //Go through all methods MethodInfo[] allMethods = aType.GetMethods(); allMethods = allMethods.Concat(aType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)) .Concat(aType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)) .ToArray(); foreach (MethodInfo aMethod in allMethods) { ILChunk theILChunk = null; Exception innerEx = null; try { //Ignore inherited methods - we don't want to process a method twice if (aMethod.DeclaringType != aType || aMethod.IsAbstract) { continue; } //Check for plugs, if: if (aMethod.GetCustomAttributes(typeof(PluggedMethodAttribute)).Count() > 0) { //Then process as plugged method theILChunk = ProcessPluggedMethod(aMethod); } else { //Else process as normal method theILChunk = ProcessUnpluggedMethod(aMethod); } } catch(Exception ex) { theILChunk = null; innerEx = ex; OK = false; } if (theILChunk == null) { OutputError(new Exception("Failed to process method!", innerEx)); } else { ILChunks.Add(theILChunk); } } //Go through all static constructors ConstructorInfo[] staticConstructors = aType.GetConstructors(BindingFlags.Static | BindingFlags.Public) .Concat(aType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)) .ToArray(); foreach (ConstructorInfo aConstructor in staticConstructors) { ILChunk theILChunk = null; Exception innerEx = null; try { //Ignore inherited constructors - we don't want to process a method twice if (aConstructor.DeclaringType != aType || aConstructor.IsAbstract) { continue; } //Process as normal method StaticConstructorDependency staticConstructorDependencyRoot = TheStaticConstructorDependencyTree[aConstructor]; if (staticConstructorDependencyRoot == null) { staticConstructorDependencyRoot = new StaticConstructorDependency() { TheConstructor = aConstructor }; TheStaticConstructorDependencyTree.Children.Add(staticConstructorDependencyRoot); } //Check for plugs, if: if (aConstructor.GetCustomAttributes(typeof(PluggedMethodAttribute)).Count() > 0) { //Then process as plugged method theILChunk = ProcessPluggedMethod(aConstructor); } else { //Else process as normal method theILChunk = ProcessUnpluggedMethod(aConstructor, staticConstructorDependencyRoot); } } catch (Exception ex) { theILChunk = null; innerEx = ex; OK = false; } if (theILChunk == null) { OutputError(new Exception("Failed to process static constructor!", innerEx)); } else { ILChunks.Add(theILChunk); } } ConstructorInfo[] constructors = aType.GetConstructors(BindingFlags.Instance | BindingFlags.Public) .Concat(aType.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)) .ToArray(); foreach (ConstructorInfo aConstructor in constructors) { ILChunk theILChunk = null; Exception innerEx = null; try { //Ignore inherited constructors - we don't want to process a method twice if (aConstructor.DeclaringType != aType || aConstructor.IsAbstract) { continue; } //Check for plugs, if: if (aConstructor.GetCustomAttributes(typeof(PluggedMethodAttribute)).Count() > 0) { //Then process as plugged method theILChunk = ProcessPluggedMethod(aConstructor); } else { //Else process as normal method theILChunk = ProcessUnpluggedMethod(aConstructor); } } catch (Exception ex) { theILChunk = null; innerEx = ex; OK = false; } if (theILChunk == null) { OutputError(new Exception("Failed to process static constructor!", innerEx)); } else { ILChunks.Add(theILChunk); } } } //Go through all other types foreach (Type aType in TheAssemblyManager.UnpluggedTypes.Values) { //Go through all methods MethodInfo[] allMethods = aType.GetMethods(); allMethods = allMethods.Concat(aType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)) .Concat(aType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)) .ToArray(); foreach (MethodInfo aMethod in allMethods) { ILChunk theILChunk = null; Exception innerEx = null; try { //Check to make sure this isn't inherited from an mscorlib type e.g. System.Object if (aMethod.DeclaringType.AssemblyQualifiedName.Contains("mscorlib")) { continue; } //Ignore inherited methods - we don't want to process a method twice if (aMethod.DeclaringType != aType || aMethod.IsAbstract) { continue; } //Process as normal method theILChunk = ProcessUnpluggedMethod(aMethod); } catch (Exception ex) { theILChunk = null; innerEx = ex; OK = false; } if (theILChunk == null) { OutputError(new Exception("Failed to process method!", innerEx)); } else { ILChunks.Add(theILChunk); } } //Go through all static constructors ConstructorInfo[] staticConstructors = aType.GetConstructors(BindingFlags.Static | BindingFlags.Public) .Concat(aType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)) .ToArray(); foreach (ConstructorInfo aConstructor in staticConstructors) { ILChunk theILChunk = null; Exception innerEx = null; try { //Ignore inherited constructors - we don't want to process a method twice if (aConstructor.DeclaringType != aType || aConstructor.IsAbstract) { continue; } //Process as normal method StaticConstructorDependency staticConstructorDependencyRoot = TheStaticConstructorDependencyTree[aConstructor]; if(staticConstructorDependencyRoot == null) { staticConstructorDependencyRoot = new StaticConstructorDependency() { TheConstructor = aConstructor }; TheStaticConstructorDependencyTree.Children.Add(staticConstructorDependencyRoot); } theILChunk = ProcessUnpluggedMethod(aConstructor, staticConstructorDependencyRoot); } catch (Exception ex) { theILChunk = null; innerEx = ex; OK = false; } if (theILChunk == null) { OutputError(new Exception("Failed to process static constructor!", innerEx)); } else { ILChunks.Add(theILChunk); } } ConstructorInfo[] constructors = aType.GetConstructors(BindingFlags.Instance | BindingFlags.Public) .Concat(aType.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)) .ToArray(); foreach (ConstructorInfo aConstructor in constructors) { ILChunk theILChunk = null; Exception innerEx = null; try { //Ignore inherited constructors - we don't want to process a method twice if (aConstructor.DeclaringType != aType || aConstructor.IsAbstract) { continue; } theILChunk = ProcessUnpluggedMethod(aConstructor); } catch (Exception ex) { theILChunk = null; innerEx = ex; OK = false; } if (theILChunk == null) { OutputError(new Exception("Failed to process static constructor!", innerEx)); } else { ILChunks.Add(theILChunk); } } } return OK; }