/// <summary> /// Emits cleanup code for when an exception occurred inside a method call. /// </summary> public static void EmitExceptionCleanupAfterCall(Assembler.Assembler aAssembler, uint aReturnSize, uint aStackSizeBeforeCall, uint aTotalArgumentSizeOfMethod) { XS.Comment("aStackSizeBeforeCall = " + aStackSizeBeforeCall); XS.Comment("aTotalArgumentSizeOfMethod = " + aTotalArgumentSizeOfMethod); XS.Comment("aReturnSize = " + aReturnSize); if (aReturnSize != 0) { // at least pop return size: XS.Comment("Cleanup return"); // cleanup result values for (int i = 0; i < aReturnSize / 4; i++) { XS.Add(XSRegisters.ESP, 4); } } if (aStackSizeBeforeCall > (aTotalArgumentSizeOfMethod)) { if (aTotalArgumentSizeOfMethod > 0) { var xExtraStack = aStackSizeBeforeCall - aTotalArgumentSizeOfMethod; XS.Comment("Cleanup extra stack"); // cleanup result values for (int i = 0; i < xExtraStack / 4; i++) { XS.Add(XSRegisters.ESP, 4); } } } }
static void Main(string[] aArgs) { try { string xSrc = aArgs[0]; var xGenerator = new AsmGenerator(); //string[] xFiles; //if (Directory.Exists(xSrc)) //{ // xFiles = Directory.GetFiles(xSrc, "*.xs"); //} //else //{ // xFiles = new string[] { xSrc }; //} //foreach (var xFile in xFiles) //{ // xGenerator.GenerateToFiles(xFile); //} var xAsm = new Assembler(); var xStreamReader = new StringReader(@"namespace Test while byte ESI[0] != 0 { ! nop } "); var xResult = xGenerator.Generate(xStreamReader); Console.WriteLine("done"); } catch (Exception ex) { Console.WriteLine(ex.ToString()); Environment.Exit(1); } }
/// <summary>Parse the input X# source code file and generate the matching target assembly /// language.</summary> /// <param name="aReader">X# source code reader.</param> /// <returns>The resulting target assembler content. The returned object contains /// a code and a data block.</returns> public Assembler Generate(TextReader aReader) { if (aReader == null) { throw new ArgumentNullException(nameof(aReader)); } mPatterns.EmitUserComments = EmitUserComments; mLineNo = 0; var xResult = new Assembler(); try { // Read one X# source code line at a time and process it. while (true) { mLineNo++; string xLine = aReader.ReadLine(); if (xLine == null) { break; } ProcessLine(xLine, mLineNo); } AssertLastFunctionComplete(); return xResult; } finally { Assembler.ClearCurrentInstance(); } }
public Comment( Assembler aAssembler, string aText ) : base() //HACK { if (aText.StartsWith(";")) { aText = aText.TrimStart(';').TrimStart(); } Text = String.Intern(aText); }
public static void Assemble(Assembler.Assembler aAssembler, uint aElementSize, MethodInfo aMethod, ILOpCode aOpCode, bool debugEnabled) { // stack == the new value // stack + 1 == the index // stack + 2 == the array DoNullReferenceCheck(aAssembler, debugEnabled, (int)(8 + Align(aElementSize, 4))); uint xStackSize = aElementSize; if (xStackSize % 4 != 0) { xStackSize += 4 - xStackSize % 4; } // calculate element offset into array memory (including header) XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: (int)xStackSize); // the index XS.Set(XSRegisters.EDX, aElementSize); XS.Multiply(XSRegisters.EDX); XS.Add(XSRegisters.EAX, ObjectImpl.FieldDataOffset + 4); XS.Set(XSRegisters.EDX, XSRegisters.ESP, sourceDisplacement: (int)xStackSize + 8); // the array XS.Add(XSRegisters.EDX, XSRegisters.EAX); XS.Push(XSRegisters.EDX); XS.Pop(XSRegisters.ECX); for (int i = (int)(aElementSize / 4) - 1; i >= 0; i -= 1) { new Comment(aAssembler, "Start 1 dword"); XS.Pop(XSRegisters.EBX); XS.Set(XSRegisters.ECX, XSRegisters.EBX, destinationIsIndirect: true); XS.Add(XSRegisters.ECX, 4); } switch (aElementSize % 4) { case 1: { new Comment(aAssembler, "Start 1 byte"); XS.Pop(XSRegisters.EBX); XS.Set(XSRegisters.ECX, XSRegisters.BL, destinationIsIndirect: true); break; } case 2: { new Comment(aAssembler, "Start 1 word"); XS.Pop(XSRegisters.EBX); XS.Set(XSRegisters.ECX, XSRegisters.BX, destinationIsIndirect: true); break; } case 0: { break; } default: throw new Exception("Remainder size " + (aElementSize % 4) + " not supported!"); } XS.Add(XSRegisters.ESP, 12); }
private void DoExecute(Assembler.Assembler assembler, MethodInfo aMethod, ILOpCode aOpCode, OpType aTargetType, bool debugEnabled) { new Comment(assembler, $"Type = {aTargetType.Value}"); if (aTargetType.Value.BaseType == typeof(ValueType)) { } else if (aTargetType.Value.BaseType == typeof(object)) { throw new NotImplementedException($"Constrained not implemented for {aTargetType.Value}"); } }
private void DoExecute(Assembler.Assembler assembler, MethodInfo aMethod, ILOpCode aOpCode, OpType aTargetType, bool debugEnabled) { // If thisType is a reference type (as opposed to a value type) then // ptr is dereferenced and passed as the ‘this’ pointer to the callvirt of method // If thisType is a value type and thisType implements method then // ptr is passed unmodified as the ‘this’ pointer to a call of method implemented by thisType // If thisType is a value type and thisType does not implement method then // ptr is dereferenced, boxed, and passed as the ‘this’ pointer to the callvirt of method new Comment(assembler, $"Type = {aTargetType.Value}"); if (aTargetType.Value.BaseType == typeof (ValueType)) { } else if (aTargetType.Value.BaseType == typeof (object)) { throw new NotImplementedException($"Constrained not implemented for {aTargetType.Value}"); } }
public static void DoNullReferenceCheck(Assembler.Assembler assembler, bool debugEnabled, uint stackOffsetToCheck) { if (stackOffsetToCheck != Align(stackOffsetToCheck, 4)) { throw new Exception("Stack offset not aligned!"); } if (debugEnabled) { new CPU.Compare {DestinationReg = CPU.RegistersEnum.ESP, DestinationDisplacement = (int) stackOffsetToCheck, DestinationIsIndirect = true, SourceValue = 0}; XS.Jump(CPU.ConditionalTestEnum.NotEqual, ".AfterNullCheck"); XS.ClearInterruptFlag(); // don't remove the call. It seems pointless, but we need it to retrieve the EIP value XS.Call(".NullCheck_GetCurrAddress"); XS.Label(".NullCheck_GetCurrAddress"); XS.Pop(XSRegisters.EAX); new CPU.Mov {DestinationRef = ElementReference.New("DebugStub_CallerEIP"), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.EAX}; XS.Call("DebugStub_SendNullReferenceOccurred"); XS.Halt(); XS.Label(".AfterNullCheck"); } }
public static void DoExecute(Cosmos.Assembler.Assembler Assembler, Type aDeclaringType, string xFieldId, bool aDerefExternalField, bool debugEnabled, Type aTypeOnStack) { var xOffset = GetFieldOffset(aDeclaringType, xFieldId); var xFields = GetFieldsInfo(aDeclaringType, false); var xFieldInfo = (from item in xFields where item.Id == xFieldId select item).Single(); XS.Comment("Field: " + xFieldInfo.Id); XS.Comment("Type: " + xFieldInfo.FieldType.ToString()); XS.Comment("Size: " + xFieldInfo.Size); XS.Comment("DeclaringType: " + aDeclaringType.FullName); XS.Comment("TypeOnStack: " + aTypeOnStack.FullName); XS.Comment("Offset: " + xOffset + " (includes object header)"); if (aDeclaringType.IsValueType && aTypeOnStack == aDeclaringType) { #region Read struct value from stack // This is a 3-step process // 1. Move the actual value below the stack (negative to ESP) // 2. Move the value at the right spot of the stack (positive to stack) // 3. Adjust stack to remove the struct // // This is necessary, as the value could otherwise overwrite the struct too soon. var xTypeStorageSize = GetStorageSize(aDeclaringType); var xFieldStorageSize = xFieldInfo.Size; // Step 1, Move the actual value below the stack (negative to ESP) CopyValue(ESP, -(int)xFieldStorageSize, ESP, xOffset, xFieldStorageSize); // Step 2 Move the value at the right spot of the stack (positive to stack) var xStackOffset = (int)(Align(xTypeStorageSize, 4) - xFieldStorageSize); CopyValue(ESP, xStackOffset, ESP, -(int)xFieldStorageSize, xFieldStorageSize); // Step 3 Adjust stack to remove the struct XS.Add(ESP, Align((uint)(xStackOffset), 4)); #endregion Read struct value from stack return; } // pushed size is always 4 or 8 var xSize = xFieldInfo.Size; if (TypeIsReferenceType(aTypeOnStack)) { DoNullReferenceCheck(Assembler, debugEnabled, 4); XS.Add(ESP, 4); } else { DoNullReferenceCheck(Assembler, debugEnabled, 0); } XS.Pop(ECX); XS.Add(ECX, (uint)(xOffset)); if (xFieldInfo.IsExternalValue && aDerefExternalField) { XS.Set(ECX, ECX, sourceIsIndirect: true); } for (int i = 1; i <= (xSize / 4); i++) { XS.Set(EAX, ECX, sourceDisplacement: (int)(xSize - (i * 4))); XS.Push(EAX); } XS.Set(EAX, 0); switch (xSize % 4) { case 1: XS.Set(AL, ECX, sourceIsIndirect: true); XS.Push(EAX); break; case 2: XS.Set(AX, ECX, sourceIsIndirect: true); XS.Push(EAX); break; case 3: //For Release XS.Set(EAX, ECX, sourceIsIndirect: true); XS.ShiftRight(EAX, 8); XS.Push(EAX); break; case 0: { break; } default: throw new Exception(string.Format("Remainder size {0} {1:D} not supported!", xFieldInfo.FieldType.ToString(), xSize)); } }
public Ldelem_Ref(Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) { XS.EnableInterrupts(); }
public abstract bool IsComplete(Assembler aAssembler);
public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) { Exchange(BX, BX); }
public Shr_Un(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public override void UpdateAddress( Assembler aAssembler, ref ulong aAddress ) { base.UpdateAddress( aAssembler, ref aAddress ); }
public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) { var xAssembler = aAssembler; var xMethodInfo = (MethodInfo) aMethodInfo; var xMethodBaseAsInfo = xMethodInfo.MethodBase as global::System.Reflection.MethodInfo; if (xMethodBaseAsInfo.ReturnType != typeof(void)) { throw new Exception("Events with return type not yet supported!"); } /* * EAX contains the GetInvocationList() array at the index at which it was last used * EDX contains the index at which the EAX is * EBX contains the number of items in the array * ECX contains the argument size */ XS.ClearInterruptFlag(); XS.Comment("Get Invoke list count"); var xGetInvocationListMethod = typeof(MulticastDelegate).GetMethod("GetInvocationList"); Ldarg.DoExecute(aAssembler, xMethodInfo, 0); XS.Call(LabelName.Get(xGetInvocationListMethod)); XS.Add(ESP, 4); XS.Pop(EAX); XS.Add(EAX, 8); XS.Set(EBX, EAX, sourceIsIndirect: true); XS.Comment("Get invoke method"); XS.Add(EAX, 8); XS.Set(EDI, EAX, sourceIsIndirect: true, sourceDisplacement: 4); XS.Comment("Get ArgSize"); int xArgSizeOffset = Ldfld.GetFieldOffset(typeof(global::System.Delegate), "$$ArgSize$$"); Ldarg.DoExecute(aAssembler, xMethodInfo, 0); XS.Add(ESP, 4); XS.Pop(ECX); XS.Add(ECX, (uint) xArgSizeOffset); XS.Set(ECX, ECX, sourceIsIndirect: true); XS.Comment("Set current invoke list index"); XS.Set(EDX, 0); XS.Label(".BEGIN_OF_LOOP"); { XS.Compare(EDX, EBX); XS.Jump(Assembler.x86.ConditionalTestEnum.GreaterThanOrEqualTo, ".END_OF_INVOKE"); XS.PushAllRegisters(); XS.Comment("Check if delegate has $this"); XS.Set(EDI, EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); XS.Add(EDI, 4); XS.Set(EDI, EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.Object System.Delegate._target")); XS.Compare(EDI, 0); XS.Jump(Assembler.x86.ConditionalTestEnum.Zero, ".NO_THIS"); XS.Label(".HAS_THIS"); XS.Push(EDI); XS.Push(0); XS.Label(".NO_THIS"); XS.Set(EDI, EAX, sourceIsIndirect: true, sourceDisplacement: 4); XS.Set(EDI, EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.IntPtr System.Delegate._methodPtr")); XS.Comment("Check if delegate has args"); XS.Compare(ECX, 0); XS.Jump(Assembler.x86.ConditionalTestEnum.Zero, ".NO_ARGS"); XS.Label(".HAS_ARGS"); XS.Sub(ESP, ECX); XS.Push(EDI); XS.Set(EDI, ESP); XS.Add(EDI, 4); XS.Set(ESI, EBP); XS.Add(ESI, 8); new Assembler.x86.Movs { Size = 8, Prefixes = Assembler.x86.InstructionPrefixes.Repeat }; XS.Pop(EDI); XS.Label(".NO_ARGS"); XS.Call(EDI); XS.PopAllRegisters(); XS.Increment(EDX); XS.Jump(".BEGIN_OF_LOOP"); } XS.Label(".END_OF_INVOKE"); XS.Set(EDX, EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); XS.Set(EDX, EDX, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "$$ReturnsValue$$")); XS.Compare(EDX, 0); XS.Jump(Assembler.x86.ConditionalTestEnum.Equal, ".NO_RETURN"); XS.Label(".HAS_RETURN"); XS.Exchange(EBP, EDX, destinationDisplacement: 8); XS.Exchange(EBP, EDX, destinationDisplacement: 4); XS.Exchange(EBP, EDX, destinationIsIndirect: true); XS.Push(EDX); XS.Set(ESP, EDI, destinationDisplacement: 12); XS.Label(".NO_RETURN"); XS.EnableInterrupts(); }
public static void DoExecute(Assembler.Assembler Assembler, MethodInfo aMethod, MethodBase aTargetMethod, uint aTargetMethodUID, ILOpCode aOp, bool debugEnabled) { string xCurrentMethodLabel = GetLabel(aMethod, aOp.Position); Type xPopType = aOp.StackPopTypes.Last(); string xNormalAddress = ""; if (aTargetMethod.IsStatic || !aTargetMethod.IsVirtual || aTargetMethod.IsFinal) { xNormalAddress = LabelName.Get(aTargetMethod); } uint xReturnSize = 0; var xMethodInfo = aTargetMethod as SysReflection.MethodInfo; if (xMethodInfo != null) { xReturnSize = Align(SizeOfType(xMethodInfo.ReturnType), 4); } uint xExtraStackSize = Call.GetStackSizeToReservate(aTargetMethod, xPopType); 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; XS.Comment("ThisOffset = " + xThisOffset); if (TypeIsReferenceType(xPopType)) { DoNullReferenceCheck(Assembler, debugEnabled, (int)xThisOffset + 4); } else { DoNullReferenceCheck(Assembler, debugEnabled, (int)xThisOffset); } if (!String.IsNullOrEmpty(xNormalAddress)) { if (xExtraStackSize > 0) { XS.Sub(ESP, xExtraStackSize); } XS.Call(xNormalAddress); } else { /* * On the stack now: * $esp Params * $esp + mThisOffset This */ if ((xPopType.IsPointer) || (xPopType.IsByRef)) { xPopType = xPopType.GetElementType(); string xTypeId = GetTypeIDLabel(xPopType); XS.Push(xTypeId, isIndirect: true); } else { XS.Set(EAX, ESP, sourceDisplacement: (int)xThisOffset + 4); XS.Push(EAX, isIndirect: true); } XS.Push(aTargetMethodUID); XS.Call(LabelName.Get(VTablesImplRefs.GetMethodAddressForTypeRef)); if (xExtraStackSize > 0) { xThisOffset -= xExtraStackSize; } /* * On the stack now: * $esp Params * $esp + mThisOffset This */ XS.Pop(ECX); XS.Label(xCurrentMethodLabel + ".AfterAddressCheck"); if (TypeIsReferenceType(xPopType)) { /* * On the stack now: * $esp + 0 Params * $esp + mThisOffset This */ // we need to see if $this is a boxed object, and if so, we need to box it XS.Set(EAX, ESP, sourceDisplacement: (int)xThisOffset + 4); XS.Compare(EAX, (int)InstanceTypeEnum.BoxedValueType, destinationIsIndirect: true, destinationDisplacement: 4, size: RegisterSize.Int32); /* * On the stack now: * $esp Params * $esp + mThisOffset This * * ECX contains the method to call * EAX contains the type pointer (not the handle!!) */ XS.Jump(CPU.ConditionalTestEnum.NotEqual, xCurrentMethodLabel + ".NotBoxedThis"); /* * On the stack now: * $esp Params * $esp + mThisOffset This * * ECX contains the method to call * EAX contains the type pointer (not the handle!!) */ XS.Add(EAX, (uint)ObjectImpl.FieldDataOffset); XS.Set(ESP, EAX, destinationDisplacement: (int)xThisOffset + 4); /* * On the stack now: * $esp Params * $esp + mThisOffset Pointer to address inside box * * ECX contains the method to call */ } XS.Label(xCurrentMethodLabel + ".NotBoxedThis"); if (xExtraStackSize > 0) { XS.Sub(ESP, xExtraStackSize); } XS.Call(ECX); XS.Label(xCurrentMethodLabel + ".AfterNotBoxedThis"); } EmitExceptionLogic(Assembler, aMethod, aOp, true, delegate { var xStackOffsetBefore = aOp.StackOffsetBeforeExecution.Value; uint xPopSize = 0; foreach (var type in aOp.StackPopTypes) { xPopSize += Align(SizeOfType(type), 4); } var xResultSize = xReturnSize; if (xResultSize % 4 != 0) { xResultSize += 4 - (xResultSize % 4); } EmitExceptionCleanupAfterCall(Assembler, xResultSize, xStackOffsetBefore, xPopSize); }); XS.Label(xCurrentMethodLabel + ".NoExceptionAfterCall"); XS.Comment("Argument Count = " + xParameters.Length); }
public LdStr(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public Ldsflda(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public Stind_I(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public static void Assemble(Cosmos.Assembler.Assembler aAssembler, int aSize, bool debugEnabled) { DoNullReferenceCheck(aAssembler, debugEnabled, Align((uint)aSize, 4)); new Comment(aAssembler, "address at: [esp + " + aSize + "]"); int xStorageSize = aSize; if (xStorageSize < 4) { xStorageSize = 4; } new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = xStorageSize }; for (int i = 0; i < (aSize / 4); i++) { new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = i * 4 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, DestinationIsIndirect = true, DestinationDisplacement = i * 4, SourceReg = CPUx86.Registers.EAX }; } switch (aSize % 4) { case 0: { break; } case 1: { new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = ((aSize / 4) * 4) }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, DestinationIsIndirect = true, SourceDisplacement = ((aSize / 4) * 4), SourceReg = CPUx86.Registers.AL }; break; } case 2: { new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = ((aSize / 4) * 4) }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, DestinationIsIndirect = true, DestinationDisplacement = ((aSize / 4) * 4), SourceReg = CPUx86.Registers.AX }; break; } case 3: { new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = ((aSize / 4) * 4) }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, DestinationIsIndirect = true, DestinationDisplacement = ((aSize / 4) * 4), SourceReg = CPUx86.Registers.AX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (((aSize / 4) * 4) + 2) }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, DestinationIsIndirect = true, DestinationDisplacement = (((aSize / 4) * 4) + 2), SourceReg = CPUx86.Registers.AL }; break; } default: throw new Exception("Error, shouldn't occur"); } new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = ( uint )(xStorageSize + 4) }; }
public Ldc_I8(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public override bool IsComplete(Assembler aAssembler) { throw new NotImplementedException("Method not implemented for instruction " + this.GetType().FullName.Substring(typeof(Instruction).Namespace.Length + 1)); }
public Box(Assembler.Assembler aAsmblr) : base(aAsmblr) { }
protected ILOp(Cosmos.Assembler.Assembler aAsmblr) { Assembler = aAsmblr; }
public Unbox_Any(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public Localloc(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public static void EmitExceptionLogic(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethodInfo, ILOpCode aCurrentOpCode, bool aDoTest, Action aCleanup) { EmitExceptionLogic(aAssembler, aMethodInfo, aCurrentOpCode, aDoTest, aCleanup, ILOp.GetLabel(aMethodInfo, aCurrentOpCode.NextPosition)); }
public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) { new Assembler.x86.Sti(); }
public static void EmitExceptionLogic(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethodInfo, ILOpCode aCurrentOpCode, bool aDoTest, Action aCleanup, string aJumpTargetNoException) { string xJumpTo = null; if (aCurrentOpCode != null && aCurrentOpCode.CurrentExceptionHandler != null) { // todo add support for nested handlers, see comment in Engine.cs //if (!((aMethodInfo.CurrentHandler.HandlerOffset < aCurrentOpOffset) || (aMethodInfo.CurrentHandler.HandlerLength + aMethodInfo.CurrentHandler.HandlerOffset) <= aCurrentOpOffset)) { new Comment(String.Format("CurrentOffset = {0}, HandlerStartOffset = {1}", aCurrentOpCode.Position, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset)); if (aCurrentOpCode.CurrentExceptionHandler.HandlerOffset > aCurrentOpCode.Position) { switch (aCurrentOpCode.CurrentExceptionHandler.Flags) { case ExceptionHandlingClauseOptions.Clause: { xJumpTo = ILOp.GetLabel(aMethodInfo, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset); break; } case ExceptionHandlingClauseOptions.Finally: { xJumpTo = ILOp.GetLabel(aMethodInfo, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset); break; } default: { throw new Exception("ExceptionHandlerType '" + aCurrentOpCode.CurrentExceptionHandler.Flags.ToString() + "' not supported yet!"); } } } } // if aDoTest is true, we check ECX for exception flags if (!aDoTest) { //new CPU.Call("_CODE_REQUESTED_BREAK_"); if (xJumpTo == null) { Jump_Exception(aMethodInfo); } else { new CPU.Jump { DestinationLabel = xJumpTo }; } } else { new CPU.Test { DestinationReg = CPU.Registers.ECX, SourceValue = 2 }; if (aCleanup != null) { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Equal, DestinationLabel = aJumpTargetNoException }; aCleanup(); if (xJumpTo == null) { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = GetMethodLabel(aMethodInfo) + AppAssembler.EndOfMethodLabelNameException }; } else { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = xJumpTo }; } } else { if (xJumpTo == null) { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = GetMethodLabel(aMethodInfo) + AppAssembler.EndOfMethodLabelNameException }; } else { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = xJumpTo }; } } } }
public abstract void WriteText(Assembler aAssembler, TextWriter aOutput);
public override void AssembleNew(Cosmos.Assembler.Assembler aAssembler, object aMethodInfo) { // IDT is already initialized but just for base hooks, and asm only. // ie Int 1, 3 and GPF // This routine updates the IDT now that we have C# running to allow C# hooks to handle // the other INTs // We are updating the IDT, disable interrupts new CPUx86.ClearInterruptFlag(); for (int i = 0; i < 256; i++) { // These are already mapped, don't remap them. // Maybe in the future we can look at ones that are present // and skip them, but some we may want to overwrite anyways. if (i == 1 || i == 3) { continue; } new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceRef = CPUAll.ElementReference.New("__ISR_Handler_" + i.ToString("X2")) }; new CPUx86.Mov { DestinationRef = CPUAll.ElementReference.New("_NATIVE_IDT_Contents"), DestinationIsIndirect = true, DestinationDisplacement = ((i * 8) + 0), SourceReg = CPUx86.Registers.AL }; new CPUx86.Mov { DestinationRef = CPUAll.ElementReference.New("_NATIVE_IDT_Contents"), DestinationIsIndirect = true, DestinationDisplacement = ((i * 8) + 1), SourceReg = CPUx86.Registers.AH }; new CPUx86.Mov { DestinationRef = CPUAll.ElementReference.New("_NATIVE_IDT_Contents"), DestinationIsIndirect = true, DestinationDisplacement = ((i * 8) + 2), SourceValue = 0x8, Size = 8 }; new CPUx86.Mov { DestinationRef = CPUAll.ElementReference.New("_NATIVE_IDT_Contents"), DestinationIsIndirect = true, DestinationDisplacement = ((i * 8) + 5), SourceValue = 0x8E, Size = 8 }; new CPUx86.ShiftRight { DestinationReg = CPUx86.Registers.EAX, SourceValue = 16 }; new CPUx86.Mov { DestinationRef = CPUAll.ElementReference.New("_NATIVE_IDT_Contents"), DestinationIsIndirect = true, DestinationDisplacement = ((i * 8) + 6), SourceReg = CPUx86.Registers.AL }; new CPUx86.Mov { DestinationRef = CPUAll.ElementReference.New("_NATIVE_IDT_Contents"), DestinationIsIndirect = true, DestinationDisplacement = ((i * 8) + 7), SourceReg = CPUx86.Registers.AH }; } new CPUx86.Jump { DestinationLabel = "__AFTER__ALL__ISR__HANDLER__STUBS__" }; var xInterruptsWithParam = new int[] { 8, 10, 11, 12, 13, 14 }; for (int j = 0; j < 256; j++) { new CPUAll.Label("__ISR_Handler_" + j.ToString("X2")); new CPUx86.Call { DestinationLabel = "__INTERRUPT_OCCURRED__" }; if (Array.IndexOf(xInterruptsWithParam, j) == -1) { new CPUx86.Push { DestinationValue = 0 }; } new CPUx86.Push { DestinationValue = (uint)j }; new CPUx86.Pushad(); new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP }; // preserve old stack address for passing to interrupt handler // store floating point data new CPUx86.And { DestinationReg = CPUx86.Registers.ESP, SourceValue = 0xfffffff0 }; // fxsave needs to be 16-byte alligned new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = 512 }; // fxsave needs 512 bytes new CPUx86.x87.FXSave { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; // save the registers new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.ESP }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; // new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; // pass old stack address (pointer to InterruptContext struct) to the interrupt handler //new CPUx86.Move("eax", // "esp"); //new CPUx86.Push("eax"); new CPUx86.JumpToSegment { Segment = 8, DestinationLabel = "__ISR_Handler_" + j.ToString("X2") + "_SetCS" }; new CPUAll.Label("__ISR_Handler_" + j.ToString("X2") + "_SetCS"); MethodBase xHandler = GetInterruptHandler((byte)j); if (xHandler == null) { xHandler = GetMethodDef(typeof(INTs).Assembly, typeof(INTs).FullName, "HandleInterrupt_Default", true); } new CPUx86.Call { DestinationLabel = CPUAll.LabelName.Get(xHandler) }; new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.x87.FXStore { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, SourceReg = CPUx86.Registers.EAX }; // this restores the stack for the FX stuff, except the pointer to the FX data new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; // "pop" the pointer new CPUx86.Popad(); new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 8 }; new CPUAll.Label("__ISR_Handler_" + j.ToString("X2") + "_END"); new CPUx86.IRET(); } new CPUAll.Label("__INTERRUPT_OCCURRED__"); new CPUx86.Return(); new CPUAll.Label("__AFTER__ALL__ISR__HANDLER__STUBS__"); new CPUx86.Noop(); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = 8 }; new CPUx86.Compare { DestinationReg = CPUx86.Registers.EAX, SourceValue = 0 }; new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Zero, DestinationLabel = ".__AFTER_ENABLE_INTERRUPTS" }; // reload interrupt list new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceRef = Cosmos.Assembler.ElementReference.New("_NATIVE_IDT_Pointer") }; new CPUx86.Mov { DestinationRef = CPUAll.ElementReference.New("static_field__Cosmos_Core_CPU_mInterruptsEnabled"), DestinationIsIndirect = true, SourceValue = 1 }; new CPUx86.Lidt { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true }; // Reenable interrupts new CPUx86.Sti(); new CPUAll.Label(".__AFTER_ENABLE_INTERRUPTS"); }
public override bool IsComplete( Assembler aAssembler ) { return true; }
public Ldelem_Ref(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public override void WriteText(Assembler aAssembler, TextWriter aOutput) { if (RawAsm != null) { aOutput.WriteLine(RawAsm); return; } if (RawDefaultValue != null) { if (RawDefaultValue.Length == 0) { aOutput.Write(Name); aOutput.Write(":"); return; } if ((from item in RawDefaultValue group item by item into i select i).Count() > 1 || RawDefaultValue.Length < 250) { if (IsGlobal) { aOutput.Write("global "); aOutput.WriteLine(Name); } aOutput.Write(Name); aOutput.Write(" db "); for (int i = 0; i < (RawDefaultValue.Length - 1); i++) { aOutput.Write(RawDefaultValue[i]); aOutput.Write(", "); } aOutput.Write(RawDefaultValue.Last()); } else { aOutput.Write("global "); aOutput.WriteLine(Name); aOutput.Write(Name); aOutput.Write(": TIMES "); aOutput.Write(RawDefaultValue.Length); aOutput.Write(" db "); aOutput.Write(RawDefaultValue[0]); } return; } if (UntypedDefaultValue != null) { if (IsGlobal) { aOutput.Write("global "); aOutput.WriteLine(Name); } aOutput.Write(Name); if (UntypedDefaultValue[0] is Int64 || UntypedDefaultValue[0] is UInt64 || UntypedDefaultValue[0] is Double) { aOutput.Write(" dq "); } else { aOutput.Write(" dd "); } Func <object, string> xGetTextForItem = delegate(object aItem) { var xElementRef = aItem as ElementReference; if (xElementRef == null) { return((aItem ?? 0).ToString()); } if (xElementRef.Offset == 0) { return(xElementRef.Name); } return(xElementRef.Name + " + " + xElementRef.Offset); }; for (int i = 0; i < (UntypedDefaultValue.Length - 1); i++) { aOutput.Write(xGetTextForItem(UntypedDefaultValue[i])); aOutput.Write(", "); } aOutput.Write(xGetTextForItem(UntypedDefaultValue.Last())); return; } if (StringValue != null) { aOutput.Write(Name); aOutput.Write(" "); aOutput.Write(Size); aOutput.Write(" "); aOutput.Write(StringValue); return; } throw new Exception("Situation unsupported!"); }
public static void Assemble(Cosmos.Assembler.Assembler aAssembler, uint aElementSize, bool isSigned, bool debugEnabled) { DoNullReferenceCheck(aAssembler, debugEnabled, 4); //if (aElementSize <= 0 || aElementSize > 8 || (aElementSize > 4 && aElementSize < 8)) //{ // throw new Exception("Unsupported size for Ldelem_Ref: " + aElementSize); //} new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceValue = aElementSize }; new CPUx86.Multiply { DestinationReg = CPUx86.Registers.EDX }; new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = (ObjectImpl.FieldDataOffset + 4) }; if (aElementSize > 4) { // we start copying the last bytes new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = aElementSize - 4 }; } // pop the array new CPUx86.Pop { DestinationReg = CPUx86.Registers.EDX }; // convert to real memory address new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.RegistersEnum.EDX, SourceIsIndirect = true }; new CPUx86.Add { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EAX }; var xSizeLeft = aElementSize; while (xSizeLeft > 0) { var xCurrentStep = Math.Min(xSizeLeft, 4); if (xSizeLeft % 4 != 0) { xCurrentStep = xSizeLeft % 4; } xSizeLeft = xSizeLeft - xCurrentStep; switch (xCurrentStep) { case 1: if (isSigned) { new CPUx86.MoveSignExtend { DestinationReg = CPUx86.Registers.ECX, Size = 8, SourceReg = CPUx86.Registers.EDX, SourceIsIndirect = true }; } else { new CPUx86.MoveZeroExtend { DestinationReg = CPUx86.Registers.ECX, Size = 8, SourceReg = CPUx86.Registers.EDX, SourceIsIndirect = true }; } new CPUx86.Push { DestinationReg = CPUx86.Registers.ECX }; break; case 2: if (isSigned) { new CPUx86.MoveSignExtend { DestinationReg = CPUx86.Registers.ECX, Size = 16, SourceReg = CPUx86.Registers.EDX, SourceIsIndirect = true }; } else { new CPUx86.MoveZeroExtend { DestinationReg = CPUx86.Registers.ECX, Size = 16, SourceReg = CPUx86.Registers.EDX, SourceIsIndirect = true }; } new CPUx86.Push { DestinationReg = CPUx86.Registers.ECX }; break; case 4: // copy a full dword new CPUx86.Push { DestinationReg = CPUx86.Registers.EDX, DestinationIsIndirect = true }; new CPUx86.Sub { DestinationReg = CPUx86.RegistersEnum.EDX, SourceValue = 4 }; // move to previous 4 bytes break; //case 8: // new CPUx86.Push {DestinationReg = CPUx86.Registers.EDX, DestinationDisplacement = 4, DestinationIsIndirect = true}; // new CPUx86.Push {DestinationReg = CPUx86.Registers.EDX, DestinationIsIndirect = true}; // break; } } }
public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) { DisableInterrupts(); // bochs magic break //Exchange(BX, BX); Halt(); }
public static void DoExecute(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethod, SysReflection.FieldInfo aField, bool debugEnabled) { bool xNeedsGC = aField.DeclaringType.IsClass && !aField.DeclaringType.IsValueType; DoExecute(aAssembler, aMethod, aField.GetFullName(), aField.DeclaringType, xNeedsGC, debugEnabled); }
public static void Assemble(Assembler.Assembler aAssembler, uint aElementSize, bool isSigned, MethodInfo aMethod, ILOpCode aOpCode, bool debugEnabled) { // stack = index // stack + 2 = array DoNullReferenceCheck(aAssembler, debugEnabled, 8); // calculate element offset into array memory (including header) XS.Pop(EAX); XS.Set(EDX, aElementSize); XS.Multiply(EDX); XS.Add(EAX, ObjectImpl.FieldDataOffset + 4); if (aElementSize > 4) { // we start copying the last bytes XS.Add(EAX, aElementSize - 4); } // pop the array now XS.Add(ESP, 4); XS.Pop(EDX); XS.Add(EDX, EAX); var xSizeLeft = aElementSize; while (xSizeLeft > 0) { var xCurrentStep = Math.Min(xSizeLeft, 4); if (xSizeLeft % 4 != 0) { xCurrentStep = xSizeLeft % 4; } xSizeLeft = xSizeLeft - xCurrentStep; switch (xCurrentStep) { case 1: if (isSigned) { new CPUx86.MoveSignExtend { DestinationReg = CPUx86.RegistersEnum.ECX, Size = 8, SourceReg = CPUx86.RegistersEnum.EDX, SourceIsIndirect = true }; } else { new CPUx86.MoveZeroExtend { DestinationReg = CPUx86.RegistersEnum.ECX, Size = 8, SourceReg = CPUx86.RegistersEnum.EDX, SourceIsIndirect = true }; } XS.Push(ECX); break; case 2: if (isSigned) { new CPUx86.MoveSignExtend { DestinationReg = CPUx86.RegistersEnum.ECX, Size = 16, SourceReg = CPUx86.RegistersEnum.EDX, SourceIsIndirect = true }; } else { new CPUx86.MoveZeroExtend { DestinationReg = CPUx86.RegistersEnum.ECX, Size = 16, SourceReg = CPUx86.RegistersEnum.EDX, SourceIsIndirect = true }; } XS.Push(ECX); break; case 4: // copy a full dword XS.Push(EDX, isIndirect: true); XS.Sub(EDX, 4); // move to previous 4 bytes break; //case 8: // new CPUx86.Push {DestinationReg = CPUx86.Registers.EDX, DestinationDisplacement = 4, DestinationIsIndirect = true}; // XS.Push(XSRegisters.EDX, isIndirect: true); // break; } } }
public static void DoExecute(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethod, string aFieldId, Type aDeclaringObject, bool aNeedsGC, bool debugEnabled) { var xType = aMethod.MethodBase.DeclaringType; int xExtraOffset = aNeedsGC ? 12 : 0; var xFields = GetFieldsInfo(aDeclaringObject); var xFieldInfo = (from item in xFields where item.Id == aFieldId select item).Single(); var xActualOffset = xFieldInfo.Offset + xExtraOffset; var xSize = xFieldInfo.Size; new Comment("Field: " + xFieldInfo.Id); new Comment("Type: " + xFieldInfo.FieldType.ToString()); new Comment("Size: " + xFieldInfo.Size); uint xRoundedSize = Align(xSize, 4); DoNullReferenceCheck(aAssembler, debugEnabled, xRoundedSize); new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)xRoundedSize }; if (debugEnabled) { new CPUx86.Push { DestinationReg = CPUx86.RegistersEnum.ECX }; new CPUx86.Pop { DestinationReg = CPUx86.RegistersEnum.ECX }; } new CPUx86.Add { DestinationReg = CPUx86.Registers.ECX, SourceValue = (uint)(xActualOffset) }; //TODO: Can't we use an x86 op to do a byte copy instead and be faster? for (int i = 0; i < (xSize / 4); i++) { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((i * 4)), SourceReg = CPUx86.Registers.EAX }; } switch (xSize % 4) { case 1: { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.Registers.AL }; break; } case 2: { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.Registers.AX }; break; } case 3: { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; // move 2 lower bytes new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.Registers.AX }; // shift third byte to lowest new CPUx86.ShiftRight { DestinationReg = CPUx86.Registers.EAX, SourceValue = 16 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4) + 2, SourceReg = CPUx86.Registers.AL }; break; } case 0: { break; } default: throw new Exception("Remainder size " + (xSize % 4) + " not supported!"); } #if !SKIP_GC_CODE if (aNeedsGC) { new CPUx86.Push { DestinationReg = CPUx86.Registers.ECX }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Call { DestinationLabel = LabelName.Get(GCImplementationRefs.DecRefCountRef) }; new CPUx86.Call { DestinationLabel = LabelName.Get(GCImplementationRefs.DecRefCountRef) }; } #endif new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; }
public Constrained(Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public Stsfld(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public static Assembler Optimize(Assembler asmb) { return asmb; Assembler asmblr = asmb; List<Instruction> instr = asmb.Instructions; //List<DataMember> dmbrs = asmb.DataMembers; SortedDictionary<string, Instruction> labels = new SortedDictionary<string, Instruction>(); List<Instruction> comments = new List<Instruction>(); List<String> usedLabels = new List<string>(); usedLabels.Add("KernelStart"); foreach (Instruction ins in instr) { if (ins is Label) { if (((Label)ins).IsGlobal) { usedLabels.Add(((Label)ins).QualifiedName); } labels.Add(((Label)ins).QualifiedName, ins); } else if (ins is x86.JumpToSegment) { if (((x86.JumpToSegment)ins).DestinationRef != null) { usedLabels.Add(((x86.JumpToSegment)ins).DestinationRef.Name); } else { usedLabels.Add(((x86.JumpToSegment)ins).DestinationLabel); } } else if (ins is x86.JumpBase) { usedLabels.Add(((x86.JumpBase)ins).DestinationLabel); } else if (ins is x86.Call) { usedLabels.Add(((x86.Call)ins).DestinationLabel); } else if (ins is x86.Push) { if (((x86.Push)ins).DestinationRef != null) { usedLabels.Add(((x86.Push)ins).DestinationRef.Name); } } else if (ins is x86.Mov) { if (((x86.Mov)ins).SourceRef != null) { usedLabels.Add(((x86.Mov)ins).SourceRef.Name); } } } foreach (string s in usedLabels) { labels.Remove(s); } usedLabels = null; instr.RemoveAll( delegate(Instruction inst) { if (inst is Comment) return true; else if (inst is Label) { if (labels.ContainsKey(((Label)inst).QualifiedName)) return true; return false; } return false; } ); labels = null; comments = null; asmblr.Instructions = instr; //asmblr.DataMembers = dmbrs; return asmblr; }
public static void DoExecute(Cosmos.Assembler.Assembler Assembler, MethodInfo aCurrentMethod, MethodBase aTargetMethod, ILOpCode aOp, string currentLabel, string nextLabel, bool debugEnabled) { var xMethodInfo = aTargetMethod as SysReflection.MethodInfo; string xNormalAddress = LabelName.Get(aTargetMethod); var xParameters = aTargetMethod.GetParameters(); // todo: implement exception support uint xExtraStackSize = GetStackSizeToReservate(aTargetMethod); if (!aTargetMethod.IsStatic) { uint xThisOffset = 0; foreach (var xItem in xParameters) { xThisOffset += Align(SizeOfType(xItem.ParameterType), 4); } var stackOffsetToCheck = xThisOffset; if (TypeIsReferenceType(aTargetMethod.DeclaringType)) { DoNullReferenceCheck(Assembler, debugEnabled, (int)stackOffsetToCheck + 4); } else { DoNullReferenceCheck(Assembler, debugEnabled, (int)stackOffsetToCheck); } } if (xExtraStackSize > 0) { XS.Sub(XSRegisters.ESP, (uint)xExtraStackSize); } XS.Call(xNormalAddress); uint xReturnSize = 0; if (xMethodInfo != null) { xReturnSize = SizeOfType(xMethodInfo.ReturnType); } if (aCurrentMethod != null) { EmitExceptionLogic(Assembler, aCurrentMethod, aOp, true, delegate { var xStackOffsetBefore = aOp.StackOffsetBeforeExecution.Value; uint xPopSize = 0; foreach (var type in aOp.StackPopTypes) { xPopSize += Align(SizeOfType(type), 4); } var xResultSize = xReturnSize; if (xResultSize % 4 != 0) { xResultSize += 4 - (xResultSize % 4); } ILOp.EmitExceptionCleanupAfterCall(Assembler, xResultSize, xStackOffsetBefore, xPopSize); }, nextLabel); } }
public static void EmitExceptionLogic(Assembler.Assembler aAssembler, MethodInfo aMethodInfo, ILOpCode aCurrentOpCode, bool aDoTest, Action aCleanup, string aJumpTargetNoException = null) { if (aJumpTargetNoException == null) { aJumpTargetNoException = GetLabel(aMethodInfo, aCurrentOpCode.NextPosition); } string xJumpTo = null; if (aCurrentOpCode != null && aCurrentOpCode.CurrentExceptionHandler != null) { // todo add support for nested handlers, see comment in Engine.cs //if (!((aMethodInfo.CurrentHandler.HandlerOffset < aCurrentOpOffset) || (aMethodInfo.CurrentHandler.HandlerLength + aMethodInfo.CurrentHandler.HandlerOffset) <= aCurrentOpOffset)) { XS.Comment(String.Format("CurrentOffset = {0}, HandlerStartOffset = {1}", aCurrentOpCode.Position, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset)); if (aCurrentOpCode.CurrentExceptionHandler.HandlerOffset > aCurrentOpCode.Position) { switch (aCurrentOpCode.CurrentExceptionHandler.Flags) { case ExceptionHandlingClauseOptions.Clause: { xJumpTo = GetLabel(aMethodInfo, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset); break; } case ExceptionHandlingClauseOptions.Finally: { xJumpTo = GetLabel(aMethodInfo, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset); break; } default: { throw new Exception("ExceptionHandlerType '" + aCurrentOpCode.CurrentExceptionHandler.Flags.ToString() + "' not supported yet!"); } } } } // if aDoTest is true, we check ECX for exception flags if (!aDoTest) { //new CPU.Call("_CODE_REQUESTED_BREAK_"); if (xJumpTo == null) { Jump_Exception(aMethodInfo); } else { XS.Jump(xJumpTo); } } else { XS.Test(XSRegisters.ECX, 2); if (aCleanup != null) { XS.Jump(CPU.ConditionalTestEnum.Equal, aJumpTargetNoException); aCleanup(); if (xJumpTo == null) { XS.Jump(CPU.ConditionalTestEnum.NotEqual, GetMethodLabel(aMethodInfo) + AppAssembler.EndOfMethodLabelNameException); } else { XS.Jump(CPU.ConditionalTestEnum.NotEqual, xJumpTo); } } else { if (xJumpTo == null) { XS.Jump(CPU.ConditionalTestEnum.NotEqual, GetMethodLabel(aMethodInfo) + AppAssembler.EndOfMethodLabelNameException); } else { XS.Jump(CPU.ConditionalTestEnum.NotEqual, xJumpTo); } } } }
public abstract void WriteData( Assembler aAssembler, Stream aOutput );
public virtual void UpdateAddress(Assembler aAssembler, ref ulong aAddress) { StartAddress = aAddress; }
public abstract void WriteText( Assembler aAssembler, TextWriter aOutput );
public override void WriteText(Assembler aAssembler, System.IO.TextWriter aOutput) { aOutput.Write(Code); }
public override void UpdateAddress(Assembler aAssembler, ref ulong aAddress) { base.UpdateAddress(aAssembler, ref aAddress); }
public Callvirt(Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public Newarr(Assembler.Assembler aAsmblr) : base(aAsmblr) { }
public static void DoExecute(Cosmos.Assembler.Assembler Assembler, MethodInfo aMethod, Type aDeclaringType, string aField, bool aDerefValue, bool aDebugEnabled, Type aTypeOnStack) { var xFieldInfo = ResolveField(aDeclaringType, aField, true); DoExecute(Assembler, aMethod, aDeclaringType, xFieldInfo, aDerefValue, aDebugEnabled, aTypeOnStack); }
public AppAssembler(int aComPort, string assemblerLogFile) { Assembler = CreateAssembler(aComPort); mLog = new StreamWriter(assemblerLogFile, false); InitILOps(); }
public override void WriteText( Assembler aAssembler, System.IO.TextWriter aOutput ) { aOutput.Write( "; " ); aOutput.Write( Text ); }
public override bool IsComplete(Assembler aAssembler) { return(true); }
public abstract void WriteData(Assembler aAssembler, Stream aOutput);
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) { new CPUx86.Call { DestinationLabel = LabelName.Get(xCctor) }; ILOp.EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck"); new Label(".AfterCCTorExceptionCheck"); } } if (objectType.IsValueType) { #region Valuetypes new 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); new 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); } new Comment("ArgSize: " + xArgSize); // Set ESP so we can push the struct ptr int xShift = (int)(xArgSize - xStorageSize); new Comment("Shift: " + xShift); if (xShift < 0) { new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)Math.Abs(xShift) }; } else if (xShift > 0) { new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)xShift }; } // push struct ptr new CPUx86.Push { DestinationReg = CPUx86.Registers.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.Registers.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; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; // EAX contains a memory handle now, lets dereference it to a pointer new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.RegistersEnum.EAX, SourceIsIndirect = true }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true, SourceDisplacement = 8 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceValue = 2 }; new CPUx86.Multiply { DestinationReg = CPUx86.Registers.EDX }; new CPUx86.Push { DestinationReg = CPUx86.Registers.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; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; new CPUx86.ShiftLeft { DestinationReg = CPUx86.Registers.EAX, SourceValue = 1 }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; } else if (xParams.Length == 2 && xParams[0].ParameterType == typeof(char) && xParams[1].ParameterType == typeof(int)) { xHasCalcSize = true; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; new CPUx86.ShiftLeft { DestinationReg = CPUx86.Registers.EAX, SourceValue = 1 }; new CPUx86.Push { DestinationReg = CPUx86.Registers.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 new CPUx86.Push { DestinationValue = (uint)(xMemSize + xExtraSize) }; if (xHasCalcSize) { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX }; } // todo: probably we want to check for exceptions after calling Alloc new CPUx86.Call { DestinationLabel = LabelName.Get(GCImplementationRefs.AllocNewObjectRef) }; new Label(".AfterAlloc"); new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = 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); new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, SourceRef = Cosmos.Assembler.ElementReference.New(strTypeId), SourceIsIndirect = true }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EBX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = (uint)InstanceTypeEnum.NormalObject, Size = 32 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 8, SourceValue = (uint)xGCFieldCount, Size = 32 }; 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.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xSize + 4) }; } } new CPUx86.Call { DestinationLabel = 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 ? new CPUx86.Test { DestinationReg = CPUx86.Registers.ECX, SourceValue = 2 }; string xNoErrorLabel = currentLabel + ".NoError" + LabelName.LabelCount.ToString(); new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Equal, DestinationLabel = 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 new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 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); new Label(xNoErrorLabel); } new CPUx86.Pop { DestinationReg = CPUx86.Registers.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); new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; } }