/// <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) { //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 Type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetNewArrMethodInfo().ID); //New array must: // - Allocate memory on the heap for the object // - If no memory is left, throw a panic attack because we're out of memory... // - Call the specified constructor int currOpPosition = conversionState.PositionOf(theOp); //Attempt to allocate memory on the heap for the new array //This involves: // - (Number of elements is already on the stack) // - Pushing the element type reference onto the stack // - Calling GC NewArr method // - Check the pointer == 0, if so, out of memory //Push type reference string typeIdStr = conversionState.TheILLibrary.GetTypeInfo(elementType).ID; conversionState.AddExternalLabel(typeIdStr); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = typeIdStr }); //Push a dword for return value (i.e. new array pointer) conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); //Get the GC.NewArr method ID (i.e. ASM label) string methodLabel = conversionState.GetNewArrMethodInfo().ID; //Call GC.NewArr conversionState.Append(new ASMOps.Call() { Target = methodLabel }); //Pop the return value (i.e. new array pointer) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); //Remove args from stack conversionState.Append(new ASMOps.Add() { Src = "8", Dest = "ESP" }); //Check if pointer == 0? conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); //If it isn't 0, not out of memory so continue execution conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "NotNullMem" }); //If we are out of memory, we have a massive problem //Because it means we don't have space to create a new exception object //So ultimately we just have to throw a kernel panic //Throw a panic attack... ( :/ ) by calling kernel Halt(uint lastAddress) //result.AppendLine("call GetEIP"); //result.AppendLine("push dword esp"); //result.AppendLine("push dword ebp"); //result.AppendLine("pushad"); //result.AppendLine("mov dword eax, 0xDEADBEEF"); //result.AppendLine("mov dword ebx, 0x2"); //result.AppendLine("mov dword ecx, 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_GC_Enabled], 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_Heap_PreventAllocation], 0"); //result.AppendLine("jmp method_System_Void_RETEND_Kernel_PreReqs_DECLEND_PageFaultDetection_NAMEEND___Fail"); conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); //Insert the not null label conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotNullMem" }); //Push new array pointer conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isNewGCObject = true, isGCManaged = true, isValue = 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 either or both values to shift left are floating point values or /// if the values are 8 bytes in size. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either or both values to multiply are not 4 or 8 bytes /// in size or if the values are of different size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); int currOpPosition = conversionState.PositionOf(theOp); if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Shift left on floats is unsupported!"); } else { if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EAX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if ((itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! 4,8 not supported."); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4)) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); //Pop item A (8 bytes) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); //Check shift size conversionState.Append(new ASMOps.Cmp() { Arg1 = "ECX", Arg2 = "32" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpGreaterThanEqual, DestILPosition = currOpPosition, Extension = "ShiftMoreThan32", UnsignedTest = true }); //Shld (< 32) conversionState.Append(new ASMOps.Shl() { Src = "EAX", Dest = "EDX", Count = "CL" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "End" }); //Shld (>= 32) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ShiftMoreThan32" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "EDX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EAX" }); conversionState.Append(new ASMOps.Sub() { Src = "32", Dest = "ECX" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EDX" }); //Push result conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //Note: Shifting by more than 64 bits is pointless since the value will be annihilated entirely. // "64" fits well within the low 32-bits // So for this op, we do the same as the 8-4 byte version but discard the top four bytes // of the second operand // Except we must check the high bytes for non-zero value. If they are non-zero, we simply // push a result of zero. //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); //Pop item A (8 bytes) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); //Check high 4 bytes of second param conversionState.Append(new ASMOps.Cmp() { Arg1 = "EBX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "Zero" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "End2" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Zero" }); conversionState.Append(new ASMOps.Cmp() { Arg1 = "ECX", Arg2 = "32" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpGreaterThanEqual, DestILPosition = currOpPosition, Extension = "ShiftMoreThan32", UnsignedTest = true }); //Shld (< 32) conversionState.Append(new ASMOps.Shl() { Src = "EAX", Dest = "EDX", Count = "CL" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "End1" }); //Shl (>= 32) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ShiftMoreThan32" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "EDX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EAX" }); conversionState.Append(new ASMOps.Sub() { Src = "32", Dest = "ECX" }); conversionState.Append(new ASMOps.Shl() { Src = "CL", Dest = "EDX" }); //Push result conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End1" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "End2" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, 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> public override void Convert(ILConversionState conversionState, ILOp theOp) { MethodBase constructorMethod = theOp.MethodToCall; Type objectType = constructorMethod.DeclaringType; //New obj must: // - Ignore for creation of Delegates // - Allocate memory on the heap for the object // - If no memory is left, throw a panic attack because we're out of memory... // - Call the specified constructor if (typeof(Delegate).IsAssignableFrom(objectType)) { conversionState.Append(new ASMOps.Comment("Ignore newobj calls for Delegates")); //Still need to: // - Remove the "object" param but preserve the "function pointer" StackItem funcPtrItem = conversionState.CurrentStackFrame.Stack.Pop();; conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Push(funcPtrItem); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "4($sp)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = "4", Dest = "$sp" }); return; } Types.MethodInfo constructorMethodInfo = conversionState.TheILLibrary.GetMethodInfo(constructorMethod); conversionState.AddExternalLabel(conversionState.GetNewObjMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(constructorMethodInfo.ID); int currOpPosition = conversionState.PositionOf(theOp); //Attempt to allocate memory on the heap for the new object //This involves: // - Pushing the type reference onto the stack // - Calling GC NewObj method // - Check the pointer == 0, if so, out of memory //Push type reference string typeIdStr = conversionState.TheILLibrary.GetTypeInfo(objectType).ID; conversionState.AddExternalLabel(typeIdStr); conversionState.Append(new ASMOps.La() { Dest = "$t4", Label = typeIdStr }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t4" }); //Push a word for return value (i.e. new object pointer) conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); //Get the GC.NewObj method ID (i.e. ASM label) string methodLabel = conversionState.GetNewObjMethodInfo().ID; //Call GC.NewObj conversionState.Append(new ASMOps.Call() { Target = methodLabel }); //Pop the return value (i.e. new object pointer) conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); //Remove arg 0 from stack conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = "4", Dest = "$sp" }); //Check if pointer == 0? //If it isn't 0, not out of memory so continue execution conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchNotZero, Src1 = "$t0", DestILPosition = currOpPosition, Extension = "NotNullMem" }); //If we are out of memory, we have a massive problem //Because it means we don't have space to create a new exception object //So ultimately we just have to throw a kernel panic //Throw a panic attack... ( :/ ) by calling kernel Halt(uint lastAddress) //result.AppendLine("call GetEIP"); //result.AppendLine("push dword esp"); //result.AppendLine("push dword ebp"); //result.AppendLine("pushad"); //result.AppendLine("mov dword eax, 0xDEADBEEF"); //result.AppendLine("mov dword ebx, 0x1"); //result.AppendLine("mov dword ecx, 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_GC_Enabled], 1"); //result.AppendLine("mov dword [staticfield_System_Boolean_Kernel_FOS_System_Heap_PreventAllocation], 0"); //result.AppendLine("jmp method_System_Void_RETEND_Kernel_PreReqs_DECLEND_PageFaultDetection_NAMEEND___Fail"); conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); //Insert the not null label conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotNullMem" }); //Call the specified constructor //This involves: // - Push empty dword onto stack // - Move all args down by one dword // - Move object reference into dword as first arg // - Call constructor conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$zero" }); int sizeOfArgs = 0; ParameterInfo[] allParams = constructorMethod.GetParameters(); foreach (ParameterInfo aParam in allParams) { sizeOfArgs += conversionState.TheILLibrary.GetTypeInfo(aParam.ParameterType).SizeOnStackInBytes; conversionState.CurrentStackFrame.Stack.Pop(); } conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$sp", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.RegToReg }); if (sizeOfArgs > 0) { if (sizeOfArgs % 4 != 0) { throw new InvalidOperationException("sizeOfArgs not exact multiple of 4!"); } conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = (sizeOfArgs / 4).ToString(), Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "ShiftArgsLoop" }); //Decrement counter ($t2) conversionState.Append(new ASMOps.Sub() { Src1 = "$t2", Src2 = "1", Dest = "$t2" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($t1)", Dest = "$t3" }); GlobalMethods.LoadData(conversionState, theOp, "$t1", "$t3", 4, 4); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t3", Dest = "0($t1)" }); GlobalMethods.StoreData(conversionState, theOp, "$t1", "$t3", 0, 4); conversionState.Append(new ASMOps.Add() { Src1 = "$t1", Src2 = "4", Dest = "$t1" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchNotZero, Src1 = "$t2", DestILPosition = currOpPosition, Extension = "ShiftArgsLoop" }); } //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "0($t1)" }); GlobalMethods.StoreData(conversionState, theOp, "$t1", "$t0", 0, 4); conversionState.Append(new ASMOps.Call() { Target = constructorMethodInfo.ID }); //Only remove args from stack - we want the object pointer to remain on the stack conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = sizeOfArgs.ToString(), Dest = "$sp" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isNewGCObject = true, isGCManaged = true }); }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { string xCurrentMethodLabel = GetLabel(aMethod, aOpCode); OpType xType = ( OpType )aOpCode; string xTypeID = GetTypeIDLabel(xType.Value); //mTypeId = GetService<IMetaDataInfoService>().GetTypeIdLabel( mCastAsType ); // todo: throw an exception when the class does not support the cast! string mReturnNullLabel = xCurrentMethodLabel + "_ReturnNull"; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; new CPUx86.Compare { DestinationReg = CPUx86.Registers.EAX, SourceValue = 0 }; new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Zero, DestinationLabel = mReturnNullLabel }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true }; new CPUx86.Push { DestinationRef = Cosmos.Assembler.ElementReference.New(xTypeID), DestinationIsIndirect = true }; SysReflection.MethodBase xMethodIsInstance = ReflectionUtilities.GetMethodBase(typeof(VTablesImpl), "IsInstance", "System.Int32", "System.Int32"); // new OpMethod( ILOpCode.Code.Call, 0, 0, xMethodIsInstance, aOpCode.CurrentExceptionHandler ) ); IL.Call.DoExecute(Assembler, aMethod, xMethodIsInstance, aOpCode, xCurrentMethodLabel, xCurrentMethodLabel + "_After_IsInstance_Call", DebugEnabled); new Label(xCurrentMethodLabel + "_After_IsInstance_Call"); new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Compare { DestinationReg = CPUx86.Registers.EAX, SourceValue = 0 }; new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Equal, DestinationLabel = mReturnNullLabel }; new CPUx86.Jump { DestinationLabel = ILOp.GetLabel(aMethod, aOpCode.NextPosition) }; new Label(mReturnNullLabel); new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; string xAllocInfoLabelName = LabelName.Get(GCImplementationRefs.AllocNewObjectRef); #warning TODO: Emit new exceptions //new Newobj( Assembler ).Execute( aMethod, aOpCode ); //Newobj.Assemble( Assembler, // typeof( InvalidCastException ).GetConstructor( new Type[ 0 ] ), // GetService<IMetaDataInfoService>().GetTypeIdLabel( typeof( InvalidCastException ) ), // mThisLabel, // mMethodInfo, // mCurrentILOffset, // mThisLabel + "_After_NewException", // GetService<IMetaDataInfoService>().GetTypeInfo( typeof( InvalidCastException ) ), // GetService<IMetaDataInfoService>().GetMethodInfo( typeof( InvalidCastException ).GetConstructor( new Type[ 0 ] ), false ), // GetServiceProvider(), // xAllocInfo.LabelName ); new Label(xCurrentMethodLabel + "_After_NewException"); //Call.EmitExceptionLogic( Assembler, ( uint )mCurrentILOffset, mMethodInfo, mNextOpLabel, false, null ); }
public void SizeOfType_ForColorStruct_Returns24() { var size = ILOp.SizeOfType(typeof(Color)); Assert.That(size, Is.EqualTo(24)); }
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(); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { rotateStackItems(conversionState, theOp.StackSwitch_Items, 1); }
/// <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 either or both values to multiply are floating point values or /// if the values are 8 bytes in size. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either or both values to multiply are not 4 or 8 bytes /// in size or if the values are of different size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Divide floats is unsupported!"); } else { if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); //Do the multiplication conversionState.Append(new ASMOps.Mul() { Src1 = "$t0", Src2 = "$t1", Signed = true }); //Load the result conversionState.Append(new ASMOps.Mflo() { Dest = "$t0" }); //Result stored in $t0 conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = itemA.isValue && itemB.isValue }); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be 32-32 or 64-64."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { Logger.LogWarning(Errors.ILCompiler_ScanILOpCustomWarning_ErrorCode, "", 0, string.Format(Errors.ErrorMessages[Errors.ILCompiler_ScanILOpCustomWarning_ErrorCode], "All 64-bit multiplication is treated as unsigned. Ensure you didn't intend signed 64-bit multiplication. Signed 64-bit multiplication is not supported yet.")); //A = item A, B = item B //L = low bits, H = high bits // => A = AL + AH, B = BL + BH // A * B = (AL + AH) * (BL + BH) // = (AL * BL) + (AL * BH) + (AH * BL) (Ignore: + (AH * BH)) // AH = 12($sp) // AL = 8($sp) // BH = 4($sp) // BL = 0($sp) // mov $t0, 0 - Zero out registers conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); // mov $t1, 0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); // mov $t2, 0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); // mov $t3, 0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t3", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); // mov $t0, 0($sp) - Load BL conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // mov $t1, 8($sp) - Load AL conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "8($sp)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // mul $t1 - BL * AL, result in $lo:$hi conversionState.Append(new ASMOps.Mul() { Src1 = "$t0", Src2 = "$t1", Signed = false }); conversionState.Append(new ASMOps.Mfhi() { Dest = "$t3" }); conversionState.Append(new ASMOps.Mflo() { Dest = "$t0" }); // push $t3 - Push result keeping high bits conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); // push $t0 conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); // - Add 8 to offsets for result(s) // mov $t0, 0 - Zero out registers conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); // mov $t3, 0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t3", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); // mov $t0 4+8($sp) - Load BH conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "12($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // mul $t1 - BH * AL, result in $lo:$hi conversionState.Append(new ASMOps.Mul() { Src1 = "$t0", Src2 = "$t1" }); conversionState.Append(new ASMOps.Mflo() { Dest = "$t0" }); // push $t0 - Push result truncating high bits conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); // - Add 12 to offsets for result(s) // mov $t0, 0 - Zero out registers conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); // mov $t3, 0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t3", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); // mov $t0, 0+12($sp) - Load BL conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "12($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // mov $t1, 12+12($sp) - Load AH conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "24($sp)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // mul $t1 - BL * AH, result in $lo:$hi conversionState.Append(new ASMOps.Mul() { Src1 = "$t0", Src2 = "$t1" }); conversionState.Append(new ASMOps.Mflo() { Dest = "$t0" }); // push $t0 - Push result truncating high bits conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); // - Add 16 to offsets for result(s) // AL * BL = 8($sp) , 64 bits // AL * BH = 4($sp) , 32 bits - high bits // AH * BL = 0($sp) , 32 bits - high bits // mov $t0, 8($sp) - Load AL * BL conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "8($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // mov $t3, 12($sp) conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "12($sp)", Dest = "$t3", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // mov $t1, 0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); // mov $t2, 4($sp) - Load AL * BH conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($sp)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // add $t3, $t2 - Add (AL * BL) + (AL * BH), result in $lo:$hi conversionState.Append(new ASMOps.Add() { Src1 = "$t2", Src2 = "$t3", Dest = "$t3" }); // mov $t2, 0($sp) - Load AH * BL conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // add $t3, $t2 - Add ((AL * BL) + (AL * BH)) + (AH * BL), result in $lo:$hi conversionState.Append(new ASMOps.Add() { Src1 = "$t2", Src2 = "$t3", Dest = "$t3" }); // add $sp, 16+16 - Remove temp results and input values from stack conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = "32", Dest = "$sp" }); // push $t3 - Push final result conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); // push $t0 conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, isNewGCObject = false, sizeOnStackInBytes = 8, isGCManaged = false, isValue = itemA.isValue && itemB.isValue }); } } }
/// <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?!"); } }
/// <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"> /// If either value is < 4 bytes in length or /// operands are not of the same size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop item to duplicate StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Duplicate float vals not suppported yet!"); } if (itemA.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else if (itemA.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } else { throw new NotSupportedException("Stack item size not supported by duplicate op!"); } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged, isValue = itemA.isValue }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged, isValue = itemA.isValue }); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { try { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } catch { throw new NotSupportedException("The metadata token specifies a fieldref or methodref which isn't supported yet!"); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged, isValue = itemA.isValue }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged, isValue = itemA.isValue }); }
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 }; 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> /// 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" }); } } } }
void Next() { Int32 offset = m_position; OpCode opCode = OpCodes.Nop; int token = 0; // read first 1 or 2 bytes as opCode Byte code = ReadByte(); if (code != 0xFE) opCode = s_OneByteOpCodes[code]; else { code = ReadByte(); opCode = s_TwoByteOpCodes[code]; } //Console.WriteLine("opcode: " + opCode); current = new ILOp(); //current.opType = opCode.OpCodeType; current.opCode = opCode; //current.opType = opCode.OperandType; switch (opCode.OperandType) { case OperandType.InlineNone: //ilg.Emit(opCode); break; case OperandType.ShortInlineBrTarget: SByte shortDelta = ReadSByte(); //ilg.Emit(opCode, shortDelta); break; case OperandType.InlineBrTarget: Int32 delta = ReadInt32(); //ilg.Emit(opCode, delta); break; case OperandType.ShortInlineI: byte int8 = ReadByte(); //ilg.Emit(opCode, int8); break; case OperandType.InlineI: Int32 int32 = ReadInt32(); //ilg.Emit(opCode, int32); break; case OperandType.InlineI8: Int64 int64 = ReadInt64(); //ilg.Emit(opCode, int64); break; case OperandType.ShortInlineR: Single float32 = ReadSingle(); //ilg.Emit(opCode, float32); break; case OperandType.InlineR: Double float64 = ReadDouble(); //ilg.Emit(opCode, float64); break; case OperandType.ShortInlineVar: Byte index8 = ReadByte(); //ilg.Emit(opCode, index8); break; case OperandType.InlineVar: UInt16 index16 = ReadUInt16(); //ilg.Emit(opCode, index16); break; case OperandType.InlineString: token = ReadInt32(); current.operandType = "String"; current.operand = m_enclosingMethod.Module.ResolveString(token); //ilg.Emit(opCode, m_enclosingMethod.Module.ResolveString(token)); break; case OperandType.InlineSig: token = ReadInt32(); //ilg.Emit(opCode, m_enclosingMethod.Module.ResolveSignature(token)); throw new NotImplementedException(); break; case OperandType.InlineField: token = ReadInt32(); FieldInfo fi = m_enclosingMethod.Module.ResolveField(token); current.operandType = "Reflection.FieldInfo"; current.operand = fi.DeclaringType.FullName + Type.Delimiter + fi.Name; //ilg.Emit(opCode, m_enclosingMethod.Module.ResolveField(token)); break; case OperandType.InlineType: token = ReadInt32(); current.operandType = "Type"; Type t = m_enclosingMethod.Module.ResolveType(token); current.operand = t.FullName; //ilg.Emit(opCode, m_enclosingMethod.Module.ResolveType(token)); break; case OperandType.InlineTok: token = ReadInt32(); //ilg.Emit(opCode, token); break; case OperandType.InlineMethod: token = ReadInt32(); MethodInfo mi = (MethodInfo)m_enclosingMethod.Module.ResolveMethod(token); current.operandType = "Reflection.MethodInfo"; current.operand = mi.DeclaringType.FullName + Type.Delimiter + mi.Name; //ilg.Emit(opCode, mi); break; case OperandType.InlineSwitch: throw new NotImplementedException(); Int32 cases = ReadInt32(); Int32[] deltas = new Int32[cases]; for (Int32 i = 0; i < cases; i++) deltas[i] = ReadInt32(); break; default: throw new BadImageFormatException("unexpected OperandType " + opCode.OperandType); } }
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 divide operands are floating point numbers or if attempting to divide 64-bit numbers. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either operand is < 4 bytes long. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Divide floats is unsupported!"); } else { if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); if ((OpCodes)theOp.opCode.Value == OpCodes.Div_Un) { //Do the division conversionState.Append(new ASMOps.Div() { Arg1 = "$t0", Arg2 = "$t1", Signed = false }); } else { //Do the division conversionState.Append(new ASMOps.Div() { Arg1 = "$t0", Arg2 = "$t1", Signed = true }); } //Result stored in $t0 conversionState.Append(new ASMOps.Mflo() { Dest = "$t0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be the 32-32 or 64-64."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //SUPPORT - 64-bit division throw new NotSupportedException("64-bit by 64-bit division not supported yet!"); } } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { conversionState.CurrentStackFrame.Stack.Pop(); }
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 }); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { }
/// <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 }); }
public OpNeg(ILOp val) { this.Val = val; }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { Type elementType = null; bool pushValue = true; int sizeToPush = 4; bool isFloat = false; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldelem: { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); } break; case OpCodes.Ldelema: { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); pushValue = false; } break; case OpCodes.Ldelem_R4: case OpCodes.Ldelem_R8: 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; elementType = typeof(byte); break; case OpCodes.Ldelem_U2: sizeToPush = 2; elementType = typeof(UInt16); break; case OpCodes.Ldelem_Ref: elementType = null; break; case OpCodes.Ldelem_U4: elementType = typeof(UInt32); break; case OpCodes.Ldelem_I4: elementType = typeof(Int32); break; case OpCodes.Ldelem_I8: sizeToPush = 8; elementType = typeof(Int64); break; } // 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 }); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4)) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } }
public static void DoExecute(Cosmos.Assembler.Assembler Assembler, MethodInfo aMethod, MethodBase aTargetMethod, uint aTargetMethodUID, ILOpCode aOp, bool debugEnabled) { string xCurrentMethodLabel = GetLabel(aMethod, aOp.Position); // mTargetMethodInfo = GetService<IMetaDataInfoService>().GetMethodInfo(mMethod // , mMethod, mMethodDescription, null, mCurrentMethodInfo.DebugMode); string xNormalAddress = ""; if (aTargetMethod.IsStatic || !aTargetMethod.IsVirtual || aTargetMethod.IsFinal) { xNormalAddress = LabelName.Get(aTargetMethod); } // mMethodIdentifier = GetService<IMetaDataInfoService>().GetMethodIdLabel(mMethod); int xArgCount = aTargetMethod.GetParameters().Length; uint xReturnSize = 0; var xMethodInfo = aTargetMethod as SysReflection.MethodInfo; if (xMethodInfo != null) { xReturnSize = Align(SizeOfType(xMethodInfo.ReturnType), 4); } // Extracted from MethodInformation: Calculated offset // var xRoundedSize = ReturnSize; //if (xRoundedSize % 4 > 0) { // xRoundedSize += (4 - (ReturnSize % 4)); //} //ExtraStackSize = (int)xRoundedSize; uint xExtraStackSize = Call.GetStackSizeToReservate(aTargetMethod); uint xThisOffset = 0; var xParameters = aTargetMethod.GetParameters(); foreach (var xItem in xParameters) { xThisOffset += Align(SizeOfType(xItem.ParameterType), 4); } // This is finding offset to self? It looks like we dont need offsets of other // arguments, but only self. If so can calculate without calculating all fields // Might have to go to old data structure for the offset... // Can we add this method info somehow to the data passed in? // mThisOffset = mTargetMethodInfo.Arguments[0].Offset; new Comment(Assembler, "ThisOffset = " + xThisOffset); Call.DoNullReferenceCheck(Assembler, debugEnabled, xThisOffset); // Action xEmitCleanup = delegate() { // foreach (MethodInformation.Argument xArg in mTargetMethodInfo.Arguments) { // new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = xArg.Size }; // } // }; //EmitCompareWithNull( Assembler, // mCurrentMethodInfo, // delegate( CPUx86.Compare c ) // { // c.DestinationReg = CPUx86.Registers.ESP; // c.DestinationIsIndirect = true; // c.DestinationDisplacement = mThisOffset; // }, // mLabelName, // mLabelName + "_AfterNullRefCheck", // xEmitCleanup, // ( int )mCurrentILOffset, // GetService<IMetaDataInfoService>().GetTypeIdLabel( typeof( NullReferenceException ) ), // GetService<IMetaDataInfoService>().GetTypeInfo( typeof( NullReferenceException ) ), // GetService<IMetaDataInfoService>().GetMethodInfo( typeof( NullReferenceException ).GetConstructor( Type.EmptyTypes ), false ), // GetServiceProvider() ); // todo: add exception support new Label(xCurrentMethodLabel + ".AfterNullRefCheck"); if (!String.IsNullOrEmpty(xNormalAddress)) { if (xExtraStackSize > 0) { new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)xExtraStackSize }; } new CPUx86.Call { DestinationLabel = xNormalAddress }; } else { /* * On the stack now: * $esp Params * $esp + mThisOffset This */ new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)xThisOffset }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true }; new CPUx86.Push { DestinationValue = aTargetMethodUID }; new CPUx86.Call { DestinationLabel = LabelName.Get(VTablesImplRefs.GetMethodAddressForTypeRef) }; if (xExtraStackSize > 0) { xThisOffset -= xExtraStackSize; } /* * On the stack now: * $esp Params * $esp + mThisOffset This */ //Call.EmitExceptionLogic( Assembler, // mCurrentILOffset, // mCurrentMethodInfo, // mLabelName + "_AfterAddressCheck", // true, // xEmitCleanup ); new Label(xCurrentMethodLabel + ".AfterAddressCheck"); if (xMethodInfo.DeclaringType == typeof(object)) { /* * On the stack now: * $esp method to call * $esp + 4 Params * $esp + mThisOffset + 4 This */ // we need to see if $this is a boxed object, and if so, we need to box it new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)(xThisOffset + 4) }; //new CPUx86.Compare { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = ( ( uint )InstanceTypeEnum.BoxedValueType ), Size = 32 }; //InstanceTypeEnum.BoxedValueType == 3 => new CPUx86.Compare { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 3, Size = 32 }; /* * On the stack now: * $esp Params * $esp + mThisOffset This * * EAX contains the method to call */ new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.NotEqual, DestinationLabel = xCurrentMethodLabel + ".NotBoxedThis" }; new CPUx86.Pop { DestinationReg = CPUx86.Registers.ECX }; /* * On the stack now: * $esp Params * $esp + mThisOffset This * * ECX contains the method to call */ new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)xThisOffset }; /* * On the stack now: * $esp Params * $esp + mThisOffset This * * ECX contains the method to call * EAX contains $This, but boxed */ //new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = ( uint )ObjectImpl.FieldDataOffset }; //public const int FieldDataOffset = 12; // ObjectImpl says that. so.. new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 12 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)xThisOffset, SourceReg = CPUx86.Registers.EAX }; /* * On the stack now: * $esp Params * $esp + mThisOffset Pointer to address inside box * * ECX contains the method to call */ new CPUx86.Push { DestinationReg = CPUx86.Registers.ECX }; /* * On the stack now: * $esp Method to call * $esp + 4 Params * $esp + mThisOffset + 4 This */ } new Label(xCurrentMethodLabel + ".NotBoxedThis"); new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; if (xExtraStackSize > 0) { new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = xExtraStackSize }; } new CPUx86.Call { DestinationReg = CPUx86.Registers.EAX }; new Label(xCurrentMethodLabel + ".AfterNotBoxedThis"); } ILOp.EmitExceptionLogic(Assembler, aMethod, aOp, true, delegate() { var xResultSize = xReturnSize; if (xResultSize % 4 != 0) { xResultSize += 4 - (xResultSize % 4); } for (int i = 0; i < xResultSize / 4; i++) { new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; } }); new Label(xCurrentMethodLabel + ".NoExceptionAfterCall"); new Comment(Assembler, "Argument Count = " + xParameters.Length.ToString()); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { MethodBase constructorMethod = theOp.MethodToCall; Type objectType = constructorMethod.DeclaringType; if (typeof(Delegate).IsAssignableFrom(objectType)) { StackItem funcPtrItem = conversionState.CurrentStackFrame.Stack.Pop();; conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Push(funcPtrItem); return; } Types.MethodInfo constructorMethodInfo = conversionState.TheILLibrary.GetMethodInfo(constructorMethod); ParameterInfo[] allParams = constructorMethod.GetParameters(); foreach (ParameterInfo aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isNewGCObject = true, isGCManaged = 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 either or both values to 'or' are floating point values. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if either or both values to multiply are not 4 or 8 bytes /// in size or if the values are of different size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemB.sizeOnStackInBytes < 4 || itemA.sizeOnStackInBytes < 4) { throw new InvalidOperationException("Invalid stack operand sizes!"); } else if (itemB.isFloat || itemA.isFloat) { //SUPPORT - floats throw new NotSupportedException("Add floats is unsupported!"); } else { if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { //Pop item B conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); //Pop item A conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Or() { Src1 = "$t1", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = itemA.isValue && itemB.isValue }); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4) || (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 8)) { throw new InvalidOperationException("Invalid stack operand sizes! They should be the same size."); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { //Pop item B to $t2:$t1 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); //Pop item A to $t3:$t0 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); //Or $t2:$t1 with $t3:$t0 conversionState.Append(new ASMOps.Or() { Src1 = "$t1", Src2 = "$t0", Dest = "$t0" }); conversionState.Append(new ASMOps.Or() { Src1 = "$t2", Src2 = "$t3", Dest = "$t3" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t3" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false, isValue = itemA.isValue && itemB.isValue }); } } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isNewGCObject = true, isGCManaged = true, isValue = false }); }
protected override void DoInterpretStackTypes(ref bool aSituationChanged) { base.DoInterpretStackTypes(ref aSituationChanged); switch (OpCode) { case Code.Add: case Code.Add_Ovf: case Code.Add_Ovf_Un: case Code.Mul: case Code.Mul_Ovf: case Code.Mul_Ovf_Un: case Code.Div: case Code.Div_Un: case Code.Sub: case Code.Sub_Ovf: case Code.Sub_Ovf_Un: case Code.Rem: case Code.Rem_Un: case Code.Xor: case Code.And: case Code.Or: if (StackPushTypes[0] != null) { return; } if (!StackPopTypes.Contains(null)) { // PopTypes set, but PushType not yet, so fill it. if (StackPopTypes[0] == typeof(bool) && StackPopTypes[1] == typeof(bool)) { StackPushTypes[0] = typeof(bool); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(bool) && StackPopTypes[1] == typeof(Int32)) || (StackPopTypes[0] == typeof(Int32) && StackPopTypes[1] == typeof(bool))) { StackPushTypes[0] = typeof(Int32); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(IntPtr) && StackPopTypes[1] == typeof(uint *)) || (StackPopTypes[0] == typeof(uint *) && StackPopTypes[1] == typeof(IntPtr))) { StackPushTypes[0] = typeof(uint *); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(UIntPtr) && StackPopTypes[1] == typeof(uint *)) || (StackPopTypes[0] == typeof(uint *) && StackPopTypes[1] == typeof(UIntPtr))) { StackPushTypes[0] = typeof(uint *); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(uint) && StackPopTypes[1] == typeof(byte *)) || (StackPopTypes[0] == typeof(byte *) && StackPopTypes[1] == typeof(uint))) { StackPushTypes[0] = typeof(byte *); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(byte *)) || (StackPopTypes[0] == typeof(byte *) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(byte *); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(IntPtr) && StackPopTypes[1] == typeof(byte *)) || (StackPopTypes[0] == typeof(byte *) && StackPopTypes[1] == typeof(IntPtr))) { StackPushTypes[0] = typeof(byte *); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(IntPtr) && StackPopTypes[1] == typeof(char *)) || (StackPopTypes[0] == typeof(char *) && StackPopTypes[1] == typeof(IntPtr))) { StackPushTypes[0] = typeof(char *); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(UIntPtr) && StackPopTypes[1] == typeof(char *)) || (StackPopTypes[0] == typeof(char *) && StackPopTypes[1] == typeof(UIntPtr))) { StackPushTypes[0] = typeof(char *); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(IntPtr) && StackPopTypes[1] == typeof(uint)) || (StackPopTypes[0] == typeof(uint) && StackPopTypes[1] == typeof(IntPtr))) { StackPushTypes[0] = typeof(UIntPtr); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(UIntPtr)) || (StackPopTypes[0] == typeof(UIntPtr) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(UIntPtr); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(IntPtr)) || (StackPopTypes[0] == typeof(IntPtr) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(IntPtr); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(uint)) || (StackPopTypes[0] == typeof(uint) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(short) && StackPopTypes[1] == typeof(ushort)) || (StackPopTypes[0] == typeof(ushort) && StackPopTypes[1] == typeof(short))) { StackPushTypes[0] = typeof(short); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(byte)) || (StackPopTypes[0] == typeof(byte) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(short)) || (StackPopTypes[0] == typeof(short) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(long) && StackPopTypes[1] == typeof(ulong)) || (StackPopTypes[0] == typeof(ulong) && StackPopTypes[1] == typeof(long))) { StackPushTypes[0] = typeof(long); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(ushort)) || (StackPopTypes[0] == typeof(ushort) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(byte) && StackPopTypes[1] == typeof(uint)) || (StackPopTypes[0] == typeof(uint) && StackPopTypes[1] == typeof(byte))) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(ushort) && StackPopTypes[1] == typeof(uint)) || (StackPopTypes[0] == typeof(uint) && StackPopTypes[1] == typeof(ushort))) { StackPushTypes[0] = typeof(uint); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(char)) || (StackPopTypes[0] == typeof(char) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(IntPtr) && StackPopTypes[1] == typeof(UIntPtr)) || (StackPopTypes[0] == typeof(UIntPtr) && StackPopTypes[1] == typeof(IntPtr))) { StackPushTypes[0] = typeof(UIntPtr); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(IntPtr) && StackPopTypes[1] == typeof(IntPtr)) { StackPushTypes[0] = typeof(IntPtr); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(uint) && StackPopTypes[1] == typeof(uint)) { StackPushTypes[0] = typeof(uint); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(uint) && StackPopTypes[1] == typeof(char)) { StackPushTypes[0] = typeof(uint); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(byte) && StackPopTypes[1] == typeof(byte)) { StackPushTypes[0] = typeof(byte); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(byte) && StackPopTypes[1] == typeof(ushort) || StackPopTypes[0] == typeof(ushort) && StackPopTypes[1] == typeof(byte)) { StackPushTypes[0] = typeof(ushort); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(int)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(bool)) || (StackPopTypes[0] == typeof(bool) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(ushort) && StackPopTypes[1] == typeof(ushort)) { StackPushTypes[0] = typeof(ushort); aSituationChanged = true; return; } //Changed if (StackPopTypes[0] == typeof(short) && StackPopTypes[1] == typeof(short)) { StackPushTypes[0] = typeof(short); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(long) && StackPopTypes[1] == typeof(long)) { StackPushTypes[0] = typeof(long); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(ulong) && StackPopTypes[1] == typeof(ulong)) { StackPushTypes[0] = typeof(ulong); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(Double) && StackPopTypes[1] == typeof(Double)) { StackPushTypes[0] = typeof(Double); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(Single) && StackPopTypes[1] == typeof(Single)) { StackPushTypes[0] = typeof(Single); aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(Char) && StackPopTypes[1] == typeof(Char)) { StackPushTypes[0] = typeof(Char); aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(int) && StackPopTypes[1] == typeof(sbyte)) || (StackPopTypes[0] == typeof(sbyte) && StackPopTypes[1] == typeof(int))) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (StackPopTypes[0] == StackPopTypes[1] && StackPopTypes[0].IsPointer) { StackPushTypes[0] = StackPopTypes[0]; aSituationChanged = true; return; } if (StackPopTypes[0] == typeof(int) && StackPopTypes[1].IsPointer) { StackPushTypes[0] = StackPopTypes[1]; aSituationChanged = true; return; } if ((StackPopTypes[0] == typeof(IntPtr) || StackPopTypes[0] == typeof(UIntPtr)) && StackPopTypes[1].IsPointer) { StackPushTypes[0] = StackPopTypes[1]; aSituationChanged = true; return; } if (OpCode == Code.Add && ((StackPopTypes[0] == typeof(IntPtr) && (StackPopTypes[1].IsPointer || StackPopTypes[1].IsByRef)) || ((StackPopTypes[0].IsPointer || StackPopTypes[0].IsByRef) && StackPopTypes[1] == typeof(IntPtr)))) { if (StackPopTypes[0] == typeof(IntPtr)) { StackPushTypes[0] = StackPopTypes[1]; } else { StackPushTypes[0] = StackPopTypes[0]; } aSituationChanged = true; return; } throw new NotImplementedException(string.Format("{0} on types '{1}' and '{2}' not yet implemented!", OpCode, StackPopTypes[0], StackPopTypes[1])); } break; case Code.Localloc: StackPushTypes[0] = typeof(void *); aSituationChanged = true; return; case Code.Stelem_I2: var xTypeValue = StackPopTypes[0]; if (xTypeValue == null) { return; } if (xTypeValue == typeof(byte) || xTypeValue == typeof(char) || xTypeValue == typeof(short) || xTypeValue == typeof(ushort) || xTypeValue == typeof(int)) { return; } throw new NotImplementedException(String.Format("Stelem_I2 storing type '{0}' is not implemented!", xTypeValue)); case Code.Shl: case Code.Shr: case Code.Shr_Un: xTypeValue = StackPopTypes[1]; var xTypeShift = StackPopTypes[0]; if (xTypeValue == null || xTypeShift == null) { return; } if (xTypeValue == typeof(int) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (xTypeValue == typeof(byte) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (xTypeValue == typeof(long) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(long); aSituationChanged = true; return; } if (xTypeValue == typeof(IntPtr) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (xTypeValue == typeof(int) && xTypeShift == typeof(IntPtr)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (xTypeValue == typeof(ushort) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (xTypeValue == typeof(char) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (xTypeValue == typeof(uint) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (xTypeValue == typeof(long) && xTypeShift == typeof(IntPtr)) { StackPushTypes[0] = typeof(long); aSituationChanged = true; return; } if (xTypeValue == typeof(IntPtr) && xTypeShift == typeof(IntPtr)) { StackPushTypes[0] = typeof(IntPtr); aSituationChanged = true; return; } if (xTypeValue == typeof(IntPtr) && xTypeShift == typeof(IntPtr)) { StackPushTypes[0] = typeof(IntPtr); aSituationChanged = true; return; } if (xTypeValue == typeof(ulong) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(ulong); aSituationChanged = true; return; } if (xTypeValue == typeof(sbyte) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } if (xTypeValue == typeof(short) && xTypeShift == typeof(int)) { StackPushTypes[0] = typeof(int); aSituationChanged = true; return; } throw new NotImplementedException(String.Format("{0} with types {1} and {2} is not implemented!", OpCode, xTypeValue.FullName, xTypeShift.FullName)); case Code.Ldelem_Ref: if (StackPushTypes[0] != null) { return; } var xTypeArray = StackPopTypes[1]; if (xTypeArray == null) { return; } if (!xTypeArray.IsArray) { throw new Exception("Ldelem Array type is not an array (Actual = " + xTypeArray.FullName + ")"); } StackPushTypes[0] = xTypeArray.GetElementType(); aSituationChanged = true; break; case Code.Not: case Code.Neg: if (StackPushTypes[0] != null) { return; } if (StackPopTypes[0] != null) { StackPushTypes[0] = StackPopTypes[0]; aSituationChanged = true; return; } break; case Code.Dup: if (StackPushTypes[0] != null && StackPushTypes[1] != null) { return; } if (StackPopTypes[0] != null) { StackPushTypes[0] = StackPopTypes[0]; StackPushTypes[1] = StackPopTypes[0]; aSituationChanged = true; return; } return; case Code.Stind_I1: if (StackPopTypes[1] == null || StackPopTypes[0] == null) { return; } if (!ILOp.IsIntegralType(StackPopTypes[0])) { throw new Exception("Wrong value type: " + StackPopTypes[0].FullName); } if (!ILOp.IsPointer(StackPopTypes[1])) { throw new Exception("Wrong Pointer type: " + StackPopTypes[1].FullName); } break; case Code.Stind_I2: if (StackPopTypes[1] == null || StackPopTypes[0] == null) { return; } if (!ILOp.IsIntegralType(StackPopTypes[0])) { throw new Exception("Wrong value type: " + StackPopTypes[0].FullName); } if (!ILOp.IsPointer(StackPopTypes[1])) { throw new Exception("Wrong Pointer type: " + StackPopTypes[1].FullName); } break; case Code.Stind_I4: if (StackPopTypes[1] == null || StackPopTypes[0] == null) { return; } if (!ILOp.IsIntegralType(StackPopTypes[0])) { throw new Exception("Wrong value type: " + StackPopTypes[0].FullName); } if (!ILOp.IsPointer(StackPopTypes[1])) { throw new Exception("Wrong Pointer type: " + StackPopTypes[1].FullName); } break; case Code.Stind_I8: if (StackPopTypes[1] == null || StackPopTypes[0] == null) { return; } if (!ILOp.IsIntegralType(StackPopTypes[0])) { throw new Exception("Wrong value type: " + StackPopTypes[0].FullName); } if (!ILOp.IsPointer(StackPopTypes[1])) { throw new Exception("Wrong Pointer type: " + StackPopTypes[1].FullName); } break; case Code.Stind_I: if (StackPopTypes[1] == null || StackPopTypes[0] == null) { return; } if (!ILOp.IsIntegralTypeOrPointer(StackPopTypes[0])) { throw new Exception("Wrong value type: " + StackPopTypes[0].FullName); } if (!ILOp.IsPointer(StackPopTypes[1])) { throw new Exception("Wrong Pointer type: " + StackPopTypes[1].FullName); } break; case Code.Ldind_Ref: if (StackPushTypes[0] != null) { return; } if (StackPopTypes[0] == null) { return; } if (!StackPopTypes[0].IsByRef && !StackPopTypes[0].IsPointer) { throw new Exception("Invalid ref type: " + StackPopTypes[0].FullName); } if (StackPopTypes[0].IsPointer) { StackPushTypes[0] = typeof(object); } else { StackPushTypes[0] = StackPopTypes[0].GetElementType(); } aSituationChanged = true; break; } }
public static void Assemble(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethod, OpMethod xMethod, string currentLabel, Type objectType, MethodBase constructor) { // call cctor: if (aMethod != null) { var xCctor = (objectType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); ILOp.EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } } if (objectType.IsValueType) { #region Valuetypes XS.Comment("ValueType"); /* * Current sitation on stack: * $ESP Arg * $ESP+.. other items * * What should happen: * + The stack should be increased to allow space to contain: * + .ctor arguments * + struct _pointer_ (ref to start of emptied space) * + empty space for struct * + arguments should be copied to the new place * + old place where arguments were should be cleared * + pointer should be set * + call .ctor */ // Size of return value - we need to make room for this on the stack. uint xStorageSize = Align(SizeOfType(objectType), 4); XS.Comment("StorageSize: " + xStorageSize); if (xStorageSize == 0) { throw new Exception("ValueType storage size cannot be 0."); } //var xStorageSize = aCtorDeclTypeInfo.StorageSize; uint xArgSize = 0; var xParameterList = constructor.GetParameters(); foreach (var xParam in xParameterList) { xArgSize = xArgSize + Align(SizeOfType(xParam.ParameterType), 4); } XS.Comment("ArgSize: " + xArgSize); // Set ESP so we can push the struct ptr int xShift = (int)(xArgSize - xStorageSize); XS.Comment("Shift: " + xShift); if (xShift < 0) { XS.Sub(XSRegisters.ESP, (uint)Math.Abs(xShift)); } else if (xShift > 0) { XS.Add(XSRegisters.ESP, (uint)xShift); } // push struct ptr XS.Push(XSRegisters.ESP); // Shift args foreach (var xParam in xParameterList) { uint xArgSizeForThis = Align(SizeOfType(xParam.ParameterType), 4); for (int i = 1; i <= xArgSizeForThis / 4; i++) { new CPUx86.Push { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)xStorageSize }; } } new Call(aAssembler).Execute(aMethod, xMethod); // Need to put these *after* the call because the Call pops the args from the stack // and we have mucked about on the stack, so this makes it right before the next // op. #endregion Valuetypes } else { // If not ValueType, then we need gc var xParams = constructor.GetParameters(); // array length + 8 bool xHasCalcSize = false; #region Special string handling // try calculating size: if (constructor.DeclaringType == typeof(string)) { if (xParams.Length == 1 && xParams[0].ParameterType == typeof(char[])) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); // EAX contains a memory handle now, lets dereference it to a pointer XS.Set(EAX, EAX, sourceIsIndirect: true); XS.Set(XSRegisters.EAX, XSRegisters.EAX, sourceDisplacement: 8); XS.Set(XSRegisters.EDX, 2); XS.Multiply(XSRegisters.EDX); XS.Push(XSRegisters.EAX); } else if (xParams.Length == 3 && (xParams[0].ParameterType == typeof(char[]) || xParams[0].ParameterType == typeof(char *)) && xParams[1].ParameterType == typeof(int) && xParams[2].ParameterType == typeof(int)) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.ShiftLeft(XSRegisters.EAX, 1); XS.Push(XSRegisters.EAX); } else if (xParams.Length == 2 && xParams[0].ParameterType == typeof(char) && xParams[1].ParameterType == typeof(int)) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.ShiftLeft(XSRegisters.EAX, 1); XS.Push(XSRegisters.EAX); } else { throw new NotImplementedException("In NewObj, a string ctor implementation is missing!"); } } #endregion Special string handling uint xMemSize = GetStorageSize(objectType); int xExtraSize = 12; // additional size for set values after alloc XS.Push((uint)(xMemSize + xExtraSize)); if (xHasCalcSize) { XS.Pop(XSRegisters.EAX); XS.Add(ESP, EAX, destinationIsIndirect: true); } // todo: probably we want to check for exceptions after calling Alloc XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Label(".AfterAlloc"); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack now 3 times. Once from the Alloc return value, twice from the pushes //? ?? uint xObjSize;// = 0; //int xGCFieldCount = ( from item in aCtorDeclTypeInfo.Fields.Values //where item.NeedsGC //select item ).Count(); //int xGCFieldCount = ( from item in aCtorDeclTypeInfo.Fields.Values //where item.NeedsGC //select item ).Count(); int xGCFieldCount = objectType.GetFields().Count(x => x.FieldType.IsValueType); // todo: use a cleaner approach here. this class shouldnt assemble the string string strTypeId = GetTypeIDLabel(constructor.DeclaringType); XS.Pop(XSRegisters.EAX); XS.Set(EAX, EAX, sourceIsIndirect: true); XS.Set(EBX, strTypeId, sourceIsIndirect: true); XS.Set(EAX, EBX, destinationIsIndirect: true); XS.Set(EAX, (uint)InstanceTypeEnum.NormalObject, destinationDisplacement: 4, size: RegisterSize.Int32); XS.Set(EAX, (uint)xGCFieldCount, destinationDisplacement: 8, size: RegisterSize.Int32); uint xSize = (uint)(from item in xParams let xQSize = Align(SizeOfType(item.ParameterType), 4) select(int) xQSize).Take(xParams.Length).Sum(); foreach (var xParam in xParams) { uint xParamSize = Align(SizeOfType(xParam.ParameterType), 4); new Comment(aAssembler, String.Format("Arg {0}: {1}", xParam.Name, xParamSize)); for (int i = 0; i < xParamSize; i += 4) { new CPUx86.Push { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xSize + 4) }; } } XS.Call(LabelName.Get(constructor)); // should the complete error handling happen by ILOp.EmitExceptionLogic? if (aMethod != null) { // todo: only happening for real methods now, not for ctor's ? XS.Test(XSRegisters.ECX, 2); string xNoErrorLabel = currentLabel + ".NoError" + LabelName.LabelCount.ToString(); XS.Jump(CPUx86.ConditionalTestEnum.Equal, xNoErrorLabel); //for( int i = 1; i < aCtorMethodInfo.Arguments.Length; i++ ) //{ // new CPUx86.Add // { // DestinationReg = CPUx86.Registers.ESP, // SourceValue = ( aCtorMethodInfo.Arguments[ i ].Size % 4 == 0 // ? aCtorMethodInfo.Arguments[ i ].Size // : ( ( aCtorMethodInfo.Arguments[ i ].Size / 4 ) * 4 ) + 1 ) // }; //} PushAlignedParameterSize(constructor); // an exception occurred, we need to cleanup the stack, and jump to the exit XS.Add(XSRegisters.ESP, 4); //new Comment(aAssembler, "[ Newobj.Execute cleanup start count = " + aAssembler.Stack.Count.ToString() + " ]"); //foreach( var xStackInt in Assembler.Stack ) //{ // new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = ( uint )xStackInt.Size }; //} new Comment(aAssembler, "[ Newobj.Execute cleanup end ]"); Jump_Exception(aMethod); XS.Label(xNoErrorLabel); } XS.Pop(XSRegisters.EAX); //for( int i = 1; i < aCtorMethodInfo.Arguments.Length; i++ ) //{ // new CPUx86.Add // { // DestinationReg = CPUx86.Registers.ESP, // SourceValue = ( aCtorMethodInfo.Arguments[ i ].Size % 4 == 0 // ? aCtorMethodInfo.Arguments[ i ].Size // : ( ( aCtorMethodInfo.Arguments[ i ].Size / 4 ) * 4 ) + 1 ) // }; //} PushAlignedParameterSize(constructor); XS.Push(XSRegisters.EAX); } }
public ILOpSpec(ILOp op, OpCode opcode) { Op = op; OpCode = opcode; }