/source2/IL2CPU/Cosmos.IL2CPU/ILOp.cs
C# | 356 lines | 302 code | 31 blank | 23 comment | 61 complexity | 247d6268c2b2aeeffff4e5f77573f278 MD5 | raw file
Possible License(s): BSD-2-Clause
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Reflection;
- using Cosmos.IL2CPU.Plugs;
- using Cosmos.Assembler;
- using CPU = Cosmos.Assembler.x86;
- using Cosmos.IL2CPU.ILOpCodes;
- using Cosmos.Debug.Common;
- using Cosmos.IL2CPU.X86.IL;
- using System.Runtime.InteropServices;
-
- namespace Cosmos.IL2CPU {
- public abstract class ILOp {
- public static IDictionary<Type, IDictionary<string, PlugFieldAttribute>> mPlugFields;
- protected readonly Cosmos.Assembler.Assembler Assembler;
-
- protected ILOp(Cosmos.Assembler.Assembler aAsmblr) {
- Assembler = aAsmblr;
- }
-
- // This is called execute and not assemble, as the scanner
- // could be used for other things, profiling, analysis, reporting, etc
- public abstract void Execute(MethodInfo aMethod, ILOpCode aOpCode);
-
- public static string GetTypeIDLabel(Type aType) {
- return "VMT__TYPE_ID_HOLDER__" + DataMember.FilterStringForIncorrectChars(LabelName.GetFullName(aType) + " ASM_IS__" + aType.Assembly.GetName().Name);
- }
-
- public static uint Align(uint aSize, uint aAlign) {
- var xSize = aSize;
- if ((xSize % aAlign) != 0) {
- xSize += aAlign - (xSize % aAlign);
- }
- return xSize;
- }
-
- public static string GetLabel(MethodInfo aMethod, ILOpCode aOpCode) {
- return GetLabel(aMethod, aOpCode.Position);
- }
-
- public static string GetMethodLabel(MethodBase aMethod) {
- return LabelName.Get(aMethod);
- }
-
- public static string GetMethodLabel(MethodInfo aMethod) {
- if (aMethod.PluggedMethod != null) {
- return "PLUG_FOR___" + GetMethodLabel(aMethod.PluggedMethod.MethodBase);
- } else {
- return GetMethodLabel(aMethod.MethodBase);
- }
- }
-
- public static string GetLabel(MethodInfo aMethod, int aPos) {
- return LabelName.Get(GetMethodLabel(aMethod), aPos);
- }
-
- public override string ToString() {
- return GetType().Name;
- }
-
- protected static void Jump_Exception(MethodInfo aMethod) {
- // todo: port to numeric labels
- new CPU.Jump { DestinationLabel = GetMethodLabel(aMethod) + AppAssembler.EndOfMethodLabelNameException };
- }
-
- protected static void Jump_End(MethodInfo aMethod) {
- new CPU.Jump { DestinationLabel = GetMethodLabel(aMethod) + AppAssembler.EndOfMethodLabelNameNormal };
- }
-
- public static uint GetStackCountForLocal(MethodInfo aMethod, LocalVariableInfo aField) {
- var xSize = SizeOfType(aField.LocalType);
- var xResult = xSize / 4;
- if (xSize % 4 != 0) {
- xResult++;
- }
- return xResult;
- }
-
- public static uint GetEBPOffsetForLocal(MethodInfo aMethod, int localIndex) {
- var xBody = aMethod.MethodBase.GetMethodBody();
- uint xOffset = 4;
- for (int i = 0; i < xBody.LocalVariables.Count; i++) {
- if (i == localIndex) {
- break;
- }
- var xField = xBody.LocalVariables[i];
- xOffset += GetStackCountForLocal(aMethod, xField) * 4;
- }
- return xOffset;
- }
-
- public static uint SizeOfType(Type aType) {
- if (aType.FullName == "System.Void") {
- return 0;
- } else if ((!aType.IsValueType && aType.IsClass) || aType.IsInterface) {
- return 4;
- }
- if (aType.IsByRef) {
- return 4;
- }
- switch (aType.FullName) {
- case "System.Char":
- return 2;
- case "System.Byte":
- case "System.SByte":
- return 1;
- case "System.UInt16":
- case "System.Int16":
- return 2;
- case "System.UInt32":
- case "System.Int32":
- return 4;
- case "System.UInt64":
- case "System.Int64":
- return 8;
- //TODO: for now hardcode IntPtr and UIntPtr to be 32-bit
- case "System.UIntPtr":
- case "System.IntPtr":
- return 4;
- case "System.Boolean":
- return 1;
- case "System.Single":
- return 4;
- case "System.Double":
- return 8;
- case "System.Decimal":
- return 16;
- case "System.Guid":
- return 16;
- case "System.Enum":
- return 4;
- case "System.DateTime":
- return 8;
- }
- if (aType.FullName != null && aType.FullName.EndsWith("*")) {
- // pointer
- return 4;
- }
- // array
- //TypeSpecification xTypeSpec = aType as TypeSpecification;
- //if (xTypeSpec != null) {
- // return 4;
- //}
- if (aType.IsEnum) {
- return SizeOfType(aType.GetField("value__").FieldType);
- }
- if (aType.IsValueType) {
- var xSla = aType.StructLayoutAttribute;
- if (xSla != null) {
- if (xSla.Size > 0) {
- return (uint)xSla.Size;
- }
- }
- return (uint)(from item in GetFieldsInfo(aType)
- select (int)item.Size).Sum();
- }
- return 4;
- }
-
- public static uint GetEBPOffsetForLocalForDebugger(MethodInfo aMethod, int localIndex) {
- // because the memory is readed in positiv direction, we need to add additional size if greater than 4
- uint xOffset = GetEBPOffsetForLocal(aMethod, localIndex);
- var xBody = aMethod.MethodBase.GetMethodBody();
- var xField = xBody.LocalVariables[localIndex];
- xOffset += GetStackCountForLocal(aMethod, xField) * 4 - 4;
- return xOffset;
- }
-
- protected void ThrowNotImplementedException(string aMessage) {
- new CPU.Push {
- DestinationRef = Cosmos.Assembler.ElementReference.New(LdStr.GetContentsArrayName(aMessage))
- };
- new CPU.Call {
- DestinationLabel = LabelName.Get(typeof(ExceptionHelper).GetMethod("ThrowNotImplemented", BindingFlags.Static | BindingFlags.Public))
- };
- }
-
- protected void ThrowOverflowException() {
- new CPU.Call {
- DestinationLabel = LabelName.Get(
- typeof(ExceptionHelper).GetMethod("ThrowOverflow", BindingFlags.Static | BindingFlags.Public, null, new Type[] { }, null))
- };
- }
-
- private static void DoGetFieldsInfo(Type aType, List<X86.IL.FieldInfo> aFields) {
- var xCurList = new Dictionary<string, X86.IL.FieldInfo>();
- var xFields = (from item in aType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
- orderby item.Name, item.DeclaringType.ToString()
- select item).ToArray();
- for (int i = 0; i < xFields.Length; i++) {
- var xField = xFields[i];
- // todo: should be possible to have GetFields only return fields from a given type, thus removing need of next statement
- if (xField.DeclaringType != aType) {
- continue;
- }
-
- var xId = xField.GetFullName();
- var xInfo = new X86.IL.FieldInfo(xId, SizeOfType(xField.FieldType), aType, xField.FieldType);
- var xFieldOffsetAttrib = xField.GetCustomAttributes(typeof(FieldOffsetAttribute), true).FirstOrDefault() as FieldOffsetAttribute;
- if (xFieldOffsetAttrib != null) {
- xInfo.Offset = (uint)xFieldOffsetAttrib.Value;
- }
- aFields.Add(xInfo);
- xCurList.Add(xId, xInfo);
- }
-
- // now check plugs
- IDictionary<string, PlugFieldAttribute> xPlugFields;
- if (mPlugFields.TryGetValue(aType, out xPlugFields)) {
- foreach (var xPlugField in xPlugFields) {
- X86.IL.FieldInfo xPluggedField = null;
- if (xCurList.TryGetValue(xPlugField.Key, out xPluggedField)) {
- // plugfield modifies an already existing field
-
- // TODO: improve.
- if (xPlugField.Value.IsExternalValue) {
- xPluggedField.IsExternalValue = true;
- xPluggedField.FieldType = xPluggedField.FieldType.MakePointerType();
- xPluggedField.Size = 4;
- }
- } else {
- xPluggedField = new X86.IL.FieldInfo(xPlugField.Value.FieldId, SizeOfType(xPlugField.Value.FieldType), aType, xPlugField.Value.FieldType);
- aFields.Add(xPluggedField);
- }
- }
- }
-
- if (aType.BaseType != null) {
- DoGetFieldsInfo(aType.BaseType, aFields);
- }
- }
-
- protected static List<X86.IL.FieldInfo> GetFieldsInfo(Type aType) {
- var xResult = new List<X86.IL.FieldInfo>();
- DoGetFieldsInfo(aType, xResult);
- xResult.Reverse();
- uint xOffset = 0;
- foreach (var xInfo in xResult) {
- if (!xInfo.IsOffsetSet) {
- xInfo.Offset = xOffset;
- }
- xOffset += xInfo.Size;
- }
- var xDebugInfs = new List<FIELD_INFO>();
- foreach (var xInfo in xResult) {
- xDebugInfs.Add(new FIELD_INFO() {
- TYPE = xInfo.FieldType.AssemblyQualifiedName,
- OFFSET = (int)xInfo.Offset,
- NAME = GetNameForField(xInfo),
- });
- }
- DebugInfo.CurrentInstance.WriteFieldInfoToFile(xDebugInfs);
- List<DebugInfo.Field_Map> xFieldMapping = new List<DebugInfo.Field_Map>();
- GetFieldMapping(xResult, xFieldMapping, aType);
- DebugInfo.CurrentInstance.WriteFieldMappingToFile(xFieldMapping);
- return xResult;
- }
-
- private static void GetFieldMapping(List<X86.IL.FieldInfo> aFieldInfs, List<DebugInfo.Field_Map> aFieldMapping, Type aType) {
- DebugInfo.Field_Map xFMap = new DebugInfo.Field_Map();
- xFMap.TypeName = aType.AssemblyQualifiedName;
- foreach (var xInfo in aFieldInfs) {
- xFMap.FieldNames.Add(GetNameForField(xInfo));
- }
- aFieldMapping.Add(xFMap);
- }
-
- private static string GetNameForField(X86.IL.FieldInfo inf) {
- // First we need to separate out the
- // actual name of field from the type of the field.
- int loc = inf.Id.IndexOf(' ');
- if (loc >= 0) {
- string fName = inf.Id.Substring(loc, inf.Id.Length - loc);
- return inf.DeclaringType.AssemblyQualifiedName + fName;
- } else {
- return inf.Id;
- }
- }
-
- protected static uint GetStorageSize(Type aType) {
- return (from item in GetFieldsInfo(aType)
- orderby item.Offset descending
- select item.Offset + item.Size).FirstOrDefault();
- }
-
- public static void EmitExceptionLogic(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethodInfo, ILOpCode aCurrentOpCode, bool aDoTest, Action aCleanup) {
- EmitExceptionLogic(aAssembler, aMethodInfo, aCurrentOpCode, aDoTest, aCleanup, ILOp.GetLabel(aMethodInfo, aCurrentOpCode.NextPosition));
- }
- public static void EmitExceptionLogic(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethodInfo, ILOpCode aCurrentOpCode, bool aDoTest, Action aCleanup, string aJumpTargetNoException) {
- string xJumpTo = null;
- if (aCurrentOpCode != null && aCurrentOpCode.CurrentExceptionHandler != null) {
- // todo add support for nested handlers, see comment in Engine.cs
- //if (!((aMethodInfo.CurrentHandler.HandlerOffset < aCurrentOpOffset) || (aMethodInfo.CurrentHandler.HandlerLength + aMethodInfo.CurrentHandler.HandlerOffset) <= aCurrentOpOffset)) {
- new Comment(String.Format("CurrentOffset = {0}, HandlerStartOffset = {1}", aCurrentOpCode.Position, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset));
- if (aCurrentOpCode.CurrentExceptionHandler.HandlerOffset > aCurrentOpCode.Position) {
- switch (aCurrentOpCode.CurrentExceptionHandler.Flags) {
- case ExceptionHandlingClauseOptions.Clause: {
- xJumpTo = ILOp.GetLabel(aMethodInfo, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset);
- break;
- }
- case ExceptionHandlingClauseOptions.Finally: {
- xJumpTo = ILOp.GetLabel(aMethodInfo, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset);
- break;
- }
- default: {
- throw new Exception("ExceptionHandlerType '" + aCurrentOpCode.CurrentExceptionHandler.Flags.ToString() + "' not supported yet!");
- }
- }
- }
- }
- // if aDoTest is true, we check ECX for exception flags
- if (!aDoTest) {
- //new CPU.Call("_CODE_REQUESTED_BREAK_");
- if (xJumpTo == null) {
- Jump_Exception(aMethodInfo);
- } else {
- new CPU.Jump { DestinationLabel = xJumpTo };
- }
-
- } else {
- new CPU.Test { DestinationReg = CPU.Registers.ECX, SourceValue = 2 };
-
- if (aCleanup != null) {
- new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Equal, DestinationLabel = aJumpTargetNoException };
- aCleanup();
- if (xJumpTo == null) {
- new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = GetMethodLabel(aMethodInfo) + AppAssembler.EndOfMethodLabelNameException };
- } else {
- new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = xJumpTo };
- }
- } else {
- if (xJumpTo == null) {
- new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = GetMethodLabel(aMethodInfo) + AppAssembler.EndOfMethodLabelNameException };
- } else {
- new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = xJumpTo };
- }
- }
- }
- }
-
- public static bool IsIntegerSigned(Type aType) {
- switch (aType.FullName) {
- case "System.SByte":
- case "System.Int16":
- case "System.Int32":
- case "System.Int64":
- //TODO not sure about this case "System.IntPtr":
- //TODO not sure aobut this case "System.Enum":
- return true;
- }
- return false;
- }
- }
- }