public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xType = (OpType)aOpCode; var xTypeID = GetTypeIDLabel(xType.Value); var xCurrentMethodLabel = GetLabel(aMethod, aOpCode); var xAfterIsInstanceCallLabel = xCurrentMethodLabel + "_After_IsInstance_Call"; var xInvalidCastLabel = xCurrentMethodLabel + "_InvalidCast"; var xNextPositionLabel = GetLabel(aMethod, aOpCode.NextPosition); XS.Set(EAX, ESP, sourceDisplacement: 4); XS.Compare(EAX, 0); XS.Jump(ConditionalTestEnum.Zero, xNextPositionLabel); XS.Push(EAX, isIndirect: true); XS.Push(xTypeID, isIndirect: true); XS.Push(Convert.ToUInt32(xType.Value.IsInterface)); MethodBase xMethodIsInstance = VTablesImplRefs.IsInstanceRef; Call.DoExecute(Assembler, aMethod, xMethodIsInstance, aOpCode, xCurrentMethodLabel, xAfterIsInstanceCallLabel, DebugEnabled); XS.Label(xAfterIsInstanceCallLabel); XS.Pop(EAX); XS.Compare(EAX, 0); XS.Jump(ConditionalTestEnum.Equal, xInvalidCastLabel); XS.Jump(xNextPositionLabel); XS.Label(xInvalidCastLabel); XS.Call(LabelName.Get(ExceptionHelperRefs.ThrowInvalidCastExceptionRef)); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { OpType xType = (OpType)aOpCode; if (IsReferenceType(xType.Value)) { return; } uint xSize = Align(SizeOfType(xType.Value), 4); string xTypeID = GetTypeIDLabel(xType.Value); XS.Push(ObjectUtils.FieldDataOffset + xSize); XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Pop(ESI); XS.Set(EBX, xTypeID, sourceIsIndirect: true); XS.Set(ESI, EBX, destinationIsIndirect: true); XS.Set(ESI, (uint)ObjectUtils.InstanceTypeEnum.BoxedValueType, destinationDisplacement: 4, size: RegisterSize.Int32); new Comment(Assembler, "xSize is " + xSize); for (int i = 0; i < (xSize / 4); i++) { XS.Pop(EDX); XS.Set(ESI, EDX, destinationDisplacement: (ObjectUtils.FieldDataOffset + (i * 4)), size: RegisterSize.Int32); } XS.Push(ESI); XS.Push(0); }
protected void ThrowOverflowException() { new CPU.Call { DestinationLabel = LabelName.Get(typeof(ExceptionHelper).GetMethod("ThrowOverflow", BindingFlags.Static | BindingFlags.Public)) }; }
// this code is mostly copied from Newarr.cs in Il2CPU, just the code to find the size and length is different public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { string xTypeID = ILOp.GetTypeIDLabel(typeof(Array)); MethodBase xCtor = typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)[0]; string xCtorName = LabelName.Get(xCtor); XS.Set(ECX, EBP, sourceDisplacement: 8); // size XS.Set(EDX, EBP, sourceDisplacement: 12); // length XS.Push(ECX); // size of element XS.Set(EAX, ECX); XS.Multiply(EDX); // total element size XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // total array size XS.Push(EAX); XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Label(".AfterAlloc"); XS.Pop(EAX); XS.Pop(ESI); XS.Push(EAX); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack 3 times now, once from the return value, twice from the pushes; XS.Pop(EAX); XS.Set(EBX, xTypeID, sourceIsIndirect: true); // array type id XS.Set(EAX, EBX, destinationIsIndirect: true); // array type id XS.Set(EAX, (uint)ObjectUtils.InstanceTypeEnum.Array, destinationDisplacement: 4, destinationIsIndirect: true); XS.Set(EAX, ESI, destinationDisplacement: 8, destinationIsIndirect: true); XS.Set(EAX, ECX); XS.Push(0); XS.Call(xCtorName); XS.Push(0); }
protected void ThrowNotImplementedException(string aMessage) { XS.Push(LdStr.GetContentsArrayName(aMessage)); new CPU.Call { DestinationLabel = LabelName.Get(typeof(ExceptionHelper).GetMethod("ThrowNotImplemented", BindingFlags.Static | BindingFlags.Public)) }; }
public static void SetAllStates(bool state) { Instance.maskState.list.Clear(); if (state) { Instance.maskState.list.AddRange(LabelName.Get()); } }
protected void ThrowNotImplementedException(string aMessage) { new CPU.Push { DestinationRef = Cosmos.Assembler.ElementReference.New(LdStr.GetContentsArrayName(aMessage)) }; new CPU.Call { DestinationLabel = LabelName.Get(typeof(ExceptionHelper).GetMethod("ThrowNotImplemented", BindingFlags.Static | BindingFlags.Public)) }; }
public static void DoExecute(Cosmos.Assembler.Assembler assembler, _MethodInfo aMethod, string field, Type declaringType, ILOpCode aCurrentOpCode) { // call cctor: var xCctor = (declaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); if (aCurrentOpCode != null) { ILOp.EmitExceptionLogic(assembler, aMethod, aCurrentOpCode, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } } string xDataName = field; XS.Push(xDataName); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xType = (ILOpCodes.OpType)aOpCode; uint xSize = SizeOfType(xType.Value.GetElementType() ?? xType.Value); string xTypeID = GetTypeIDLabel(xType.Value.GetElementType() ?? xType.Value); MethodBase xCtor = typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)[0]; string xCtorName = LabelName.Get(xCtor); XS.Comment("Element Size = " + xSize); XS.Pop(EAX); // element count XS.Push(EAX); XS.Set(EDX, xSize); XS.Multiply(EDX); // total element size XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // total array size XS.Push(EAX); //XS.Push(0x4E3A44A9); //XS.LiteralCode("Call DebugStub_SendSimpleNumber"); //XS.Pop(EAX); //XS.Push(".AfterAlloc"); //XS.LiteralCode("Call DebugStub_SendSimpleNumber"); //XS.Pop(EAX); XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Label(".AfterAlloc"); XS.Pop(EAX); // location //XS.LiteralCode("Call DebugStub_SendSimpleNumber"); XS.Pop(ESI); // element count XS.Push(EAX); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack 3 times now, once from the return value, twice from the pushes; XS.Pop(EAX); XS.Set(EBX, xTypeID, sourceIsIndirect: true); // array type id XS.Set(EAX, EBX, destinationIsIndirect: true); // array type id XS.Set(EAX, (uint)ObjectUtils.InstanceTypeEnum.Array, destinationDisplacement: 4, destinationIsIndirect: true); XS.Set(EAX, ESI, destinationDisplacement: 8, destinationIsIndirect: true); // element count XS.Set(EAX, xSize, destinationDisplacement: 12, destinationIsIndirect: true); // element size XS.Push(0); XS.Call(xCtorName); XS.Push(0); }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { Cosmos.IL2CPU.ILOpCodes.OpType xType = (Cosmos.IL2CPU.ILOpCodes.OpType)aOpCode; uint xSize = SizeOfType(xType.Value); //TODO cache it to reduce calculation string xTypeID = GetTypeIDLabel(typeof(Array)); MethodBase xCtor = typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)[0]; string xCtorName = LabelName.Get(xCtor); new Comment(Assembler, "Element Size = " + xSize); // element count is on the stack XS.Pop(XSRegisters.ESI); XS.Push(XSRegisters.ESI); //Assembler.StackSizes.Push(xElementCountSize); XS.Push(xSize); new Mul(Assembler).Execute(aMethod, aOpCode); // the total items size is now on the stack XS.Push((ObjectImpl.FieldDataOffset + 4)); new Add(Assembler).Execute(aMethod, aOpCode); // the total array size is now on the stack. XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack 3 times now, once from the return value, twice from the pushes; XS.Pop(XSRegisters.EAX); XS.Set(EAX, EAX, sourceIsIndirect: true); XS.Set(EBX, xTypeID, sourceIsIndirect: true); XS.Set(EAX, EBX, destinationIsIndirect: true); XS.Add(XSRegisters.EAX, 4); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.EAX, DestinationIsIndirect = true, SourceValue = (uint)InstanceTypeEnum.Array, Size = 32 }; XS.Add(XSRegisters.EAX, 4); XS.Set(EAX, ESI, destinationIsIndirect: true, size: RegisterSize.Int32); XS.Add(XSRegisters.EAX, 4); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.EAX, DestinationIsIndirect = true, SourceValue = (uint)xSize, Size = 32 }; XS.Call(xCtorName); }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { OpType xType = (OpType)aOpCode; uint xSize = Align(SizeOfType(xType.Value), 4); string xTypeID = GetTypeIDLabel(xType.Value); new CPUx86.Push { DestinationValue = (ObjectImpl.FieldDataOffset + xSize) }; new CPUx86.Call { DestinationLabel = LabelName.Get(GCImplementationRefs.AllocNewObjectRef) }; new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESI, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, SourceRef = Cosmos.Assembler.ElementReference.New(xTypeID), SourceIsIndirect = true }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESI, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EBX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESI, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = (uint)InstanceTypeEnum.BoxedValueType, Size = 32 }; new Comment(Assembler, "xSize is " + xSize); for (int i = 0; i < (xSize / 4); i++) { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EDX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESI, DestinationIsIndirect = true, DestinationDisplacement = (ObjectImpl.FieldDataOffset + (i * 4)), SourceReg = CPUx86.Registers.EDX, Size = 32 }; } new CPUx86.Push { DestinationReg = CPUx86.RegistersEnum.EAX }; }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackType = aOpCode.StackPopTypes[0]; var xNoThrowLabel = GetLabel(aMethod, aOpCode) + ".NoThrow"; switch (SizeOfType(xStackType)) { case 4: XS.Pop(EAX); XS.And(EAX, 0x7FFFFFFF); XS.Compare(EAX, 0x7F800000); XS.Jump(ConditionalTestEnum.Below, xNoThrowLabel); XS.SSE2.ConvertSS2SD(XMM0, EAX); XS.Sub(ESP, 8); XS.SSE2.MoveSD(ESP, XMM0, true); break; case 8: XS.Set(EAX, ESP, sourceDisplacement: 4); XS.And(EAX, 0x7FFFFFFF); XS.Compare(EAX, 0x7F800000); XS.Jump(ConditionalTestEnum.Below, xNoThrowLabel); break; default: throw new NotImplementedException(); } XS.Call(LabelName.Get(ExceptionHelperRefs.ThrowNotFiniteNumberExceptionRef)); XS.Label(xNoThrowLabel); }
public static void DoExecute(Cosmos.Assembler.Assembler assembler, MethodInfo aMethod, string field, Type declaringType, ILOpCode aCurrentOpCode) { // call cctor: var xCctor = (declaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault(); if (xCctor != null) { new CPUx86.Call { DestinationLabel = LabelName.Get(xCctor) }; if (aCurrentOpCode != null) { ILOp.EmitExceptionLogic(assembler, aMethod, aCurrentOpCode, true, null, ".AfterCCTorExceptionCheck"); new Label(".AfterCCTorExceptionCheck"); } } string xDataName = field; new CPUx86.Push { DestinationRef = Cosmos.Assembler.ElementReference.New(xDataName) }; }
public override void AssembleNew(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 XS.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; } XS.Set(EAX, "__ISR_Handler_" + i.ToString("X2")); XS.Set("_NATIVE_IDT_Contents", AL, destinationDisplacement: (i * 8) + 0); XS.Set("_NATIVE_IDT_Contents", AH, destinationDisplacement: (i * 8) + 1); XS.Set("_NATIVE_IDT_Contents", 0x8, destinationDisplacement: (i * 8) + 2, size: RegisterSize.Byte8); XS.Set("_NATIVE_IDT_Contents", 0x8E, destinationDisplacement: (i * 8) + 5, size: RegisterSize.Byte8); XS.ShiftRight(EAX, 16); XS.Set("_NATIVE_IDT_Contents", AL, destinationDisplacement: (i * 8) + 6); XS.Set("_NATIVE_IDT_Contents", AH, destinationDisplacement: (i * 8) + 7); } XS.Jump("__AFTER__ALL__ISR__HANDLER__STUBS__"); var xInterruptsWithParam = new[] { 8, 10, 11, 12, 13, 14 }; for (int j = 0; j < 256; j++) { XS.Label("__ISR_Handler_" + j.ToString("X2")); XS.Call("__INTERRUPT_OCCURRED__"); if (Array.IndexOf(xInterruptsWithParam, j) == -1) { XS.Push(0); } XS.Push((uint)j); if (j != 0x20) { XS.PushAllRegisters(); XS.Sub(ESP, 4); XS.Set(EAX, ESP); // preserve old stack address for passing to interrupt handler // store floating point data XS.And(ESP, 0xfffffff0); // fxsave needs to be 16-byte alligned XS.Sub(ESP, 512); // fxsave needs 512 bytes XS.SSE.FXSave(ESP, isIndirect: true); // save the registers XS.Set(EAX, ESP, destinationIsIndirect: true); XS.Push(EAX); // XS.Push(EAX); // pass old stack address (pointer to InterruptContext struct) to the interrupt handler XS.JumpToSegment(8, "__ISR_Handler_" + j.ToString("X2") + "_SetCS"); XS.Label("__ISR_Handler_" + j.ToString("X2") + "_SetCS"); MethodBase xHandler = GetInterruptHandler((byte)j); if (xHandler == null) { xHandler = GetMethodDef(typeof(Cosmos.Core.INTs).Assembly, typeof(Cosmos.Core.INTs).FullName, "HandleInterrupt_Default", true); } XS.Call(LabelName.Get(xHandler)); XS.Pop(EAX); XS.SSE.FXRestore(ESP, isIndirect: true); XS.Set(ESP, EAX); // this restores the stack for the FX stuff, except the pointer to the FX data XS.Add(ESP, 4); // "pop" the pointer XS.PopAllRegisters(); } else { new LiteralAssemblerCode("pushad"); new LiteralAssemblerCode("mov eax, ds"); new LiteralAssemblerCode("push eax"); new LiteralAssemblerCode("mov eax, es"); new LiteralAssemblerCode("push eax"); new LiteralAssemblerCode("mov eax, fs"); new LiteralAssemblerCode("push eax"); new LiteralAssemblerCode("mov eax, gs"); new LiteralAssemblerCode("push eax"); new LiteralAssemblerCode("mov ax, 0x10"); new LiteralAssemblerCode("mov ds, ax"); new LiteralAssemblerCode("mov es, ax"); new LiteralAssemblerCode("mov fs, ax"); new LiteralAssemblerCode("mov gs, ax"); new LiteralAssemblerCode("mov eax, esp"); XS.Set("static_field__Cosmos_Core_INTs_mStackContext", EAX, destinationIsIndirect: true); XS.Call(LabelName.Get(GetMethodDef(typeof(Cosmos.Core.Processing.ProcessorScheduler).Assembly, typeof(Cosmos.Core.Processing.ProcessorScheduler).FullName, "SwitchTask", true))); XS.Set(EAX, "static_field__Cosmos_Core_INTs_mStackContext", sourceIsIndirect: true); new LiteralAssemblerCode("mov esp, eax"); new LiteralAssemblerCode("pop eax"); new LiteralAssemblerCode("mov gs, eax"); new LiteralAssemblerCode("pop eax"); new LiteralAssemblerCode("mov fs, eax"); new LiteralAssemblerCode("pop eax"); new LiteralAssemblerCode("mov es, eax"); new LiteralAssemblerCode("pop eax"); new LiteralAssemblerCode("mov ds, eax"); new LiteralAssemblerCode("popad"); } XS.Add(ESP, 8); XS.Label("__ISR_Handler_" + j.ToString("X2") + "_END"); XS.InterruptReturn(); } XS.Label("__INTERRUPT_OCCURRED__"); XS.Return(); XS.Label("__AFTER__ALL__ISR__HANDLER__STUBS__"); XS.Noop(); XS.Set(EAX, EBP, sourceDisplacement: 8); XS.Compare(EAX, 0); XS.Jump(ConditionalTestEnum.Zero, ".__AFTER_ENABLE_INTERRUPTS"); // reload interrupt list XS.Set(EAX, "_NATIVE_IDT_Pointer"); XS.Set(AsmMarker.Labels[AsmMarker.Type.Processor_IntsEnabled], 1, destinationIsIndirect: true, size: RegisterSize.Byte8); XS.LoadIdt(EAX, isIndirect: true); // Reenable interrupts XS.EnableInterrupts(); XS.Label(".__AFTER_ENABLE_INTERRUPTS"); }
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 AssembleNew(Assembler aAssembler, object aMethodInfo) { int start = 0; for (int i = start; i < 256; i++) { if (i == 1 || i == 3) { //continue; // was used for debugging } XS.Set(XSRegisters.EAX, "_isr" + i.ToString("X2")); XS.Set("_NATIVE_IDT_Contents", XSRegisters.AL, destinationDisplacement: (i * 8) + 0); XS.Set("_NATIVE_IDT_Contents", XSRegisters.AH, destinationDisplacement: (i * 8) + 1); XS.Set("_NATIVE_IDT_Contents", 0x08, destinationDisplacement: (i * 8) + 2, size: XSRegisters.RegisterSize.Byte8); XS.Set("_NATIVE_IDT_Contents", 0x00, destinationDisplacement: (i * 8) + 4, size: XSRegisters.RegisterSize.Byte8); XS.Set("_NATIVE_IDT_Contents", 0x8E, destinationDisplacement: (i * 8) + 5, size: XSRegisters.RegisterSize.Byte8); XS.ShiftRight(XSRegisters.EAX, 16); XS.Set("_NATIVE_IDT_Contents", XSRegisters.AL, destinationDisplacement: (i * 8) + 6); XS.Set("_NATIVE_IDT_Contents", XSRegisters.AH, destinationDisplacement: (i * 8) + 7); } XS.Jump("skip_isrhandlers"); var xInterruptsWithParam = new[] { 8, 10, 11, 12, 13, 14 }; for (int j = start; j < 256; j++) { XS.Label("_isr" + j.ToString("X2")); XS.ClearInterruptFlag(); XS.Call("__INTERRUPT_OCCURRED__"); if (global::System.Array.IndexOf(xInterruptsWithParam, j) == -1) { XS.Push(0); } XS.Push((uint)j); XS.Jump("CommonISRBase"); } XS.Label("CommonISRBase"); XS.PushAllRegisters(); XS.Set(XSRegisters.EAX, XSRegisters.ESP); XS.Set("static_field__Kernel_System_Core_ISR_old_esp", XSRegisters.EAX, destinationIsIndirect: true); XS.Sub(XSRegisters.ESP, 4); XS.Set(XSRegisters.EAX, XSRegisters.ESP); XS.And(XSRegisters.ESP, 0xfffffff0); XS.Sub(XSRegisters.ESP, 512); XS.SSE.FXSave(XSRegisters.ESP, isIndirect: true); XS.Set(XSRegisters.EAX, XSRegisters.ESP, destinationIsIndirect: true); XS.Push(XSRegisters.EAX); XS.Push(XSRegisters.EAX); XS.Set("static_field__Kernel_System_Core_ISR_Registers", XSRegisters.EAX, destinationIsIndirect: true); MethodBase xHandler = GetMethodDef(typeof(ISR).Assembly, typeof(ISR).FullName, "CommonISRHandler", true); XS.Call(LabelName.Get(xHandler)); XS.Pop(XSRegisters.EAX); XS.SSE.FXRestore(XSRegisters.ESP, isIndirect: true); XS.Set(XSRegisters.ESP, XSRegisters.EAX); XS.Add(XSRegisters.ESP, 4); XS.Set(XSRegisters.EAX, "static_field__Kernel_System_Core_ISR_old_esp", sourceIsIndirect: true); XS.Set(XSRegisters.ESP, XSRegisters.EAX); XS.PopAllRegisters(); XS.Add(XSRegisters.ESP, 8); XS.InterruptReturn(); XS.Label("skip_isrhandlers"); }
public override void AssembleNew(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(XSRegisters.ESP, 4); XS.Pop(XSRegisters.EAX); XS.Add(XSRegisters.EAX, 8); XS.Set(XSRegisters.EBX, XSRegisters.EAX, sourceIsIndirect: true); XS.Comment("Get invoke method"); XS.Add(XSRegisters.EAX, 8); XS.Set(XSRegisters.EDI, XSRegisters.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(XSRegisters.ESP, 4); XS.Pop(XSRegisters.ECX); XS.Add(XSRegisters.ECX, (uint)xArgSizeOffset); XS.Set(XSRegisters.ECX, XSRegisters.ECX, sourceIsIndirect: true); XS.Comment("Set current invoke list index"); XS.Set(XSRegisters.EDX, 0); XS.Label(".BEGIN_OF_LOOP"); { XS.Compare(XSRegisters.EDX, XSRegisters.EBX); XS.Jump(x86.ConditionalTestEnum.GreaterThanOrEqualTo, ".END_OF_INVOKE"); XS.PushAllRegisters(); XS.Comment("Check if delegate has $this"); XS.Set(XSRegisters.EDI, XSRegisters.EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); XS.Add(XSRegisters.EDI, 4); XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.Object System.Delegate._target")); XS.Compare(XSRegisters.EDI, 0); XS.Jump(x86.ConditionalTestEnum.Zero, ".NO_THIS"); XS.Label(".HAS_THIS"); XS.Push(XSRegisters.EDI); XS.Push(0); XS.Label(".NO_THIS"); XS.Set(XSRegisters.EDI, XSRegisters.EAX, sourceIsIndirect: true, sourceDisplacement: 4); XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.IntPtr System.Delegate._methodPtr")); XS.Comment("Check if delegate has args"); XS.Compare(XSRegisters.ECX, 0); XS.Jump(x86.ConditionalTestEnum.Zero, ".NO_ARGS"); XS.Label(".HAS_ARGS"); XS.Sub(XSRegisters.ESP, XSRegisters.ECX); XS.Push(XSRegisters.EDI); XS.Set(XSRegisters.EDI, XSRegisters.ESP); XS.Add(XSRegisters.EDI, 4); XS.Set(XSRegisters.ESI, XSRegisters.EBP); XS.Add(XSRegisters.ESI, 8); new x86.Movs { Size = 8, Prefixes = x86.InstructionPrefixes.Repeat }; XS.Pop(XSRegisters.EDI); XS.Label(".NO_ARGS"); XS.Call(XSRegisters.EDI); XS.PopAllRegisters(); XS.Increment(XSRegisters.EDX); XS.Jump(".BEGIN_OF_LOOP"); } XS.Label(".END_OF_INVOKE"); XS.Set(XSRegisters.EDX, XSRegisters.EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); XS.Set(XSRegisters.EDX, XSRegisters.EDX, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "$$ReturnsValue$$")); XS.Compare(XSRegisters.EDX, 0); XS.Jump(x86.ConditionalTestEnum.Equal, ".NO_RETURN"); XS.Label(".HAS_RETURN"); XS.Exchange(XSRegisters.EBP, XSRegisters.EDX, destinationDisplacement: 8); XS.Exchange(XSRegisters.EBP, XSRegisters.EDX, destinationDisplacement: 4); XS.Exchange(XSRegisters.EBP, XSRegisters.EDX, destinationIsIndirect: true); XS.Push(XSRegisters.EDX); XS.Set(XSRegisters.ESP, XSRegisters.EDI, destinationDisplacement: 12); XS.Label(".NO_RETURN"); XS.EnableInterrupts(); }
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 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 static string GetLabel(_MethodInfo aMethod, int aPos) { return(LabelName.Get(GetLabel(aMethod), aPos)); }
/// <summary> /// <para>This method implements Multicast Invoke. This means that it should call all delegates /// in the current multicast delegate. </para> /// <para>The argument size is available in the <code>$$ArgSize$$</code> field. This value is already rounded to 4byte boundaries</para> /// </summary> /// <param name="aAssembler"></param> public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) { if (aMethodInfo == null) { throw new Exception("This AssemblerMethod needs MethodInfo!"); } /* * 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 */ var xMethodInfo = (MethodInfo)aMethodInfo; new Label("____DEBUG_FOR_MULTICAST___"); // new CPUx86.Cli();//DEBUG ONLY //#warning reenable interupts when issue is fixed!!! new Comment("move address of delgate to eax"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = Ldarg.GetArgumentDisplacement(xMethodInfo, 0) }; var xGetInvocationListMethod = typeof(MulticastDelegate).GetMethod("GetInvocationList"); new Comment("push address of delgate to stack"); new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; //addrof this new CPUx86.Call { DestinationLabel = LabelName.Get(xGetInvocationListMethod) }; new Comment("get address from return value -> eax"); new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX };; //list new Comment("eax+=8 is where the offset where an array's count is"); new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 8 }; //addrof list.count?? new Comment("store count in ebx"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; //list.count new Comment("eax+=8 is where the offset where an array's items start"); new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 8 }; //why? -- start of list i think? MtW: the array's .Length is at +8 new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceValue = 0 }; new Comment("ecx = ptr to delegate object"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = Ldarg.GetArgumentDisplacement(xMethodInfo, 0) }; //addrof the delegate new Comment("ecx points to the size of the delegated methods arguments"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, SourceReg = CPUx86.Registers.ECX, SourceIsIndirect = true, SourceDisplacement = (Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "$$ArgSize$$")) }; //the size of the arguments to the method? + 12??? -- 12 is the size of the current call stack.. i think new CPUx86.Xor { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EDX };; //make sure edx is 0 new Label(".BEGIN_OF_LOOP"); new CPUx86.Compare { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EBX }; //are we at the end of this list new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Equal, DestinationLabel = ".END_OF_INVOKE_" }; //then we better stop //new CPUx86.Compare("edx", 0); //new CPUx86.JumpIfLessOrEqual(".noreturnYet"); //new CPUx86.Add("esp", 4); //new CPU.Label(".noreturnYet"); //new CPU.Comment("space for the return value"); //new CPUx86.Pushd("0"); new CPUx86.Pushad(); new Comment("esi points to where we will copy the methods argumetns from"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESI, SourceReg = CPUx86.Registers.ESP }; new Comment("edi = ptr to delegate object"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = Ldarg.GetArgumentDisplacement(xMethodInfo, 0) }; new Comment("edi = ptr to delegate object should be a pointer to the delgates context ie (this) for the methods "); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EDI, SourceIsIndirect = true, SourceDisplacement = (Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.Object System.Delegate._target")) }; //i really dont get the +12. MtW: +12 because of extra header of the type (object type, object id, field count) new CPUx86.Compare { DestinationReg = CPUx86.Registers.EDI, SourceValue = 0 }; new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Zero, DestinationLabel = ".NO_THIS" }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EDI }; new Label(".NO_THIS"); new Comment("make space for us to copy the arguments too"); new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceReg = CPUx86.Registers.ECX }; new Comment("move the current delegate to edi"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; new Comment("move the methodptr from that delegate to edi "); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EDI, SourceIsIndirect = true, SourceDisplacement = Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.IntPtr System.Delegate._methodPtr") }; // new Comment("save methodptr on the stack"); new CPUx86.Push { DestinationReg = CPUx86.Registers.EDI }; new Comment("move location to copy args to"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.ESP }; new Comment("get above the saved methodptr"); new CPUx86.Add { DestinationReg = CPUx86.Registers.EDI, SourceValue = 4 }; //we allocated the argsize on the stack once, and it we need to get above the original args new Comment("we allocated argsize on the stack once"); new Comment("add 32 for the Pushad + 16 for the current stack + 4 for the return value"); new CPUx86.Add { DestinationReg = CPUx86.Registers.ESI, SourceValue = 52 }; new CPUx86.Movs { Size = 8, Prefixes = CPUx86.InstructionPrefixes.Repeat }; new CPUx86.Pop { DestinationReg = CPUx86.Registers.EDI }; new CPUx86.Call { DestinationReg = CPUx86.Registers.EDI }; new Comment("store return -- return stored into edi after popad"); //new CPUx86.Move("edx", "[" + MethodInfo.Arguments[0].VirtualAddresses[0] + "]");//addrof the delegate //new CPUx86.Move("edx", "[edx+" + (MethodInfo.Arguments[0].TypeInfo.Fields["$$ReturnsValue$$"].Offset + 12) + "]"); //new CPUx86.Compare(Registers_Old.EDX, 0); //new CPUx86.JumpIfEqual(".getReturn"); //new CPUx86.Move(Registers_Old.EAX, "[esp]"); //new CPUx86.Move("[esp+0x20]", Registers_Old.EAX); //new CPU.Label(".getReturn"); new Comment("edi = ptr to delegate object"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = Cosmos.IL2CPU.X86.IL.Ldarg.GetArgumentDisplacement(xMethodInfo, 0) }; new Comment("edi = ptr to delegate object should be a pointer to the delgates context ie (this) for the methods "); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EDI, SourceIsIndirect = true, SourceDisplacement = Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.Object System.Delegate._target") }; //i really dont get the +12, MtW: that's for the object header //new CPUx86.Compare("edi", "0"); //new CPUx86.JumpIfEqual(".noTHIStoPop"); //new CPUx86.Move("edx", "[" + MethodInfo.Arguments[0].VirtualAddresses[0] + "]");//addrof the delegate //new CPUx86.Move("edx", "[edx+" + (MethodInfo.Arguments[0].TypeInfo.Fields["$$ReturnsValue$$"].Offset + 12) + "]"); //new CPUx86.Compare(Registers_Old.EDX, 0); //new JumpIfNotEqual(".needToPopThis"); //new CPU.Comment("ecx = ptr to delegate object"); //new CPUx86.Move("ecx", "[" + MethodInfo.Arguments[0].VirtualAddresses[0] + "]");//addrof the delegate //new CPU.Comment("ecx points to the size of the delegated methods arguments"); //new CPUx86.Move("ecx", "[ecx + " + (MethodInfo.Arguments[0].TypeInfo.Fields["$$ArgSize$$"].Offset + 12) + "]");//the size of the arguments to the method? + 12??? -- 12 is the size of the current call stack.. i think //new CPUx86.Compare("ecx", "0"); //new CPUx86.JumpIfLessOrEqual(".noTHIStoPop"); //new CPU.Label(".needToPopThis"); //new CPUx86.Pop("edi"); //new CPUx86.Move("[esp]", "edi"); new Label(".noTHIStoPop"); new CPUx86.Popad(); new CPUx86.INC { DestinationReg = CPUx86.Registers.EDX }; new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 4 }; new CPUx86.Jump { DestinationLabel = ".BEGIN_OF_LOOP" }; new Label(".END_OF_INVOKE_"); new Comment("get the return value"); //new CPUx86.Pop("eax"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = Ldarg.GetArgumentDisplacement(xMethodInfo, 0) }; //addrof the delegate new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EDX, SourceIsIndirect = true, SourceDisplacement = Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "$$ReturnsValue$$") }; new CPUx86.Compare { DestinationReg = CPUx86.Registers.EDX, SourceValue = 0 }; new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Equal, DestinationLabel = ".noReturn" }; //may have to expand the return... idk new CPUx86.Xchg { DestinationReg = CPUx86.Registers.EBP, DestinationIsIndirect = true, DestinationDisplacement = 8, SourceReg = CPUx86.Registers.EDX }; new CPUx86.Xchg { DestinationReg = CPUx86.Registers.EBP, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceReg = CPUx86.Registers.EDX }; new CPUx86.Xchg { DestinationReg = CPUx86.Registers.EBP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EDX }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EDX }; //ebp new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = 12, SourceReg = CPUx86.Registers.EDI }; new Label(".noReturn"); // new CPUx86.Sti(); //#warning remove this ^ sti call when issue is fixed!!! //MethodInfo.Arguments[0]. // new CPUx86.Move("ebx", "[eax + " + (MethodInfo.Arguments[0].TypeInfo.Fields["$$ArgSize$$"].Offset + 12) + "]"); //new CPUx86.Move("eax", CPUx86.Registers_Old. }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xType = aMethod.MethodBase.DeclaringType; var xOpCode = (OpField)aOpCode; SysReflection.FieldInfo xField = xOpCode.Value; // call cctor: var xCctor = (xField.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); ILOp.EmitExceptionLogic(Assembler, aMethod, aOpCode, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } //Assembler.Stack.Pop(); //int aExtraOffset;// = 0; //bool xNeedsGC = xField.FieldType.IsClass && !xField.FieldType.IsValueType; var xSize = SizeOfType(xField.FieldType); //if( xNeedsGC ) //{ // aExtraOffset = 12; //} string xDataName = DataMember.GetStaticFieldName(xField); var xTypeNeedsGC = TypeIsReferenceType(xField.FieldType); if (xTypeNeedsGC) { XS.Push(xDataName, isIndirect: true, displacement: 4); XS.Push(0); return; } if (xSize >= 4) { for (int i = 1; i <= (xSize / 4); i++) { // Pop("eax"); // Move(Assembler, "dword [" + mDataName + " + 0x" + (i * 4).ToString("X") + "]", "eax"); new CPUx86.Push { DestinationRef = Cosmos.Assembler.ElementReference.New(xDataName), DestinationIsIndirect = true, DestinationDisplacement = (int)(xSize - (i * 4)) }; } switch (xSize % 4) { case 1: { XS.Set(XSRegisters.EAX, 0); XS.Set(XSRegisters.AL, xDataName, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); break; } case 2: { XS.Set(XSRegisters.EAX, 0); XS.Set(XSRegisters.AX, xDataName, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); break; } case 0: { break; } default: //EmitNotImplementedException( Assembler, GetServiceProvider(), "Ldsfld: Remainder size " + ( xSize % 4 ) + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel ); throw new NotImplementedException(); //break; } } else { switch (xSize) { case 1: { XS.Set(XSRegisters.EAX, 0); XS.Set(XSRegisters.AL, xDataName, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); break; } case 2: { XS.Set(XSRegisters.EAX, 0); XS.Set(XSRegisters.AX, xDataName, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); break; } case 0: { break; } default: //EmitNotImplementedException( Assembler, GetServiceProvider(), "Ldsfld: Remainder size " + ( xSize % 4 ) + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel ); throw new NotImplementedException(); //break; } } }
public static string GetLabel(MethodBase aMethod) { return(LabelName.Get(aMethod)); }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { XS.Push(LabelName.Get(((OpMethod)aOpCode).Value)); }
public static void Assemble(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) ?? Array.Empty <ConstructorInfo>()).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } } if (objectType.IsValueType) { #region Valuetypes XS.Comment("ValueType"); XS.Comment("Type: " + objectType); /* * 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."); } uint xArgSize = 0; var xParameterList = constructor.GetParameters(); foreach (var xParam in xParameterList) { xArgSize = xArgSize + Align(SizeOfType(xParam.ParameterType), 4); } XS.Comment("ArgSize: " + xArgSize); // set source of args copy XS.Set(ESI, ESP); // allocate space for struct XS.Sub(ESP, xStorageSize + 4); // set destination and count of args copy XS.Set(EDI, ESP); XS.Set(ECX, xArgSize / 4); // move the args to their new location new CPUx86.Movs { Size = 32, Prefixes = CPUx86.InstructionPrefixes.Repeat }; // set struct ptr XS.Set(EAX, ESP); XS.Add(EAX, xArgSize + 4); XS.Set(ESP, EAX, destinationDisplacement: (int)xArgSize); XS.Push(EAX); var xOpType = new OpType(xMethod.OpCode, xMethod.Position, xMethod.NextPosition, xMethod.Value.DeclaringType, xMethod.CurrentExceptionRegion); new Initobj(aAssembler).Execute(aMethod, xOpType); 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, sourceDisplacement: 4, sourceIsIndirect: true); // address XS.Set(EAX, EAX, sourceDisplacement: 8, sourceIsIndirect: true); // element count XS.Set(EDX, 2); // element size XS.Multiply(EDX); XS.Push(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(EAX, 1); XS.Push(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(EAX, 1); XS.Push(EAX); } /* * TODO see if something is needed in stack / register to make them really work */ else if (xParams.Length == 3 && (xParams[0].ParameterType == typeof(sbyte *) && xParams[1].ParameterType == typeof(int) && xParams[2].ParameterType == typeof(int))) { xHasCalcSize = true; XS.Push(ESP, isIndirect: true); } else if (xParams.Length == 1 && xParams[0].ParameterType == typeof(sbyte *)) { xHasCalcSize = true; /* xParams[0] contains a C / ASCII Z string the following ASM is de facto the C strlen() function */ var xSByteCountLabel = currentLabel + ".SByteCount"; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.Or(ECX, 0xFFFFFFFF); XS.Label(xSByteCountLabel); XS.Increment(EAX); XS.Increment(ECX); XS.Compare(EAX, 0, destinationIsIndirect: true); XS.Jump(CPUx86.ConditionalTestEnum.NotEqual, xSByteCountLabel); XS.Push(ECX); } 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(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 // todo: use a cleaner approach here. this class shouldnt assemble the string string strTypeId = GetTypeIDLabel(constructor.DeclaringType); XS.Pop(EAX); XS.Set(EBX, strTypeId, sourceIsIndirect: true); XS.Set(EAX, EBX, destinationIsIndirect: true); XS.Set(EAX, (uint)ObjectUtils.InstanceTypeEnum.NormalObject, destinationDisplacement: 4, destinationIsIndirect: true, size: RegisterSize.Int32); XS.Set(EAX, xMemSize, destinationDisplacement: 8, destinationIsIndirect: true, size: RegisterSize.Int32); uint xSize = (uint)(from item in xParams let xQSize = Align(SizeOfType(item.ParameterType), 4) select(int) xQSize).Take(xParams.Length).Sum(); XS.Push(0); foreach (var xParam in xParams) { uint xParamSize = Align(SizeOfType(xParam.ParameterType), 4); XS.Comment($"Arg {xParam.Name}: {xParamSize}"); for (int i = 0; i < xParamSize; i += 4) { XS.Push(ESP, isIndirect: true, displacement: (int)(xSize + 8)); } } 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(ECX, 2); string xNoErrorLabel = currentLabel + ".NoError" + LabelName.LabelCount.ToString(); XS.Jump(CPUx86.ConditionalTestEnum.Equal, xNoErrorLabel); PushAlignedParameterSize(constructor); // an exception occurred, we need to cleanup the stack, and jump to the exit XS.Add(ESP, 4); new Comment(aAssembler, "[ Newobj.Execute cleanup end ]"); Jump_Exception(aMethod); XS.Label(xNoErrorLabel); } XS.Pop(EAX); PushAlignedParameterSize(constructor); XS.Push(EAX); XS.Push(0); } }
public static void DoExecute(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 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 (IsReferenceType(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 (IsReferenceType(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)ObjectUtils.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)ObjectUtils.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 static void DoExecute(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethod, string aFieldId, Type aDeclaringObject, bool aNeedsGC, bool debugEnabled) { var xType = aMethod.MethodBase.DeclaringType; var xFields = GetFieldsInfo(aDeclaringObject, false); var xFieldInfo = (from item in xFields where item.Id == aFieldId select item).Single(); var xActualOffset = Ldfld.GetFieldOffset(aDeclaringObject, aFieldId); var xSize = xFieldInfo.Size; new Comment("Field: " + xFieldInfo.Id); new Comment("Type: " + xFieldInfo.FieldType.ToString()); new Comment("Size: " + xFieldInfo.Size); new Comment("Offset: " + xActualOffset + " (includes object header)"); uint xRoundedSize = Align(xSize, 4); DoNullReferenceCheck(aAssembler, debugEnabled, xRoundedSize); new Comment("After Nullref check"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)xRoundedSize }; // ECX contains the object pointer now if (aNeedsGC) { // for reference types (or boxed types), ECX actually contains the handle now, so we need to convert it to a memory address new Comment("Dereference memory handle now"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, SourceReg = CPUx86.Registers.ECX, SourceIsIndirect = true }; } 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 override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xType = aMethod.MethodBase.DeclaringType; var xOpCode = (ILOpCodes.OpField)aOpCode; SysReflection.FieldInfo xField = xOpCode.Value; var xIsReferenceType = TypeIsReferenceType(xField.FieldType); // call cctor: var xCctor = (xField.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault(); if (xCctor != null && xCctor.DeclaringType != aMethod.MethodBase.DeclaringType) { XS.Call(LabelName.Get(xCctor)); ILOp.EmitExceptionLogic(Assembler, aMethod, aOpCode, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } //int aExtraOffset;// = 0; //bool xNeedsGC = xField.FieldType.IsClass && !xField.FieldType.IsValueType; uint xSize = SizeOfType(xField.FieldType); //if( xNeedsGC ) //{ // aExtraOffset = 12; //} new Comment(Assembler, "Type = '" + xField.FieldType.FullName /*+ "', NeedsGC = " + xNeedsGC*/); uint xOffset = 0; var xFields = xField.DeclaringType.GetFields(); foreach (SysReflection.FieldInfo xInfo in xFields) { if (xInfo == xField) { break; } xOffset += SizeOfType(xInfo.FieldType); } string xDataName = DataMember.GetStaticFieldName(xField); if (xIsReferenceType) { XS.Add(XSRegisters.ESP, 4); XS.Pop(XSRegisters.EAX); XS.Set(ElementReference.New(xDataName).Name, XSRegisters.EAX, destinationIsIndirect: true, destinationDisplacement: 4); return; } for (int i = 0; i < (xSize / 4); i++) { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = ElementReference.New(xDataName, i * 4), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.EAX }; } switch (xSize % 4) { case 1: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.AL }; break; } case 2: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = Cosmos.Assembler.ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.AX }; break; } case 0: { break; } default: //EmitNotImplementedException(Assembler, GetServiceProvider(), "Ldsfld: Remainder size " + (xSize % 4) + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel); throw new NotImplementedException(); //break; } }
private void LoadBootEntries() { mBootEntries = new Dictionary <MethodBase, int?>(); mForceIncludes = new List <MemberInfo>(); var xCheckedAssemblies = new List <string>(); foreach (string xRef in References) { LogMessage("Checking Reference: " + xRef); if (File.Exists(xRef)) { LogMessage(" Exists"); var xAssembly = AssemblyLoadContext.Default.LoadFromAssemblyCacheOrPath(xRef); CheckAssembly(xAssembly); } } void CheckAssembly(Assembly aAssembly) { // Just for debugging //LogMessage("Checking Assembly: " + aAssembly.Location); xCheckedAssemblies.Add(aAssembly.GetName().ToString()); foreach (var xType in aAssembly.GetTypes()) { var xForceIncludeAttribute = xType.GetCustomAttribute <ForceInclude>(); if (xForceIncludeAttribute != null) { ForceInclude(xType, xForceIncludeAttribute); } foreach (var xMethod in xType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) { xForceIncludeAttribute = xMethod.GetCustomAttribute <ForceInclude>(); if (xForceIncludeAttribute != null) { ForceInclude(xMethod, xForceIncludeAttribute); } var xBootEntryAttribute = xMethod.GetCustomAttribute <BootEntry>(); if (xBootEntryAttribute != null) { var xEntryIndex = xBootEntryAttribute.EntryIndex; LogMessage("Boot Entry found: Name: " + xMethod + ", Entry Index: " + (xEntryIndex.HasValue ? xEntryIndex.Value.ToString() : "null")); if (xMethod.ReturnType != typeof(void)) { throw new NotSupportedException("Boot Entry should return void! Method: " + LabelName.Get(xMethod)); } if (xMethod.GetParameters().Length != 0) { throw new NotSupportedException("Boot Entry shouldn't have parameters! Method: " + LabelName.Get(xMethod)); } mBootEntries.Add(xMethod, xEntryIndex); } } if (xType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(m => m.GetCustomAttribute <BootEntry>() != null).Any()) { throw new NotSupportedException("Boot Entry should be static! Type: " + LabelName.GetFullName(xType)); } } foreach (var xReference in aAssembly.GetReferencedAssemblies()) { try { if (!xCheckedAssemblies.Contains(xReference.ToString())) { var xAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(xReference); if (xAssembly != null) { CheckAssembly(xAssembly); } } } catch (FileNotFoundException) { if (xReference.Name.Contains("Cosmos")) { LogWarning("Cosmos Assembly not found!" + Environment.NewLine + "Assembly Name: " + xReference.FullName); } } } } if (mBootEntries.Count == 0) { throw new NotSupportedException("No boot entries found!"); } if (mBootEntries.Where(e => e.Value == null).Count() == 0) { throw new NotImplementedException("No default boot entries found!"); } mBootEntries = mBootEntries.OrderBy(e => e.Value) .OrderByDescending(e => e.Value.HasValue) .ToDictionary(e => e.Key, e => e.Value); if (mBootEntries.Count > 1) { var xLastEntryIndex = mBootEntries.Values.ElementAt(0); for (int i = 1; i < mBootEntries.Count; i++) { var xEntryIndex = mBootEntries.Values.ElementAt(i); if (xLastEntryIndex == xEntryIndex) { throw new NotSupportedException("Two boot entries with the same entry index were found! Methods: '" + LabelName.GetFullName(mBootEntries.Keys.ElementAt(i - 1)) + "' and '" + LabelName.GetFullName(mBootEntries.Keys.ElementAt(i)) + "'"); } xLastEntryIndex = xEntryIndex; } } }
public static string GetFullName(this MethodBase aMethod) { return(LabelName.Get(aMethod)); }