private MethodIL EmitIL() { PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream marshallingCodestream = pInvokeILCodeStreams.MarshallingCodeStream; ILCodeStream unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream; ILCodeStream cleanupCodestream = pInvokeILCodeStreams.CleanupCodeStream; // Marshalling is wrapped in a finally block to guarantee cleanup ILExceptionRegionBuilder tryFinally = emitter.NewFinallyRegion(); marshallingCodestream.BeginTry(tryFinally); cleanupCodestream.BeginHandler(tryFinally); // Marshal the arguments bool isHRSwappedRetVal = !_flags.PreserveSig && !_targetMethod.Signature.ReturnType.IsVoid; for (int i = isHRSwappedRetVal ? 1 : 0; i < _marshallers.Length; i++) { _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams); } if (isHRSwappedRetVal) { _marshallers[0].EmitMarshallingIL(pInvokeILCodeStreams); } // make the call switch (_targetMethod) { case DelegateMarshallingMethodThunk delegateMethod: EmitDelegateCall(delegateMethod, pInvokeILCodeStreams); break; case CalliMarshallingMethodThunk calliMethod: EmitCalli(pInvokeILCodeStreams, calliMethod); break; default: EmitPInvokeCall(pInvokeILCodeStreams); break; } ILCodeLabel lReturn = emitter.NewCodeLabel(); unmarshallingCodestream.Emit(ILOpcode.leave, lReturn); unmarshallingCodestream.EndTry(tryFinally); cleanupCodestream.Emit(ILOpcode.endfinally); cleanupCodestream.EndHandler(tryFinally); cleanupCodestream.EmitLabel(lReturn); _marshallers[0].LoadReturnValue(cleanupCodestream); cleanupCodestream.Emit(ILOpcode.ret); return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired())); }
private MethodIL EmitIL() { if (!_importMetadata.Flags.PreserveSig) { throw new NotSupportedException(); } if (MarshalHelpers.ShouldCheckForPendingException(_targetMethod.Context.Target, _importMetadata)) { throw new NotSupportedException(); } if (_targetMethod.IsUnmanagedCallersOnly) { throw new NotSupportedException(); } if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute")) { throw new NotSupportedException(); } PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream marshallingCodestream = pInvokeILCodeStreams.MarshallingCodeStream; ILCodeStream unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream; ILCodeStream cleanupCodestream = pInvokeILCodeStreams.CleanupCodeStream; // Marshalling is wrapped in a finally block to guarantee cleanup ILExceptionRegionBuilder tryFinally = emitter.NewFinallyRegion(); marshallingCodestream.BeginTry(tryFinally); cleanupCodestream.BeginHandler(tryFinally); // Marshal the arguments for (int i = 0; i < _marshallers.Length; i++) { _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams); } EmitPInvokeCall(pInvokeILCodeStreams); ILCodeLabel lReturn = emitter.NewCodeLabel(); unmarshallingCodestream.Emit(ILOpcode.leave, lReturn); unmarshallingCodestream.EndTry(tryFinally); cleanupCodestream.Emit(ILOpcode.endfinally); cleanupCodestream.EndHandler(tryFinally); cleanupCodestream.EmitLabel(lReturn); _marshallers[0].LoadReturnValue(cleanupCodestream); cleanupCodestream.Emit(ILOpcode.ret); return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod))); }
public override MethodIL EmitIL() { // We will generate the following code: // // object ret; // object[] args = new object[parameterCount]; // args[0] = param0; // args[1] = param1; // ... // try { // ret = ((Func<object[], object>)dlg.m_helperObject)(args); // } finally { // param0 = (T0)args[0]; // only generated for each byref argument // } // return (TRet)ret; ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); TypeDesc objectType = Context.GetWellKnownType(WellKnownType.Object); TypeDesc objectArrayType = objectType.MakeArrayType(); ILLocalVariable argsLocal = emitter.NewLocal(objectArrayType); bool hasReturnValue = !Signature.ReturnType.IsVoid; bool hasRefArgs = false; if (Signature.Length > 0) { codeStream.EmitLdc(Signature.Length); codeStream.Emit(ILOpcode.newarr, emitter.NewToken(objectType)); codeStream.EmitStLoc(argsLocal); for (int i = 0; i < Signature.Length; i++) { TypeDesc paramType = Signature[i]; bool paramIsByRef = false; if (paramType.IsByRef) { hasRefArgs |= paramType.IsByRef; paramIsByRef = true; paramType = ((ByRefType)paramType).ParameterType; } hasRefArgs |= paramType.IsByRef; codeStream.EmitLdLoc(argsLocal); codeStream.EmitLdc(i); codeStream.EmitLdArg(i + 1); ILToken paramToken = emitter.NewToken(paramType); if (paramIsByRef) { codeStream.Emit(ILOpcode.ldobj, paramToken); } codeStream.Emit(ILOpcode.box, paramToken); codeStream.Emit(ILOpcode.stelem_ref); } } else { MethodDesc emptyObjectArrayMethod = Context.GetHelperEntryPoint("DelegateHelpers", "GetEmptyObjectArray"); codeStream.Emit(ILOpcode.call, emitter.NewToken(emptyObjectArrayMethod)); codeStream.EmitStLoc(argsLocal); } ILExceptionRegionBuilder tryFinallyRegion = null; if (hasRefArgs) { // we emit a try/finally to update the args array even if an exception is thrown tryFinallyRegion = emitter.NewFinallyRegion(); codeStream.BeginTry(tryFinallyRegion); } codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); MetadataType funcType = Context.SystemModule.GetKnownType("System", "Func`2"); TypeDesc instantiatedFunc = funcType.MakeInstantiatedType(objectArrayType, objectType); codeStream.Emit(ILOpcode.castclass, emitter.NewToken(instantiatedFunc)); codeStream.EmitLdLoc(argsLocal); MethodDesc invokeMethod = instantiatedFunc.GetKnownMethod("Invoke", null); codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod)); ILLocalVariable retLocal = (ILLocalVariable)(-1); if (hasReturnValue) { retLocal = emitter.NewLocal(objectType); codeStream.EmitStLoc(retLocal); } else { codeStream.Emit(ILOpcode.pop); } if (hasRefArgs) { ILCodeLabel returnLabel = emitter.NewCodeLabel(); codeStream.Emit(ILOpcode.leave, returnLabel); codeStream.EndTry(tryFinallyRegion); // copy back ref/out args codeStream.BeginHandler(tryFinallyRegion); for (int i = 0; i < Signature.Length; i++) { TypeDesc paramType = Signature[i]; if (paramType.IsByRef) { paramType = ((ByRefType)paramType).ParameterType; ILToken paramToken = emitter.NewToken(paramType); // Update parameter codeStream.EmitLdArg(i + 1); codeStream.EmitLdLoc(argsLocal); codeStream.EmitLdc(i); codeStream.Emit(ILOpcode.ldelem_ref); codeStream.Emit(ILOpcode.unbox_any, paramToken); codeStream.Emit(ILOpcode.stobj, paramToken); } } codeStream.Emit(ILOpcode.endfinally); codeStream.EndHandler(tryFinallyRegion); codeStream.EmitLabel(returnLabel); } if (hasReturnValue) { codeStream.EmitLdLoc(retLocal); codeStream.Emit(ILOpcode.unbox_any, emitter.NewToken(Signature.ReturnType)); } codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }