/// <summary> /// Executes the IL Reader for the specified library. /// </summary> /// <param name="TheLibrary">The library to read.</param> /// <returns>The return value from the IL Reader.</returns> private static CompileResult ExecuteILReader(ILLibrary TheLibrary) { CompileResult result = CompileResult.OK; if (TheLibrary.ILRead) { return(result); } TheLibrary.ILRead = true; foreach (ILLibrary depLib in TheLibrary.Dependencies) { result = result == CompileResult.OK ? ExecuteILReader(depLib) : result; } foreach (Types.TypeInfo aTypeInfo in TheLibrary.TypeInfos) { foreach (Types.MethodInfo aMethodInfo in aTypeInfo.MethodInfos) { TheLibrary.ILBlocks.Add(aMethodInfo, ILReader.Read(aMethodInfo)); } } return(result); }
/// <summary> /// Loads an IL Library from the specified file. /// </summary> /// <param name="FilePath">The path to the file to load as an IL Library.</param> /// <returns>The loaded IL Library.</returns> private static ILLibrary LoadILLibraryFromFile(string FilePath) { if (string.IsNullOrWhiteSpace(FilePath)) { Logger.LogError(Errors.Loader_LibraryPathNullOrEmpty_ErrorCode, FilePath, 0, Errors.ErrorMessages[Errors.Loader_LibraryPathNullOrEmpty_ErrorCode]); return null; } else if (!File.Exists(FilePath)) { Logger.LogError(Errors.Loader_LibraryFileDoesntExist_ErrorCode, FilePath, 0, Errors.ErrorMessages[Errors.Loader_LibraryFileDoesntExist_ErrorCode]); return null; } try { ILLibrary result = new ILLibrary(); result.TheAssembly = Assembly.LoadFrom(FilePath); return result; } catch (Exception ex) { Logger.LogError(Errors.Loader_UnexpectedError_ErrorCode, FilePath, 0, string.Format( Errors.ErrorMessages[Errors.Loader_UnexpectedError_ErrorCode], ex.Message, ex.StackTrace)); } return null; }
/// <summary> /// Executes the IL Reader for the specified library. /// </summary> /// <param name="TheLibrary">The library to read.</param> /// <returns>The return value from the IL Reader.</returns> private static CompileResult ExecuteILReader(ILLibrary TheLibrary) { CompileResult result = CompileResult.OK; if (TheLibrary.ILRead) { return result; } TheLibrary.ILRead = true; foreach (ILLibrary depLib in TheLibrary.Dependencies) { result = result == CompileResult.OK ? ExecuteILReader(depLib) : result; } foreach (Types.TypeInfo aTypeInfo in TheLibrary.TypeInfos) { foreach (Types.MethodInfo aMethodInfo in aTypeInfo.MethodInfos) { TheLibrary.ILBlocks.Add(aMethodInfo, ILReader.Read(aMethodInfo)); } } return result; }
/// <summary> /// Executes the IL Scanner for the specified library. /// </summary> /// <param name="TheLibrary">The library to scan.</param> /// <returns>The return value from the IL Scanner.</returns> private static CompileResult ExecuteILScanner(ILLibrary TheLibrary) { CompileResult result = CompileResult.OK; result = ILScanner.Scan(TheLibrary); return(result); }
/// <summary> /// Scans the specified type's non-static fields. /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="TheTypeInfo">The type to scan the non-static fields of.</param> /// <param name="FieldTablesBlock">The ASM block for the fields table for the library currently being compiled.</param> private static void ScanFields(ILLibrary TheLibrary, Types.TypeInfo TheTypeInfo, ASM.ASMBlock FieldTablesBlock) { string currentTypeId = TheTypeInfo.ID; string currentTypeName = TheTypeInfo.UnderlyingType.FullName; List <Tuple <string, string, string> > AllFieldInfo = new List <Tuple <string, string, string> >(); if (TheTypeInfo.UnderlyingType.BaseType == null || (TheTypeInfo.UnderlyingType.BaseType.FullName != "System.Array" && TheTypeInfo.UnderlyingType.BaseType.FullName != "System.MulticastDelegate")) { foreach (Types.FieldInfo anOwnField in TheTypeInfo.FieldInfos) { if (!anOwnField.IsStatic) { Types.TypeInfo FieldTypeInfo = TheLibrary.GetTypeInfo(anOwnField.FieldType); string fieldOffsetVal = anOwnField.OffsetInBytes.ToString(); string fieldSizeVal = (FieldTypeInfo.IsValueType ? FieldTypeInfo.SizeOnHeapInBytes : FieldTypeInfo.SizeOnStackInBytes).ToString(); string fieldTypeIdVal = FieldTypeInfo.ID; FieldTablesBlock.AddExternalLabel(fieldTypeIdVal); AllFieldInfo.Add(new Tuple <string, string, string>(fieldOffsetVal, fieldSizeVal, fieldTypeIdVal)); } } } string parentTypeFieldTablePtr = "0"; bool parentPtrIsExternal = false; if (TheTypeInfo.UnderlyingType.BaseType != null) { if (!TheTypeInfo.UnderlyingType.BaseType.AssemblyQualifiedName.Contains("mscorlib")) { Types.TypeInfo baseTypeInfo = TheLibrary.GetTypeInfo(TheTypeInfo.UnderlyingType.BaseType); parentPtrIsExternal = (ScannedTypes.ContainsKey(baseTypeInfo.ID) && ScannedTypes[baseTypeInfo.ID] != TheLibrary) || !TheLibrary.TypeInfos.Contains(baseTypeInfo); parentTypeFieldTablePtr = baseTypeInfo.ID + "_FieldTable"; } } { string fieldOffsetVal = "0"; string fieldSizeVal = "0"; string fieldTypeIdVal = parentTypeFieldTablePtr; if (parentPtrIsExternal) { FieldTablesBlock.AddExternalLabel(fieldTypeIdVal); } AllFieldInfo.Add(new Tuple <string, string, string>(fieldOffsetVal, fieldSizeVal, fieldTypeIdVal)); } List <Tuple <string, int> > TableEntryFieldInfos = GetSpecialClassFieldInfo(TheLibrary, typeof(Attributes.FieldInfoStructAttribute)); ASM.ASMOp newFieldTableOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.FieldTable, currentTypeId, currentTypeName, AllFieldInfo, TableEntryFieldInfos); FieldTablesBlock.Append(newFieldTableOp); }
/// <summary> /// Executes the IL Preprocessor for the specified library. /// </summary> /// <param name="TheLibrary">The library to preprocess.</param> /// <returns>The return value from the IL Preprocessor.</returns> private static CompileResult ExecuteILPreprocessor(ILLibrary TheLibrary) { CompileResult result = CompileResult.OK; ILPreprocessor.Preprocess(TheLibrary); ILPreprocessor.PreprocessSpecialClasses(TheLibrary); ILPreprocessor.PreprocessSpecialMethods(TheLibrary); return(result); }
/// <summary> /// Scans the specified plugged IL block. /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="theMethodInfo">The method which generated the IL block.</param> /// <param name="theILBlock">The IL block to scan.</param> /// <returns>CompileResult.OK.</returns> private static CompileResult ScanPluggedILBlock(ILLibrary TheLibrary, Types.MethodInfo theMethodInfo, ILBlock theILBlock) { TheLibrary.TheASMLibrary.ASMBlocks.Add(new ASM.ASMBlock() { PlugPath = theILBlock.PlugPath, OriginMethodInfo = theMethodInfo, Priority = theMethodInfo.Priority }); return(CompileResult.OK); }
/// <summary> /// Scans the specified type's methods. /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="TheTypeInfo">The type to scan the methods of.</param> /// <param name="MethodTablesBlock">The ASM block for the methods table for the library currently being compiled.</param> private static void ScanMethods(ILLibrary TheLibrary, Types.TypeInfo TheTypeInfo, ASM.ASMBlock MethodTablesBlock) { string currentTypeId = TheTypeInfo.ID; string currentTypeName = TheTypeInfo.UnderlyingType.FullName; List <Tuple <string, string> > AllMethodInfo = new List <Tuple <string, string> >(); if (TheTypeInfo.UnderlyingType.BaseType == null || TheTypeInfo.UnderlyingType.BaseType.FullName != "System.Array") { foreach (Types.MethodInfo aMethodInfo in TheTypeInfo.MethodInfos) { if (!aMethodInfo.IsStatic && !aMethodInfo.UnderlyingInfo.IsAbstract) { string methodID = aMethodInfo.ID; string methodIDValue = aMethodInfo.IDValue.ToString(); MethodTablesBlock.AddExternalLabel(methodID); AllMethodInfo.Add(new Tuple <string, string>(methodID, methodIDValue)); } } } string parentTypeMethodTablePtr = "0"; bool parentPtrIsExternal = false; if (TheTypeInfo.UnderlyingType.BaseType != null) { if (!TheTypeInfo.UnderlyingType.BaseType.AssemblyQualifiedName.Contains("mscorlib")) { Types.TypeInfo baseTypeInfo = TheLibrary.GetTypeInfo(TheTypeInfo.UnderlyingType.BaseType); parentPtrIsExternal = (ScannedTypes.ContainsKey(baseTypeInfo.ID) && ScannedTypes[baseTypeInfo.ID] != TheLibrary) || !TheLibrary.TypeInfos.Contains(baseTypeInfo); parentTypeMethodTablePtr = baseTypeInfo.ID + "_MethodTable"; } } { string methodID = parentTypeMethodTablePtr; string methodIDValue = "0"; if (parentPtrIsExternal) { MethodTablesBlock.AddExternalLabel(methodID); } AllMethodInfo.Add(new Tuple <string, string>(methodID, methodIDValue)); } List <Tuple <string, int> > TableEntryFieldInfos = GetSpecialClassFieldInfo(TheLibrary, typeof(Attributes.MethodInfoStructAttribute)); ASM.ASMOp newMethodTableOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.MethodTable, currentTypeId, currentTypeName, AllMethodInfo, TableEntryFieldInfos); MethodTablesBlock.Append(newMethodTableOp); }
/// <summary> /// Scans the specified type (excludes fields and methods). /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="TheTypeInfo">The type to scan.</param> /// <param name="TypesTableBlock">The ASM block for the types table for the library currently being compiled.</param> private static void ScanType(ILLibrary TheLibrary, Types.TypeInfo TheTypeInfo, ASM.ASMBlock TypesTableBlock) { string TypeId = TheTypeInfo.ID; string SizeVal = TheTypeInfo.SizeOnHeapInBytes.ToString(); string IdVal = (TypesScanned++).ToString(); string StackSizeVal = TheTypeInfo.SizeOnStackInBytes.ToString(); string IsValueTypeVal = (TheTypeInfo.IsValueType ? "1" : "0"); string MethodTablePointer = TypeId + "_MethodTable"; string IsPointerTypeVal = (TheTypeInfo.IsPointer ? "1" : "0"); string BaseTypeIdVal = "0"; if (TheTypeInfo.UnderlyingType.BaseType != null) { if (!TheTypeInfo.UnderlyingType.BaseType.AssemblyQualifiedName.Contains("mscorlib")) { Types.TypeInfo baseTypeInfo = TheLibrary.GetTypeInfo(TheTypeInfo.UnderlyingType.BaseType); BaseTypeIdVal = baseTypeInfo.ID; //Declared external to this library, so won't appear in this library's type tables if ((ScannedTypes.ContainsKey(baseTypeInfo.ID) && ScannedTypes[baseTypeInfo.ID] != TheLibrary) || !TheLibrary.TypeInfos.Contains(baseTypeInfo)) { TypesTableBlock.AddExternalLabel(BaseTypeIdVal); } } } string FieldTablePointer = TypeId + "_FieldTable"; string TypeSignatureLiteralLabel = TheLibrary.AddStringLiteral(TheTypeInfo.UnderlyingType.FullName); // Legacy string TypeIdLiteralLabel = TheLibrary.AddStringLiteral(TheTypeInfo.ID); Types.TypeInfo typeTypeInfo = ILLibrary.SpecialClasses[typeof(Attributes.TypeClassAttribute)].First(); List <Types.FieldInfo> OrderedFields = typeTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderBy(x => x.OffsetInBytes).ToList(); List <Tuple <string, Types.TypeInfo> > FieldInformation = new List <Tuple <string, Types.TypeInfo> >(); foreach (Types.FieldInfo aTypeField in OrderedFields) { Types.TypeInfo FieldTypeInfo = TheLibrary.GetTypeInfo(aTypeField.FieldType); FieldInformation.Add(new Tuple <string, Types.TypeInfo>(aTypeField.Name, FieldTypeInfo)); } ASM.ASMOp newTypeTableOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.TypeTable, TypeId, SizeVal, IdVal, StackSizeVal, IsValueTypeVal, MethodTablePointer, IsPointerTypeVal, BaseTypeIdVal, FieldTablePointer, TypeSignatureLiteralLabel, TypeIdLiteralLabel, FieldInformation); TypesTableBlock.Append(newTypeTableOp); TypesTableBlock.AddExternalLabel(MethodTablePointer); TypesTableBlock.AddExternalLabel(FieldTablePointer); TypesTableBlock.AddExternalLabel(TypeSignatureLiteralLabel); TypesTableBlock.AddExternalLabel(TypeIdLiteralLabel); }
private static List <Tuple <string, int> > GetSpecialClassFieldInfo(ILLibrary TheLibrary, Type SpecialClassType) { Types.TypeInfo InformationAboutInfoStruct = ILLibrary.SpecialClasses[SpecialClassType].First(); List <Types.FieldInfo> InfoStruct_OrderedFields = InformationAboutInfoStruct.FieldInfos.Where(x => !x.IsStatic).OrderBy(x => x.OffsetInBytes).ToList(); List <Tuple <string, int> > InfoStruct_OrderedFieldInfo_Subset = new List <Tuple <string, int> >(); foreach (Types.FieldInfo aField in InfoStruct_OrderedFields) { Types.TypeInfo FieldTypeInfo = TheLibrary.GetTypeInfo(aField.FieldType); InfoStruct_OrderedFieldInfo_Subset.Add(new Tuple <string, int>(aField.Name, FieldTypeInfo.IsValueType ? FieldTypeInfo.SizeOnHeapInBytes : FieldTypeInfo.SizeOnStackInBytes)); } return(InfoStruct_OrderedFieldInfo_Subset); }
/// <summary> /// Compiles the specified IL library and any dependencies using the IL Reader, Il Preprocessor and IL Scanner. /// </summary> /// <remarks> /// The IL Compiler's steps read in the IL bytes for each block into IL ops and then preprocess and compile them /// into ASM ops. /// </remarks> /// <param name="TheLibrary">The library to compile.</param> /// <returns>CompileResult.OK if all steps complete successfully.</returns> public static CompileResult Compile(ILLibrary TheLibrary) { CompileResult Result = ExecuteILReader(TheLibrary); if (Result == CompileResult.OK) { Result = ExecuteILPreprocessor(TheLibrary); if (Result == CompileResult.OK) { Result = ExecuteILScanner(TheLibrary); } } return Result; }
/// <summary> /// Compiles the specified IL library and any dependencies using the IL Reader, Il Preprocessor and IL Scanner. /// </summary> /// <remarks> /// The IL Compiler's steps read in the IL bytes for each block into IL ops and then preprocess and compile them /// into ASM ops. /// </remarks> /// <param name="TheLibrary">The library to compile.</param> /// <returns>CompileResult.OK if all steps complete successfully.</returns> public static CompileResult Compile(ILLibrary TheLibrary) { CompileResult Result = ExecuteILReader(TheLibrary); if (Result == CompileResult.OK) { Result = ExecuteILPreprocessor(TheLibrary); if (Result == CompileResult.OK) { Result = ExecuteILScanner(TheLibrary); } } return(Result); }
/// <summary> /// Scans the specified type's static fields. /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="TheTypeInfo">The type to scan the static fields of.</param> /// <param name="StaticFieldsBlock">The ASM block for the static fields for the library currently being compiled.</param> private static void ScanStaticFields(ILLibrary TheLibrary, Types.TypeInfo TheTypeInfo, ASM.ASMBlock StaticFieldsBlock) { foreach (Types.FieldInfo aFieldInfo in TheTypeInfo.FieldInfos) { if (aFieldInfo.IsStatic) { Types.TypeInfo fieldTypeInfo = TheLibrary.GetTypeInfo(aFieldInfo.FieldType); string FieldID = aFieldInfo.ID; string Size = fieldTypeInfo.SizeOnStackInBytes.ToString(); ASM.ASMOp newStaticFieldOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.StaticField, FieldID, Size); StaticFieldsBlock.Append(newStaticFieldOp); } } }
/* Tasks of the IL Preprocessor: * - Pre-processing for special classes / methods: * - Static constructors * - Pre-scan IL ops to: * - Type Scan any local variable which are of an unscanned types * - Inject general ops (method start, method end, etc.) * - Inject GC IL ops * - Inject wrapping try-finally for GC * - Inject IL ops for try-catch-finally */ /// <summary> /// Preprocesses the specified IL library and any dependencies. /// </summary> /// <param name="TheLibrary">The library to preprocess.</param> public static void Preprocess(ILLibrary TheLibrary) { if (TheLibrary == null) { return; } if (TheLibrary.ILPreprocessed) { return; } TheLibrary.ILPreprocessed = true; foreach (IL.ILLibrary aDependency in TheLibrary.Dependencies) { Preprocess(aDependency); } foreach (Types.MethodInfo aMethodInfo in TheLibrary.ILBlocks.Keys) { PreprocessMethodInfo(TheLibrary, aMethodInfo); } foreach (Types.MethodInfo aMethodInfo in TheLibrary.ILBlocks.Keys) { if (!aMethodInfo.IsPlugged) { DealWithCatchHandlers(aMethodInfo, TheLibrary.ILBlocks[aMethodInfo]); InjectGeneral1(aMethodInfo, TheLibrary.ILBlocks[aMethodInfo]); InjectGC(TheLibrary, aMethodInfo, TheLibrary.ILBlocks[aMethodInfo]); InjectGeneral2(aMethodInfo, TheLibrary.ILBlocks[aMethodInfo]); InjectTryCatchFinally(aMethodInfo, TheLibrary.ILBlocks[aMethodInfo]); PreprocessILOps(TheLibrary, aMethodInfo, TheLibrary.ILBlocks[aMethodInfo]); } } }
/// <summary> /// Injects the garbage collector related IL ops into the specified method. /// </summary> /// <param name="TheLibrary">The library being compiled.</param> /// <param name="theMethodInfo">The method to inject ops into.</param> /// <param name="theILBlock">The IL block for the method to inject ops into.</param> private static void InjectGC(ILLibrary TheLibrary, Types.MethodInfo theMethodInfo, ILBlock theILBlock) { if (theMethodInfo.ApplyGC) { // Find the index of the MethodStart op int MethodStartOpPos = theILBlock.PositionOf(theILBlock.ILOps.Where(x => x is ILOps.MethodStart).First()); // Inject ops for incrementing ref. count of args at start of method int InjectIncArgsRefCountPos = MethodStartOpPos + 1; foreach (Types.VariableInfo argInfo in theMethodInfo.ArgumentInfos) { if (argInfo.TheTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(InjectIncArgsRefCountPos, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldarg, ValueBytes = BitConverter.GetBytes(argInfo.Position) }); theILBlock.ILOps.Insert(InjectIncArgsRefCountPos + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.IncrementRefCountMethodAttribute)].First().UnderlyingInfo }); } } // The following two things can be done within the same loop: // Inject ops for inc./dec. ref. counts of objects when written to: // - Arguments / Locals // - Fields / Static Fields // - Elements of Arrays // Add Cleanup Block and Inject finally-block ops for it // - Also remember the op for storing return value (if any) ILPreprocessState preprocessState = new ILPreprocessState() { TheILLibrary = TheLibrary, Input = theILBlock, CurrentStackFrame = new StackFrame() }; ExceptionHandledBlock CleanupExBlock = new ExceptionHandledBlock(); for (int opIndx = 0; opIndx < theILBlock.ILOps.Count; opIndx++) { ILOp currOp = theILBlock.ILOps[opIndx]; bool IncRefCount = false; int incOpIndexBy = 0; switch ((ILOp.OpCodes)currOp.opCode.Value) { case ILOp.OpCodes.Stsfld: #region Stsfld { int metadataToken = Utilities.ReadInt32(currOp.ValueBytes, 0); System.Reflection.FieldInfo theField = theMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.TypeInfo theFieldTypeInfo = TheLibrary.GetTypeInfo(theField.FieldType); if (theFieldTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(opIndx, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldsfld, ValueBytes = currOp.ValueBytes }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); IncRefCount = true; incOpIndexBy = 2; } } #endregion break; case ILOp.OpCodes.Stloc: case ILOp.OpCodes.Stloc_0: case ILOp.OpCodes.Stloc_1: case ILOp.OpCodes.Stloc_2: case ILOp.OpCodes.Stloc_3: case ILOp.OpCodes.Stloc_S: #region Stloc { UInt16 localIndex = 0; switch ((ILOp.OpCodes)currOp.opCode.Value) { case ILOp.OpCodes.Stloc: localIndex = (UInt16)Utilities.ReadInt16(currOp.ValueBytes, 0); break; case ILOp.OpCodes.Stloc_0: localIndex = 0; break; case ILOp.OpCodes.Stloc_1: localIndex = 1; break; case ILOp.OpCodes.Stloc_2: localIndex = 2; break; case ILOp.OpCodes.Stloc_3: localIndex = 3; break; case ILOp.OpCodes.Stloc_S: localIndex = (UInt16)currOp.ValueBytes[0]; break; } Types.TypeInfo LocalTypeInfo = theMethodInfo.LocalInfos[localIndex].TheTypeInfo; if (LocalTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(opIndx, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldloc, ValueBytes = BitConverter.GetBytes(localIndex) }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); IncRefCount = true; incOpIndexBy = 2; } } #endregion break; case ILOp.OpCodes.Stfld: #region Stfld { int metadataToken = Utilities.ReadInt32(currOp.ValueBytes, 0); System.Reflection.FieldInfo theField = theMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.TypeInfo theFieldTypeInfo = TheLibrary.GetTypeInfo(theField.FieldType); if (theFieldTypeInfo.IsGCManaged) { // Items on stack: // - Object reference // - (New) Value to store // // We want to load the current value of the field // for which we must duplicate the object ref // But first, we must remove the (new) value to store // off the stack, while also storing it to put back // on the stack after so the store can continue // // So: // 1. Switch value to store and object ref on stack // 3. Duplicate the object ref // 4. Load the field value // 5. Call dec ref count // 6. Switch value to store and object ref back again //USE A SWITCH STACK ITEMS OP!! theILBlock.ILOps.Insert(opIndx, new ILOps.StackSwitch() { StackSwitch_Items = 2 }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Dup }); theILBlock.ILOps.Insert(opIndx + 2, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldfld, ValueBytes = currOp.ValueBytes }); theILBlock.ILOps.Insert(opIndx + 3, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); theILBlock.ILOps.Insert(opIndx + 4, new ILOps.StackSwitch() { StackSwitch_Items = 2 }); IncRefCount = true; incOpIndexBy = 5; } } #endregion break; case ILOp.OpCodes.Stelem: case ILOp.OpCodes.Stelem_Ref: #region Stelem / Stelem_Ref { bool doDecrement = false; bool isRefOp = false; if ((ILOp.OpCodes)currOp.opCode.Value == ILOp.OpCodes.Stelem_Ref) { doDecrement = preprocessState.CurrentStackFrame.Stack.Peek().isGCManaged; isRefOp = true; } else { int metadataToken = Utilities.ReadInt32(currOp.ValueBytes, 0); Type elementType = theMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); doDecrement = TheLibrary.GetTypeInfo(elementType).IsGCManaged; } if (doDecrement) { // Items on stack: // - Array reference // - Index // - (New) Value to store // // We want to load the current value of the element at Index in the array // for which we must duplicate the array ref and index // But first, we must remove the (new) value to store // off the stack, while also storing it to put back // on the stack after so the store can continue // // So: // 1. Switch (rotate) 1 times the top 3 values so that index is on top // 2. Duplicate the index // 3. Switch (rotate) 2 times the top 4 values so that array ref is on top // 4. Duplicate the array ref // 5. Switch (rotate) 4 times the top 5 values so that duplicate array ref and index are on top // 6. Do LdElem op to load existing element value // 7. Call GC.DecrementRefCount // 8. Switch (rotate) 1 times the top 3 values so that the stack is in its original state // (9. Continue to increment ref count as normal) // // The following is a diagram of the stack manipulation occurring here: // Key: A=Array ref, I=Index, V=Value to store, E=Loaded element // Top-most stack item appears last // // 1) Rotate x 1 2) Duplicate 3) Rot x 2 4) Dup // A,I,V ---------> V,A,I ---------> V,A,I,I ---------> I,I,V,A ---------> I,I,V,A,A // // // 5) Rot x 4 6) Ldelem 7) Call GC (Dec) // I,I,V,A,A ---------> I,V,A,A,I ---------> I,V,A,E ---------> I,V,A // // // 8) Rot x 1 9) Dup 10) Call GC (Inc) // I,V,A ---------> A,I,V ---------> A,I,V,V ---------> A,I,V #region 1. theILBlock.ILOps.Insert(opIndx, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(3), StackSwitch_Items = 3 }); incOpIndexBy++; #endregion #region 2. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Dup }); incOpIndexBy++; #endregion #region 3. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(4), StackSwitch_Items = 4 }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(4), StackSwitch_Items = 4 }); incOpIndexBy++; #endregion #region 4. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Dup }); incOpIndexBy++; #endregion #region 5. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(5), StackSwitch_Items = 5 }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(5), StackSwitch_Items = 5 }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(5), StackSwitch_Items = 5 }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(5), StackSwitch_Items = 5 }); incOpIndexBy++; #endregion #region 6. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = isRefOp ? System.Reflection.Emit.OpCodes.Ldelem_Ref : System.Reflection.Emit.OpCodes.Ldelem, ValueBytes = currOp.ValueBytes }); incOpIndexBy++; #endregion #region 7. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); incOpIndexBy++; #endregion #region 8. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(3), StackSwitch_Items = 3 }); incOpIndexBy++; #endregion IncRefCount = true; } } #endregion break; case ILOp.OpCodes.Starg: case ILOp.OpCodes.Starg_S: #region Starg { UInt16 index = (ILOp.OpCodes)currOp.opCode.Value == ILOp.OpCodes.Starg_S ? (UInt16)currOp.ValueBytes[0] : (UInt16)Utilities.ReadInt16(currOp.ValueBytes, 0); if (theMethodInfo.ArgumentInfos[index].TheTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(opIndx, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldarg, ValueBytes = BitConverter.GetBytes(index) }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); IncRefCount = true; incOpIndexBy = 2; } } #endregion break; } if (IncRefCount && !preprocessState.CurrentStackFrame.Stack.Peek().isNewGCObject) { theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Dup }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.IncrementRefCountMethodAttribute)].First().UnderlyingInfo }); incOpIndexBy++; } // If op changed if (theILBlock.ILOps[opIndx] != currOp) { theILBlock.ILOps[opIndx].Offset = currOp.Offset; theILBlock.ILOps[opIndx].BytesSize = currOp.BytesSize; } // <= is correct. E.g. if 1 extra op added, incOpIndex=1 so <= results in currOp processed // + extra op processed bool UseNextOpAsCleanupStart = false; for (int i = 0; i <= incOpIndexBy; i++) { currOp = theILBlock.ILOps[opIndx]; if (UseNextOpAsCleanupStart) { UseNextOpAsCleanupStart = false; CleanupExBlock.Offset = currOp.Offset; } if (currOp is ILOps.MethodStart) { TargetArchitecture.MethodStartOp.PerformStackOperations(preprocessState, theILBlock.ILOps[opIndx]); UseNextOpAsCleanupStart = true; } else if (currOp is ILOps.MethodEnd) { TargetArchitecture.MethodEndOp.PerformStackOperations(preprocessState, theILBlock.ILOps[opIndx]); } else if (currOp is ILOps.StackSwitch) { TargetArchitecture.StackSwitchOp.PerformStackOperations(preprocessState, theILBlock.ILOps[opIndx]); } else { // Leave unsupported ops for the IL Scanner to deal with (or later code e.g. castclass op) if (TargetArchitecture.TargetILOps.ContainsKey((ILOp.OpCodes)currOp.opCode.Value)) { ILOp ConverterOp = TargetArchitecture.TargetILOps[(ILOp.OpCodes)currOp.opCode.Value]; ConverterOp.PerformStackOperations(preprocessState, currOp); } } if (i > 0) { opIndx++; } } } if (theMethodInfo.ArgumentInfos.Count > 0 || theMethodInfo.LocalInfos.Count > 0) { bool AddCleanupBlock = false; foreach (Types.VariableInfo anArgInfo in theMethodInfo.ArgumentInfos) { if (anArgInfo.TheTypeInfo.IsGCManaged) { AddCleanupBlock = true; break; } } if (!AddCleanupBlock) { foreach (Types.VariableInfo aLocInfo in theMethodInfo.LocalInfos) { if (aLocInfo.TheTypeInfo.IsGCManaged) { AddCleanupBlock = true; break; } } } if (AddCleanupBlock) { ILOp lastOp = theILBlock.ILOps.Last(); int lastOpOffset = lastOp.Offset; int lastOpIndex = theILBlock.ILOps.Count - 1; bool MethodHasReturnValue = false; // If there is a return value, we will need to temp store it if (theMethodInfo.UnderlyingInfo is System.Reflection.MethodInfo) { Type returnType = ((System.Reflection.MethodInfo)theMethodInfo.UnderlyingInfo).ReturnType; //Void return type = no return value if (returnType != typeof(void)) { // Add local variable for storing return value int lastLocalOffset = theMethodInfo.LocalInfos.Count > 0 ? theMethodInfo.LocalInfos.Last().Offset : 0; int lastLocalSize = theMethodInfo.LocalInfos.Count > 0 ? theMethodInfo.LocalInfos.Last().TheTypeInfo.SizeOnStackInBytes : 0; theMethodInfo.LocalInfos.Add(new Types.VariableInfo() { UnderlyingType = returnType, TheTypeInfo = TheLibrary.GetTypeInfo(returnType), Position = theMethodInfo.LocalInfos.Count, Offset = lastLocalOffset + lastLocalSize }); // Add op for storing return value, update op offsets theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Stloc, Offset = lastOpOffset, BytesSize = lastOp.BytesSize, ValueBytes = BitConverter.GetBytes(theMethodInfo.LocalInfos.Count - 1) }); lastOpIndex++; MethodHasReturnValue = true; } } ILOp leaveOp; // Add the Leave op of the try-block theILBlock.ILOps.Insert(lastOpIndex, leaveOp = new ILOp() { opCode = System.Reflection.Emit.OpCodes.Leave, Offset = lastOpOffset, BytesSize = lastOp.BytesSize, ValueBytes = BitConverter.GetBytes(0) }); lastOpIndex++; FinallyBlock CleanupFinallyBlock = new FinallyBlock() { Offset = lastOpOffset + lastOp.BytesSize, Length = 0 }; CleanupExBlock.Length = lastOpOffset - CleanupExBlock.Offset; CleanupExBlock.FinallyBlocks.Add(CleanupFinallyBlock); int cleanupOpsOffset = lastOpOffset + 1; // Add cleanup code for local variables (including the return value local) foreach (Types.VariableInfo aLocInfo in theMethodInfo.LocalInfos) { if (aLocInfo.TheTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldloc, Offset = cleanupOpsOffset, BytesSize = 1, ValueBytes = BitConverter.GetBytes(aLocInfo.Position) }); cleanupOpsOffset++; lastOpIndex++; theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, Offset = cleanupOpsOffset, BytesSize = 1, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); cleanupOpsOffset++; lastOpIndex++; CleanupFinallyBlock.Length += 2; } } // Add cleanup code for arguments foreach (Types.VariableInfo anArgInfo in theMethodInfo.ArgumentInfos) { if (anArgInfo.TheTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldarg, Offset = cleanupOpsOffset, BytesSize = 1, ValueBytes = BitConverter.GetBytes(anArgInfo.Position) }); cleanupOpsOffset++; lastOpIndex++; theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, Offset = cleanupOpsOffset, BytesSize = 1, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); cleanupOpsOffset++; lastOpIndex++; CleanupFinallyBlock.Length += 2; } } // Add end finally op theILBlock.ILOps.Insert(lastOpIndex, leaveOp.LoadAtILOpAfterOp = new ILOp() { opCode = System.Reflection.Emit.OpCodes.Endfinally, Offset = cleanupOpsOffset, BytesSize = 1 }); cleanupOpsOffset++; lastOpIndex++; CleanupFinallyBlock.Length++; // Add restore return value op if (MethodHasReturnValue) { theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldloc, Offset = cleanupOpsOffset, BytesSize = 1, ValueBytes = BitConverter.GetBytes(theMethodInfo.LocalInfos.Count - 1) }); cleanupOpsOffset++; lastOpIndex++; } // Add ex block to the method theILBlock.ExceptionHandledBlocks.Add(CleanupExBlock); // Replace any Ret ops contained within Cleanup Block with: // - Op to store return value (if any) // - Leave op bool Inside = false; for(int opIndx = 0; opIndx < theILBlock.ILOps.Count; opIndx++) { if (theILBlock.ILOps[opIndx].Offset > CleanupExBlock.Offset + CleanupExBlock.Length) { break; } else if (theILBlock.ILOps[opIndx].Offset >= CleanupExBlock.Offset) { Inside = true; } if (Inside && (ILOp.OpCodes)theILBlock.ILOps[opIndx].opCode.Value == ILOp.OpCodes.Ret) { ILOp ARetOp = theILBlock.ILOps[opIndx]; theILBlock.ILOps.RemoveAt(opIndx); if (MethodHasReturnValue) { theILBlock.ILOps.Insert(opIndx, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Stloc, Offset = ARetOp.Offset, ValueBytes = BitConverter.GetBytes(theMethodInfo.LocalInfos.Count - 1) }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { Offset = ARetOp.Offset, opCode = System.Reflection.Emit.OpCodes.Leave, ValueBytes = BitConverter.GetBytes(0), LoadAtILOpAfterOp = leaveOp.LoadAtILOpAfterOp }); } else { theILBlock.ILOps.Insert(opIndx, new ILOp() { Offset = ARetOp.Offset, opCode = System.Reflection.Emit.OpCodes.Leave, ValueBytes = BitConverter.GetBytes(0), LoadAtILOpAfterOp = leaveOp.LoadAtILOpAfterOp }); } } } } } } }
/// <summary> /// Preprocesses the IL ops of the specified method/IL block. /// </summary> /// <param name="TheLibrary">The library being compiled.</param> /// <param name="theMethodInfo">The method to preprocess.</param> /// <param name="theILBlock">The IL block for the method to preprocess.</param> private static void PreprocessILOps(ILLibrary TheLibrary, Types.MethodInfo theMethodInfo, ILBlock theILBlock) { StaticConstructorDependency staticConstructorDependencyRoot = null; if (theMethodInfo.UnderlyingInfo is System.Reflection.ConstructorInfo && theMethodInfo.IsStatic) { System.Reflection.ConstructorInfo aConstructor = (System.Reflection.ConstructorInfo)theMethodInfo.UnderlyingInfo; staticConstructorDependencyRoot = ILLibrary.TheStaticConstructorDependencyTree[aConstructor]; if (staticConstructorDependencyRoot == null) { staticConstructorDependencyRoot = new StaticConstructorDependency() { TheConstructor = aConstructor }; ILLibrary.TheStaticConstructorDependencyTree.Children.Add(staticConstructorDependencyRoot); } } ILPreprocessState preprosState = new ILPreprocessState() { TheILLibrary = TheLibrary, Input = theILBlock }; for (int i = 0; i < theILBlock.ILOps.Count; i++) { ILOp theOp = theILBlock.ILOps[i]; // Remove cast class ops if ((ILOp.OpCodes)theOp.opCode.Value == ILOp.OpCodes.Castclass) { theILBlock.ILOps.RemoveAt(i); i--; continue; } else if ((ILOp.OpCodes)theOp.opCode.Value == ILOp.OpCodes.Call) { if (theOp.MethodToCall != null && theOp.MethodToCall.DeclaringType.AssemblyQualifiedName.Contains("mscorlib")) { //We do not want to process ops which attempt to call methods in mscorlib! theILBlock.ILOps.RemoveAt(i); i--; //We do not allow calls to methods declared in MSCorLib. //Some of these calls can just be ignored (e.g. GetTypeFromHandle is // called by typeof operator). //Ones which can't be ignored, will result in an error...by virtue of // the fact that they were ignored when they were required. //But just to make sure we save ourselves a headache later when // runtime debugging, output a message saying we ignored the call. // TODO - IL level comments // result.ASM.AppendLine("; Call to method defined in MSCorLib ignored:"); // DEBUG INFO // result.ASM.AppendLine("; " + anILOpInfo.MethodToCall.DeclaringType.FullName + "." + anILOpInfo.MethodToCall.Name); // DEBUG INFO //If the method is a call to a constructor in MsCorLib: if (theOp.MethodToCall is System.Reflection.ConstructorInfo) { //Then we can presume it was a call to a base-class constructor (e.g. the Object constructor) // and so we just need to remove any args that were loaded onto the stack. // TODO: result.ASM.AppendLine("; Method to call was constructor so removing params"); // DEBUG INFO //Remove args from stack //If the constructor was non-static, then the first arg is the instance reference. if (!theOp.MethodToCall.IsStatic) { i++; theILBlock.ILOps.Insert(i, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Pop }); } foreach (System.Reflection.ParameterInfo anInfo in theOp.MethodToCall.GetParameters()) { i++; theILBlock.ILOps.Insert(i, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Pop }); } } } } try { ILOp ConverterOp = TargetArchitecture.TargetILOps[(ILOp.OpCodes)theOp.opCode.Value]; ConverterOp.Preprocess(preprosState, theOp); if (staticConstructorDependencyRoot != null) { //Create our static constructor dependency tree //Each of these ops could try to access a static method or field switch ((ILOp.OpCodes)theOp.opCode.Value) { case 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 if(theOp.ValueBytes != null && theOp.ValueBytes.Length > 0) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); System.Reflection.MethodBase methodBaseInf = theMethodInfo.UnderlyingInfo.Module.ResolveMethod(metadataToken); if (!(methodBaseInf.IsConstructor || methodBaseInf is System.Reflection.ConstructorInfo)) { System.Reflection.MethodInfo methodInf = (System.Reflection.MethodInfo)methodBaseInf; System.Reflection.ConstructorInfo[] staticConstructors = methodInf.DeclaringType.GetConstructors(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public) .Concat(methodInf.DeclaringType.GetConstructors(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) .ToArray(); if (staticConstructors.Length > 0) { System.Reflection.ConstructorInfo TheConstructor = staticConstructors[0]; if (staticConstructorDependencyRoot[TheConstructor] == null) { staticConstructorDependencyRoot.Children.Add(new StaticConstructorDependency() { TheConstructor = TheConstructor }); } } } } break; case ILOp.OpCodes.Ldsfld: case ILOp.OpCodes.Ldsflda: case ILOp.OpCodes.Stsfld: { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); System.Reflection.FieldInfo fieldInf = theMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); System.Reflection.ConstructorInfo[] staticConstructors = fieldInf.DeclaringType.GetConstructors(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public) .Concat(fieldInf.DeclaringType.GetConstructors(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) .ToArray(); if (staticConstructors.Length > 0) { System.Reflection.ConstructorInfo TheConstructor = staticConstructors[0]; if (staticConstructorDependencyRoot[TheConstructor] == null) { staticConstructorDependencyRoot.Children.Add(new StaticConstructorDependency() { TheConstructor = TheConstructor }); } } } break; } } } catch (KeyNotFoundException) { //Ignore - will be caught by Il scanner } catch (Exception ex) { Logger.LogError("ILPRE", theILBlock.TheMethodInfo.ToString(), 0, "Il Preprocessor error: PreprocessILOps: " + ex.Message); } } }
/// <summary> /// Gets the next unique ID for a method of the specified type. /// </summary> /// <remarks> /// Used for generatign IDs to go in the method tables for use in virtual calls (callvirt Il ops). /// </remarks> /// <param name="TheLibrary">The IL library being compiled.</param> /// <param name="aTypeInfo">The type to get the next method ID from.</param> /// <returns>The next unique method ID.</returns> private static int GetMethodIDGenerator(ILLibrary TheLibrary, Types.TypeInfo aTypeInfo) { int totalGen = aTypeInfo.MethodIDGenerator; if (aTypeInfo.UnderlyingType.BaseType != null) { if (!aTypeInfo.UnderlyingType.BaseType.AssemblyQualifiedName.Contains("mscorlib")) { totalGen += GetMethodIDGenerator(TheLibrary, aTypeInfo.UnderlyingType.BaseType); } } return totalGen; }
/// <summary> /// Gets the next unique ID for a method of the specified type. /// </summary> /// <remarks> /// Used for generatign IDs to go in the method tables for use in virtual calls (callvirt Il ops). /// </remarks> /// <param name="TheLibrary">The IL library being compiled.</param> /// <param name="aType">The type to get the next method ID from.</param> /// <returns>The next unique method ID.</returns> private static int GetMethodIDGenerator(ILLibrary TheLibrary, Type aType) { Types.TypeInfo aTypeInfo = TheLibrary.GetTypeInfo(aType); return GetMethodIDGenerator(TheLibrary, aTypeInfo); }
/// <summary> /// Preprocesses the specified method. /// </summary> /// <param name="TheLibrary">The library being compiled.</param> /// <param name="theMethodInfo">The method to preprocess.</param> private static void PreprocessMethodInfo(ILLibrary TheLibrary, Types.MethodInfo theMethodInfo) { if (theMethodInfo.Preprocessed) { return; } theMethodInfo.Preprocessed = true; string sig = theMethodInfo.Signature; bool SetMethodID = true; if (!theMethodInfo.IsConstructor) { System.Reflection.MethodInfo methodInf = (System.Reflection.MethodInfo)theMethodInfo.UnderlyingInfo; if (methodInf.GetBaseDefinition() != methodInf) { Types.MethodInfo baseMethodInfo = TheLibrary.GetMethodInfo(methodInf.GetBaseDefinition()); PreprocessMethodInfo(TheLibrary, baseMethodInfo); theMethodInfo.IDValue = baseMethodInfo.IDValue; SetMethodID = false; } } if (SetMethodID) { Types.TypeInfo declarerTypeInfo = TheLibrary.GetTypeInfo(theMethodInfo.UnderlyingInfo.DeclaringType); int ID = GetMethodIDGenerator(TheLibrary, declarerTypeInfo); theMethodInfo.IDValue = ID + 1; declarerTypeInfo.MethodIDGenerator++; } int totalLocalsOffset = 0; foreach (Types.VariableInfo aVarInfo in theMethodInfo.LocalInfos) { //Causes processing of the type - in case it hasn't already been processed Types.TypeInfo aTypeInfo = TheLibrary.GetTypeInfo(aVarInfo.UnderlyingType); aVarInfo.TheTypeInfo = aTypeInfo; aVarInfo.Offset = totalLocalsOffset; totalLocalsOffset += aTypeInfo.SizeOnStackInBytes; } int totalArgsSize = 0; if (!theMethodInfo.IsStatic) { Types.VariableInfo newVarInfo = new Types.VariableInfo() { UnderlyingType = theMethodInfo.UnderlyingInfo.DeclaringType, Position = 0, TheTypeInfo = TheLibrary.GetTypeInfo(theMethodInfo.UnderlyingInfo.DeclaringType) }; theMethodInfo.ArgumentInfos.Add(newVarInfo); totalArgsSize += newVarInfo.TheTypeInfo.SizeOnStackInBytes; } System.Reflection.ParameterInfo[] args = theMethodInfo.UnderlyingInfo.GetParameters(); foreach (System.Reflection.ParameterInfo argItem in args) { Types.VariableInfo newVarInfo = new Types.VariableInfo() { UnderlyingType = argItem.ParameterType, Position = theMethodInfo.ArgumentInfos.Count, TheTypeInfo = TheLibrary.GetTypeInfo(argItem.ParameterType) }; theMethodInfo.ArgumentInfos.Add(newVarInfo); totalArgsSize += newVarInfo.TheTypeInfo.SizeOnStackInBytes; } //System.Reflection.ParameterInfo returnArgItem = (theMethodInfo.IsConstructor ? null : ((System.Reflection.MethodInfo)theMethodInfo.UnderlyingInfo).ReturnParameter); //if (returnArgItem != null) //{ // Types.VariableInfo newVarInfo = new Types.VariableInfo() // { // UnderlyingType = returnArgItem.ParameterType, // Position = theMethodInfo.ArgumentInfos.Count, // TheTypeInfo = TheLibrary.GetTypeInfo(returnArgItem.ParameterType) // }; // theMethodInfo.ArgumentInfos.Add(newVarInfo); // totalArgsSize += newVarInfo.TheTypeInfo.SizeOnStackInBytes; //} int offset = totalArgsSize; for (int i = 0; i < theMethodInfo.ArgumentInfos.Count; i++) { offset -= theMethodInfo.ArgumentInfos[i].TheTypeInfo.SizeOnStackInBytes; theMethodInfo.ArgumentInfos[i].Offset = offset; } }
/// <summary> /// Preprocesses any special methods within the specified library. /// </summary> /// <param name="RootLibrary">The root library being compiled.</param> public static void PreprocessSpecialMethods(ILLibrary RootLibrary) { // Setup calls to Static Constructors Types.MethodInfo CallStaticConstructorsInfo = ILLibrary.SpecialMethods[typeof(Attributes.CallStaticConstructorsMethodAttribute)].First(); ILBlock CallStaticConstructorsBlock = RootLibrary.GetILBlock(CallStaticConstructorsInfo); List<System.Reflection.ConstructorInfo> staticConstructorsToCall = ILLibrary.TheStaticConstructorDependencyTree.Flatten(); foreach (System.Reflection.ConstructorInfo anInfo in staticConstructorsToCall) { CallStaticConstructorsBlock.ILOps.Insert(CallStaticConstructorsBlock.ILOps.Count - 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, ValueBytes = null, MethodToCall = anInfo } ); } }
/// <summary> /// Executes the IL Scanner for the specified library. /// </summary> /// <param name="TheLibrary">The library to scan.</param> /// <returns>The return value from the IL Scanner.</returns> private static CompileResult ExecuteILScanner(ILLibrary TheLibrary) { CompileResult result = CompileResult.OK; result = ILScanner.Scan(TheLibrary); return result; }
public static void SaveLibraryInfo(string FolderPath, IL.ILLibrary TheLibrary) { string RootAssemblyName = Utilities.CleanFileName(TheLibrary.TheAssembly.GetName().Name); using (StreamWriter Str = new StreamWriter(Path.Combine(FolderPath, RootAssemblyName + "_Dependencies.txt"), false)) { foreach (IL.ILLibrary DependencyLibrary in TheLibrary.Dependencies) { Str.WriteLine(Utilities.CleanFileName(DependencyLibrary.TheAssembly.GetName().Name)); } } using (StreamWriter Str = new StreamWriter(Path.Combine(FolderPath, RootAssemblyName + "_Library.txt"), false)) { foreach (Types.TypeInfo ATypeInfo in TheLibrary.TypeInfos) { //TypeID //¬BaseTypeID:[ID] //¬IsGCManaged:[Boolean] //¬IsPointer:[Boolean] //¬IsValueType:[Boolean] //¬SizeOnHeapInBytes:[Integer] //¬SizeOnStackInBytes:[Integer] //|Field:[ID] //~Type:[TypeID] //~IsStatic:[Boolean] //~Name:[String] //~OffsetInBytes:[Integer] //|Method:[ID] //~ApplyDebug:[Boolean] //~ApplyGC:[Boolean] //~IDValue:[Integer] //~IsConstructor:[Boolean] //~IsPlugged:[Boolean] //~IsStatic:[Boolean] //~Signature:[String] //~Argument:Offset|Position|TypeID //~Local:Offset|Position|TypeID Str.WriteLine(ATypeInfo.ID); if (ATypeInfo.UnderlyingType.BaseType != null && !ATypeInfo.UnderlyingType.BaseType.AssemblyQualifiedName.Contains("mscorlib")) { Str.WriteLine("¬BaseTypeID:" + TheLibrary.GetTypeInfo(ATypeInfo.UnderlyingType.BaseType).ID); } Str.WriteLine("¬IsGCManaged:" + ATypeInfo.IsGCManaged.ToString()); Str.WriteLine("¬IsPointer:" + ATypeInfo.IsPointer.ToString()); Str.WriteLine("¬IsValueType:" + ATypeInfo.IsValueType.ToString()); Str.WriteLine("¬SizeOnHeapInBytes:" + ATypeInfo.SizeOnHeapInBytes.ToString()); Str.WriteLine("¬SizeOnStackInBytes:" + ATypeInfo.SizeOnStackInBytes.ToString()); foreach (Types.FieldInfo AFieldInfo in ATypeInfo.FieldInfos) { Str.WriteLine("|Field:" + AFieldInfo.ID); Str.WriteLine("~Type:" + TheLibrary.GetTypeInfo(AFieldInfo.FieldType).ID); Str.WriteLine("~IsStatic:" + AFieldInfo.IsStatic.ToString()); Str.WriteLine("~Name:" + AFieldInfo.Name); Str.WriteLine("~OffsetInBytes:" + AFieldInfo.OffsetInBytes.ToString()); } foreach (Types.MethodInfo AMethodInfo in ATypeInfo.MethodInfos) { Str.WriteLine("|Method:" + AMethodInfo.ID); Str.WriteLine("~ApplyDebug:" + AMethodInfo.ApplyDebug.ToString()); Str.WriteLine("~ApplyGC:" + AMethodInfo.ApplyGC.ToString()); Str.WriteLine("~IDValue:" + AMethodInfo.IDValue.ToString()); Str.WriteLine("~IsConstructor:" + AMethodInfo.IsConstructor.ToString()); Str.WriteLine("~IsPlugged:" + AMethodInfo.IsPlugged.ToString()); Str.WriteLine("~IsStatic:" + AMethodInfo.IsStatic.ToString()); Str.WriteLine("~Signature:" + AMethodInfo.Signature); Type RetType = (AMethodInfo.IsConstructor ? typeof(void) : ((System.Reflection.MethodInfo)AMethodInfo.UnderlyingInfo).ReturnType); Str.WriteLine("~ReturnSize:" + Types.TypeScanner.GetSizeOnStackInBytes(RetType)); foreach (Types.VariableInfo AnArgumentInfo in AMethodInfo.ArgumentInfos) { Str.WriteLine("~Argument:" + AnArgumentInfo.Offset.ToString() + "|" + AnArgumentInfo.Position.ToString() + "|" + AnArgumentInfo.TheTypeInfo.ID); } foreach (Types.VariableInfo ALocalInfo in AMethodInfo.LocalInfos) { Str.WriteLine("~Local:" + ALocalInfo.Offset.ToString() + "|" + ALocalInfo.Position.ToString() + "|" + ALocalInfo.TheTypeInfo.ID); } } } } }
/// <summary> /// Performs the link. /// </summary> /// <param name="TheLibrary">The root library to link.</param> /// <returns>CompileResult.OK if the link succeeded. Otherwise, CompileResult.Fail.</returns> public static CompileResult Link(IL.ILLibrary TheLibrary, bool dependency = false, string Name = null) { bool OK = true; // If: Link to ELF and Libraries // - Link sub-libs to .a files // - Link main lib to .elf file (if present) // If: Link to ISO // - Generate basic link-script // - Generate full link-script by inserting necessary file location instructions for all object files // - Execute ld to build bin file // - Execute ISO9660Generator to build .ISO file if (Options.LinkMode == Options.LinkModes.ELF) { // Check for main method. If found, that library gets linked to Executable not Shared Lib List <string> depLibNames = new List <string>(); foreach (IL.ILLibrary depLib in TheLibrary.Dependencies) { string depLibName = Utilities.CleanFileName(depLib.TheAssembly.GetName().Name); if (Options.ShortenDependencyNames) { if (!DependencyNameMapping.ContainsKey(depLibName)) { DependencyNameMapping.Add(depLibName, (NameGenerator++).ToString()); } depLibName = DependencyNameMapping[depLibName]; } depLibNames.Add(depLibName); OK = OK && (Link(depLib, true, depLibName) == CompileResult.OK); if (!OK) { break; } } if (!OK) { return(CompileResult.Fail); } List <ASM.ASMBlock> SequencedASMBlocks = new List <ASM.ASMBlock>(); SequencedASMBlocks.AddRange(TheLibrary.TheASMLibrary.ASMBlocks); SequencedASMBlocks.Sort(GetOrder); SequencedASMBlocks.ForEach(delegate(ASM.ASMBlock block) { if (block != null && block.OriginMethodInfo != null) { DebugDataWriter.AddMethodMapping(block.OriginMethodInfo.ID, block.ASMOutputFilePath); } }); // Find start method if any, use as ENTRY point bool ExecutableOutput = false; string EntryPoint = null; if (IL.ILLibrary.SpecialMethods.ContainsKey(typeof(Attributes.MainMethodAttribute))) { Types.MethodInfo mainMethodInfo = IL.ILLibrary.SpecialMethods[typeof(Attributes.MainMethodAttribute)].First(); IL.ILBlock mainMethodBlock = TheLibrary.GetILBlock(mainMethodInfo, false); if (mainMethodBlock != null) { ExecutableOutput = true; EntryPoint = mainMethodInfo.ID; } } if (Options.ShortenDependencyNames && string.IsNullOrWhiteSpace(Name)) { Name = "Driver"; } string AssemblyName = string.IsNullOrWhiteSpace(Name) ? Utilities.CleanFileName(TheLibrary.TheAssembly.GetName().Name) : Name; DebugDataWriter.SaveDataFiles(Options.OutputPath, AssemblyName); DebugDataWriter.SaveLibraryInfo(Options.OutputPath, TheLibrary); LinkInformation LinkInfo = new LinkInformation() { ToolsPath = Options.ToolsPath, LinkScriptCmdPath = Path.Combine(Options.OutputPath, @"DriversCompiler\" + AssemblyName + "_linker_command.txt"), LinkScriptPath = Path.Combine(Options.OutputPath, @"DriversCompiler\" + AssemblyName + "_linker.ld"), BinPath = Path.Combine(Options.OutputPath, "Output\\" + (ExecutableOutput ? AssemblyName + ".elf" : "Lib" + AssemblyName + ".a")), MapPath = Path.Combine(Options.OutputPath, AssemblyName + ".map"), ASMPath = Path.Combine(Options.OutputPath, AssemblyName + ".new.asm"), LdWorkingDir = Path.Combine(Options.OutputPath, "") + "\\", ExecutableOutput = ExecutableOutput, EntryPoint = EntryPoint, SequencedASMBlocks = SequencedASMBlocks, depLibNames = depLibNames }; if (!Directory.Exists(Path.GetDirectoryName(LinkInfo.BinPath))) { Directory.CreateDirectory(Path.GetDirectoryName(LinkInfo.BinPath)); } OK = TargetArchitecture.TargetFunctions.LinkELF(TheLibrary, LinkInfo); if (OK) { DebugDataWriter.ProcessMapFile(LinkInfo.MapPath); } } else if (Options.LinkMode == Options.LinkModes.ISO) { List <ASM.ASMBlock> SequencedASMBlocks = new List <ASM.ASMBlock>(); List <IL.ILLibrary> FlattenedLibs = TheLibrary.Flatten(); foreach (IL.ILLibrary depLib in FlattenedLibs) { SequencedASMBlocks.AddRange(depLib.TheASMLibrary.ASMBlocks); DebugDataWriter.SaveLibraryInfo(Options.OutputPath, depLib); } SequencedASMBlocks.Sort(GetOrder); SequencedASMBlocks.ForEach(delegate(ASM.ASMBlock block) { if (block != null && block.OriginMethodInfo != null) { DebugDataWriter.AddMethodMapping(block.OriginMethodInfo.ID, block.ASMOutputFilePath); } }); string AssemblyName = Utilities.CleanFileName(TheLibrary.TheAssembly.GetName().Name); DebugDataWriter.SaveDataFiles(Options.OutputPath, AssemblyName); DebugDataWriter.SaveLibraryInfo(Options.OutputPath, TheLibrary); LinkInformation LinkInfo = new LinkInformation() { ToolsPath = Options.ToolsPath, ISOGenPath = Path.Combine(Options.ToolsPath, @"ISO9660Generator.exe"), ISOToolsDirPath = Path.Combine(Options.ToolsPath, @"ISO"), ISODirPath = Path.Combine(Options.OutputPath, @"DriversCompiler\ISO"), LinkScriptPath = Path.Combine(Options.OutputPath, @"DriversCompiler\linker.ld"), BinPath = Path.Combine(Options.OutputPath, @"DriversCompiler\ISO\Kernel.bin"), ISOLinuxPath = Path.Combine(Options.OutputPath, @"DriversCompiler\ISO\" + (Options.BuildMode == Options.BuildModes.Debug ? "isolinux-debug.bin" : "isolinux.bin")), ISOPath = Path.Combine(Options.OutputPath, AssemblyName + ".iso"), MapPath = Path.Combine(Options.OutputPath, AssemblyName + ".map"), ASMPath = Path.Combine(Options.OutputPath, AssemblyName + ".new.asm"), LdWorkingDir = Path.Combine(Options.OutputPath, "DriversCompiler") + "\\", SequencedASMBlocks = SequencedASMBlocks }; if (Directory.Exists(LinkInfo.ISODirPath)) { Directory.Delete(LinkInfo.ISODirPath, true); } CopyDirectory(LinkInfo.ISOToolsDirPath, LinkInfo.ISODirPath, true); OK = TargetArchitecture.TargetFunctions.LinkISO(TheLibrary, LinkInfo); if (OK) { DebugDataWriter.ProcessMapFile(LinkInfo.MapPath); } } return(OK ? CompileResult.OK : CompileResult.Fail); }
/// <summary> /// Scans the specified non-plugged IL block. /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="theMethodInfo">The method which generated the IL block.</param> /// <param name="theILBlock">The IL block to scan.</param> /// <returns>CompileResult.OK.</returns> private static CompileResult ScanNonpluggedILBlock(ILLibrary TheLibrary, Types.MethodInfo theMethodInfo, ILBlock theILBlock) { CompileResult result = CompileResult.OK; ASM.ASMBlock TheASMBlock = new ASM.ASMBlock() { OriginMethodInfo = theMethodInfo, Priority = theMethodInfo.Priority }; ILConversionState convState = new ILConversionState() { TheILLibrary = TheLibrary, CurrentStackFrame = new StackFrame(), Input = theILBlock, Result = TheASMBlock }; foreach (ILOp anOp in theILBlock.ILOps) { try { string commentText = TheASMBlock.GenerateILOpLabel(convState.PositionOf(anOp), "") + " -- " + anOp.opCode.ToString() + " -- Offset: " + anOp.Offset.ToString("X2"); ASM.ASMOp newCommentOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.Comment, commentText); TheASMBlock.ASMOps.Add(newCommentOp); int currCount = TheASMBlock.ASMOps.Count; if (anOp is ILOps.MethodStart) { TargetArchitecture.MethodStartOp.Convert(convState, anOp); } else if (anOp is ILOps.MethodEnd) { TargetArchitecture.MethodEndOp.Convert(convState, anOp); } else if (anOp is ILOps.StackSwitch) { TargetArchitecture.StackSwitchOp.Convert(convState, anOp); } else { ILOp ConverterOp = TargetArchitecture.TargetILOps[(ILOp.OpCodes)anOp.opCode.Value]; ConverterOp.Convert(convState, anOp); } if (anOp.LabelRequired) { if (currCount < TheASMBlock.ASMOps.Count) { TheASMBlock.ASMOps[currCount].ILLabelPosition = convState.PositionOf(anOp); TheASMBlock.ASMOps[currCount].RequiresILLabel = true; } } } catch (KeyNotFoundException) { result = CompileResult.PartialFailure; Logger.LogError(Errors.ILCompiler_ScanILOpFailure_ErrorCode, theMethodInfo.ToString(), anOp.Offset, string.Format(Errors.ErrorMessages[Errors.ILCompiler_ScanILOpFailure_ErrorCode], "Conversion IL op not found: " + Enum.GetName(typeof(ILOp.OpCodes), anOp.opCode.Value) + ".")); } catch (InvalidOperationException) { result = CompileResult.PartialFailure; Logger.LogError(Errors.ILCompiler_ScanILOpFailure_ErrorCode, theMethodInfo.ToString(), anOp.Offset, string.Format(Errors.ErrorMessages[Errors.ILCompiler_ScanILOpFailure_ErrorCode], Enum.GetName(typeof(ILOp.OpCodes), anOp.opCode.Value))); } catch (NotSupportedException ex) { result = CompileResult.PartialFailure; Logger.LogError(Errors.ILCompiler_ScanILOpFailure_ErrorCode, theMethodInfo.ToString(), anOp.Offset, string.Format(Errors.ErrorMessages[Errors.ILCompiler_ScanILOpFailure_ErrorCode], "An IL op reported something as not supported. " + Enum.GetName(typeof(ILOp.OpCodes), anOp.opCode.Value) + ". " + ex.Message)); } catch (Exception ex) { result = CompileResult.Fail; Logger.LogError(Errors.ILCompiler_ScanILOpFailure_ErrorCode, theMethodInfo.ToString(), anOp.Offset, string.Format(Errors.ErrorMessages[Errors.ILCompiler_ScanILOpFailure_ErrorCode], ex.Message)); } } TheLibrary.TheASMLibrary.ASMBlocks.Add(TheASMBlock); return(result); }
public abstract bool LinkISO(IL.ILLibrary TheLibrary, LinkInformation LinkInfo);
/// <summary> /// Scans the specified type's non-static fields. /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="TheTypeInfo">The type to scan the non-static fields of.</param> /// <param name="FieldTablesBlock">The ASM block for the fields table for the library currently being compiled.</param> private static void ScanFields(ILLibrary TheLibrary, Types.TypeInfo TheTypeInfo, ASM.ASMBlock FieldTablesBlock) { string currentTypeId = TheTypeInfo.ID; string currentTypeName = TheTypeInfo.UnderlyingType.FullName; List<Tuple<string, string, string>> AllFieldInfo = new List<Tuple<string, string, string>>(); if (TheTypeInfo.UnderlyingType.BaseType == null || (TheTypeInfo.UnderlyingType.BaseType.FullName != "System.Array" && TheTypeInfo.UnderlyingType.BaseType.FullName != "System.MulticastDelegate")) { foreach (Types.FieldInfo anOwnField in TheTypeInfo.FieldInfos) { if (!anOwnField.IsStatic) { Types.TypeInfo FieldTypeInfo = TheLibrary.GetTypeInfo(anOwnField.FieldType); string fieldOffsetVal = anOwnField.OffsetInBytes.ToString(); string fieldSizeVal = (FieldTypeInfo.IsValueType ? FieldTypeInfo.SizeOnHeapInBytes : FieldTypeInfo.SizeOnStackInBytes).ToString(); string fieldTypeIdVal = FieldTypeInfo.ID; FieldTablesBlock.AddExternalLabel(fieldTypeIdVal); AllFieldInfo.Add(new Tuple<string, string, string>(fieldOffsetVal, fieldSizeVal, fieldTypeIdVal)); } } } string parentTypeFieldTablePtr = "0"; bool parentPtrIsExternal = false; if (TheTypeInfo.UnderlyingType.BaseType != null) { if (!TheTypeInfo.UnderlyingType.BaseType.AssemblyQualifiedName.Contains("mscorlib")) { Types.TypeInfo baseTypeInfo = TheLibrary.GetTypeInfo(TheTypeInfo.UnderlyingType.BaseType); parentPtrIsExternal = (ScannedTypes.ContainsKey(baseTypeInfo.ID) && ScannedTypes[baseTypeInfo.ID] != TheLibrary) || !TheLibrary.TypeInfos.Contains(baseTypeInfo); parentTypeFieldTablePtr = baseTypeInfo.ID + "_FieldTable"; } } { string fieldOffsetVal = "0"; string fieldSizeVal = "0"; string fieldTypeIdVal = parentTypeFieldTablePtr; if (parentPtrIsExternal) { FieldTablesBlock.AddExternalLabel(fieldTypeIdVal); } AllFieldInfo.Add(new Tuple<string, string, string>(fieldOffsetVal, fieldSizeVal, fieldTypeIdVal)); } List<Tuple<string, int>> TableEntryFieldInfos = GetSpecialClassFieldInfo(TheLibrary, typeof(Attributes.FieldInfoStructAttribute)); ASM.ASMOp newFieldTableOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.FieldTable, currentTypeId, currentTypeName, AllFieldInfo, TableEntryFieldInfos); FieldTablesBlock.Append(newFieldTableOp); }
/// <summary> /// Scans the specified type's methods. /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="TheTypeInfo">The type to scan the methods of.</param> /// <param name="MethodTablesBlock">The ASM block for the methods table for the library currently being compiled.</param> private static void ScanMethods(ILLibrary TheLibrary, Types.TypeInfo TheTypeInfo, ASM.ASMBlock MethodTablesBlock) { string currentTypeId = TheTypeInfo.ID; string currentTypeName = TheTypeInfo.UnderlyingType.FullName; List<Tuple<string, string>> AllMethodInfo = new List<Tuple<string, string>>(); if (TheTypeInfo.UnderlyingType.BaseType == null || TheTypeInfo.UnderlyingType.BaseType.FullName != "System.Array") { foreach (Types.MethodInfo aMethodInfo in TheTypeInfo.MethodInfos) { if (!aMethodInfo.IsStatic && !aMethodInfo.UnderlyingInfo.IsAbstract) { string methodID = aMethodInfo.ID; string methodIDValue = aMethodInfo.IDValue.ToString(); MethodTablesBlock.AddExternalLabel(methodID); AllMethodInfo.Add(new Tuple<string, string>(methodID, methodIDValue)); } } } string parentTypeMethodTablePtr = "0"; bool parentPtrIsExternal = false; if (TheTypeInfo.UnderlyingType.BaseType != null) { if (!TheTypeInfo.UnderlyingType.BaseType.AssemblyQualifiedName.Contains("mscorlib")) { Types.TypeInfo baseTypeInfo = TheLibrary.GetTypeInfo(TheTypeInfo.UnderlyingType.BaseType); parentPtrIsExternal = (ScannedTypes.ContainsKey(baseTypeInfo.ID) && ScannedTypes[baseTypeInfo.ID] != TheLibrary) || !TheLibrary.TypeInfos.Contains(baseTypeInfo); parentTypeMethodTablePtr = baseTypeInfo.ID + "_MethodTable"; } } { string methodID = parentTypeMethodTablePtr; string methodIDValue = "0"; if (parentPtrIsExternal) { MethodTablesBlock.AddExternalLabel(methodID); } AllMethodInfo.Add(new Tuple<string,string>(methodID, methodIDValue)); } List<Tuple<string, int>> TableEntryFieldInfos = GetSpecialClassFieldInfo(TheLibrary, typeof(Attributes.MethodInfoStructAttribute)); ASM.ASMOp newMethodTableOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.MethodTable, currentTypeId, currentTypeName, AllMethodInfo, TableEntryFieldInfos); MethodTablesBlock.Append(newMethodTableOp); }
/// <summary> /// Gets the next unique ID for a method of the specified type. /// </summary> /// <remarks> /// Used for generatign IDs to go in the method tables for use in virtual calls (callvirt Il ops). /// </remarks> /// <param name="TheLibrary">The IL library being compiled.</param> /// <param name="aTypeInfo">The type to get the next method ID from.</param> /// <returns>The next unique method ID.</returns> private static int GetMethodIDGenerator(ILLibrary TheLibrary, Types.TypeInfo aTypeInfo, bool useMethodCount = false) { int totalGen = 0; if (useMethodCount) { totalGen = aTypeInfo.MethodInfos.Count; } else { totalGen = aTypeInfo.MethodIDGenerator; } if (aTypeInfo.UnderlyingType.BaseType != null) { if (!aTypeInfo.UnderlyingType.BaseType.AssemblyQualifiedName.Contains("mscorlib")) { totalGen += GetMethodIDGenerator(TheLibrary, aTypeInfo.UnderlyingType.BaseType, true); } } return totalGen; }
/// <summary> /// Preprocesses any special classes within the specified library. /// </summary> /// <param name="RootLibrary">The root library being compiled.</param> public static void PreprocessSpecialClasses(ILLibrary RootLibrary) { //Is there anything to do here? }
/// <summary> /// Scans the specified type (excludes fields and methods). /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="TheTypeInfo">The type to scan.</param> /// <param name="TypesTableBlock">The ASM block for the types table for the library currently being compiled.</param> private static void ScanType(ILLibrary TheLibrary, Types.TypeInfo TheTypeInfo, ASM.ASMBlock TypesTableBlock) { string TypeId = TheTypeInfo.ID; string SizeVal = TheTypeInfo.SizeOnHeapInBytes.ToString(); string IdVal = (TypesScanned++).ToString(); string StackSizeVal = TheTypeInfo.SizeOnStackInBytes.ToString(); string IsValueTypeVal = (TheTypeInfo.IsValueType ? "1" : "0"); string MethodTablePointer = TypeId + "_MethodTable"; string IsPointerTypeVal = (TheTypeInfo.IsPointer ? "1" : "0"); string BaseTypeIdVal = "0"; if (TheTypeInfo.UnderlyingType.BaseType != null) { if (!TheTypeInfo.UnderlyingType.BaseType.AssemblyQualifiedName.Contains("mscorlib")) { Types.TypeInfo baseTypeInfo = TheLibrary.GetTypeInfo(TheTypeInfo.UnderlyingType.BaseType); BaseTypeIdVal = baseTypeInfo.ID; //Declared external to this library, so won't appear in this library's type tables if ((ScannedTypes.ContainsKey(baseTypeInfo.ID) && ScannedTypes[baseTypeInfo.ID] != TheLibrary) || !TheLibrary.TypeInfos.Contains(baseTypeInfo)) { TypesTableBlock.AddExternalLabel(BaseTypeIdVal); } } } string FieldTablePointer = TypeId + "_FieldTable"; string TypeSignatureLiteralLabel = TheLibrary.AddStringLiteral(TheTypeInfo.UnderlyingType.FullName); // Legacy string TypeIdLiteralLabel = TheLibrary.AddStringLiteral(TheTypeInfo.ID); Types.TypeInfo typeTypeInfo = ILLibrary.SpecialClasses[typeof(Attributes.TypeClassAttribute)].First(); List<Types.FieldInfo> OrderedFields = typeTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderBy(x => x.OffsetInBytes).ToList(); List<Tuple<string, Types.TypeInfo>> FieldInformation = new List<Tuple<string, Types.TypeInfo>>(); foreach (Types.FieldInfo aTypeField in OrderedFields) { Types.TypeInfo FieldTypeInfo = TheLibrary.GetTypeInfo(aTypeField.FieldType); FieldInformation.Add(new Tuple<string, Types.TypeInfo>(aTypeField.Name, FieldTypeInfo)); } ASM.ASMOp newTypeTableOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.TypeTable, TypeId, SizeVal, IdVal, StackSizeVal, IsValueTypeVal, MethodTablePointer, IsPointerTypeVal, BaseTypeIdVal, FieldTablePointer, TypeSignatureLiteralLabel, TypeIdLiteralLabel, FieldInformation); TypesTableBlock.Append(newTypeTableOp); TypesTableBlock.AddExternalLabel(MethodTablePointer); TypesTableBlock.AddExternalLabel(FieldTablePointer); TypesTableBlock.AddExternalLabel(TypeSignatureLiteralLabel); TypesTableBlock.AddExternalLabel(TypeIdLiteralLabel); }
/// <summary> /// Scans the specified library and any dependencies. /// </summary> /// <param name="TheLibrary">The library to scan.</param> /// <returns> /// CompileResult.OK if completed successfully. /// Otherwise CompileResult.PartialFail or CompileResult.Error depending on /// the extent of the problem. /// </returns> public static CompileResult Scan(ILLibrary TheLibrary) { CompileResult result = CompileResult.OK; if (TheLibrary.ILScanned) { return result; } TheLibrary.ILScanned = true; foreach (ILLibrary depLib in TheLibrary.Dependencies) { Scan(depLib); } // Create / Add Static Fields ASM Block ASM.ASMBlock StaticFieldsBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) - 9 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(StaticFieldsBlock); // Create / Add Types Table ASM Block ASM.ASMBlock TypesTableBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) - 8 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(TypesTableBlock); // Create / Add Method Tables ASM Block ASM.ASMBlock MethodTablesBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) + 0 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(MethodTablesBlock); // Create / Add Field Tables ASM Block ASM.ASMBlock FieldTablesBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) + 1 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(FieldTablesBlock); // Don't use foreach or you get collection modified exceptions for (int i = 0; i < TheLibrary.TypeInfos.Count; i++) { Types.TypeInfo aTypeInfo = TheLibrary.TypeInfos[i]; if (!ScannedTypes.ContainsKey(aTypeInfo.ID)) { ScannedTypes.Add(aTypeInfo.ID, TheLibrary); ScanStaticFields(TheLibrary, aTypeInfo, StaticFieldsBlock); ScanType(TheLibrary, aTypeInfo, TypesTableBlock); ScanMethods(TheLibrary, aTypeInfo, MethodTablesBlock); ScanFields(TheLibrary, aTypeInfo, FieldTablesBlock); } } foreach (Types.MethodInfo aMethodInfo in TheLibrary.ILBlocks.Keys) { ILBlock anILBlock = TheLibrary.ILBlocks[aMethodInfo]; CompileResult singleResult = CompileResult.OK; if (anILBlock.Plugged) { singleResult = ScanPluggedILBlock(TheLibrary, aMethodInfo, anILBlock); } else { singleResult = ScanNonpluggedILBlock(TheLibrary, aMethodInfo, anILBlock); } if (result != CompileResult.OK) { result = singleResult; } } // Create / Add String Literals ASM Block #region String Literals Block ASM.ASMBlock StringLiteralsBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) - 10 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(StringLiteralsBlock); string StringTypeId = ILLibrary.SpecialClasses[typeof(Attributes.StringClassAttribute)].First().ID; StringLiteralsBlock.AddExternalLabel(StringTypeId); foreach (KeyValuePair<string, string> aStringLiteral in TheLibrary.StringLiterals) { string value = aStringLiteral.Value; byte[] lengthBytes = BitConverter.GetBytes(value.Length); ASM.ASMOp newLiteralOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.StringLiteral, aStringLiteral.Key, StringTypeId, lengthBytes, value.ToCharArray()); StringLiteralsBlock.Append(newLiteralOp); } #endregion return result; }
/// <summary> /// Gets the next unique ID for a method of the specified type. /// </summary> /// <remarks> /// Used for generatign IDs to go in the method tables for use in virtual calls (callvirt Il ops). /// </remarks> /// <param name="TheLibrary">The IL library being compiled.</param> /// <param name="aType">The type to get the next method ID from.</param> /// <returns>The next unique method ID.</returns> private static int GetMethodIDGenerator(ILLibrary TheLibrary, Type aType, bool useMethodCount = false) { Types.TypeInfo aTypeInfo = TheLibrary.GetTypeInfo(aType); return GetMethodIDGenerator(TheLibrary, aTypeInfo, useMethodCount); }
private static List<Tuple<string, int>> GetSpecialClassFieldInfo(ILLibrary TheLibrary, Type SpecialClassType) { Types.TypeInfo InformationAboutInfoStruct = ILLibrary.SpecialClasses[SpecialClassType].First(); List<Types.FieldInfo> InfoStruct_OrderedFields = InformationAboutInfoStruct.FieldInfos.Where(x => !x.IsStatic).OrderBy(x => x.OffsetInBytes).ToList(); List<Tuple<string, int>> InfoStruct_OrderedFieldInfo_Subset = new List<Tuple<string, int>>(); foreach (Types.FieldInfo aField in InfoStruct_OrderedFields) { Types.TypeInfo FieldTypeInfo = TheLibrary.GetTypeInfo(aField.FieldType); InfoStruct_OrderedFieldInfo_Subset.Add(new Tuple<string, int>(aField.Name, FieldTypeInfo.IsValueType ? FieldTypeInfo.SizeOnHeapInBytes : FieldTypeInfo.SizeOnStackInBytes)); } return InfoStruct_OrderedFieldInfo_Subset; }
/// <summary> /// Executes the IL Preprocessor for the specified library. /// </summary> /// <param name="TheLibrary">The library to preprocess.</param> /// <returns>The return value from the IL Preprocessor.</returns> private static CompileResult ExecuteILPreprocessor(ILLibrary TheLibrary) { CompileResult result = CompileResult.OK; ILPreprocessor.Preprocess(TheLibrary); ILPreprocessor.PreprocessSpecialClasses(TheLibrary); ILPreprocessor.PreprocessSpecialMethods(TheLibrary); return result; }
/// <summary> /// Scans the specified plugged IL block. /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="theMethodInfo">The method which generated the IL block.</param> /// <param name="theILBlock">The IL block to scan.</param> /// <returns>CompileResult.OK.</returns> private static CompileResult ScanPluggedILBlock(ILLibrary TheLibrary, Types.MethodInfo theMethodInfo, ILBlock theILBlock) { TheLibrary.TheASMLibrary.ASMBlocks.Add(new ASM.ASMBlock() { PlugPath = theILBlock.PlugPath, OriginMethodInfo = theMethodInfo, Priority = theMethodInfo.Priority }); return CompileResult.OK; }
/// <summary> /// Scans the specified non-plugged IL block. /// </summary> /// <param name="TheLibrary">The library currently being compiled.</param> /// <param name="theMethodInfo">The method which generated the IL block.</param> /// <param name="theILBlock">The IL block to scan.</param> /// <returns>CompileResult.OK.</returns> private static CompileResult ScanNonpluggedILBlock(ILLibrary TheLibrary, Types.MethodInfo theMethodInfo, ILBlock theILBlock) { CompileResult result = CompileResult.OK; ASM.ASMBlock TheASMBlock = new ASM.ASMBlock() { OriginMethodInfo = theMethodInfo, Priority = theMethodInfo.Priority }; ILConversionState convState = new ILConversionState() { TheILLibrary = TheLibrary, CurrentStackFrame = new StackFrame(), Input = theILBlock, Result = TheASMBlock }; foreach (ILOp anOp in theILBlock.ILOps) { try { string commentText = TheASMBlock.GenerateILOpLabel(convState.PositionOf(anOp), "") + " -- " + anOp.opCode.ToString() + " -- Offset: " + anOp.Offset.ToString("X2"); ASM.ASMOp newCommentOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.Comment, commentText); TheASMBlock.ASMOps.Add(newCommentOp); int currCount = TheASMBlock.ASMOps.Count; if (anOp is ILOps.MethodStart) { TargetArchitecture.MethodStartOp.Convert(convState, anOp); } else if (anOp is ILOps.MethodEnd) { TargetArchitecture.MethodEndOp.Convert(convState, anOp); } else if (anOp is ILOps.StackSwitch) { TargetArchitecture.StackSwitchOp.Convert(convState, anOp); } else { ILOp ConverterOp = TargetArchitecture.TargetILOps[(ILOp.OpCodes)anOp.opCode.Value]; ConverterOp.Convert(convState, anOp); } if (anOp.LabelRequired) { if (currCount < TheASMBlock.ASMOps.Count) { TheASMBlock.ASMOps[currCount].ILLabelPosition = convState.PositionOf(anOp); TheASMBlock.ASMOps[currCount].RequiresILLabel = true; } } } catch (KeyNotFoundException) { result = CompileResult.PartialFailure; Logger.LogError(Errors.ILCompiler_ScanILOpFailure_ErrorCode, theMethodInfo.ToString(), anOp.Offset, string.Format(Errors.ErrorMessages[Errors.ILCompiler_ScanILOpFailure_ErrorCode], Enum.GetName(typeof(ILOp.OpCodes), anOp.opCode.Value), "Conversion for IL op not found.")); } catch (InvalidOperationException ex) { result = CompileResult.PartialFailure; Logger.LogError(Errors.ILCompiler_ScanILOpFailure_ErrorCode, theMethodInfo.ToString(), anOp.Offset, string.Format(Errors.ErrorMessages[Errors.ILCompiler_ScanILOpFailure_ErrorCode], Enum.GetName(typeof(ILOp.OpCodes), anOp.opCode.Value), ex.Message)); } catch (NotSupportedException ex) { result = CompileResult.PartialFailure; Logger.LogError(Errors.ILCompiler_ScanILOpFailure_ErrorCode, theMethodInfo.ToString(), anOp.Offset, string.Format(Errors.ErrorMessages[Errors.ILCompiler_ScanILOpFailure_ErrorCode], Enum.GetName(typeof(ILOp.OpCodes), anOp.opCode.Value), "An IL op reported something as not supported : " + ex.Message)); } catch (Exception ex) { result = CompileResult.Fail; Logger.LogError(Errors.ILCompiler_ScanILOpFailure_ErrorCode, theMethodInfo.ToString(), anOp.Offset, string.Format(Errors.ErrorMessages[Errors.ILCompiler_ScanILOpFailure_ErrorCode], Enum.GetName(typeof(ILOp.OpCodes), anOp.opCode.Value), ex.Message)); } } TheLibrary.TheASMLibrary.ASMBlocks.Add(TheASMBlock); return result; }
/// <summary> /// Scans the specified library and any dependencies. /// </summary> /// <param name="TheLibrary">The library to scan.</param> /// <returns> /// CompileResult.OK if completed successfully. /// Otherwise CompileResult.PartialFail or CompileResult.Error depending on /// the extent of the problem. /// </returns> public static CompileResult Scan(ILLibrary TheLibrary) { CompileResult result = CompileResult.OK; if (TheLibrary.ILScanned) { return(result); } TheLibrary.ILScanned = true; foreach (ILLibrary depLib in TheLibrary.Dependencies) { Scan(depLib); } // Create / Add Static Fields ASM Block ASM.ASMBlock StaticFieldsBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) - 9 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(StaticFieldsBlock); // Create / Add Types Table ASM Block ASM.ASMBlock TypesTableBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) - 8 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(TypesTableBlock); // Create / Add Method Tables ASM Block ASM.ASMBlock MethodTablesBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) + 0 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(MethodTablesBlock); // Create / Add Field Tables ASM Block ASM.ASMBlock FieldTablesBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) + 1 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(FieldTablesBlock); // Don't use foreach or you get collection modified exceptions for (int i = 0; i < TheLibrary.TypeInfos.Count; i++) { Types.TypeInfo aTypeInfo = TheLibrary.TypeInfos[i]; if (!ScannedTypes.ContainsKey(aTypeInfo.ID)) { ScannedTypes.Add(aTypeInfo.ID, TheLibrary); ScanStaticFields(TheLibrary, aTypeInfo, StaticFieldsBlock); ScanType(TheLibrary, aTypeInfo, TypesTableBlock); ScanMethods(TheLibrary, aTypeInfo, MethodTablesBlock); ScanFields(TheLibrary, aTypeInfo, FieldTablesBlock); } } foreach (Types.MethodInfo aMethodInfo in TheLibrary.ILBlocks.Keys) { ILBlock anILBlock = TheLibrary.ILBlocks[aMethodInfo]; CompileResult singleResult = CompileResult.OK; if (anILBlock.Plugged) { singleResult = ScanPluggedILBlock(TheLibrary, aMethodInfo, anILBlock); } else { singleResult = ScanNonpluggedILBlock(TheLibrary, aMethodInfo, anILBlock); } if (result != CompileResult.OK) { result = singleResult; } } // Create / Add String Literals ASM Block #region String Literals Block ASM.ASMBlock StringLiteralsBlock = new ASM.ASMBlock() { Priority = (long.MinValue / 2) - 10 }; TheLibrary.TheASMLibrary.ASMBlocks.Add(StringLiteralsBlock); string StringTypeId = ILLibrary.SpecialClasses[typeof(Attributes.StringClassAttribute)].First().ID; StringLiteralsBlock.AddExternalLabel(StringTypeId); foreach (KeyValuePair <string, string> aStringLiteral in TheLibrary.StringLiterals) { string value = aStringLiteral.Value; byte[] lengthBytes = BitConverter.GetBytes(value.Length); ASM.ASMOp newLiteralOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.StringLiteral, aStringLiteral.Key, StringTypeId, lengthBytes, value.ToCharArray()); StringLiteralsBlock.Append(newLiteralOp); } #endregion return(result); }
/// <summary> /// Loads all the dependencies of a library. /// </summary> /// <param name="aLibrary">The library to load dependencies of.</param> /// <returns>The number of dependencies loaded.</returns> public static int LoadDependencies(ILLibrary aLibrary) { if (aLibrary == null) { return 0; } int DependenciesLoaded = 0; Assembly RootAssembly = aLibrary.TheAssembly; AssemblyName[] refAssemblyNames = RootAssembly.GetReferencedAssemblies(); foreach (AssemblyName aRefName in refAssemblyNames) { if (IsAssemblyFullNameIgnored(aRefName.FullName)) { continue; } string refFilePath = Path.Combine(Path.GetDirectoryName(RootAssembly.Location), aRefName.Name + ".dll"); ILLibrary refLibrary = LoadILLibrary(refFilePath); if (refLibrary == null) { throw new NullReferenceException("Loaded dependency library was null!"); } else { if (LibraryCache.ContainsKey(refLibrary.ToString())) { aLibrary.Dependencies.Add(LibraryCache[refLibrary.ToString()]); } else { aLibrary.Dependencies.Add(refLibrary); LibraryCache.Add(refLibrary.ToString(), refLibrary); } } } return DependenciesLoaded; }