/** * Defines a new MethodBuilder that calls the specified C++ (non-virtual) method using its mangled name */ protected virtual MethodBuilder GetPInvokeForMethod(CppTypeInfo typeInfo, PInvokeSignature sig) { var entryPoint = sig.Name; if (entryPoint == null) { throw new NotSupportedException("Could not mangle method name."); } string lib; if (IsInline(sig.OrigMethod) && typeInfo.Library.InlineMethodPolicy == InlineMethods.SurrogateLib) { lib = typeInfo.Library.Name + "-inline"; } else { lib = typeInfo.Library.Name; } var builder = typeInfo.emit_info.type_builder.DefinePInvokeMethod(entryPoint, lib, entryPoint, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl, CallingConventions.Standard, sig.ReturnType, sig.ParameterTypes.ToArray(), sig.CallingConvention.Value, CharSet.Ansi); builder.SetImplementationFlags(builder.GetMethodImplementationFlags() | MethodImplAttributes.PreserveSig); ReflectionHelper.ApplyMethodParameterAttributes(sig.OrigMethod, builder, true); return(builder); }
protected override MethodBuilder DefineMethod (CppTypeInfo typeInfo, PInvokeSignature sig, ref int vtableIndex) { var builder = base.DefineMethod (typeInfo, sig, ref vtableIndex); // increment vtableIndex an extra time for that extra vdtor slot (already incremented once in base) if (IsVirtual (sig.OrigMethod) && sig.Type == MethodType.NativeDtor) vtableIndex++; return builder; }
protected override MethodBuilder DefineMethod(CppTypeInfo typeInfo, PInvokeSignature sig, ref int vtableIndex) { var builder = base.DefineMethod(typeInfo, sig, ref vtableIndex); // increment vtableIndex an extra time for that extra vdtor slot (already incremented once in base) if (IsVirtual(sig.OrigMethod) && sig.Type == MethodType.NativeDtor) { vtableIndex++; } return(builder); }
/* protected override void AddBase (CppTypeInfo baseType, BaseVirtualMethods location) { if (TypeComplete) return; // When adding a non-primary base class's complete vtable, we need to reserve space for // the stuff before the address point of the vtptr.. // Includes vbase & vcall offsets (virtual inheritance), offset to top, and RTTI info if (addVTable) { // FIXME: virtual inheritance virtual_methods.Add (null); virtual_methods.Add (null); vt_overrides.Add (2); vt_delegate_types.Add (2); } base.AddBase (baseType, addVTable); } */ protected override bool OnVTableDuplicate (ref int iter, ref int adj, PInvokeSignature sig, PInvokeSignature dup) { var isOverride = base.OnVTableDuplicate (ref iter, ref adj, sig, dup); if (isOverride && sig.Type == MethodType.NativeDtor) { // also remove that pesky extra dtor virtual_methods.RemoveAt (iter + 1); vt_overrides.Remove (1); vt_delegate_types.Remove (1); vtable_index_adjustments.Add (0); adj--; return true; } return false; }
protected virtual bool OnVTableDuplicate(ref int iter, ref int adj, PInvokeSignature sig, PInvokeSignature dup) { // This predicate ensures that duplicates are only removed // if declared in different classes (i.e. overridden methods). // We usually want to allow the same exact virtual methods to appear // multiple times, in the case of nonvirtual diamond inheritance, for example. if (!sig.OrigMethod.Equals(dup.OrigMethod)) { virtual_methods.RemoveAt(iter--); vt_overrides.Remove(1); vt_delegate_types.Remove(1); adj--; return(true); } return(false); }
/* * protected override void AddBase (CppTypeInfo baseType, BaseVirtualMethods location) * { * if (TypeComplete) * return; * * // When adding a non-primary base class's complete vtable, we need to reserve space for * // the stuff before the address point of the vtptr.. * // Includes vbase & vcall offsets (virtual inheritance), offset to top, and RTTI info * if (addVTable) { * * // FIXME: virtual inheritance * virtual_methods.Add (null); * virtual_methods.Add (null); * * vt_overrides.Add (2); * vt_delegate_types.Add (2); * } * * base.AddBase (baseType, addVTable); * } */ protected override bool OnVTableDuplicate(ref int iter, ref int adj, PInvokeSignature sig, PInvokeSignature dup) { var isOverride = base.OnVTableDuplicate(ref iter, ref adj, sig, dup); if (isOverride && sig.Type == MethodType.NativeDtor) { // also remove that pesky extra dtor virtual_methods.RemoveAt(iter + 1); vt_overrides.Remove(1); vt_delegate_types.Remove(1); vtable_index_adjustments.Add(0); adj--; return(true); } return(false); }
/** * Emits IL to call the native method. nativeMethod should be either a method obtained by * GetPInvokeForMethod or the MethodInfo of a vtable method. * To complete method, emit OpCodes.Ret. */ protected virtual void EmitNativeCall (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr) { var il = typeInfo.emit_info.current_il; var interfaceMethod = psig.OrigMethod; var interfaceArgs = interfaceMethod.GetParameters (); int argLoadStart = 1; // For static methods, just strip off arg0 (.net this pointer) if (!IsStatic (interfaceMethod)) { argLoadStart = 2; // For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr il.Emit (OpCodes.Ldloc_S, nativePtr); } // load and marshal arguments for (int i = argLoadStart; i <= interfaceArgs.Length; i++) { il.Emit (OpCodes.Ldarg, i); EmitOutboundMarshal (il, interfaceArgs [i - 1].ParameterType, psig.ParameterTypes [i - 1]); } il.Emit (OpCodes.Call, nativeMethod); // Marshal return value if (psig.Type != MethodType.NativeCtor) EmitInboundMarshal (il, psig.ReturnType, interfaceMethod.ReturnType); }
protected virtual void EmitDestruct(CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder cppInstancePtr, LocalBuilder nativePtr) { Debug.Assert(psig.Type == MethodType.NativeDtor); var il = typeInfo.emit_info.current_il; // we don't do anything if the object wasn't managed alloc if (cppInstancePtr == null) { return; } EmitCheckManagedAlloc(il, cppInstancePtr); EmitResetVTable(typeInfo, cppInstancePtr); EmitNativeCall(typeInfo, nativeMethod, psig, nativePtr); }
protected virtual void EmitConstruct (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder cppInstancePtr, LocalBuilder nativePtr) { Debug.Assert (psig.Type == MethodType.NativeCtor); var il = typeInfo.emit_info.current_il; EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr); if (cppInstancePtr != null && psig.OrigMethod.ReturnType == typeof (CppInstancePtr)) { EmitInitVTable (typeInfo, cppInstancePtr); il.Emit (OpCodes.Ldloc_S, cppInstancePtr); } else if (psig.OrigMethod.DeclaringType.GetInterfaces ().Any (i => i.IsGenericType && i.GetGenericTypeDefinition () == typeof (ICppClassOverridable<>))) { throw new InvalidProgramException ("In ICppClassOverridable, native constructors must take as first argument and return CppInstancePtr"); } }
protected virtual void EmitDestruct (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder cppInstancePtr, LocalBuilder nativePtr) { Debug.Assert (psig.Type == MethodType.NativeDtor); var il = typeInfo.emit_info.current_il; // we don't do anything if the object wasn't managed alloc if (cppInstancePtr == null) return; EmitCheckManagedAlloc (il, cppInstancePtr); EmitResetVTable (typeInfo, cppInstancePtr); EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr); }
protected virtual MethodBuilder DefineMethod (CppTypeInfo typeInfo, PInvokeSignature psig, ref int vtableIndex) { var interfaceMethod = psig.OrigMethod; // 1. Generate managed trampoline to call native method var trampoline = GetMethodBuilder (typeInfo, interfaceMethod); var il = typeInfo.emit_info.current_il = trampoline.GetILGenerator (); switch (psig.Type) { case MethodType.NotImplemented: il.Emit (OpCodes.Ldstr, "This method is not available."); il.Emit (OpCodes.Newobj, notimplementedexception); il.Emit (OpCodes.Throw); goto case MethodType.NoOp; // fallthrough case MethodType.NoOp: // return NULL if method is supposed to return a value if (!interfaceMethod.ReturnType.Equals (typeof (void))) il.Emit (OpCodes.Ldnull); il.Emit (OpCodes.Ret); return trampoline; case MethodType.ManagedAlloc: EmitManagedAlloc (typeInfo, interfaceMethod); il.Emit (OpCodes.Ret); return trampoline; } var isStatic = IsStatic (interfaceMethod); LocalBuilder cppInstancePtr = null; LocalBuilder nativePtr = null; // If we're an instance method, load up the "this" pointer if (!isStatic) { if (psig.ParameterTypes.Count == 0) throw new ArgumentException ("First argument to non-static C++ method must be instance pointer."); // 2. Load the native C++ instance pointer EmitLoadInstancePtr (il, interfaceMethod.GetParameters () [0].ParameterType, out cppInstancePtr, out nativePtr); // 3. Make sure our native pointer is a valid reference. If not, throw ObjectDisposedException EmitCheckDisposed (il, nativePtr, psig.Type); } MethodInfo nativeMethod; if (IsVirtual (interfaceMethod) && psig.Type != MethodType.NativeDtor) { nativeMethod = EmitPrepareVirtualCall (typeInfo, cppInstancePtr, vtableIndex++); } else { if (IsVirtual (interfaceMethod)) vtableIndex++; nativeMethod = GetPInvokeForMethod (typeInfo, psig); } switch (psig.Type) { case MethodType.NativeCtor: EmitConstruct (typeInfo, nativeMethod, psig, cppInstancePtr, nativePtr); break; case MethodType.NativeDtor: EmitDestruct (typeInfo, nativeMethod, psig, cppInstancePtr, nativePtr); break; default: EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr); break; } il.Emit (OpCodes.Ret); return trampoline; }
/** * Defines a new MethodBuilder that calls the specified C++ (non-virtual) method using its mangled name */ protected virtual MethodBuilder GetPInvokeForMethod (CppTypeInfo typeInfo, PInvokeSignature sig) { var entryPoint = sig.Name; if (entryPoint == null) throw new NotSupportedException ("Could not mangle method name."); string lib; if (IsInline (sig.OrigMethod) && typeInfo.Library.InlineMethodPolicy == InlineMethods.SurrogateLib) lib = typeInfo.Library.Name + "-inline"; else lib = typeInfo.Library.Name; var builder = typeInfo.emit_info.type_builder.DefinePInvokeMethod (entryPoint, lib, entryPoint, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl, CallingConventions.Standard, sig.ReturnType, sig.ParameterTypes.ToArray (), sig.CallingConvention.Value, CharSet.Ansi); builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig); ReflectionHelper.ApplyMethodParameterAttributes (sig.OrigMethod, builder, true); return builder; }
protected override void EmitNativeCall(CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr) { var il = typeInfo.emit_info.current_il; var method = psig.OrigMethod; var returnType = method.ReturnType; var hiddenReturnByValue = ReturnByHiddenArgument(typeInfo, method); LocalBuilder returnValue = null; if (hiddenReturnByValue) { returnValue = il.DeclareLocal(typeof(CppInstancePtr)); if (typeof(ICppObject).IsAssignableFrom(returnType)) { il.Emit(OpCodes.Ldc_I4, GetTypeInfo(returnType).NativeSize); } else if (returnType.IsValueType) { il.Emit(OpCodes.Ldc_I4, Marshal.SizeOf(returnType)); } il.Emit(OpCodes.Newobj, cppip_fromsize); il.Emit(OpCodes.Stloc, returnValue); il.Emit(OpCodes.Ldloca, returnValue); il.Emit(OpCodes.Call, cppip_native); } base.EmitNativeCall(typeInfo, nativeMethod, psig, nativePtr); if (hiddenReturnByValue) { EmitCreateCppObjectFromNative(il, returnType, returnValue); if (returnType.IsValueType) { // FIXME: This dispose should prolly be in a Finally block.. il.Emit(OpCodes.Ldloca, returnValue); il.Emit(OpCodes.Call, cppip_dispose); } } }
/** * Emits IL to call the native method. nativeMethod should be either a method obtained by * GetPInvokeForMethod or the MethodInfo of a vtable method. * To complete method, emit OpCodes.Ret. */ protected virtual void EmitNativeCall(CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr) { var il = typeInfo.emit_info.current_il; var interfaceMethod = psig.OrigMethod; var interfaceArgs = interfaceMethod.GetParameters (); var returnType = interfaceMethod.ReturnType; var hiddenReturnByValue = ReturnByHiddenArgument (typeInfo, interfaceMethod); LocalBuilder returnValue = null; if (hiddenReturnByValue) { returnValue = il.DeclareLocal (typeof (CppInstancePtr)); if (typeof (ICppObject).IsAssignableFrom (returnType)) il.Emit (OpCodes.Ldc_I4, GetTypeInfo (returnType).NativeSize); else if (returnType.IsValueType) il.Emit (OpCodes.Ldc_I4, Marshal.SizeOf (returnType)); il.Emit (OpCodes.Newobj, cppip_fromsize); il.Emit (OpCodes.Stloc, returnValue); il.Emit (OpCodes.Ldloca, returnValue); il.Emit (OpCodes.Call, cppip_native); } int argLoadStart = 1; // For static methods, just strip off arg0 (.net this pointer) if (!this.IsStatic (interfaceMethod)) { argLoadStart = 2; // For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr il.Emit (OpCodes.Ldloc_S, nativePtr); } // load and marshal arguments for (int i = argLoadStart; i <= interfaceArgs.Length; i++) { il.Emit (OpCodes.Ldarg, i); this.EmitOutboundMarshal (il, interfaceArgs[i - 1].ParameterType, psig.ParameterTypes[i - 1]); } il.Emit (OpCodes.Call, nativeMethod); // Marshal return value if (psig.Type != MethodType.NativeCtor) this.EmitInboundMarshal (il, psig.ReturnType, interfaceMethod.ReturnType); if (hiddenReturnByValue) { EmitCreateCppObjectFromNative (il, returnType, returnValue); if (returnType.IsValueType) { // FIXME: This dispose should prolly be in a Finally block.. il.Emit (OpCodes.Ldloca, returnValue); il.Emit (OpCodes.Call, cppip_dispose); } } }
protected override void EmitNativeCall (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr) { var il = typeInfo.emit_info.current_il; var method = psig.OrigMethod; var returnType = method.ReturnType; var hiddenReturnByValue = ReturnByHiddenArgument (typeInfo, method); LocalBuilder returnValue = null; if (hiddenReturnByValue) { returnValue = il.DeclareLocal (typeof (CppInstancePtr)); if (typeof (ICppObject).IsAssignableFrom (returnType)) il.Emit (OpCodes.Ldc_I4, GetTypeInfo (returnType).NativeSize); else if (returnType.IsValueType) il.Emit (OpCodes.Ldc_I4, Marshal.SizeOf (returnType)); il.Emit (OpCodes.Newobj, cppip_fromsize); il.Emit (OpCodes.Stloc, returnValue); il.Emit (OpCodes.Ldloca, returnValue); il.Emit (OpCodes.Call, cppip_native); } base.EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr); if (hiddenReturnByValue) { EmitCreateCppObjectFromNative (il, returnType, returnValue); if (returnType.IsValueType) { // FIXME: This dispose should prolly be in a Finally block.. il.Emit (OpCodes.Ldloca, returnValue); il.Emit (OpCodes.Call, cppip_dispose); } } }
protected virtual void EmitConstruct(CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder cppInstancePtr, LocalBuilder nativePtr) { Debug.Assert(psig.Type == MethodType.NativeCtor); var il = typeInfo.emit_info.current_il; EmitNativeCall(typeInfo, nativeMethod, psig, nativePtr); if (cppInstancePtr != null && psig.OrigMethod.ReturnType == typeof(CppInstancePtr)) { EmitInitVTable(typeInfo, cppInstancePtr); il.Emit(OpCodes.Ldloc_S, cppInstancePtr); } else if (psig.OrigMethod.DeclaringType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICppClassOverridable <>))) { throw new InvalidProgramException("In ICppClassOverridable, native constructors must take as first argument and return CppInstancePtr"); } }
protected virtual MethodBuilder DefineMethod(CppTypeInfo typeInfo, PInvokeSignature psig, ref int vtableIndex) { var interfaceMethod = psig.OrigMethod; // 1. Generate managed trampoline to call native method var trampoline = GetMethodBuilder(typeInfo, interfaceMethod); var il = typeInfo.emit_info.current_il = trampoline.GetILGenerator(); switch (psig.Type) { case MethodType.NotImplemented: il.Emit(OpCodes.Ldstr, "This method is not available."); il.Emit(OpCodes.Newobj, notimplementedexception); il.Emit(OpCodes.Throw); goto case MethodType.NoOp; // fallthrough case MethodType.NoOp: // return NULL if method is supposed to return a value if (!interfaceMethod.ReturnType.Equals(typeof(void))) { il.Emit(OpCodes.Ldnull); } il.Emit(OpCodes.Ret); return(trampoline); case MethodType.ManagedAlloc: EmitManagedAlloc(typeInfo, interfaceMethod); il.Emit(OpCodes.Ret); return(trampoline); } var isStatic = IsStatic(interfaceMethod); LocalBuilder cppInstancePtr = null; LocalBuilder nativePtr = null; // If we're an instance method, load up the "this" pointer if (!isStatic) { if (psig.ParameterTypes.Count == 0) { throw new ArgumentException("First argument to non-static C++ method must be instance pointer."); } // 2. Load the native C++ instance pointer EmitLoadInstancePtr(il, interfaceMethod.GetParameters() [0].ParameterType, out cppInstancePtr, out nativePtr); // 3. Make sure our native pointer is a valid reference. If not, throw ObjectDisposedException EmitCheckDisposed(il, nativePtr, psig.Type); } MethodInfo nativeMethod; if (IsVirtual(interfaceMethod) && psig.Type != MethodType.NativeDtor) { nativeMethod = EmitPrepareVirtualCall(typeInfo, cppInstancePtr, vtableIndex++); } else { if (IsVirtual(interfaceMethod)) { vtableIndex++; } nativeMethod = GetPInvokeForMethod(typeInfo, psig); } switch (psig.Type) { case MethodType.NativeCtor: EmitConstruct(typeInfo, nativeMethod, psig, cppInstancePtr, nativePtr); break; case MethodType.NativeDtor: EmitDestruct(typeInfo, nativeMethod, psig, cppInstancePtr, nativePtr); break; default: EmitNativeCall(typeInfo, nativeMethod, psig, nativePtr); break; } il.Emit(OpCodes.Ret); return(trampoline); }
/** * Emits IL to call the native method. nativeMethod should be either a method obtained by * GetPInvokeForMethod or the MethodInfo of a vtable method. * To complete method, emit OpCodes.Ret. */ protected virtual void EmitNativeCall(CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr) { var il = typeInfo.emit_info.current_il; var interfaceMethod = psig.OrigMethod; var interfaceArgs = interfaceMethod.GetParameters(); int argLoadStart = 1; // For static methods, just strip off arg0 (.net this pointer) if (!IsStatic(interfaceMethod)) { argLoadStart = 2; // For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr il.Emit(OpCodes.Ldloc_S, nativePtr); } // load and marshal arguments for (int i = argLoadStart; i <= interfaceArgs.Length; i++) { il.Emit(OpCodes.Ldarg, i); EmitOutboundMarshal(il, interfaceArgs [i - 1].ParameterType, psig.ParameterTypes [i - 1]); } il.Emit(OpCodes.Call, nativeMethod); // Marshal return value if (psig.Type != MethodType.NativeCtor) { EmitInboundMarshal(il, psig.ReturnType, interfaceMethod.ReturnType); } }
public virtual PInvokeSignature GetPInvokeSignature(CppTypeInfo typeInfo, MethodInfo method) { var methodType = GetMethodType (typeInfo, method); var parameters = method.GetParameters (); var pinvokeTypes = new List<Type> (parameters.Length); foreach (var pi in parameters) { pinvokeTypes.Add (ToPInvokeType (pi.ParameterType, pi)); } Type returnType = method.ReturnType; if (methodType == MethodType.NativeCtor) returnType = typeof(void); else if (method.ReturnTypeCustomAttributes.IsDefined(typeof(ByRefAttribute), false)) returnType = typeof(IntPtr); else returnType = ToPInvokeType (method.ReturnType, method.ReturnTypeCustomAttributes); var psig = new PInvokeSignature { OrigMethod = method, Name = GetMangledMethodName (typeInfo, method), Type = methodType, CallingConvention = GetCallingConvention (method), ParameterTypes = pinvokeTypes, ReturnType = returnType }; if (ReturnByHiddenArgument (typeInfo, method)) { psig.ParameterTypes.Insert (0, typeof (IntPtr)); psig.ReturnType = typeof (void); } return psig; }