public override MethodIL EmitIL() { Debug.Assert(Signature.Length > 0); var emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); // Load all arguments except delegate's 'this' TypeDesc boxThisType = null; TypeDesc[] parameters = new TypeDesc[Signature.Length - 1]; for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); if (i == 0) { // Ensure that we're working with an object type by boxing it here. // This is to allow delegates which are generic over thier first parameter // to have valid code in their thunk. if (Signature[i].IsSignatureVariable) { boxThisType = Signature[i]; codeStream.Emit(ILOpcode.box, emitter.NewToken(boxThisType)); } } else { parameters[i - 1] = Signature[i]; } } // Call a helper to get the actual method target codeStream.EmitLdArg(0); if (Signature[0].IsByRef) { codeStream.Emit(ILOpcode.ldnull); } else { codeStream.EmitLdArg(1); if (boxThisType != null) { codeStream.Emit(ILOpcode.box, emitter.NewToken(boxThisType)); } } codeStream.Emit(ILOpcode.call, emitter.NewToken(SystemDelegateType.GetKnownMethod("GetActualTargetFunctionPointer", null))); MethodSignature targetSignature = new MethodSignature(0, 0, Signature.ReturnType, parameters); codeStream.Emit(ILOpcode.calli, emitter.NewToken(targetSignature)); codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); ArrayType invocationListArrayType = SystemDelegateType.MakeArrayType(); ILLocalVariable delegateArrayLocal = emitter.NewLocal(invocationListArrayType); ILLocalVariable invocationCountLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable iteratorLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable delegateToCallLocal = emitter.NewLocal(SystemDelegateType); ILLocalVariable returnValueLocal = 0; if (!Signature.ReturnType.IsVoid) { returnValueLocal = emitter.NewLocal(Signature.ReturnType); } // Fill in delegateArrayLocal // Delegate[] delegateArrayLocal = (Delegate[])this.m_helperObject // ldarg.0 (this pointer) // ldfld Delegate.HelperObjectField // castclass Delegate[] // stloc delegateArrayLocal codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); codeStream.Emit(ILOpcode.castclass, emitter.NewToken(invocationListArrayType)); codeStream.EmitStLoc(delegateArrayLocal); // Fill in invocationCountLocal // int invocationCountLocal = this.m_extraFunctionPointerOrData // ldarg.0 (this pointer) // ldfld Delegate.m_extraFunctionPointerOrData // stloc invocationCountLocal codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField)); codeStream.EmitStLoc(invocationCountLocal); // Fill in iteratorLocal // int iteratorLocal = 0; // ldc.0 // stloc iteratorLocal codeStream.EmitLdc(0); codeStream.EmitStLoc(iteratorLocal); // Loop across every element of the array. ILCodeLabel startOfLoopLabel = emitter.NewCodeLabel(); codeStream.EmitLabel(startOfLoopLabel); // Implement as do/while loop. We only have this stub in play if we're in the multicast situation // Find the delegate to call // Delegate = delegateToCallLocal = delegateArrayLocal[iteratorLocal]; // ldloc delegateArrayLocal // ldloc iteratorLocal // ldelem System.Delegate // stloc delegateToCallLocal codeStream.EmitLdLoc(delegateArrayLocal); codeStream.EmitLdLoc(iteratorLocal); codeStream.Emit(ILOpcode.ldelem, emitter.NewToken(SystemDelegateType)); codeStream.EmitStLoc(delegateToCallLocal); // Call the delegate // returnValueLocal = delegateToCallLocal(...); // ldloc delegateToCallLocal // ldfld System.Delegate.m_firstParameter // ldarg 1, n // ldloc delegateToCallLocal // ldfld System.Delegate.m_functionPointer // calli returnValueType thiscall (all the params) // IF there is a return value // stloc returnValueLocal codeStream.EmitLdLoc(delegateToCallLocal); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FirstParameterField)); for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } codeStream.EmitLdLoc(delegateToCallLocal); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FunctionPointerField)); codeStream.Emit(ILOpcode.calli, emitter.NewToken(Signature)); if (returnValueLocal != 0) { codeStream.EmitStLoc(returnValueLocal); } // Increment iteratorLocal // ++iteratorLocal; // ldloc iteratorLocal // ldc.i4.1 // add // stloc iteratorLocal codeStream.EmitLdLoc(iteratorLocal); codeStream.EmitLdc(1); codeStream.Emit(ILOpcode.add); codeStream.EmitStLoc(iteratorLocal); // Check to see if the loop is done codeStream.EmitLdLoc(invocationCountLocal); codeStream.EmitLdLoc(iteratorLocal); codeStream.Emit(ILOpcode.bne_un, startOfLoopLabel); // Return to caller. If the delegate has a return value, be certain to return that. // return returnValueLocal; // ldloc returnValueLocal // ret if (returnValueLocal != 0) { codeStream.EmitLdLoc(returnValueLocal); } codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }