public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); bool valueisFloat = Utilities.IsFloat(theField.FieldType); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); int stackSize = fieldTypeInfo.SizeOnStackInBytes; StackItem objPointer = conversionState.CurrentStackFrame.Stack.Pop(); if ((OpCodes)theOp.opCode.Value == OpCodes.Ldflda) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = valueisFloat, sizeOnStackInBytes = stackSize, isGCManaged = fieldTypeInfo.IsGCManaged }); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldsfld: { Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); int size = theTypeInfo.SizeOnStackInBytes; bool isFloat = Utilities.IsFloat(theField.FieldType); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = isFloat, sizeOnStackInBytes = (size == 8 ? 8 : 4), isGCManaged = theTypeInfo.IsGCManaged, isValue = theTypeInfo.IsValueType }); } break; case OpCodes.Ldsflda: conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = false }); break; } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); if (methodToCall is MethodInfo) { Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged, isValue = retTypeInfo.IsValueType }; int bytesToAdd = 0; List <Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } if (bytesToAdd > 0) { if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if (methodToCall is ConstructorInfo) { ConstructorInfo aConstructor = (ConstructorInfo)methodToCall; if (aConstructor.IsStatic) { //Static constructors do not have parameters or return values } else { ParameterInfo[] allParams = methodToCall.GetParameters(); foreach (ParameterInfo aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); } } } }
/// <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> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point or /// if the value is not 4 or 8 bytes in size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.TypeInfo objTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.DeclaringType); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); Types.FieldInfo theFieldInfo = conversionState.TheILLibrary.GetFieldInfo(objTypeInfo, theField.Name); int offset = theFieldInfo.OffsetInBytes; int stackSize = fieldTypeInfo.SizeOnStackInBytes; int memSize = fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : stackSize; StackItem value = conversionState.CurrentStackFrame.Stack.Pop(); StackItem objPointer = conversionState.CurrentStackFrame.Stack.Pop(); if (value.isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing fields of type float not supported yet!"); } //Get object pointer conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = stackSize.ToString() + "($sp)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); //Pop and mov value for (int i = 0; i < memSize; i += 2) { if (memSize - i == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Halfword, Dest = "$t0" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "$t0", Dest = (offset + i).ToString() + "($t2)" }); GlobalMethods.StoreData(conversionState, theOp, "$t2", "$t0", (offset + i), 1); } else { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Halfword, Dest = "$t0" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = (offset + i).ToString() + "($t2)" }); GlobalMethods.StoreData(conversionState, theOp, "$t2", "$t0", (offset + i), 2); } } // Rounds down || Pop object pointer conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = ((((stackSize - memSize) / 2) * 2) + 4).ToString(), Dest = "$sp" }); }
/// <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); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { Type retType = (conversionState.Input.TheMethodInfo.IsConstructor ? typeof(void) : ((MethodInfo)conversionState.Input.TheMethodInfo.UnderlyingInfo).ReturnType); Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); if (retTypeInfo.SizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Pop(); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load static field //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the object to load Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); //Get the object size information int size = theTypeInfo.SizeOnStackInBytes; //Load the object onto the stack conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); for (int i = size - 4; i >= 0; i -= 4) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ECX+" + i.ToString() + "]", Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } int extra = size % 4; for (int i = extra - 1; i >= 0; i--) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[ECX+" + i.ToString() + "]", Dest = "AL" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Byte, Src = "AL" }); } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = size, isGCManaged = false }); }
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> /// 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); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); int size = theTypeInfo.SizeOnStackInBytes; conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = size, isGCManaged = false }); }
/// <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> /// Gets the type info for the specified actual type. /// </summary> /// <param name="theType">The type to get type info for.</param> /// <param name="topLevel">Whether to search the library's dependencies or not. Faslse to search dependencies.</param> /// <param name="FullyProcess">Default: true. /// Should only be set to false by the TypeScanner. /// Used to prevent reentrancy (/circular) processing within the type scanner. /// </param> /// <returns>The type info or null if not found.</returns> private Types.TypeInfo GetTypeInfo(Type theType, bool topLevel, bool FullyProcess) { foreach (Types.TypeInfo aTypeInfo in TypeInfos) { if (aTypeInfo.UnderlyingType.Equals(theType)) { return(aTypeInfo); } } foreach (ILLibrary depLib in Dependencies) { Types.TypeInfo result = depLib.GetTypeInfo(theType, false, FullyProcess); if (result != null) { return(result); } } if (topLevel) { Types.TypeInfo theTypeInfo = Types.TypeScanner.ScanType(this, theType); if (FullyProcess) { int count = 0; do { count = TypeInfos.Count; int start = count - 1; for (int i = start; i < count; i++) { Types.TypeScanner.ProcessType(this, TypeInfos[i]); } for (int i = start; i < count; i++) { Types.TypeScanner.ProcessTypeFields(this, TypeInfos[i]); } }while (count < TypeInfos.Count); } return(theTypeInfo); } else { return(null); } }
/// <summary> /// Gets the field info for the specified field from the specified type. /// </summary> /// <param name="aTypeInfo">The type to get the field from.</param> /// <param name="FieldName">The name of the field to get info for.</param> /// <returns>The field info.</returns> /// <exception cref="System.NullReferenceException">Thrown if the field is not found.</exception> public Types.FieldInfo GetFieldInfo(Types.TypeInfo aTypeInfo, string FieldName) { foreach (Types.FieldInfo aFieldInfo in aTypeInfo.FieldInfos) { if (aFieldInfo.Name.Equals(FieldName)) { return(aFieldInfo); } } if (aTypeInfo.UnderlyingType.BaseType != null && !aTypeInfo.UnderlyingType.AssemblyQualifiedName.Contains("mscorlib")) { Types.TypeInfo baseTypeInfo = GetTypeInfo(aTypeInfo.UnderlyingType.BaseType); return(GetFieldInfo(baseTypeInfo, FieldName)); } throw new NullReferenceException("Field \"" + FieldName + "\" not found in type \"" + aTypeInfo.ToString() + "\"."); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = (theTypeInfo.IsValueType ? theTypeInfo.SizeOnHeapInBytes : theTypeInfo.SizeOnStackInBytes).ToString() }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the object to load Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); //Get the object size information int size = theTypeInfo.IsValueType ? theTypeInfo.SizeOnHeapInBytes : theTypeInfo.SizeOnStackInBytes; conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); //Load the object onto the stack conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Dest = "ECX", Src = "[ESP+" + theTypeInfo.SizeOnStackInBytes + "]" }); if (size == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[ECX]" }); } else if (size == 2) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[ECX]" }); } else if (size >= 4) { for (int i = 0; i < size; i += 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); switch (size - i) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[ECX+" + i + "]" }); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[ECX+" + i + "]" }); break; case 3: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[ECX+" + i + "]" }); conversionState.Append(new ASMOps.Shr() { Src = "16", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[ECX+" + (i + 1) + "]" }); break; default: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "[ECX+" + i + "]" }); break; } } } else { throw new ArgumentOutOfRangeException("Storing object with unsupported size! Size: " + size.ToString()); } conversionState.Append(new ASMOps.Add() { Dest = "ESP", Src = "4" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if field to load is a floating value or the field to load /// is not of size 4 or 8 bytes. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Get the field's token that is used to get FieldInfo from the assembly int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the field info from the referencing assembly FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); //Get the database type information about the object that contains the field Types.TypeInfo objTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.DeclaringType); int offset = conversionState.TheILLibrary.GetFieldInfo(objTypeInfo, theField.Name).OffsetInBytes; //Is the value to load a floating pointer number? bool valueisFloat = Utilities.IsFloat(theField.FieldType); //Get the size of the value to load (in bytes, as it will appear on the stack) Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); int stackSize = fieldTypeInfo.SizeOnStackInBytes; int memSize = theField.FieldType.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : stackSize; //Pop the object pointer from our stack StackItem objPointer = conversionState.CurrentStackFrame.Stack.Pop(); //If the value to load is a float, erm...abort... if (valueisFloat) { //SUPPORT - floats throw new NotSupportedException("Loading fields of type float not supported yet!"); } //Pop object pointer conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); if ((OpCodes)theOp.opCode.Value == OpCodes.Ldflda) { conversionState.Append(new ASMOps.Add() { Src1 = "$t2", Src2 = offset.ToString(), Dest = "$t2" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t2" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else { //Push value at pointer+offset int sizeNotInMem = stackSize - memSize; int sizeToSub = (sizeNotInMem / 2) * 2; //Rounds down for (int i = 0; i < sizeToSub; i += 2) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Halfword, Src = "$zero" }); } for (int i = memSize + (memSize % 2); i > 0; i -= 2) { if (sizeToSub != sizeNotInMem) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = (offset + i - 2).ToString() + "($t2)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t2", "$t0", (offset + i - 2), 1); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Halfword, Src = "$t0" }); } else { //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = (offset + i - 2).ToString() + "($t2)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t2", "$t0", (offset + i - 2), 2); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Halfword, Src = "$t0" }); } } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = valueisFloat, sizeOnStackInBytes = stackSize, isGCManaged = fieldTypeInfo.IsGCManaged }); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load static field //Load the metadata token used to get the field info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the field info for the field to load FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); //Get the ID (i.e. ASM label) of the field to load string fieldID = conversionState.GetFieldInfo(theField.DeclaringType, theField.Name).ID; conversionState.AddExternalLabel(fieldID); //Load the field or field address switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldsfld: { Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); int size = /*theTypeInfo.IsValueType ? theTypeInfo.SizeOnHeapInBytes : */ theTypeInfo.SizeOnStackInBytes; bool isFloat = Utilities.IsFloat(theField.FieldType); if (isFloat) { //SUPPORT - floats throw new NotSupportedException("Loading static fields of type float not supported yet!"); } conversionState.Append(new ASMOps.La() { Label = fieldID, Dest = "$t1" }); if (size == 1) { conversionState.Append(new ASMOps.Xor() { Src1 = "$t0", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "0($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else if (size == 2) { conversionState.Append(new ASMOps.Xor() { Src1 = "$t0", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else if (size == 4) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else if (size == 8) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t1)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else { throw new ArgumentOutOfRangeException("Loading static field that has stack size greater than 8 not supported!"); } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = isFloat, sizeOnStackInBytes = (size == 8 ? 8 : 4), isGCManaged = theTypeInfo.IsGCManaged, isValue = theTypeInfo.IsValueType }); } break; case OpCodes.Ldsflda: //Load the address of the field i.e. address of the ASM label conversionState.Append(new ASMOps.La() { Label = fieldID, Dest = "$t4" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t4" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = false }); break; } }
public override void Convert(ILConversionState conversionState, ILOp theOp) { //Store the return value //Get the return type Type retType = (conversionState.Input.TheMethodInfo.IsConstructor ? typeof(void) : ((MethodInfo)conversionState.Input.TheMethodInfo.UnderlyingInfo).ReturnType); Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); //Get the size of the return type on stack int retSize = retTypeInfo.SizeOnStackInBytes; //If the size isn't 0 (i.e. isn't "void" which has no return value) if (retSize != 0) { //Pop the return value off our stack StackItem retItem = conversionState.CurrentStackFrame.Stack.Pop(); //If it is float, well, we don't support it yet... if (retItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Floats return type not supported yet!"); } //Otherwise, store the return value at [ebp+8] //[ebp+8] because that is last "argument" // - read the calling convention spec else if (retSize == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Dest = "8($fp)", Src = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (retSize == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Dest = "8($fp)", Src = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Dest = "12($fp)", Src = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else { throw new NotSupportedException("Return type size not supported / invalid!"); } } //Once return value is off the stack, remove the locals //Deallocate stack space for locals //Only bother if there are any locals if (conversionState.Input.TheMethodInfo.LocalInfos.Count > 0) { //Get the total size of all locals int totalBytes = 0; foreach (Types.VariableInfo aLocal in conversionState.Input.TheMethodInfo.LocalInfos) { totalBytes += aLocal.TheTypeInfo.SizeOnStackInBytes; } //Move esp past the locals conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = totalBytes.ToString(), Dest = "$sp" }); } //Restore ebp to previous method's ebp conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$fp" }); //This pop also takes last value off the stack which //means top item is the return address //So ret command can now be correctly executed. }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if field to load is a floating value or the field to load /// is not of size 4 or 8 bytes. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { conversionState.CurrentStackFrame.Stack.Pop(); Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); // 1. Check array reference is not null // 1.1. Move array ref into eax // 1.2. Compare eax (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 2. Load array length // 1.1. Move array ref into eax conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP]", Dest = "EAX" }); // 1.2. Compare eax (array ref) to 0 conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "ContinueExecution1" }); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ContinueExecution1" }); //2. Load array length // - Pop array ref conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); // - Load length from array ref conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ECX+" + lengthOffset.ToString() + "]", Dest = "EAX" }); // - Push array length conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = true }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if constant is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID); Type elementType = null; bool pushValue = true; int sizeToPush = 4; bool signExtend = true; bool isFloat = false; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldelem: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); } break; case OpCodes.Ldelema: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); pushValue = false; } break; case OpCodes.Ldelem_R4: case OpCodes.Ldelem_R8: //TODO - Add more LdElem op variants support throw new NotSupportedException("Ldelem op variant not supported yet!"); case OpCodes.Ldelem_I1: sizeToPush = 1; elementType = typeof(sbyte); break; case OpCodes.Ldelem_I2: sizeToPush = 2; elementType = typeof(Int16); break; case OpCodes.Ldelem_U1: sizeToPush = 1; signExtend = false; elementType = typeof(byte); break; case OpCodes.Ldelem_U2: sizeToPush = 2; signExtend = false; elementType = typeof(UInt16); break; case OpCodes.Ldelem_Ref: signExtend = false; elementType = null; break; case OpCodes.Ldelem_U4: signExtend = false; elementType = typeof(UInt32); break; case OpCodes.Ldelem_I4: elementType = typeof(Int32); break; case OpCodes.Ldelem_I8: sizeToPush = 8; elementType = typeof(Int64); break; } if (isFloat) { //TODO - Support floats throw new NotSupportedException("LdElem for floats not supported yet!"); } //Get element from array and push the value onto the stack // (or for LdElemA push the address of the value) //This involves: // 1. Check array reference is not null // - If it is, throw NullReferenceException // 2. Check array element type is correct // - If not, throw ArrayTypeMismatchException // 3. Check index to get is > -1 and < array length // - If not, throw IndexOutOfRangeException // 4. Calculate address of element // 5. Push the element onto the stack //Stack setup upon entering this op: (top-most downwards) // 0. Index of element to get as Int32 (word) // 1. Array object reference as address (word) Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); // 1. Check array reference is not null // 1.1. Move array ref into $t0 // 1.2. Compare $t0 (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 1.1. Move array ref into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 1.2. Compare $t0 (array ref) to 0 // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", BranchType = ASMOps.BranchOp.BranchNotZero, DestILPosition = currOpPosition, Extension = "Continue1", UnsignedTest = true }); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue1" }); // 2. Check array element type is correct // 2.1. Move element type ref into $t0 // 2.2. Move element type ref from array object into $t1 // 2.3. Compare $t0 to $t1 // 2.4. If the same, jump to continue execution further down // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //string ContinueExecutionLabel2 = ContinueExecutionLabelBase + "2"; //// 2.1. Move element type ref into $t0 int elemTypeOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "elemType").OffsetInBytes; // 3. Check index to get is > -1 and < array length // 3.1. Move index into $t0 // 3.2. Move array length into $t1 // 3.2. Compare $t0 to 0 // 3.3. Jump if greater than to next test condition (3.5) // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.5. Compare $t0 to $t1 // 3.6. Jump if less than to continue execution further down // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.1. Move index into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 3.2. Move array length into $t2 // - Calculate the offset of the field from the start of the array object int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; // - Move array ref into $t1 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($sp)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // - Move length value (offset($t1)) into $t1 //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = lengthOffset.ToString() + "($t1)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t1", "$t1", lengthOffset, 4); // 3.2. Compare $t0 to 0 // 3.3. Jump if greater than to next test condition (3.5) conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", Src2 = "$zero", BranchType = ASMOps.BranchOp.BranchGreaterThanEqual, DestILPosition = currOpPosition, Extension = "Continue3_1", UnsignedTest = false }); // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.5. Compare $t0 to $t1 // 3.6. Jump if less than to continue execution further down conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", Src2 = "$t1", BranchType = ASMOps.BranchOp.BranchLessThan, DestILPosition = currOpPosition, Extension = "Continue3_2", UnsignedTest = false }); // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_2" }); // 4. Calculate address of element // 4.1. Pop index into $t1 // 4.2. Pop array ref into $t0 // 4.3. Move element type ref (from array ref) into $t0 // 4.4. Move IsValueType (from element ref type) into $t2 // 4.5. If IsValueType, continue to 4.6., else goto 4.8. // 4.6. Move Size (from element type ref) into $t0 // 4.7. Skip over 4.8. // 4.8. Move StackSize (from element type ref) into $t0 // 4.9. Mulitply $t0 by $t1 (index by element size) // 4.10. Move array ref into $t1 // 4.11. Add enough to go past Kernel.FOS_System.Array fields // 4.12. Add $t0 and $t1 (array ref + fields + (index * element size)) // 4.1. Pop index into $t1 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); // 4.2. Move array ref into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 4.3. Move element type ref (from array ref) into $t0 //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = elemTypeOffset.ToString() + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", elemTypeOffset, 4); // 4.4. Move IsValueType (from element ref type) into $t2 int isValueTypeOffset = conversionState.GetTypeFieldOffset("IsValueType"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = isValueTypeOffset.ToString() + "($t0)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t2", isValueTypeOffset, 1); // 4.5. If IsValueType, continue to 4.6., else goto 4.8. conversionState.Append(new ASMOps.Branch() { Src1 = "$t2", BranchType = ASMOps.BranchOp.BranchZero, DestILPosition = currOpPosition, Extension = "Continue4_1", UnsignedTest = true }); // 4.6. Move Size (from element type ref) into $t0 int sizeOffset = conversionState.GetTypeFieldOffset("Size"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = sizeOffset.ToString() + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", sizeOffset, 4); // 4.7. Skip over 4.8. conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "Continue4_2" }); // 4.8. Move StackSize (from element type ref) into $t0 conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_1" }); int stackSizeOffset = conversionState.GetTypeFieldOffset("StackSize"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = stackSizeOffset + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", stackSizeOffset, 4); // 4.9. Mulitply $t0 by $t1 (index by element size) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_2" }); conversionState.Append(new ASMOps.Mul() { Src1 = "$t1", Src2 = "$t0", Signed = true }); // 4.10. Pop array ref into $t1 conversionState.Append(new ASMOps.Mflo() { Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); // 4.11. Add enough to go past Kernel.FOS_System.Array fields int allFieldsOffset = 0; #region Offset calculation { Types.FieldInfo highestOffsetFieldInfo = arrayTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderByDescending(x => x.OffsetInBytes).First(); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(highestOffsetFieldInfo.UnderlyingInfo.FieldType); allFieldsOffset = highestOffsetFieldInfo.OffsetInBytes + (fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : fieldTypeInfo.SizeOnStackInBytes); } #endregion conversionState.Append(new ASMOps.Add() { Src1 = "$t1", Src2 = allFieldsOffset.ToString(), Dest = "$t1" }); // 4.12. Add $t0 and $t1 (array ref + fields + (index * element size)) conversionState.Append(new ASMOps.Add() { Src1 = "$t1", Src2 = "$t0", Dest = "$t0" }); // 5. Push the element onto the stack // 5.1. Push value at ($t0) (except for LdElemA op in which case just push address) if (pushValue) { switch (sizeToPush) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 1, signExtend); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 2, signExtend); break; case 4: //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 4); break; case 8: //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 4); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($t0)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t2", 4, 4); break; } if (sizeToPush == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t2" }); } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t1" }); } else { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } // 5.2. Pop index and array ref from our stack conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); // 5.3. Push element onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = sizeToPush > 4 ? 8 : 4, isFloat = isFloat, isNewGCObject = false, isGCManaged = pushValue ? (elementType == null || conversionState.TheILLibrary.GetTypeInfo(elementType).IsGCManaged) : false }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if any argument or the return value is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID); //The method to call is a method base //A method base can be either a method info i.e. a normal method //or a constructor method. The two types are treated separately. if (methodToCall is MethodInfo) { //Need to do callvirt related stuff to load address of method to call // - Check for invoke of a delegate - if so, treat rather differently from normal callvirt if (typeof(Delegate).IsAssignableFrom(((MethodInfo)methodToCall).DeclaringType)) { //Callvirt to delegate method // - We only support calls to Invoke at the moment if (methodToCall.Name != "Invoke") { throw new NotSupportedException("Callvirt to Delegate method not supported! Method name: " + methodToCall.Name); } int bytesForAllParams = ((MethodInfo)methodToCall).GetParameters().Select(x => conversionState.TheILLibrary.GetTypeInfo(x.ParameterType).SizeOnStackInBytes).Sum(); // - Move into $t0 address of function to call from stack - delegate reference is function pointer //All the parameters for the method that was called List <Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); int bytesForParams = allParams.Select(x => conversionState.TheILLibrary.GetTypeInfo(x).SizeOnStackInBytes).Sum(); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = bytesForParams + "($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); //Allocate space on the stack for the return value as necessary Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged, isValue = retTypeInfo.IsValueType }; //We do not push the return value onto the stack unless it has size > 0 //We do not push the return value onto our stack at this point - it is pushed after the call is done if (returnItem.sizeOnStackInBytes != 0) { if (returnItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Cannot handle float return values!"); } else if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); } else { throw new NotSupportedException("Invalid return stack operand size!"); } } //Append the actual call conversionState.Append(new ASMOps.Call() { Target = "$t0" }); //After a call, we need to remove the return value and parameters from the stack //This is most easily done by just adding the total number of bytes for params and //return value to the stack pointer ($sp register). //Stores the number of bytes to add // - Initially at least 4 for the delegate (method) ref/pointer int bytesToAdd = 4; //Go through all params that must be removed foreach (Type aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } //If there is a return value on the stack if (returnItem.sizeOnStackInBytes != 0) { //We need to store the return value then pop all the params //We now push the return value onto our stack as, //after all is said and done below, it will be the //top item on the stack conversionState.CurrentStackFrame.Stack.Push(returnItem); //SUPPORT - floats (with above) //Pop the return value into the $t0 register //We will push it back on after params are skipped over. if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); } } //Skip over the params conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = bytesToAdd.ToString(), Dest = "$sp" }); //If necessary, push the return value onto the stack. if (returnItem.sizeOnStackInBytes != 0) { //SUPPORT - floats (with above) //The return value was stored in $t0 //So push it back onto the stack if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } } } else { //Normal callvirt // - Get object ref from loaded args // - Check object ref not null // - Get type table entry from object ref // - Get method table from type table entry // - Scan method table for the method we want // - If found, load method address // - Else, check for parent type method table // - If no parent type method table, throw exception // - Else, scan parent type method table string methodIDValueWanted = methodToCallInfo.IDValue.ToString(); int currOpPosition = conversionState.PositionOf(theOp); Types.TypeInfo declaringTypeInfo = conversionState.TheILLibrary.GetTypeInfo(methodToCall.DeclaringType); //DB_Type declaringDBType = DebugDatabase.GetType(conversionState.GetTypeID(methodToCall.DeclaringType)); //Get object ref int bytesForAllParams = ((MethodInfo)methodToCall).GetParameters().Select(x => conversionState.TheILLibrary.GetTypeInfo(x.ParameterType).SizeOnStackInBytes).Sum(); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = bytesForAllParams + "($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); //Check object ref conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchNotZero, Src1 = "$t0", Src2 = "$zero", DestILPosition = currOpPosition, Extension = "NotNull" }); conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotNull" }); //Get type ref int typeOffset = conversionState.TheILLibrary.GetFieldInfo(declaringTypeInfo, "_Type").OffsetInBytes; //conversionState.Append(new ASMOps.La() { Dest = "$t1", Label = "type_Testing1_String" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = typeOffset.ToString() + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", typeOffset, 4); //Get method table ref int methodTablePtrOffset = conversionState.GetTypeFieldOffset("MethodTablePtr"); //conversionState.Append(new ASMOps.La() { Dest = "$t0", Label = "type_Testing1_String_MethodTable" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = methodTablePtrOffset.ToString() + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", methodTablePtrOffset, 4); //Loop through entries conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "LoopMethodTable" }); //Load ID Val for current entry //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 4); //Compare to wanted ID value conversionState.Append(new ASMOps.Mov() { Src = methodIDValueWanted, Dest = "$t4", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //If equal, load method address into $t0 conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchNotEqual, Src1 = "$t1", Src2 = "$t4", DestILPosition = currOpPosition, Extension = "NotEqual" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", 4, 4); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "Call" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotEqual" }); //Else, compare to 0 to check for end of table conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchZero, Src1 = "$t1", DestILPosition = currOpPosition, Extension = "EndOfTable" }); //Not 0? Move to next entry then loop again conversionState.Append(new ASMOps.Add() { Src1 = "$t0", Src2 = "8", Dest = "$t0" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "LoopMethodTable" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "EndOfTable" }); //Compare address value to 0 //If not zero, there is a parent method table to check //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 4, 4); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchZero, Src1 = "$t1", DestILPosition = currOpPosition, Extension = "NotFound" }); //Load parent method table and loop conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t1", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.RegToReg }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "LoopMethodTable" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotFound" }); //Throw exception! conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Call" }); //Allocate space on the stack for the return value as necessary Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged, isValue = retTypeInfo.IsValueType }; //We do not push the return value onto the stack unless it has size > 0 //We do not push the return value onto our stack at this point - it is pushed after the call is done if (returnItem.sizeOnStackInBytes != 0) { if (returnItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Cannot handle float return values!"); } else if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); } else { throw new NotSupportedException("Invalid return stack operand size!"); } } //Append the actual call conversionState.Append(new ASMOps.Call() { Target = "$t0" }); //After a call, we need to remove the return value and parameters from the stack //This is most easily done by just adding the total number of bytes for params and //return value to the stack pointer ($sp register). //Stores the number of bytes to add int bytesToAdd = 0; //All the parameters for the method that was called List <Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); //Go through each one if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { //Pop the parameter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the parameter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } //If the number of bytes to add to skip over params is > 0 if (bytesToAdd > 0) { //If there is a return value on the stack if (returnItem.sizeOnStackInBytes != 0) { //We need to store the return value then pop all the params //We now push the return value onto our stack as, //after all is said and done below, it will be the //top item on the stack conversionState.CurrentStackFrame.Stack.Push(returnItem); //SUPPORT - floats (with above) //Pop the return value into the $t0 register //We will push it back on after params are skipped over. if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); } } //Skip over the params conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = bytesToAdd.ToString(), Dest = "$sp" }); //If necessary, push the return value onto the stack. if (returnItem.sizeOnStackInBytes != 0) { //SUPPORT - floats (with above) //The return value was stored in $t0 //So push it back onto the stack if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } } } //No params to skip over but we might still need to store return value else if (returnItem.sizeOnStackInBytes != 0) { //The return value will be the top item on the stack. //So all we need to do is push the return item onto our stack. conversionState.CurrentStackFrame.Stack.Push(returnItem); } } } else if (methodToCall is ConstructorInfo) { throw new NotSupportedException("How the hell are we getting callvirts to constructor methods?!"); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); if (methodToCall is MethodInfo) { if (typeof(Delegate).IsAssignableFrom(((MethodInfo)methodToCall).DeclaringType)) { List <Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged, isValue = retTypeInfo.IsValueType }; int bytesToAdd = 4; foreach (Type aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else { string methodIDValueWanted = methodToCallInfo.IDValue.ToString(); int currOpPosition = conversionState.PositionOf(theOp); Types.TypeInfo declaringTypeInfo = conversionState.TheILLibrary.GetTypeInfo(methodToCall.DeclaringType); Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged, isValue = retTypeInfo.IsValueType }; int bytesToAdd = 0; List <Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } if (bytesToAdd > 0) { if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.FieldInfo theFieldInfo = conversionState.GetFieldInfo(theField.DeclaringType, theField.Name); Types.TypeInfo theFieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theFieldInfo.FieldType); string fieldId = theFieldInfo.ID; int size = /*theFieldTypeInfo.IsValueType ? theFieldTypeInfo.SizeOnHeapInBytes : */ theFieldTypeInfo.SizeOnStackInBytes; bool isFloat = Utilities.IsFloat(theField.FieldType); conversionState.AddExternalLabel(fieldId); StackItem value = conversionState.CurrentStackFrame.Stack.Pop(); if (isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing static fields of type float not supported yet!"); } conversionState.Append(new ASMOps.La() { Dest = "$t4", Label = fieldId }); if (size == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "$t1", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (size == 2) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "$t1", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (size == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (size == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "4($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else { throw new ArgumentOutOfRangeException("Storing static field that has stack size greater than 8 not supported!"); } if (value.sizeOnStackInBytes - size > 0) { conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = (value.sizeOnStackInBytes - size).ToString(), Dest = "$sp" }); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if any argument or the return value is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); conversionState.AddExternalLabel(methodToCallInfo.ID); //The method to call is a method base //A method base can be either a method info i.e. a normal method //or a constructor method. The two types are treated separately. if (methodToCall is MethodInfo) { //Allocate space on the stack for the return value as necessary Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged }; //We do not push the return value onto the stack unless it has size > 0 //We do not push the return value onto our stack at this point - it is pushed after the call is done if (returnItem.sizeOnStackInBytes != 0) { if (returnItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Cannot handle float return values!"); } else if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else { throw new NotSupportedException("Invalid return stack operand size!"); } } //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodToCallInfo.ID }); //After a call, we need to remove the return value and parameters from the stack //This is most easily done by just adding the total number of bytes for params and //return value to the stack pointer (ESP register). //Stores the number of bytes to add int bytesToAdd = 0; //All the parameters for the method that was called List <Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); //Go through each one if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } //If the number of bytes to add to skip over params is > 0 if (bytesToAdd > 0) { //If there is a return value on the stack if (returnItem.sizeOnStackInBytes != 0) { //We need to store the return value then pop all the params //We now push the return value onto our stack as, //after all is said and done below, it will be the //top item on the stack conversionState.CurrentStackFrame.Stack.Push(returnItem); //SUPPORT - floats (with above) //Pop the return value into the eax register //We will push it back on after params are skipped over. if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); } } //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); //If necessary, push the return value onto the stack. if (returnItem.sizeOnStackInBytes != 0) { //SUPPORT - floats (with above) //The return value was stored in eax //So push it back onto the stack if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } } } //No params to skip over but we might still need to store return value else if (returnItem.sizeOnStackInBytes != 0) { //The return value will be the top item on the stack. //So all we need to do is push the return item onto our stack. conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if (methodToCall is ConstructorInfo) { ConstructorInfo aConstructor = (ConstructorInfo)methodToCall; if (aConstructor.IsStatic) { //Static constructors do not have parameters or return values //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodToCallInfo.ID }); } else { //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodToCallInfo.ID }); //After a call, we need to remove the parameters from the stack //This is most easily done by just adding the total number of bytes for params //to the stack pointer (ESP register). //Stores the number of bytes to add int bytesToAdd = 0; //All the parameters for the method that was called ParameterInfo[] allParams = methodToCall.GetParameters(); //Go through each one foreach (ParameterInfo aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam.ParameterType).SizeOnStackInBytes; } //Add 4 bytes for the instance ref bytesToAdd += 4; //If the number of bytes to add to skip over params is > 0 if (bytesToAdd > 0) { //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); } } } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if constant is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID); Type elementType = null; bool pushValue = true; int sizeToPush = 4; bool signExtend = true; bool isFloat = false; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldelem: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); } break; case OpCodes.Ldelema: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); pushValue = false; } break; case OpCodes.Ldelem_R4: case OpCodes.Ldelem_R8: //TODO - Add more LdElem op variants support throw new NotSupportedException("Ldelem op variant not supported yet!"); case OpCodes.Ldelem_I1: sizeToPush = 1; elementType = typeof(sbyte); break; case OpCodes.Ldelem_I2: sizeToPush = 2; elementType = typeof(Int16); break; case OpCodes.Ldelem_U1: sizeToPush = 1; signExtend = false; elementType = typeof(byte); break; case OpCodes.Ldelem_U2: sizeToPush = 2; signExtend = false; elementType = typeof(UInt16); break; case OpCodes.Ldelem_Ref: signExtend = false; elementType = null; break; case OpCodes.Ldelem_U4: signExtend = false; elementType = typeof(UInt32); break; case OpCodes.Ldelem_I4: elementType = typeof(Int32); break; case OpCodes.Ldelem_I8: sizeToPush = 8; elementType = typeof(Int64); break; } if (isFloat) { //TODO - Support floats throw new NotSupportedException("LdElem for floats not supported yet!"); } //Get element from array and push the value onto the stack // (or for LdElemA push the address of the value) //This involves: // 1. Check array reference is not null // - If it is, throw NullReferenceException // 2. Check array element type is correct // - If not, throw ArrayTypeMismatchException // 3. Check index to get is > -1 and < array length // - If not, throw IndexOutOfRangeException // 4. Calculate address of element // 5. Push the element onto the stack //Stack setup upon entering this op: (top-most downwards) // 0. Index of element to get as Int32 (dword) // 1. Array object reference as address (dword) Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); // 1. Check array reference is not null // 1.1. Move array ref into EAX // 1.2. Compare EAX (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 1.1. Move array ref into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+4]", Dest = "EAX" }); // 1.2. Compare EAX (array ref) to 0 conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "Continue1" }); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue1" }); // 2. Check array element type is correct // 2.1. Move element type ref into EAX // 2.2. Move element type ref from array object into EBX // 2.3. Compare EAX to EBX // 2.4. If the same, jump to continue execution further down // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //string ContinueExecutionLabel2 = ContinueExecutionLabelBase + "2"; //// 2.1. Move element type ref into EAX int elemTypeOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "elemType").OffsetInBytes; //if (elementType != null) //{ // result.AppendLine(string.Format("mov EAX, {0}", conversionState.GetTypeIdString(conversionState.GetTypeID(elementType)))); // // 2.2. Move element type ref from array object into EBX // // - Calculate the offset of the field from the start of the array object // // - Move array ref into EBX //GlobalMethods.CheckAddrFromRegister(result, conversionState, "ESP", 4); // result.AppendLine("mov EBX, [ESP+4]"); // // - Move elemType ref ([EBX+offset]) into EBX // GlobalMethods.CheckAddrFromRegister(result, conversionState, "EBX", elemTypeOffset); // result.AppendLine(string.Format("mov EBX, [EBX+{0}]", elemTypeOffset)); // // 2.3. Compare EAX to EBX // result.AppendLine("cmp EAX, EBX"); // // 2.4. If the same, jump to continue execution further down // result.AppendLine("je " + ContinueExecutionLabel2); // // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException // result.AppendLine(string.Format("call {0}", conversionState.GetMethodID(conversionState.ThrowArrayTypeMismatchExceptionMethod))); // result.AppendLine(ContinueExecutionLabel2 + ":"); //} // 3. Check index to get is > -1 and < array length // 3.1. Move index into EAX // 3.2. Move array length into EBX // 3.2. Compare EAX to 0 // 3.3. Jump if greater than to next test condition (3.5) // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.5. Compare EAX to EBX // 3.6. Jump if less than to continue execution further down // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.1. Move index into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP]", Dest = "EAX" }); // 3.2. Move array length into ECX // - Calculate the offset of the field from the start of the array object int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; // - Move array ref into EBX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+4]", Dest = "EBX" }); // - Move length value ([EBX+offset]) into EBX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EBX+" + lengthOffset.ToString() + "]", Dest = "EBX" }); // 3.2. Compare EAX to 0 conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); // 3.3. Jump if greater than to next test condition (3.5) conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpGreaterThanEqual, DestILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.5. Compare EAX to EBX conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "EBX" }); // 3.6. Jump if less than to continue execution further down conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpLessThan, DestILPosition = currOpPosition, Extension = "Continue3_2" }); // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_2" }); // 4. Calculate address of element // 4.1. Pop index into EBX // 4.2. Pop array ref into EAX // 4.3. Move element type ref (from array ref) into EAX // 4.4. Move IsValueType (from element ref type) into ECX // 4.5. If IsValueType, continue to 4.6., else goto 4.8. // 4.6. Move Size (from element type ref) into EAX // 4.7. Skip over 4.8. // 4.8. Move StackSize (from element type ref) into EAX // 4.9. Mulitply EAX by EBX (index by element size) // 4.10. Move array ref into EBX // 4.11. Add enough to go past Kernel.FOS_System.Array fields // 4.12. Add EAX and EBX (array ref + fields + (index * element size)) // 4.1. Pop index into EBX conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); // 4.2. Move array ref into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP]", Dest = "EAX" }); // 4.3. Move element type ref (from array ref) into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + elemTypeOffset.ToString() + "]", Dest = "EAX" }); // 4.4. Move IsValueType (from element ref type) into ECX int isValueTypeOffset = conversionState.GetTypeFieldOffset("IsValueType"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "ECX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[EAX+" + isValueTypeOffset.ToString() + "]", Dest = "CL" }); // 4.5. If IsValueType, continue to 4.6., else goto 4.8. conversionState.Append(new ASMOps.Cmp() { Arg1 = "ECX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "Continue4_1" }); // 4.6. Move Size (from element type ref) into EAX int sizeOffset = conversionState.GetTypeFieldOffset("Size"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + sizeOffset.ToString() + "]", Dest = "EAX" }); // 4.7. Skip over 4.8. conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "Continue4_2" }); // 4.8. Move StackSize (from element type ref) into EAX conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_1" }); int stackSizeOffset = conversionState.GetTypeFieldOffset("StackSize"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + stackSizeOffset + "]", Dest = "EAX" }); // 4.9. Mulitply EAX by EBX (index by element size) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_2" }); conversionState.Append(new ASMOps.Mul() { Arg = "EBX" }); // 4.10. Pop array ref into EBX conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); // 4.11. Add enough to go past Kernel.FOS_System.Array fields int allFieldsOffset = 0; #region Offset calculation { Types.FieldInfo highestOffsetFieldInfo = arrayTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderByDescending(x => x.OffsetInBytes).First(); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(highestOffsetFieldInfo.UnderlyingInfo.FieldType); allFieldsOffset = highestOffsetFieldInfo.OffsetInBytes + (fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : fieldTypeInfo.SizeOnStackInBytes); } #endregion conversionState.Append(new ASMOps.Add() { Src = allFieldsOffset.ToString(), Dest = "EBX" }); // 4.12. Add EAX and EBX (array ref + fields + (index * element size)) conversionState.Append(new ASMOps.Add() { Src = "EBX", Dest = "EAX" }); // 5. Push the element onto the stack // 5.1. Push value at [EAX] (except for LdElemA op in which case just push address) if (pushValue) { switch (sizeToPush) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EBX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[EAX]", Dest = "BL" }); if (signExtend) { throw new NotSupportedException("Sign extend byte to 4 bytes in LdElem not supported!"); } break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EBX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[EAX]", Dest = "BX" }); if (signExtend) { conversionState.Append(new ASMOps.Cwde()); } break; case 4: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX]", Dest = "EBX" }); break; case 8: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX]", Dest = "EBX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+4]", Dest = "ECX" }); break; } if (sizeToPush == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "ECX" }); } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EBX" }); } else { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } // 5.2. Pop index and array ref from our stack conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); // 5.3. Push element onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = sizeToPush > 4 ? 8 : 4, isFloat = isFloat, isNewGCObject = false, isGCManaged = pushValue ? (elementType == null || conversionState.TheILLibrary.GetTypeInfo(elementType).IsGCManaged) : false }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if field to load is a floating value or the field to load /// is not of size 4 or 8 bytes. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { conversionState.CurrentStackFrame.Stack.Pop(); Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); // 1. Check array reference is not null // 1.1. Move array ref into $t0 // 1.2. Compare $t0 (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 2. Load array length // 1.1. Move array ref into eax conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 1.2. Compare eax (array ref) to 0 // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", Src2 = "0", BranchType = ASMOps.BranchOp.BranchNotZero, DestILPosition = currOpPosition, Extension = "ContinueExecution1", UnsignedTest = false }); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ContinueExecution1" }); //2. Load array length // - Pop array ref conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); // - Load length from array ref //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = lengthOffset.ToString() + "($t2)", Dest = "$t0" }); GlobalMethods.LoadData(conversionState, theOp, "$t2", "$t0", lengthOffset, 4); // - Push array length conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = true }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load static field //Load the metadata token used to get the field info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the field info for the field to load FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); //Get the ID (i.e. ASM label) of the field to load string fieldID = conversionState.GetFieldInfo(theField.DeclaringType, theField.Name).ID; conversionState.AddExternalLabel(fieldID); //Load the field or field address switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldsfld: { Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); int size = theTypeInfo.IsValueType ? theTypeInfo.SizeOnHeapInBytes : theTypeInfo.SizeOnStackInBytes; bool isFloat = Utilities.IsFloat(theField.FieldType); if (isFloat) { //SUPPORT - floats throw new NotSupportedException("Loading static fields of type float not supported yet!"); } if (size == 1) { conversionState.Append(new ASMOps.Xor() { Src = "EAX", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[" + fieldID + "]", Dest = "AL" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else if (size == 2) { conversionState.Append(new ASMOps.Xor() { Src = "EAX", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[" + fieldID + "]", Dest = "AX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else { for (int i = size; i > 0;) { int diff = i % 4; diff = diff == 0 ? 4 : diff; i -= diff; switch (diff) { case 1: conversionState.Append(new ASMOps.Xor() { Src = "EAX", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[" + fieldID + " + " + i + "]", Dest = "AL" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); break; case 2: conversionState.Append(new ASMOps.Xor() { Src = "EAX", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[" + fieldID + " + " + i + "]", Dest = "AX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); break; case 3: conversionState.Append(new ASMOps.Xor() { Src = "EAX", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[" + fieldID + " + " + i + "]", Dest = "AL" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "AX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[" + fieldID + " + " + (i + 1) + "]", Dest = "AX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "AX" }); break; default: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[" + fieldID + " + " + i + "]", Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); break; } } } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = isFloat, sizeOnStackInBytes = theTypeInfo.SizeOnStackInBytes, isGCManaged = theTypeInfo.IsGCManaged, isValue = theTypeInfo.IsValueType }); } break; case OpCodes.Ldsflda: //Load the address of the field i.e. address of the ASM label conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = fieldID }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = false }); break; } }
/// <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> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown when loading a static float field. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the object to load Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); //Get the object size information int memSize = theTypeInfo.IsValueType ? theTypeInfo.SizeOnHeapInBytes : theTypeInfo.SizeOnStackInBytes; //Load the object onto the stack conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); int irregularSize = memSize % 4; if (irregularSize > 0) { conversionState.Append(new ASMOps.Xor() { Src = "EAX", Dest = "EAX" }); switch (irregularSize) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[ECX+" + (memSize - 1).ToString() + "]", Dest = "AL" }); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[ECX+" + (memSize - 2).ToString() + "]", Dest = "AX" }); break; case 3: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[ECX+" + (memSize - 1).ToString() + "]", Dest = "AL" }); conversionState.Append(new ASMOps.Shl() { Dest = "EAX", Src = "16" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[ECX+" + (memSize - 3).ToString() + "]", Dest = "AX" }); break; } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } for (int i = memSize - irregularSize - 4; i >= 0; i -= 4) { conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ECX+" + i.ToString() + "]", Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } // Pop address conversionState.CurrentStackFrame.Stack.Pop(); // Push value conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = memSize, isGCManaged = false, isValue = theTypeInfo.IsValueType }); }