/// <summary> /// Preprocesses the given ASM block. /// </summary> /// <param name="theBlock">The block to preprocess.</param> private static void Preprocess(ASMBlock theBlock) { // Due to "insert 0", asm ops are constructed in reverse order here string currMethodLabel = theBlock.GenerateMethodLabel(); if (currMethodLabel != null) { ASM.ASMOp newLabelOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.Label, true); theBlock.ASMOps.Insert(0, newLabelOp); } if (currMethodLabel != null) { ASM.ASMOp newGlobalLabelOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.GlobalLabel, currMethodLabel); theBlock.ASMOps.Insert(0, newGlobalLabelOp); } foreach (string anExternalLabel in theBlock.ExternalLabels.Distinct()) { if (anExternalLabel != currMethodLabel) { ASM.ASMOp newExternalLabelOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.ExternalLabel, anExternalLabel); theBlock.ASMOps.Insert(0, newExternalLabelOp); } } ASM.ASMOp newHeaderOp = TargetArchitecture.CreateASMOp(ASM.OpCodes.Header); theBlock.ASMOps.Insert(0, newHeaderOp); }
/// <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> /// 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 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); } } }
/// <summary> /// Processes the given ASM block. /// </summary> /// <param name="TheBlock">The ASM block to process.</param> private static void ProcessBlock(ASMBlock TheBlock) { string ASMText = ""; if (TheBlock.Plugged) { string ASMPlugPath = Path.Combine(Options.OutputPath, TheBlock.PlugPath); // Legacy file name support if (Options.TargetArchitecture == "x86" && !File.Exists(ASMPlugPath + "." + Options.TargetArchitecture + ".asm")) { if (!File.Exists(ASMPlugPath + ".x86_32.asm")) { throw new FileNotFoundException("Plug file not found! File name: " + ASMPlugPath + "." + Options.TargetArchitecture + ".asm", ASMPlugPath + "." + Options.TargetArchitecture + ".asm"); } else { ASMPlugPath += ".x86_32.asm"; } } else { ASMPlugPath += "." + Options.TargetArchitecture + ".asm"; } if (!File.Exists(ASMPlugPath)) { throw new FileNotFoundException("Plug file not found! File name: " + ASMPlugPath, ASMPlugPath); } ASMText = File.ReadAllText(ASMPlugPath); ASMText = ASMText.Replace("%KERNEL_CALL_STATIC_CONSTRUCTORS_METHOD%", IL.ILLibrary.SpecialMethods[typeof(Attributes.CallStaticConstructorsMethodAttribute)].First().ID); if (IL.ILLibrary.SpecialMethods.ContainsKey(typeof(Attributes.MainMethodAttribute))) { ASMText = ASMText.Replace("%KERNEL_MAIN_METHOD%", IL.ILLibrary.SpecialMethods[typeof(Attributes.MainMethodAttribute)].First().ID); } } else { foreach (ASMOp anASMOp in TheBlock.ASMOps) { if (anASMOp.RequiresILLabel) { ASMText += ((ASMLabel)TargetArchitecture.CreateASMOp(OpCodes.Label, anASMOp.ILLabelPosition, "")).Convert(TheBlock) + "\r\n"; } if (anASMOp is ASM.ASMOps.ASMLabel) { ASMLabel labelOp = (ASM.ASMOps.ASMLabel)anASMOp; if (labelOp.IsDebugOp) { DebugDataWriter.AddDebugOp(TheBlock.OriginMethodInfo.ID, TheBlock.GenerateILOpLabel(labelOp.ILPosition, labelOp.Extension)); } } ASMText += anASMOp.Convert(TheBlock) + "\r\n"; } } TargetArchitecture.TargetFunctions.CleanUpAssemblyCode(TheBlock, ref ASMText); if (!string.IsNullOrWhiteSpace(ASMText)) { string FileName = Utilities.CleanFileName(Guid.NewGuid().ToString() + "." + Options.TargetArchitecture) + ".s"; string OutputPath = GetASMOutputPath(); FileName = Path.Combine(OutputPath, FileName); TheBlock.ASMOutputFilePath = FileName; File.WriteAllText(FileName, ASMText); } else { TheBlock.ASMOutputFilePath = null; } }
/// <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> /// 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); }