/// <summary> /// Marshals an array. Expects the array reference on the stack. Pushes a pinned /// managed reference to the first element on the stack or null if the array was /// null or empty. /// </summary> /// <returns>Type the array was marshalled into.</returns> private TypeDesc EmitArrayMarshalling(ArrayType arrayType) { Debug.Assert(arrayType.IsSzArray); ILLocalVariable vPinnedFirstElement = _emitter.NewLocal(arrayType.ParameterType.MakeByRefType(), true); ILLocalVariable vArray = _emitter.NewLocal(arrayType); ILCodeLabel lNullArray = _emitter.NewCodeLabel(); // Check for null array, or 0 element array. _marshallingCodeStream.Emit(ILOpcode.dup); _marshallingCodeStream.EmitStLoc(vArray); _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullArray); _marshallingCodeStream.EmitLdLoc(vArray); _marshallingCodeStream.Emit(ILOpcode.ldlen); _marshallingCodeStream.Emit(ILOpcode.conv_i4); _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullArray); // Array has elements. _marshallingCodeStream.EmitLdLoc(vArray); _marshallingCodeStream.EmitLdc(0); _marshallingCodeStream.Emit(ILOpcode.ldelema, _emitter.NewToken(arrayType.ElementType)); _marshallingCodeStream.EmitStLoc(vPinnedFirstElement); // Fall through. If array didn't have elements, vPinnedFirstElement is zeroinit. _marshallingCodeStream.EmitLabel(lNullArray); _marshallingCodeStream.EmitLdLoc(vPinnedFirstElement); _marshallingCodeStream.Emit(ILOpcode.conv_i); return(_context.GetWellKnownType(WellKnownType.IntPtr)); }
private TypeDesc EmitStringBuilderMarshalling() { if (GetCharSet() == PInvokeAttributes.CharSetUnicode) { // TODO: Handles [out] marshalling only for now var stringBuilderType = _context.SystemModule.GetKnownType("System.Text", "StringBuilder"); var charArrayType = _context.GetWellKnownType(WellKnownType.Char).MakeArrayType(); ILLocalVariable vStringBuilder = _emitter.NewLocal(stringBuilderType); ILLocalVariable vBuffer = _emitter.NewLocal(charArrayType); _marshallingCodeStream.EmitStLoc(vStringBuilder); _marshallingCodeStream.EmitLdLoc(vStringBuilder); _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken( _context.GetHelperEntryPoint("InteropHelpers", "GetEmptyStringBuilderBuffer"))); _marshallingCodeStream.EmitStLoc(vBuffer); _unmarshallingCodestream.EmitLdLoc(vStringBuilder); _unmarshallingCodestream.EmitLdLoc(vBuffer); _unmarshallingCodestream.Emit(ILOpcode.call, _emitter.NewToken( _context.GetHelperEntryPoint("InteropHelpers", "ReplaceStringBuilderBuffer"))); _marshallingCodeStream.EmitLdLoc(vBuffer); return(EmitArrayMarshalling(charArrayType)); } else { throw new NotSupportedException(); } }
public static List <ILLocalVariable> GetLocalVariableInfos(MethodBase aMethodBase) { string xMenthodId = $"{aMethodBase.MetadataToken}_{aMethodBase.DeclaringType?.FullName}_{aMethodBase.Name}"; if (xLocalVariableInfosCache.ContainsKey(xMenthodId)) { return(xLocalVariableInfosCache[xMenthodId]); } var xLocalVariables = new List <ILLocalVariable>(); string xLocation = aMethodBase.Module.Assembly.Location; var xGenericMethodParameters = new Type[0]; var xGenericTypeParameters = new Type[0]; if (aMethodBase.IsGenericMethod) { xGenericMethodParameters = aMethodBase.GetGenericArguments(); } if (aMethodBase.DeclaringType != null && aMethodBase.DeclaringType.IsGenericType) { xGenericTypeParameters = aMethodBase.DeclaringType.GetGenericArguments(); } var xReader = GetReader(xLocation).mMetadataReader; List <ILLocalVariable> xLocalVariablesFromPdb = null; try { if (mCurrentDebugSymbolReader?.mSymbolReader != null) { xLocalVariablesFromPdb = mCurrentDebugSymbolReader.mSymbolReader.GetLocalVariableNamesForMethod(aMethodBase.MetadataToken).ToList(); } } catch (Exception) { } var xTypes = ResolveLocalsFromSignature(xReader, aMethodBase, xGenericTypeParameters, xGenericMethodParameters).ToList(); for (int i = 0; i < xTypes.Count; i++) { int xSlot = i; string xName = "Local" + i; bool xCompilerGenerated = true; ILLocalVariable xLocal = xLocalVariablesFromPdb?.FirstOrDefault(x => x.Slot == i); if (xLocal != null) { xName = xLocal.Name; xSlot = xLocal.Slot; xCompilerGenerated = xLocal.CompilerGenerated; } xLocalVariables.Add(new ILLocalVariable(xSlot, xName, xCompilerGenerated, xTypes[i])); } xLocalVariableInfosCache.Add(xMenthodId, xLocalVariables); return(xLocalVariables); }
/// <summary> /// Marshals a ByRef. Expects the ByRef on the stack. Pushes a pinned /// unmanaged pointer to the stack. /// </summary> /// <returns>Type the ByRef was marshalled into.</returns> private TypeDesc EmitByRefMarshalling(ByRefType byRefType) { ILLocalVariable vPinnedByRef = _emitter.NewLocal(byRefType, true); _marshallingCodeStream.EmitStLoc(vPinnedByRef); _marshallingCodeStream.EmitLdLoc(vPinnedByRef); _marshallingCodeStream.Emit(ILOpcode.conv_i); return(_context.GetWellKnownType(WellKnownType.IntPtr)); }
/// <summary> /// Marshals a ByRef. Expects the ByRef on the stack. Pushes a pinned /// unmanaged pointer to the stack. /// </summary> /// <returns>Type the ByRef was marshalled into.</returns> private TypeDesc EmitByRefMarshalling(ByRefType byRefType) { if (!IsBlittableType(byRefType.ParameterType)) { throw new NotSupportedException(); } ILLocalVariable vPinnedByRef = _emitter.NewLocal(byRefType, true); _marshallingCodeStream.EmitStLoc(vPinnedByRef); _marshallingCodeStream.EmitLdLoc(vPinnedByRef); _marshallingCodeStream.Emit(ILOpcode.conv_i); return(byRefType.Context.GetWellKnownType(WellKnownType.IntPtr)); }
public void EmitLdLoca(ILLocalVariable variable) { int index = (int)variable; if (index < 0x100) { Emit(ILOpcode.ldloca_s); EmitByte((byte)index); } else { Emit(ILOpcode.ldloca); EmitUInt16((ushort)index); } }
private TypeDesc EmitStringMarshalling() { if (GetCharSet() == PInvokeAttributes.CharSetUnicode) { // // Unicode marshalling. Pin the string and push a pointer to the first character on the stack. // TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String); ILLocalVariable vPinnedString = _emitter.NewLocal(stringType, true); ILCodeLabel lNullString = _emitter.NewCodeLabel(); _marshallingCodeStream.EmitStLoc(vPinnedString); _marshallingCodeStream.EmitLdLoc(vPinnedString); _marshallingCodeStream.Emit(ILOpcode.conv_i); _marshallingCodeStream.Emit(ILOpcode.dup); // Marshalling a null string? _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString); _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken( _context.SystemModule. GetKnownType("System.Runtime.CompilerServices", "RuntimeHelpers"). GetKnownMethod("get_OffsetToStringData", null))); _marshallingCodeStream.Emit(ILOpcode.add); _marshallingCodeStream.EmitLabel(lNullString); return(_context.GetWellKnownType(WellKnownType.IntPtr)); } else { // // ANSI marshalling. Allocate a byte array, copy characters, pin first element. // var stringToAnsi = _context.GetHelperEntryPoint("InteropHelpers", "StringToAnsi"); _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken(stringToAnsi)); return(EmitArrayMarshalling(_context.GetWellKnownType(WellKnownType.Byte).MakeArrayType())); } }
public static MethodIL EmitIL(MethodDesc target) { Debug.Assert(target.Signature.Length == 1); ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); TypeSystemContext context = target.Context; TypeDesc runtimeTypeHandleType = context.GetWellKnownType(WellKnownType.RuntimeTypeHandle); Debug.Assert(target.Signature.ReturnType == runtimeTypeHandleType); if (context.SupportsCanon) { ILCodeLabel lNotCanon = emitter.NewCodeLabel(); codeStream.Emit(ILOpcode.ldarg_0); codeStream.EmitLdc((int)CanonTypeKind.NormalCanon); codeStream.Emit(ILOpcode.bne_un, lNotCanon); codeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(context.CanonType)); codeStream.Emit(ILOpcode.ret); codeStream.EmitLabel(lNotCanon); // We're not conditioning this on SupportsUniversalCanon because the runtime type loader // does a lot of comparisons against UniversalCanon and not having a RuntimeTypeHandle // for it makes these checks awkward. // Would be nice if we didn't have to emit the EEType if universal canonical code wasn't enabled // at the time of compilation. ILCodeLabel lNotUniversalCanon = emitter.NewCodeLabel(); codeStream.Emit(ILOpcode.ldarg_0); codeStream.EmitLdc((int)CanonTypeKind.UniversalCanon); codeStream.Emit(ILOpcode.bne_un, lNotUniversalCanon); codeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(context.UniversalCanonType)); codeStream.Emit(ILOpcode.ret); codeStream.EmitLabel(lNotUniversalCanon); } ILLocalVariable vNullTypeHandle = emitter.NewLocal(runtimeTypeHandleType); codeStream.EmitLdLoca(vNullTypeHandle); codeStream.Emit(ILOpcode.initobj, emitter.NewToken(runtimeTypeHandleType)); codeStream.EmitLdLoc(vNullTypeHandle); codeStream.Emit(ILOpcode.ret); return(emitter.Link(target)); }
public void EmitStLoc(ILLocalVariable variable) { int index = (int)variable; if (index < 4) { Emit((ILOpcode)(ILOpcode.stloc_0 + index)); } else if (index < 0x100) { Emit(ILOpcode.stloc_s); EmitByte((byte)index); } else { Emit(ILOpcode.stloc); EmitUInt16((ushort)index); } }
private void GenerateCreateAndChildCallCode(ILLocalVariable local) { var type = local.Type; var constructor = type.GetTypeInfo().GetConstructor(Type.EmptyTypes); if (constructor == null) { throw InvalidGraphException.NoParameterLessConstructor(type); } _il.Construct(constructor); _il.Set(local); var childTravellerInfo = _context.GetTraveller(type); var field = ILPointer.Field(ILPointer.This(), childTravellerInfo.Field); _il.InvokeMethod(field, childTravellerInfo.TravelReadMethod, _visitorVariable, local); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); ILLocalVariable returnValue = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); MetadataType startup = Context.GetHelperType("StartupCodeHelpers"); codeStream.Emit(ILOpcode.call, emitter.NewToken(startup.GetKnownMethod("Initialize", null))); // Initialize command line args // TODO: For Windows change to "InitializeCommandLineArgsW" with wmain wchar_t change. string initArgsName = (Context.Target.OperatingSystem == TargetOS.Windows) ? "InitializeCommandLineArgs" : "InitializeCommandLineArgs"; MethodDesc initArgs = startup.GetKnownMethod(initArgsName, null); codeStream.Emit(ILOpcode.ldarg_0); // argc codeStream.Emit(ILOpcode.ldarg_1); // argv codeStream.Emit(ILOpcode.call, emitter.NewToken(initArgs)); // Call program Main if (_mainMethod.Signature.Length > 0) { TypeDesc environ = Context.SystemModule.GetKnownType("System", "Environment"); codeStream.Emit(ILOpcode.call, emitter.NewToken(environ.GetKnownMethod("GetCommandLineArgs", null))); } codeStream.Emit(ILOpcode.call, emitter.NewToken(_mainMethod)); if (_mainMethod.Signature.ReturnType.IsVoid) { codeStream.EmitLdc(0); } codeStream.EmitStLoc(returnValue); codeStream.Emit(ILOpcode.call, emitter.NewToken(startup.GetKnownMethod("Shutdown", null))); codeStream.EmitLdLoc(returnValue); codeStream.Emit(ILOpcode.ret); return(emitter.Link()); }
private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream fnptrLoadStream = ilCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; bool isHRSwappedRetVal = !_flags.PreserveSig && !_targetMethod.Signature.ReturnType.IsVoid; TypeDesc nativeReturnType = _flags.PreserveSig ? _marshallers[0].NativeParameterType : context.GetWellKnownType(WellKnownType.Int32); TypeDesc[] nativeParameterTypes = new TypeDesc[isHRSwappedRetVal ? _marshallers.Length : _marshallers.Length - 1]; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastError", null))); } for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } if (isHRSwappedRetVal) { nativeParameterTypes[_marshallers.Length - 1] = _marshallers[0].NativeParameterType; } if (!_pInvokeILEmitterConfiguration.GenerateDirectCall(_targetMethod, out _)) { MetadataType lazyHelperType = context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = _interopStateManager.GetPInvokeLazyFixupField(_targetMethod); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType .GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallingConvention = _flags.UnmanagedCallingConvention; if (unmanagedCallingConvention == MethodSignatureFlags.None) { unmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConvention; } EmbeddedSignatureData[] embeddedSignatureData = null; if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "SuppressGCTransitionAttribute")) { embeddedSignatureData = new EmbeddedSignatureData[] { new EmbeddedSignatureData() { index = MethodSignature.IndexOfCustomModifiersOnReturnType, kind = EmbeddedSignatureDataKind.OptionalCustomModifier, type = context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "CallConvSuppressGCTransition") } }; } MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags | unmanagedCallingConvention, 0, nativeReturnType, nativeParameterTypes, embeddedSignatureData); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(context .GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); } else { // Eager call MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } if (!_flags.PreserveSig) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetMarshal(context) .GetKnownMethod("ThrowExceptionForHR", null))); } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastError // so that last error can be used later by calling Marshal.GetLastPInvokeError if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context) .GetKnownMethod("SaveLastError", null))); } }
public MethodIL EmitIL() { MethodSignature targetMethodSignature = _targetMethod.Signature; // We have 4 code streams: // - _marshallingCodeStream is used to convert each argument into a native type and // store that into the local // - callsiteSetupCodeStream is used to used to load each previously generated local // and call the actual target native method. // - _returnValueMarshallingCodeStream is used to convert the native return value // to managed one. // - _unmarshallingCodestream is used to propagate [out] native arguments values to // managed ones. _emitter = new ILEmitter(); _marshallingCodeStream = _emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream(); _returnValueMarshallingCodeStream = _emitter.NewCodeStream(); _unmarshallingCodestream = _emitter.NewCodeStream(); TypeDesc[] nativeParameterTypes = new TypeDesc[targetMethodSignature.Length]; // // Parameter marshalling // // // Convert each argument to something we can pass to native and store it in a local. // Then load the local in the second code stream. // for (int i = 0; i < targetMethodSignature.Length; i++) { // TODO: throw if there's custom marshalling _marshallingCodeStream.EmitLdArg(i); TypeDesc nativeType = MarshalArgument(targetMethodSignature[i]); nativeParameterTypes[i] = nativeType; ILLocalVariable vMarshalledTypeTemp = _emitter.NewLocal(nativeType); _marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp); callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp); } // // Return value marshalling // // TODO: throw if SetLastError is true // TODO: throw if there's custom marshalling TypeDesc nativeReturnType = MarshalReturnValue(targetMethodSignature.ReturnType); MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, _importMetadata); // Call the native method callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); _unmarshallingCodestream.Emit(ILOpcode.ret); return(_emitter.Link()); }
private MethodIL EmitIL() { // We have 4 code streams: // - _marshallingCodeStream is used to convert each argument into a native type and // store that into the local // - callsiteSetupCodeStream is used to used to load each previously generated local // and call the actual target native method. // - _returnValueMarshallingCodeStream is used to convert the native return value // to managed one. // - _unmarshallingCodestream is used to propagate [out] native arguments values to // managed ones. ILEmitter emitter = new ILEmitter(); ILCodeStream fnptrLoadStream = emitter.NewCodeStream(); ILCodeStream marshallingCodeStream = emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = emitter.NewCodeStream(); ILCodeStream returnValueMarshallingCodeStream = emitter.NewCodeStream(); ILCodeStream unmarshallingCodestream = emitter.NewCodeStream(); // Marshal the arguments for (int i = 0; i < _marshallers.Length; i++) { Marshaller marshaller = _marshallers[i]; marshaller.EmitMarshallingIL(emitter, marshallingCodeStream, callsiteSetupCodeStream, unmarshallingCodestream, returnValueMarshallingCodeStream); } // make the call TypeDesc nativeReturnType = _marshallers[0].NativeType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeType; } MethodDesc targetMethod = _methodData.TargetMethod; PInvokeMetadata importMetadata = _methodData.ImportMetadata; PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration = _methodData.PInvokeILEmitterConfiguration; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( _methodData.PInvokeMarshal.GetKnownMethod("ClearLastWin32Error", null))); } if (MarshalHelpers.UseLazyResolution(targetMethod, importMetadata.Module, pinvokeILEmitterConfiguration)) { MetadataType lazyHelperType = targetMethod.Context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = new PInvokeLazyFixupField((DefType)targetMethod.OwningType, importMetadata); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = PInvokeMetadata.GetUnmanagedCallingConvention(importMetadata.Attributes); MethodSignature nativeCalliSig = new MethodSignature( targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeCalliSig)); } else { // Eager call PInvokeMetadata nativeImportMetadata = new PInvokeMetadata(importMetadata.Module, importMetadata.Name ?? targetMethod.Name, importMetadata.Attributes); MethodSignature nativeSig = new MethodSignature( targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(targetMethod.OwningType, nativeSig, nativeImportMetadata, pinvokeILEmitterConfiguration.GetNextNativeMethodId()); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastWin32Error so that last error can be used later // by calling PInvokeMarshal.GetLastWin32Error if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( _methodData.PInvokeMarshal.GetKnownMethod("SaveLastWin32Error", null))); } unmarshallingCodestream.Emit(ILOpcode.ret); return(emitter.Link(targetMethod)); }
private MethodIL EmitIL() { PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream fnptrLoadStream = pInvokeILCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = pInvokeILCodeStreams.CallsiteSetupCodeStream; ILCodeStream unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream; TypeSystemContext context = _targetMethod.Context; // Marshal the arguments for (int i = 0; i < _marshallers.Length; i++) { _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams); } // make the call TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } MethodSignature nativeSig; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_importMetadata.Flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null))); } DelegateMarshallingMethodThunk delegateMethod = _targetMethod as DelegateMarshallingMethodThunk; if (delegateMethod != null) { if (delegateMethod.IsOpenStaticDelegate) { // // For Open static delegates call // InteropHelpers.GetCurrentCalleeOpenStaticDelegateFunctionPointer() // which returns a function pointer. Just call the function pointer and we are done. // TypeDesc[] parameters = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { parameters[i - 1] = _marshallers[i].ManagedParameterType; } MethodSignature managedSignature = new MethodSignature(MethodSignatureFlags.Static, 0, _marshallers[0].ManagedParameterType, parameters); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(delegateMethod.Context.GetHelperType("InteropHelpers").GetKnownMethod("GetCurrentCalleeOpenStaticDelegateFunctionPointer", null))); ILLocalVariable vDelegateStub = emitter.NewLocal(delegateMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vDelegateStub); callsiteSetupCodeStream.EmitLdLoc(vDelegateStub); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(managedSignature)); } else { // // For closed delegates call // InteropHelpers.GetCurrentCalleeDelegate<Delegate> // which returns the delegate. Do a CallVirt on the invoke method. // MethodDesc instantiatedHelper = delegateMethod.Context.GetInstantiatedMethod( delegateMethod.Context.GetHelperType("InteropHelpers").GetKnownMethod("GetCurrentCalleeDelegate", null), new Instantiation((delegateMethod.DelegateType))); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(instantiatedHelper)); ILLocalVariable vDelegateStub = emitter.NewLocal(delegateMethod.DelegateType); fnptrLoadStream.EmitStLoc(vDelegateStub); fnptrLoadStream.EmitLdLoc(vDelegateStub); MethodDesc invokeMethod = delegateMethod.DelegateType.GetKnownMethod("Invoke", null); callsiteSetupCodeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod)); } } else if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module, _pInvokeILEmitterConfiguration)) { MetadataType lazyHelperType = _targetMethod.Context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = new PInvokeLazyFixupField((DefType)_targetMethod.OwningType, _importMetadata); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = _importMetadata.Flags.UnmanagedCallingConvention; nativeSig = new MethodSignature( _targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(_targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); } else { // Eager call PInvokeMetadata nativeImportMetadata = new PInvokeMetadata(_importMetadata.Module, _importMetadata.Name ?? _targetMethod.Name, _importMetadata.Flags); nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, nativeImportMetadata, _pInvokeILEmitterConfiguration.GetNextNativeMethodId()); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastWin32Error so that last error can be used later // by calling PInvokeMarshal.GetLastWin32Error if (_importMetadata.Flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("SaveLastWin32Error", null))); } unmarshallingCodestream.Emit(ILOpcode.ret); return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired())); }
private MethodIL EmitIL() { PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream fnptrLoadStream = pInvokeILCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = pInvokeILCodeStreams.CallsiteSetupCodeStream; ILCodeStream unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream; TypeSystemContext context = _targetMethod.Context; // Marshal the arguments for (int i = 0; i < _marshallers.Length; i++) { _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams); } // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_importMetadata.Flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null))); } // make the call DelegateMarshallingMethodThunk delegateMethod = _targetMethod as DelegateMarshallingMethodThunk; if (delegateMethod != null) { EmitDelegateCall(delegateMethod, pInvokeILCodeStreams); } else { TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module, _pInvokeILEmitterConfiguration)) { MetadataType lazyHelperType = _targetMethod.Context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = new PInvokeLazyFixupField(_targetMethod); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType .GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = _importMetadata.Flags.UnmanagedCallingConvention; MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(_targetMethod.Context .GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); } else { // Eager call MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal. // SaveLastWin32Error so that last error can be used later by calling // PInvokeMarshal.GetLastWin32Error if (_importMetadata.Flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context) .GetKnownMethod("SaveLastWin32Error", null))); } unmarshallingCodestream.Emit(ILOpcode.ret); return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired())); }
/// <summary> /// Generates a calli sequence that is aware of fat function pointers and can unwrap them into /// a function pointer + instantiation argument if necessary. /// </summary> public static void EmitTransformedCalli(ILEmitter emitter, ILCodeStream codestream, MethodSignature targetSignature) { TypeSystemContext context = targetSignature.ReturnType.Context; int thisPointerParamDelta = 0; if (!targetSignature.IsStatic) thisPointerParamDelta = 1; // Start by saving the pointer to call and all the args into locals ILLocalVariable vPointerToCall = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr)); codestream.EmitStLoc(vPointerToCall); ILLocalVariable[] vParameters = new ILLocalVariable[targetSignature.Length + thisPointerParamDelta]; for (int i = thisPointerParamDelta; i < vParameters.Length; i++) { vParameters[vParameters.Length - i - 1 + thisPointerParamDelta] = emitter.NewLocal(targetSignature[targetSignature.Length - (i - thisPointerParamDelta) - 1]); codestream.EmitStLoc(vParameters[vParameters.Length - i - 1 + thisPointerParamDelta]); } if (!targetSignature.IsStatic) { vParameters[0] = emitter.NewLocal(context.GetWellKnownType(WellKnownType.Object)); codestream.EmitStLoc(vParameters[0]); } // Is this a fat pointer? codestream.EmitLdLoc(vPointerToCall); Debug.Assert(((FatFunctionPointerConstants.Offset - 1) & FatFunctionPointerConstants.Offset) == 0); codestream.EmitLdc(FatFunctionPointerConstants.Offset); codestream.Emit(ILOpcode.and); ILCodeLabel notAFatPointer = emitter.NewCodeLabel(); codestream.Emit(ILOpcode.brfalse, notAFatPointer); // // Fat pointer case // codestream.EmitLdLoc(vPointerToCall); codestream.EmitLdc(FatFunctionPointerConstants.Offset); codestream.Emit(ILOpcode.sub); // Get the pointer to call from the fat pointer codestream.Emit(ILOpcode.dup); codestream.Emit(ILOpcode.ldind_i); codestream.EmitStLoc(vPointerToCall); // Get the instantiation argument codestream.EmitLdc(context.Target.PointerSize); codestream.Emit(ILOpcode.add); codestream.Emit(ILOpcode.ldind_i); codestream.Emit(ILOpcode.ldind_i); ILLocalVariable instArg = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr)); codestream.EmitStLoc(instArg); // Load this int firstRealParameter = 0; if (!targetSignature.IsStatic) { codestream.EmitLdLoc(vParameters[0]); firstRealParameter = 1; } // Load hidden arg codestream.EmitLdLoc(instArg); // Load rest of args for (int i = firstRealParameter; i < vParameters.Length; i++) { codestream.EmitLdLoc(vParameters[i]); } codestream.EmitLdLoc(vPointerToCall); // The signature has a hidden argument TypeDesc[] newParameters = new TypeDesc[targetSignature.Length + 1]; for (int i = 0; i < targetSignature.Length; i++) newParameters[i + 1] = targetSignature[i]; newParameters[0] = context.GetWellKnownType(WellKnownType.IntPtr); MethodSignature newMethodSignature = new MethodSignature(targetSignature.Flags, targetSignature.GenericParameterCount, targetSignature.ReturnType, newParameters); codestream.Emit(ILOpcode.calli, emitter.NewToken(newMethodSignature)); ILCodeLabel done = emitter.NewCodeLabel(); codestream.Emit(ILOpcode.br, done); // // Not a fat pointer case // codestream.EmitLabel(notAFatPointer); for (int i = 0; i < vParameters.Length; i++) { codestream.EmitLdLoc(vParameters[i]); } codestream.EmitLdLoc(vPointerToCall); codestream.Emit(ILOpcode.calli, emitter.NewToken(targetSignature)); codestream.EmitLabel(done); }
public MethodIL EmitIL() { MethodSignature targetMethodSignature = _targetMethod.Signature; // We have 4 code streams: // - _marshallingCodeStream is used to convert each argument into a native type and // store that into the local // - callsiteSetupCodeStream is used to used to load each previously generated local // and call the actual target native method. // - _returnValueMarshallingCodeStream is used to convert the native return value // to managed one. // - _unmarshallingCodestream is used to propagate [out] native arguments values to // managed ones. _emitter = new ILEmitter(); ILCodeStream fnptrLoadStream = _emitter.NewCodeStream(); _marshallingCodeStream = _emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream(); _returnValueMarshallingCodeStream = _emitter.NewCodeStream(); _unmarshallingCodestream = _emitter.NewCodeStream(); TypeDesc[] nativeParameterTypes = new TypeDesc[targetMethodSignature.Length]; // // Parameter marshalling // // // Convert each argument to something we can pass to native and store it in a local. // Then load the local in the second code stream. // for (int i = 0; i < targetMethodSignature.Length; i++) { // TODO: throw if there's custom marshalling _marshallingCodeStream.EmitLdArg(i); TypeDesc nativeType = MarshalArgument(targetMethodSignature[i]); nativeParameterTypes[i] = nativeType; ILLocalVariable vMarshalledTypeTemp = _emitter.NewLocal(nativeType); _marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp); callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp); } // // Return value marshalling // // TODO: throw if SetLastError is true // TODO: throw if there's custom marshalling TypeDesc nativeReturnType = MarshalReturnValue(targetMethodSignature.ReturnType); if (UseLazyResolution(_targetMethod, _importMetadata.Module)) { MetadataType lazyHelperType = _targetMethod.Context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = new PInvokeLazyFixupField((DefType)_targetMethod.OwningType, _importMetadata); fnptrLoadStream.Emit(ILOpcode.ldsflda, _emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, _emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = PInvokeMetadata.GetUnmanagedCallingConvention(_importMetadata.Attributes); MethodSignature nativeCalliSig = new MethodSignature( targetMethodSignature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = _emitter.NewLocal(_targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, _emitter.NewToken(nativeCalliSig)); } else { // Eager call PInvokeMetadata nativeImportMetadata = new PInvokeMetadata(_importMetadata.Module, _importMetadata.Name ?? _targetMethod.Name, _importMetadata.Attributes); MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, nativeImportMetadata); callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); } _unmarshallingCodestream.Emit(ILOpcode.ret); return(_emitter.Link(_targetMethod)); }
/// <summary> /// Marshals a string. Expects the string reference on the stack. Pushes a pointer /// to the stack that is safe to pass out to native code. /// </summary> /// <returns>The type the string was marshalled into.</returns> private TypeDesc EmitStringMarshalling() { PInvokeAttributes charset = _importMetadata.Attributes & PInvokeAttributes.CharSetMask; TypeSystemContext context = _targetMethod.Context; if (charset == 0) { // ECMA-335 II.10.1.5 - Default value is Ansi. charset = PInvokeAttributes.CharSetAnsi; } if (charset == PInvokeAttributes.CharSetAuto) { charset = PInvokeAttributes.CharSetUnicode; } TypeDesc stringType = context.GetWellKnownType(WellKnownType.String); if (charset == PInvokeAttributes.CharSetUnicode) { // // Unicode marshalling. Pin the string and push a pointer to the first character on the stack. // ILLocalVariable vPinnedString = _emitter.NewLocal(stringType, true); ILCodeLabel lNullString = _emitter.NewCodeLabel(); _marshallingCodeStream.EmitStLoc(vPinnedString); _marshallingCodeStream.EmitLdLoc(vPinnedString); _marshallingCodeStream.Emit(ILOpcode.conv_i); _marshallingCodeStream.Emit(ILOpcode.dup); // Marshalling a null string? _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString); // TODO: find a safe, non-awkward way to get to OffsetToStringData _marshallingCodeStream.EmitLdc(context.Target.PointerSize + 4); _marshallingCodeStream.Emit(ILOpcode.add); _marshallingCodeStream.EmitLabel(lNullString); } else { // // ANSI marshalling. Allocate a byte array, copy characters, pin first element. // TypeDesc byteType = context.GetWellKnownType(WellKnownType.Byte); TypeDesc byteArrayType = byteType.MakeArrayType(); MethodDesc getLengthMethod = stringType.GetKnownMethod("get_Length", null); MethodDesc getCharsMethod = stringType.GetKnownMethod("get_Chars", null); ILCodeLabel lStart = _emitter.NewCodeLabel(); ILCodeLabel lNext = _emitter.NewCodeLabel(); ILCodeLabel lNullString = _emitter.NewCodeLabel(); ILCodeLabel lDone = _emitter.NewCodeLabel(); // Check for the simple case: string is null ILLocalVariable vStringToMarshal = _emitter.NewLocal(stringType); _marshallingCodeStream.EmitStLoc(vStringToMarshal); _marshallingCodeStream.EmitLdLoc(vStringToMarshal); _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString); // TODO: figure out how to reference a helper from here and call the helper instead... // byte[] byteArray = new byte[stringToMarshal.Length + 1]; _marshallingCodeStream.EmitLdLoc(vStringToMarshal); _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken(getLengthMethod)); _marshallingCodeStream.EmitLdc(1); _marshallingCodeStream.Emit(ILOpcode.add); _marshallingCodeStream.Emit(ILOpcode.newarr, _emitter.NewToken(byteType)); ILLocalVariable vByteArray = _emitter.NewLocal(byteArrayType); _marshallingCodeStream.EmitStLoc(vByteArray); // for (int i = 0; i < byteArray.Length - 1; i++) // byteArray[i] = (byte)stringToMarshal[i]; ILLocalVariable vIterator = _emitter.NewLocal(context.GetWellKnownType(WellKnownType.Int32)); _marshallingCodeStream.Emit(ILOpcode.ldc_i4_0); _marshallingCodeStream.EmitStLoc(vIterator); _marshallingCodeStream.Emit(ILOpcode.br, lStart); _marshallingCodeStream.EmitLabel(lNext); _marshallingCodeStream.EmitLdLoc(vByteArray); _marshallingCodeStream.EmitLdLoc(vIterator); _marshallingCodeStream.EmitLdLoc(vStringToMarshal); _marshallingCodeStream.EmitLdLoc(vIterator); _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken(getCharsMethod)); _marshallingCodeStream.Emit(ILOpcode.conv_u1); _marshallingCodeStream.Emit(ILOpcode.stelem_i1); _marshallingCodeStream.EmitLdLoc(vIterator); _marshallingCodeStream.EmitLdc(1); _marshallingCodeStream.Emit(ILOpcode.add); _marshallingCodeStream.EmitStLoc(vIterator); _marshallingCodeStream.EmitLabel(lStart); _marshallingCodeStream.EmitLdLoc(vIterator); _marshallingCodeStream.EmitLdLoc(vByteArray); _marshallingCodeStream.Emit(ILOpcode.ldlen); _marshallingCodeStream.Emit(ILOpcode.conv_i4); _marshallingCodeStream.EmitLdc(1); _marshallingCodeStream.Emit(ILOpcode.sub); _marshallingCodeStream.Emit(ILOpcode.blt, lNext); _marshallingCodeStream.EmitLdLoc(vByteArray); // Pin first element and load the byref on the stack. _marshallingCodeStream.EmitLdc(0); _marshallingCodeStream.Emit(ILOpcode.ldelema, _emitter.NewToken(byteType)); ILLocalVariable vPinnedFirstElement = _emitter.NewLocal(byteArrayType.MakeByRefType(), true); _marshallingCodeStream.EmitStLoc(vPinnedFirstElement); _marshallingCodeStream.EmitLdLoc(vPinnedFirstElement); _marshallingCodeStream.Emit(ILOpcode.conv_i); _marshallingCodeStream.Emit(ILOpcode.br, lDone); _marshallingCodeStream.EmitLabel(lNullString); _marshallingCodeStream.Emit(ILOpcode.ldnull); _marshallingCodeStream.Emit(ILOpcode.conv_i); _marshallingCodeStream.EmitLabel(lDone); } return(_targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); }
private MethodIL EmitIL() { PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream fnptrLoadStream = pInvokeILCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = pInvokeILCodeStreams.CallsiteSetupCodeStream; ILCodeStream unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream; // Marshal the arguments for (int i = 0; i < _marshallers.Length; i++) { _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams); } // make the call TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } MethodDesc targetMethod = _methodData.TargetMethod; PInvokeMetadata importMetadata = _methodData.ImportMetadata; PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration = _methodData.PInvokeILEmitterConfiguration; MethodSignature nativeSig; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( _methodData.PInvokeMarshal.GetKnownMethod("ClearLastWin32Error", null))); } if (targetMethod is DelegateMarshallingMethodThunk) { nativeSig = new MethodSignature(MethodSignatureFlags.Static, 0, nativeReturnType, nativeParameterTypes); TypeDesc[] parameters = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { parameters[i - 1] = _marshallers[i].ManagedParameterType; } MethodSignature managedSignature = new MethodSignature(MethodSignatureFlags.Static, 0, _marshallers[0].ManagedParameterType, parameters); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(targetMethod.Context.GetHelperType("InteropHelpers").GetKnownMethod("GetDelegateFunctionPointer", null))); ILLocalVariable vDelegateStub = emitter.NewLocal(targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vDelegateStub); callsiteSetupCodeStream.EmitLdLoc(vDelegateStub); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(managedSignature)); } else if (MarshalHelpers.UseLazyResolution(targetMethod, importMetadata.Module, pinvokeILEmitterConfiguration)) { MetadataType lazyHelperType = targetMethod.Context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = new PInvokeLazyFixupField((DefType)targetMethod.OwningType, importMetadata); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = PInvokeMetadata.GetUnmanagedCallingConvention(importMetadata.Attributes); nativeSig = new MethodSignature( targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); } else { // Eager call PInvokeMetadata nativeImportMetadata = new PInvokeMetadata(importMetadata.Module, importMetadata.Name ?? targetMethod.Name, importMetadata.Attributes); nativeSig = new MethodSignature( targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(targetMethod.OwningType, nativeSig, nativeImportMetadata, pinvokeILEmitterConfiguration.GetNextNativeMethodId()); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastWin32Error so that last error can be used later // by calling PInvokeMarshal.GetLastWin32Error if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( _methodData.PInvokeMarshal.GetKnownMethod("SaveLastWin32Error", null))); } unmarshallingCodestream.Emit(ILOpcode.ret); return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(targetMethod), IsStubRequired(), nativeSig)); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream argSetupStream = emitter.NewCodeStream(); ILCodeStream thisCallSiteSetupStream = emitter.NewCodeStream(); ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream(); // This function will look like // // !For each parameter to the method // !if (parameter is In Parameter) // localX is TypeOfParameterX& // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperIn(RuntimeTypeHandle) // stloc localX // !else // localX is TypeOfParameter // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperRef(RuntimeTypeHandle) // stloc localX // ldarg.2 // call DynamicInvokeArgSetupComplete(ref ArgSetupState) // *** Thiscall instruction stream starts here *** // ldarg.3 // Load targetIsThisCall // brfalse Not_this_call // ldarg.0 // Load this pointer // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType thiscall(TypeOfParameter1, ...) // !if ((ReturnType == void) // ldnull // !elif (ReturnType is pointer) // System.Reflection.Pointer.Box(ReturnType) // !else // box ReturnType // ret // *** Static call instruction stream starts here *** // Not_this_call: // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType (TypeOfParameter1, ...) // !if ((ReturnType == void) // ldnull // !elif (ReturnType is pointer) // System.Reflection.Pointer.Box(ReturnType) // !else // box ReturnType // ret ILCodeLabel lStaticCall = emitter.NewCodeLabel(); thisCallSiteSetupStream.EmitLdArg(3); // targetIsThisCall thisCallSiteSetupStream.Emit(ILOpcode.brfalse, lStaticCall); staticCallSiteSetupStream.EmitLabel(lStaticCall); thisCallSiteSetupStream.EmitLdArg(0); // thisPtr ILToken tokDynamicInvokeParamHelperRef = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null)); ILToken tokDynamicInvokeParamHelperIn = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null)); TypeDesc[] targetMethodSignature = new TypeDesc[_targetSignature.Length]; for (int paramIndex = 0; paramIndex < _targetSignature.Length; paramIndex++) { TypeDesc paramType = Context.GetSignatureVariable(paramIndex, true); DynamicInvokeMethodParameterKind paramKind = _targetSignature[paramIndex]; if (paramKind == DynamicInvokeMethodParameterKind.Pointer) { for (int i = 0; i < _targetSignature.GetNumberOfParameterPointerIndirections(paramIndex); i++) { paramType = paramType.MakePointerType(); } } ILToken tokParamType = emitter.NewToken(paramType); ILLocalVariable local = emitter.NewLocal(paramType.MakeByRefType()); thisCallSiteSetupStream.EmitLdLoc(local); staticCallSiteSetupStream.EmitLdLoc(local); argSetupStream.Emit(ILOpcode.ldtoken, tokParamType); if (paramKind == DynamicInvokeMethodParameterKind.Reference) { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperRef); targetMethodSignature[paramIndex] = paramType.MakeByRefType(); } else { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperIn); thisCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType); staticCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType); targetMethodSignature[paramIndex] = paramType; } argSetupStream.EmitStLoc(local); } argSetupStream.EmitLdArg(2); // argSetupState argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null))); thisCallSiteSetupStream.EmitLdArg(1); // methodToCall staticCallSiteSetupStream.EmitLdArg(1); // methodToCall DynamicInvokeMethodParameterKind returnKind = _targetSignature.ReturnType; TypeDesc returnType = returnKind != DynamicInvokeMethodParameterKind.None ? Context.GetSignatureVariable(_targetSignature.Length, true) : Context.GetWellKnownType(WellKnownType.Void); if (returnKind == DynamicInvokeMethodParameterKind.Pointer) { for (int i = 0; i < _targetSignature.GetNumerOfReturnTypePointerIndirections(); i++) { returnType = returnType.MakePointerType(); } } MethodSignature thisCallMethodSig = new MethodSignature(0, 0, returnType, targetMethodSignature); thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig)); MethodSignature staticCallMethodSig = new MethodSignature(MethodSignatureFlags.Static, 0, returnType, targetMethodSignature); staticCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(staticCallMethodSig)); if (returnKind == DynamicInvokeMethodParameterKind.None) { thisCallSiteSetupStream.Emit(ILOpcode.ldnull); staticCallSiteSetupStream.Emit(ILOpcode.ldnull); } else if (returnKind == DynamicInvokeMethodParameterKind.Pointer) { thisCallSiteSetupStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnType)); staticCallSiteSetupStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnType)); MethodDesc getTypeFromHandleMethod = Context.SystemModule.GetKnownType("System", "Type").GetKnownMethod("GetTypeFromHandle", null); thisCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod)); staticCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod)); MethodDesc pointerBoxMethod = Context.SystemModule.GetKnownType("System.Reflection", "Pointer").GetKnownMethod("Box", null); thisCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod)); staticCallSiteSetupStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod)); } else { Debug.Assert(returnKind == DynamicInvokeMethodParameterKind.Value); ILToken tokReturnType = emitter.NewToken(returnType); thisCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType); staticCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType); } thisCallSiteSetupStream.Emit(ILOpcode.ret); staticCallSiteSetupStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
/// <summary> /// Generates a calli sequence that is aware of fat function pointers and can unwrap them into /// a function pointer + instantiation argument if necessary. /// </summary> public static void EmitTransformedCalli(ILEmitter emitter, ILCodeStream codestream, MethodSignature targetSignature) { TypeSystemContext context = targetSignature.ReturnType.Context; int thisPointerParamDelta = 0; if (!targetSignature.IsStatic) { thisPointerParamDelta = 1; } // Start by saving the pointer to call and all the args into locals ILLocalVariable vPointerToCall = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr)); codestream.EmitStLoc(vPointerToCall); ILLocalVariable[] vParameters = new ILLocalVariable[targetSignature.Length + thisPointerParamDelta]; for (int i = thisPointerParamDelta; i < vParameters.Length; i++) { vParameters[vParameters.Length - i - 1 + thisPointerParamDelta] = emitter.NewLocal(targetSignature[targetSignature.Length - (i - thisPointerParamDelta) - 1]); codestream.EmitStLoc(vParameters[vParameters.Length - i - 1 + thisPointerParamDelta]); } if (!targetSignature.IsStatic) { vParameters[0] = emitter.NewLocal(context.GetWellKnownType(WellKnownType.Object)); codestream.EmitStLoc(vParameters[0]); } // Is this a fat pointer? codestream.EmitLdLoc(vPointerToCall); Debug.Assert(((FatFunctionPointerConstants.Offset - 1) & FatFunctionPointerConstants.Offset) == 0); codestream.EmitLdc(FatFunctionPointerConstants.Offset); codestream.Emit(ILOpcode.and); ILCodeLabel notAFatPointer = emitter.NewCodeLabel(); codestream.Emit(ILOpcode.brfalse, notAFatPointer); // // Fat pointer case // codestream.EmitLdLoc(vPointerToCall); codestream.EmitLdc(FatFunctionPointerConstants.Offset); codestream.Emit(ILOpcode.sub); // Get the pointer to call from the fat pointer codestream.Emit(ILOpcode.dup); codestream.Emit(ILOpcode.ldind_i); codestream.EmitStLoc(vPointerToCall); // Get the instantiation argument codestream.EmitLdc(context.Target.PointerSize); codestream.Emit(ILOpcode.add); codestream.Emit(ILOpcode.ldind_i); codestream.Emit(ILOpcode.ldind_i); ILLocalVariable instArg = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr)); codestream.EmitStLoc(instArg); // Load this int firstRealParameter = 0; if (!targetSignature.IsStatic) { codestream.EmitLdLoc(vParameters[0]); firstRealParameter = 1; } // Load hidden arg codestream.EmitLdLoc(instArg); // Load rest of args for (int i = firstRealParameter; i < vParameters.Length; i++) { codestream.EmitLdLoc(vParameters[i]); } codestream.EmitLdLoc(vPointerToCall); // The signature has a hidden argument TypeDesc[] newParameters = new TypeDesc[targetSignature.Length + 1]; for (int i = 0; i < targetSignature.Length; i++) { newParameters[i + 1] = targetSignature[i]; } newParameters[0] = context.GetWellKnownType(WellKnownType.IntPtr); MethodSignature newMethodSignature = new MethodSignature(targetSignature.Flags, targetSignature.GenericParameterCount, targetSignature.ReturnType, newParameters); codestream.Emit(ILOpcode.calli, emitter.NewToken(newMethodSignature)); ILCodeLabel done = emitter.NewCodeLabel(); codestream.Emit(ILOpcode.br, done); // // Not a fat pointer case // codestream.EmitLabel(notAFatPointer); for (int i = 0; i < vParameters.Length; i++) { codestream.EmitLdLoc(vParameters[i]); } codestream.EmitLdLoc(vPointerToCall); codestream.Emit(ILOpcode.calli, emitter.NewToken(targetSignature)); codestream.EmitLabel(done); // Workaround for https://github.com/dotnet/corert/issues/2073 codestream.Emit(ILOpcode.nop); }
private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream fnptrLoadStream = ilCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null))); } for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module, _pInvokeILEmitterConfiguration)) { MetadataType lazyHelperType = context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = _interopStateManager.GetPInvokeLazyFixupField(_targetMethod); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType .GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = _flags.UnmanagedCallingConvention; MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(context .GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vNativeFunctionPointer); callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); } else { // Eager call MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig); callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod)); } // if the SetLastError flag is set in DllImport, call the PInvokeMarshal. // SaveLastWin32Error so that last error can be used later by calling // PInvokeMarshal.GetLastWin32Error if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context) .GetKnownMethod("SaveLastWin32Error", null))); } }
private void EmitILForAccessor() { Debug.Assert(_method.OwningType.IsMdArray); var codeStream = _emitter.NewCodeStream(); var context = _method.Context; var int32Type = context.GetWellKnownType(WellKnownType.Int32); var totalLocalNum = _emitter.NewLocal(int32Type); var lengthLocalNum = _emitter.NewLocal(int32Type); int pointerSize = context.Target.PointerSize; int argStartOffset = _method.Kind == ArrayMethodKind.AddressWithHiddenArg ? 2 : 1; var rangeExceptionLabel = _emitter.NewCodeLabel(); ILCodeLabel typeMismatchExceptionLabel = null; if (!_elementType.IsValueType) { // Type check if (_method.Kind == ArrayMethodKind.Set) { MethodDesc checkArrayStore = context.SystemModule.GetKnownType("System.Runtime", "RuntimeImports").GetKnownMethod("RhCheckArrayStore", null); codeStream.EmitLdArg(0); codeStream.EmitLdArg(_rank + argStartOffset); codeStream.Emit(ILOpcode.call, _emitter.NewToken(checkArrayStore)); } else if (_method.Kind == ArrayMethodKind.AddressWithHiddenArg) { TypeDesc objectType = context.GetWellKnownType(WellKnownType.Object); TypeDesc eetypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr"); typeMismatchExceptionLabel = _emitter.NewCodeLabel(); ILLocalVariable thisEEType = _emitter.NewLocal(eetypePtrType); // EETypePtr actualElementType = this.EETypePtr.ArrayElementType; codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EETypePtr", null))); codeStream.EmitStLoc(thisEEType); codeStream.EmitLdLoca(thisEEType); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("get_ArrayElementType", null))); // EETypePtr expectedElementType = hiddenArg.ArrayElementType; codeStream.EmitLdArga(1); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("get_ArrayElementType", null))); // if (expectedElementType != actualElementType) // ThrowHelpers.ThrowArrayTypeMismatchException(); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("op_Equality", null))); codeStream.Emit(ILOpcode.brfalse, typeMismatchExceptionLabel); } } for (int i = 0; i < _rank; i++) { // The first two fields are EEType pointer and total length. Lengths for each dimension follows. int lengthOffset = (2 * pointerSize + i * sizeof(int)); EmitLoadInteriorAddress(codeStream, lengthOffset); codeStream.Emit(ILOpcode.ldind_i4); codeStream.EmitStLoc(lengthLocalNum); codeStream.EmitLdArg(i + argStartOffset); // Compare with length codeStream.Emit(ILOpcode.dup); codeStream.EmitLdLoc(lengthLocalNum); codeStream.Emit(ILOpcode.bge_un, rangeExceptionLabel); // Add to the running total if we have one already if (i > 0) { codeStream.EmitLdLoc(totalLocalNum); codeStream.EmitLdLoc(lengthLocalNum); codeStream.Emit(ILOpcode.mul); codeStream.Emit(ILOpcode.add); } codeStream.EmitStLoc(totalLocalNum); } // Compute element offset // TODO: This leaves unused space for lower bounds to match CoreCLR... int firstElementOffset = (2 * pointerSize + 2 * _rank * sizeof(int)); EmitLoadInteriorAddress(codeStream, firstElementOffset); codeStream.EmitLdLoc(totalLocalNum); int elementSize = _elementType.GetElementSize().AsInt; if (elementSize != 1) { codeStream.EmitLdc(elementSize); codeStream.Emit(ILOpcode.mul); } codeStream.Emit(ILOpcode.add); switch (_method.Kind) { case ArrayMethodKind.Get: codeStream.Emit(ILOpcode.ldobj, _emitter.NewToken(_elementType)); break; case ArrayMethodKind.Set: codeStream.EmitLdArg(_rank + argStartOffset); codeStream.Emit(ILOpcode.stobj, _emitter.NewToken(_elementType)); break; case ArrayMethodKind.AddressWithHiddenArg: break; } codeStream.Emit(ILOpcode.ret); codeStream.EmitLdc(0); codeStream.EmitLabel(rangeExceptionLabel); // Assumes that there is one "int" pushed on the stack codeStream.Emit(ILOpcode.pop); MethodDesc throwHelper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowIndexOutOfRangeException"); codeStream.EmitCallThrowHelper(_emitter, throwHelper); if (typeMismatchExceptionLabel != null) { codeStream.EmitLabel(typeMismatchExceptionLabel); codeStream.EmitCallThrowHelper(_emitter, context.GetHelperEntryPoint("ThrowHelpers", "ThrowArrayTypeMismatchException")); } }
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); TypeDesc boxableParamType = DelegateDynamicInvokeThunk.ConvertToBoxableType(paramType); ILToken boxableParamToken = emitter.NewToken(boxableParamType); if (paramIsByRef) { codeStream.Emit(ILOpcode.ldobj, boxableParamToken); } codeStream.Emit(ILOpcode.box, boxableParamToken); codeStream.Emit(ILOpcode.stelem_ref); } } else { MethodDesc emptyObjectArrayMethod = Context.GetHelperEntryPoint("DelegateHelpers", "GetEmptyObjectArray"); codeStream.Emit(ILOpcode.call, emitter.NewToken(emptyObjectArrayMethod)); codeStream.EmitStLoc(argsLocal); } if (hasRefArgs) { // we emit a try/finally to update the args array even if an exception is thrown // ilgen.BeginTryBody(); } 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) { // ILGeneratorLabel returnLabel = new ILGeneratorLabel(); // ilgen.Emit(OperationCode.Leave, returnLabel); // copy back ref/out args //ilgen.BeginFinallyBlock(); for (int i = 0; i < Signature.Length; i++) { TypeDesc paramType = Signature[i]; if (paramType.IsByRef) { paramType = ((ByRefType)paramType).ParameterType; TypeDesc boxableParamType = DelegateDynamicInvokeThunk.ConvertToBoxableType(paramType); ILToken boxableParamToken = emitter.NewToken(boxableParamType); // Update parameter codeStream.EmitLdArg(i + 1); codeStream.EmitLdLoc(argsLocal); codeStream.EmitLdc(i); codeStream.Emit(ILOpcode.ldelem_ref); codeStream.Emit(ILOpcode.unbox_any, boxableParamToken); codeStream.Emit(ILOpcode.stobj, boxableParamToken); } } // ilgen.Emit(OperationCode.Endfinally); // ilgen.EndTryBody(); // ilgen.MarkLabel(returnLabel); } if (hasReturnValue) { TypeDesc boxableReturnType = DelegateDynamicInvokeThunk.ConvertToBoxableType(Signature.ReturnType); codeStream.EmitLdLoc(retLocal); codeStream.Emit(ILOpcode.unbox_any, emitter.NewToken(boxableReturnType)); } codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
private void EmitDelegateCall(DelegateMarshallingMethodThunk delegateMethod, PInvokeILCodeStreams ilCodeStreams) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream fnptrLoadStream = ilCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; Debug.Assert(delegateMethod != null); if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind.ReverseOpenStatic) { // // For Open static delegates call // InteropHelpers.GetCurrentCalleeOpenStaticDelegateFunctionPointer() // which returns a function pointer. Just call the function pointer and we are done. // TypeDesc[] parameters = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { parameters[i - 1] = _marshallers[i].ManagedParameterType; } MethodSignature managedSignature = new MethodSignature( MethodSignatureFlags.Static, 0, _marshallers[0].ManagedParameterType, parameters); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken( delegateMethod.Context.GetHelperType("InteropHelpers").GetKnownMethod( "GetCurrentCalleeOpenStaticDelegateFunctionPointer", null))); ILLocalVariable vDelegateStub = emitter.NewLocal( delegateMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(vDelegateStub); callsiteSetupCodeStream.EmitLdLoc(vDelegateStub); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(managedSignature)); } else if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind.ReverseClosed) { // // For closed delegates call // InteropHelpers.GetCurrentCalleeDelegate<Delegate> // which returns the delegate. Do a CallVirt on the invoke method. // MethodDesc instantiatedHelper = delegateMethod.Context.GetInstantiatedMethod( delegateMethod.Context.GetHelperType("InteropHelpers") .GetKnownMethod("GetCurrentCalleeDelegate", null), new Instantiation((delegateMethod.DelegateType))); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(instantiatedHelper)); ILLocalVariable vDelegateStub = emitter.NewLocal(delegateMethod.DelegateType); fnptrLoadStream.EmitStLoc(vDelegateStub); fnptrLoadStream.EmitLdLoc(vDelegateStub); MethodDesc invokeMethod = delegateMethod.DelegateType.GetKnownMethod("Invoke", null); callsiteSetupCodeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod)); } else if (delegateMethod.Kind == DelegateMarshallingMethodThunkKind .ForwardNativeFunctionWrapper) { // if the SetLastError flag is set in UnmanagedFunctionPointerAttribute, clear the error code before doing P/Invoke if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null))); } // // For NativeFunctionWrapper we need to load the native function and call it // fnptrLoadStream.EmitLdArg(0); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(InteropTypes .GetNativeFunctionPointerWrapper(context) .GetMethod("get_NativeFunctionPointer", null))); var fnPtr = emitter.NewLocal( context.GetWellKnownType(WellKnownType.IntPtr)); fnptrLoadStream.EmitStLoc(fnPtr); callsiteSetupCodeStream.EmitLdLoc(fnPtr); TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } MethodSignature nativeSig = new MethodSignature( MethodSignatureFlags.Static | _flags.UnmanagedCallingConvention, 0, nativeReturnType, nativeParameterTypes); callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig)); // if the SetLastError flag is set in UnmanagedFunctionPointerAttribute, call the PInvokeMarshal. // SaveLastWin32Error so that last error can be used later by calling // PInvokeMarshal.GetLastWin32Error if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context) .GetKnownMethod("SaveLastWin32Error", null))); } } else { Debug.Fail("Unexpected DelegateMarshallingMethodThunkKind"); } }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream argSetupStream = emitter.NewCodeStream(); ILCodeStream thisCallSiteSetupStream = emitter.NewCodeStream(); ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream(); ILCodeStream returnCodeStream = emitter.NewCodeStream(); // This function will look like // // !For each parameter to the method // !if (parameter is In Parameter) // localX is TypeOfParameterX& // ldarg.2 // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperIn(ref ArgSetupState, RuntimeTypeHandle) // stloc localX // !else // localX is TypeOfParameter // ldarg.2 // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperRef(ref ArgSetupState, RuntimeTypeHandle) // stloc localX // ldarg.2 // call DynamicInvokeArgSetupComplete(ref ArgSetupState) // *** Thiscall instruction stream starts here *** // ldarg.3 // Load targetIsThisCall // brfalse Not_this_call // ldarg.0 // Load this pointer // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType thiscall(TypeOfParameter1, ...) // br Process_return // *** Static call instruction stream starts here *** // Not_this_call: // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType (TypeOfParameter1, ...) // *** Return code stream starts here *** // Process_return: // !if (ReturnType is Byref) // dup // brfalse ByRefNull // ldobj ReturnType // !if ((ReturnType == void) // ldnull // !elif (ReturnType is pointer) // System.Reflection.Pointer.Box(ReturnType) // !else // box ReturnType // ret // // !if (ReturnType is ByRef) // ByRefNull: // throw NullReferenceException ILCodeLabel lStaticCall = emitter.NewCodeLabel(); ILCodeLabel lProcessReturn = emitter.NewCodeLabel(); thisCallSiteSetupStream.EmitLdArg(3); // targetIsThisCall thisCallSiteSetupStream.Emit(ILOpcode.brfalse, lStaticCall); staticCallSiteSetupStream.EmitLabel(lStaticCall); thisCallSiteSetupStream.EmitLdArg(0); // thisPtr ILToken tokDynamicInvokeParamHelperRef = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null)); ILToken tokDynamicInvokeParamHelperIn = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null)); TypeDesc[] targetMethodSignature = new TypeDesc[_targetSignature.Length]; for (int paramIndex = 0; paramIndex < _targetSignature.Length; paramIndex++) { TypeDesc paramType = Context.GetSignatureVariable(paramIndex, true); DynamicInvokeMethodParameterKind paramKind = _targetSignature[paramIndex]; for (int i = 0; i < _targetSignature.GetNumberOfParameterPointerIndirections(paramIndex); i++) { paramType = paramType.MakePointerType(); } ILToken tokParamType = emitter.NewToken(paramType); ILLocalVariable local = emitter.NewLocal(paramType.MakeByRefType()); thisCallSiteSetupStream.EmitLdLoc(local); staticCallSiteSetupStream.EmitLdLoc(local); argSetupStream.EmitLdArg(2); // argSetupState argSetupStream.Emit(ILOpcode.ldtoken, tokParamType); if (paramKind == DynamicInvokeMethodParameterKind.Reference) { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperRef); targetMethodSignature[paramIndex] = paramType.MakeByRefType(); } else { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperIn); thisCallSiteSetupStream.EmitLdInd(paramType); staticCallSiteSetupStream.EmitLdInd(paramType); targetMethodSignature[paramIndex] = paramType; } argSetupStream.EmitStLoc(local); } argSetupStream.EmitLdArg(2); // argSetupState argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null))); thisCallSiteSetupStream.EmitLdArg(1); // methodToCall staticCallSiteSetupStream.EmitLdArg(1); // methodToCall DynamicInvokeMethodParameterKind returnKind = _targetSignature.ReturnType; TypeDesc returnType = returnKind != DynamicInvokeMethodParameterKind.None ? Context.GetSignatureVariable(_targetSignature.Length, true) : Context.GetWellKnownType(WellKnownType.Void); for (int i = 0; i < _targetSignature.GetNumerOfReturnTypePointerIndirections(); i++) { returnType = returnType.MakePointerType(); } if (returnKind == DynamicInvokeMethodParameterKind.Reference) { returnType = returnType.MakeByRefType(); } MethodSignature thisCallMethodSig = new MethodSignature(0, 0, returnType, targetMethodSignature); thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig)); thisCallSiteSetupStream.Emit(ILOpcode.br, lProcessReturn); MethodSignature staticCallMethodSig = new MethodSignature(MethodSignatureFlags.Static, 0, returnType, targetMethodSignature); staticCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(staticCallMethodSig)); returnCodeStream.EmitLabel(lProcessReturn); ILCodeLabel lByRefReturnNull = null; if (returnKind == DynamicInvokeMethodParameterKind.None) { returnCodeStream.Emit(ILOpcode.ldnull); } else { TypeDesc returnTypeForBoxing = returnType; if (returnType.IsByRef) { // If this is a byref return, we need to dereference first returnTypeForBoxing = ((ByRefType)returnType).ParameterType; lByRefReturnNull = emitter.NewCodeLabel(); returnCodeStream.Emit(ILOpcode.dup); returnCodeStream.Emit(ILOpcode.brfalse, lByRefReturnNull); returnCodeStream.EmitLdInd(returnTypeForBoxing); } if (returnTypeForBoxing.IsPointer) { // Pointers box differently returnCodeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnTypeForBoxing)); MethodDesc getTypeFromHandleMethod = Context.SystemModule.GetKnownType("System", "Type").GetKnownMethod("GetTypeFromHandle", null); returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod)); MethodDesc pointerBoxMethod = Context.SystemModule.GetKnownType("System.Reflection", "Pointer").GetKnownMethod("Box", null); returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod)); } else { ILToken tokReturnType = emitter.NewToken(returnTypeForBoxing); returnCodeStream.Emit(ILOpcode.box, tokReturnType); } } returnCodeStream.Emit(ILOpcode.ret); if (lByRefReturnNull != null) { returnCodeStream.EmitLabel(lByRefReturnNull); MethodDesc nullReferencedExceptionHelper = Context.GetHelperEntryPoint("ThrowHelpers", "ThrowInvokeNullRefReturned"); returnCodeStream.EmitCallThrowHelper(emitter, nullReferencedExceptionHelper); } 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)); }
private void EmitILForAccessor() { Debug.Assert(_method.OwningType.IsMdArray); var codeStream = _emitter.NewCodeStream(); var context = _method.Context; var int32Type = context.GetWellKnownType(WellKnownType.Int32); var totalLocalNum = _emitter.NewLocal(int32Type); var lengthLocalNum = _emitter.NewLocal(int32Type); int pointerSize = context.Target.PointerSize; int argStartOffset = _method.Kind == ArrayMethodKind.AddressWithHiddenArg ? 2 : 1; var rangeExceptionLabel = _emitter.NewCodeLabel(); ILCodeLabel typeMismatchExceptionLabel = null; if (_elementType.IsGCPointer) { // Type check if (_method.Kind == ArrayMethodKind.Set) { MethodDesc checkArrayStore = context.SystemModule.GetKnownType("System.Runtime", "RuntimeImports").GetKnownMethod("RhCheckArrayStore", null); codeStream.EmitLdArg(0); codeStream.EmitLdArg(_rank + argStartOffset); codeStream.Emit(ILOpcode.call, _emitter.NewToken(checkArrayStore)); } else if (_method.Kind == ArrayMethodKind.AddressWithHiddenArg) { TypeDesc objectType = context.GetWellKnownType(WellKnownType.Object); TypeDesc eetypeType = context.SystemModule.GetKnownType("Internal.Runtime", "EEType"); typeMismatchExceptionLabel = _emitter.NewCodeLabel(); ILCodeLabel typeCheckPassedLabel = _emitter.NewCodeLabel(); // Codegen will pass a null hidden argument if this is a `constrained.` call to the Address method. // As per ECMA-335 III.2.3, the prefix suppresses the type check. // if (hiddenArg == IntPtr.Zero) // goto TypeCheckPassed; codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.brfalse, typeCheckPassedLabel); // EEType* actualElementType = this.EEType.RelatedParameterType; // ArrayElementType codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EEType", null))); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypeType.GetKnownMethod("get_RelatedParameterType", null))); // EEType* expectedElementType = hiddenArg->RelatedParameterType; // ArrayElementType codeStream.EmitLdArg(1); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypeType.GetKnownMethod("get_RelatedParameterType", null))); // if (TypeCast.AreTypesEquivalent(expectedElementType, actualElementType)) // ThrowHelpers.ThrowArrayTypeMismatchException(); codeStream.Emit(ILOpcode.call, _emitter.NewToken( context.SystemModule.GetKnownType("System.Runtime", "TypeCast").GetKnownMethod("AreTypesEquivalent", null))); codeStream.Emit(ILOpcode.brfalse, typeMismatchExceptionLabel); codeStream.EmitLabel(typeCheckPassedLabel); } } // Methods on Rank 1 MdArray need to be able to handle `this` that is an SzArray // because SzArray is castable to Rank 1 MdArray (but not the other way around). ILCodeLabel rangeCheckDoneLabel = null; if (_rank == 1) { TypeDesc objectType = context.GetWellKnownType(WellKnownType.Object); TypeDesc eetypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr"); ILLocalVariable thisEEType = _emitter.NewLocal(eetypePtrType); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EETypePtr", null))); codeStream.EmitStLoc(thisEEType); codeStream.EmitLdLoca(thisEEType); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("get_IsSzArray", null))); ILCodeLabel notSzArrayLabel = _emitter.NewCodeLabel(); codeStream.Emit(ILOpcode.brfalse, notSzArrayLabel); // We have an SzArray - do the bounds check differently EmitLoadInteriorAddress(codeStream, pointerSize); codeStream.Emit(ILOpcode.dup); codeStream.Emit(ILOpcode.ldind_i4); codeStream.EmitLdArg(argStartOffset); codeStream.EmitStLoc(totalLocalNum); codeStream.EmitLdLoc(totalLocalNum); codeStream.Emit(ILOpcode.ble_un, rangeExceptionLabel); codeStream.EmitLdc(pointerSize); codeStream.Emit(ILOpcode.add); rangeCheckDoneLabel = _emitter.NewCodeLabel(); codeStream.Emit(ILOpcode.br, rangeCheckDoneLabel); codeStream.EmitLabel(notSzArrayLabel); } for (int i = 0; i < _rank; i++) { // The first two fields are EEType pointer and total length. Lengths for each dimension follows. int lengthOffset = (2 * pointerSize + i * sizeof(int)); EmitLoadInteriorAddress(codeStream, lengthOffset); codeStream.Emit(ILOpcode.ldind_i4); codeStream.EmitStLoc(lengthLocalNum); codeStream.EmitLdArg(i + argStartOffset); // Compare with length codeStream.Emit(ILOpcode.dup); codeStream.EmitLdLoc(lengthLocalNum); codeStream.Emit(ILOpcode.bge_un, rangeExceptionLabel); // Add to the running total if we have one already if (i > 0) { codeStream.EmitLdLoc(totalLocalNum); codeStream.EmitLdLoc(lengthLocalNum); codeStream.Emit(ILOpcode.mul); codeStream.Emit(ILOpcode.add); } codeStream.EmitStLoc(totalLocalNum); } // Compute element offset // TODO: This leaves unused space for lower bounds to match CoreCLR... int firstElementOffset = (2 * pointerSize + 2 * _rank * sizeof(int)); EmitLoadInteriorAddress(codeStream, firstElementOffset); if (rangeCheckDoneLabel != null) { codeStream.EmitLabel(rangeCheckDoneLabel); } codeStream.EmitLdLoc(totalLocalNum); codeStream.Emit(ILOpcode.conv_u); int elementSize = _elementType.GetElementSize().AsInt; if (elementSize != 1) { codeStream.EmitLdc(elementSize); codeStream.Emit(ILOpcode.mul); } codeStream.Emit(ILOpcode.add); switch (_method.Kind) { case ArrayMethodKind.Get: codeStream.Emit(ILOpcode.ldobj, _emitter.NewToken(_elementType)); break; case ArrayMethodKind.Set: codeStream.EmitLdArg(_rank + argStartOffset); codeStream.Emit(ILOpcode.stobj, _emitter.NewToken(_elementType)); break; case ArrayMethodKind.AddressWithHiddenArg: break; } codeStream.Emit(ILOpcode.ret); codeStream.EmitLdc(0); codeStream.EmitLabel(rangeExceptionLabel); // Assumes that there is one "int" pushed on the stack codeStream.Emit(ILOpcode.pop); MethodDesc throwHelper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowIndexOutOfRangeException"); codeStream.EmitCallThrowHelper(_emitter, throwHelper); if (typeMismatchExceptionLabel != null) { codeStream.EmitLabel(typeMismatchExceptionLabel); codeStream.EmitCallThrowHelper(_emitter, context.GetHelperEntryPoint("ThrowHelpers", "ThrowArrayTypeMismatchException")); } }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream argSetupStream = emitter.NewCodeStream(); ILCodeStream callSiteSetupStream = emitter.NewCodeStream(); // This function will look like // // !For each parameter to the delegate // !if (parameter is In Parameter) // localX is TypeOfParameterX& // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperIn(RuntimeTypeHandle) // stloc localX // !else // localX is TypeOfParameter // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperRef(RuntimeTypeHandle) // stloc localX // ldarg.3 // call DynamicInvokeArgSetupComplete(ref ArgSetupState) // *** Second instruction stream starts here *** // ldarg.1 // Load this pointer // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType thiscall(TypeOfParameter1, ...) // !if ((ReturnType == void) // ldnull // !else if (ReturnType is a byref) // ldobj StripByRef(ReturnType) // box StripByRef(ReturnType) // !else // box ReturnType // ret callSiteSetupStream.EmitLdArg(1); MethodSignature delegateSignature = _delegateInfo.Signature; TypeDesc[] targetMethodParameters = new TypeDesc[delegateSignature.Length]; for (int paramIndex = 0; paramIndex < delegateSignature.Length; paramIndex++) { TypeDesc paramType = delegateSignature[paramIndex]; TypeDesc localType = paramType; targetMethodParameters[paramIndex] = paramType; if (localType.IsByRef) { // Strip ByRef localType = ((ByRefType)localType).ParameterType; } else { // Only if this is not a ByRef, convert the parameter type to something boxable. // Everything but pointer types are boxable. localType = ConvertToBoxableType(localType); } ILLocalVariable local = emitter.NewLocal(localType.MakeByRefType()); callSiteSetupStream.EmitLdLoc(local); argSetupStream.Emit(ILOpcode.ldtoken, emitter.NewToken(localType)); if (paramType.IsByRef) { argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null))); } else { argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null))); callSiteSetupStream.Emit(ILOpcode.ldobj, emitter.NewToken(paramType)); } argSetupStream.EmitStLoc(local); } argSetupStream.EmitLdArg(3); argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null))); callSiteSetupStream.EmitLdArg(2); MethodSignature targetMethodSig = new MethodSignature(0, 0, delegateSignature.ReturnType, targetMethodParameters); callSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(targetMethodSig)); if (delegateSignature.ReturnType.IsVoid) { callSiteSetupStream.Emit(ILOpcode.ldnull); } else if (delegateSignature.ReturnType.IsByRef) { TypeDesc targetType = ((ByRefType)delegateSignature.ReturnType).ParameterType; callSiteSetupStream.Emit(ILOpcode.ldobj, emitter.NewToken(targetType)); callSiteSetupStream.Emit(ILOpcode.box, emitter.NewToken(targetType)); } else { callSiteSetupStream.Emit(ILOpcode.box, emitter.NewToken(delegateSignature.ReturnType)); } callSiteSetupStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public MethodIL EmitIL() { MethodSignature targetMethodSignature = _targetMethod.Signature; // We have two code streams - one is used to convert each argument into a native type // and store that into the local. The other is used to load each previously generated local // and call the actual target native method. _emitter = new ILEmitter(); _marshallingCodeStream = _emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream(); _returnValueMarshallingCodeStream = _emitter.NewCodeStream(); TypeDesc[] nativeParameterTypes = new TypeDesc[targetMethodSignature.Length]; // // Parameter marshalling // // // Convert each argument to something we can pass to native and store it in a local. // Then load the local in the second code stream. // for (int i = 0; i < targetMethodSignature.Length; i++) { // TODO: throw if there's custom marshalling TypeDesc parameterType = targetMethodSignature[i]; _marshallingCodeStream.EmitLdArg(i); TypeDesc nativeType; if (parameterType.IsSzArray) { nativeType = EmitArrayMarshalling((ArrayType)parameterType); } else if (parameterType.IsByRef) { nativeType = EmitByRefMarshalling((ByRefType)parameterType); } else if (parameterType.IsString) { nativeType = EmitStringMarshalling(); } else if (parameterType.Category == TypeFlags.Boolean) { nativeType = EmitBooleanMarshalling(); } else { if (!IsBlittableType(parameterType)) { throw new NotSupportedException(); } nativeType = parameterType.UnderlyingType; } nativeParameterTypes[i] = nativeType; ILLocalVariable vMarshalledTypeTemp = _emitter.NewLocal(nativeType); _marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp); callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp); } // // Return value marshalling // // TODO: throw if SetLastError is true // TODO: throw if there's custom marshalling TypeDesc returnType = targetMethodSignature.ReturnType; TypeDesc nativeReturnType; if (returnType.IsVoid) { nativeReturnType = returnType; } else if (returnType.Category == TypeFlags.Boolean) { nativeReturnType = EmitBooleanReturnValueMarshalling(); } else { if (!IsBlittableType(returnType)) { throw new NotSupportedException(); } nativeReturnType = returnType; } MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, _importMetadata); // Call the native method callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); callsiteSetupCodeStream.Emit(ILOpcode.ret); return(_emitter.Link()); }