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 Assemble(Assembler aAssembler, uint aElementSize, _MethodInfo aMethod, ILOpCode aOpCode, bool debugEnabled) { DoNullReferenceCheck(aAssembler, debugEnabled, (int)(8 + Align(aElementSize, 4))); uint xStackSize = aElementSize; if (xStackSize % 4 != 0) { xStackSize += 4 - xStackSize % 4; } // Do index out of range check var xBaseLabel = GetLabel(aMethod, aOpCode); var xNoIndexOutOfRangeExeptionLabel = xBaseLabel + "_NoIndexOutOfRangeException"; var xIndexOutOfRangeExeptionLabel = xBaseLabel + "_IndexOutOfRangeException"; XS.Push(ESP, displacement: 4 + 4 + (int)xStackSize); // _, array, 0, index, value * n => _, array, 0, index, value * n, array XS.Push(0); // _, array, 0, index, value * n, array => _, array, 0, index, value * n, array, 0 Ldlen.Assemble(aAssembler, debugEnabled, false); // _, array, 0, index, value * n, array, 0 -> _, array, 0, index, value * n, length XS.Pop(EAX); //Length of array _, array, 0, index, value * n, length -> _, array, 0, index, value * n XS.Compare(EAX, ESP, sourceIsIndirect: true, sourceDisplacement: (int)xStackSize); XS.Jump(CPUx86.ConditionalTestEnum.LessThanOrEqualTo, xIndexOutOfRangeExeptionLabel); XS.Compare(EAX, 0); XS.Jump(CPUx86.ConditionalTestEnum.GreaterThanOrEqualTo, xNoIndexOutOfRangeExeptionLabel); XS.Label(xIndexOutOfRangeExeptionLabel); XS.Exchange(BX, BX); Call.DoExecute(aAssembler, aMethod, ExceptionHelperRefs.ThrowIndexOutOfRangeException, aOpCode, xNoIndexOutOfRangeExeptionLabel, debugEnabled); XS.Label(xNoIndexOutOfRangeExeptionLabel); // calculate element offset into array memory (including header) XS.Set(EAX, ESP, sourceDisplacement: (int)xStackSize); // the index XS.Set(EDX, aElementSize); XS.Multiply(EDX); XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); XS.Set(EDX, ESP, sourceDisplacement: (int)xStackSize + 8); // the array XS.Add(EDX, EAX); XS.Push(EDX); XS.Pop(ECX); //get bytes var bytes = aElementSize / 4; for (uint i = bytes; i > 0; i -= 1) { new Comment(aAssembler, "Start 1 dword"); XS.Pop(EBX); XS.Set(ECX, EBX, destinationIsIndirect: true); XS.Add(ECX, 4); } switch (aElementSize % 4) { case 1: { new Comment(aAssembler, "Start 1 byte"); XS.Pop(EBX); XS.Set(ECX, BL, destinationIsIndirect: true); break; } case 2: { new Comment(aAssembler, "Start 1 word"); XS.Pop(EBX); XS.Set(ECX, BX, destinationIsIndirect: true); break; } case 3: { new Comment(aAssembler, "Start 3 word"); XS.Pop(EBX); XS.And(EBX, 0xFFFFFF); // Only take the value of the lower three bytes XS.Set(ECX, EBX, destinationIsIndirect: true); break; } case 0: { break; } default: throw new Exception("Remainder size " + (aElementSize % 4) + " not supported!"); } XS.Add(ESP, 12); }
public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) { XS.Exchange(XSRegisters.BX, XSRegisters.BX); }