}
}
- mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE, FALSE);
+ mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS);
res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
free_hash (cache->native_wrapper_aot_check_cache);
free_hash (cache->native_func_wrapper_aot_cache);
+ free_hash (cache->native_func_wrapper_indirect_cache);
free_hash (cache->remoting_invoke_cache);
free_hash (cache->synchronized_cache);
free_hash (cache->unbox_wrapper_cache);
* \param method if non-NULL, the pinvoke method to call
* \param check_exceptions Whenever to check for pending exceptions after the native call
* \param func_param the function to call is passed as a boxed IntPtr as the first parameter
+ * \param func_param_unboxed combined with \p func_param, expect the function to call as an unboxed IntPtr as the first parameter
* \param skip_gc_trans Whenever to skip GC transitions
*
* generates IL code for the pinvoke wrapper, the generated code calls \p func .
*/
static void
-emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans)
+emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, MonoNativeWrapperFlags flags)
{
+ gboolean aot = (flags & EMIT_NATIVE_WRAPPER_AOT) != 0;
+ gboolean check_exceptions = (flags & EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS) != 0;
+ gboolean func_param = (flags & EMIT_NATIVE_WRAPPER_FUNC_PARAM) != 0;
+ gboolean func_param_unboxed = (flags & EMIT_NATIVE_WRAPPER_FUNC_PARAM_UNBOXED) != 0;
+ gboolean skip_gc_trans = (flags & EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS) != 0;
EmitMarshalContext m;
MonoMethodSignature *csig;
MonoClass *klass;
/* call the native method */
if (func_param) {
mono_mb_emit_byte (mb, CEE_LDARG_0);
- mono_mb_emit_op (mb, CEE_UNBOX, mono_defaults.int_class);
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
+ if (!func_param_unboxed) {
+ mono_mb_emit_op (mb, CEE_UNBOX, mono_defaults.int_class);
+ mono_mb_emit_byte (mb, CEE_LDIND_I);
+ }
+ if (piinfo && (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) != 0) {
mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
mono_mb_emit_byte (mb, CEE_MONO_SAVE_LAST_ERROR);
}
}
static void
-emit_native_wrapper_noilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans)
+emit_native_wrapper_noilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, MonoNativeWrapperFlags flags)
{
}
static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callers_only_attribute, "System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute")
#endif
+static gboolean type_is_blittable (MonoType *type);
+
static MonoImage*
get_method_image (MonoMethod *method)
{
}
#endif
- mono_marshal_emit_native_wrapper (get_method_image (mb->method), mb, csig, piinfo, mspecs, piinfo->addr, aot, check_exceptions, FALSE, skip_gc_trans);
+ MonoNativeWrapperFlags flags = aot ? EMIT_NATIVE_WRAPPER_AOT : (MonoNativeWrapperFlags)0;
+ flags |= check_exceptions ? EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS : (MonoNativeWrapperFlags)0;
+ flags |= skip_gc_trans ? EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS : (MonoNativeWrapperFlags)0;
+
+ mono_marshal_emit_native_wrapper (get_method_image (mb->method), mb, csig, piinfo, mspecs, piinfo->addr, flags);
info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_PINVOKE);
info->d.managed_to_native.method = method;
mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
mb->method->save_lmf = 1;
- mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, FALSE, TRUE, FALSE, FALSE);
+ mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS);
csig = mono_metadata_signature_dup_full (image, sig);
csig->pinvoke = 0;
mb = mono_mb_new (invoke->klass, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
mb->method->save_lmf = 1;
- mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, NULL, FALSE, TRUE, TRUE, FALSE);
+ mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, NULL, EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS | EMIT_NATIVE_WRAPPER_FUNC_PARAM);
info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT);
info->d.managed_to_native.method = invoke;
}
/*
+ * Gets a wrapper for an indirect call to a function with the given signature.
+ * The actual function is passed as the first argument to the wrapper.
+ *
+ * The wrapper is
+ *
+ * retType wrapper (fnPtr, arg1... argN) {
+ * enter_gc_safe;
+ * ret = fnPtr (arg1, ... argN);
+ * exit_gc_safe;
+ * return ret;
+ * }
+ *
+ */
+MonoMethod*
+mono_marshal_get_native_func_wrapper_indirect (MonoClass *caller_class, MonoMethodSignature *sig,
+ gboolean aot)
+{
+ caller_class = mono_class_get_generic_type_definition (caller_class);
+ MonoImage *image = m_class_get_image (caller_class);
+ g_assert (sig->pinvoke);
+ g_assert (!sig->hasthis && ! sig->explicit_this);
+ g_assert (!sig->is_inflated && !sig->has_type_parameters);
+
+ g_assertf (type_is_blittable (sig->ret), "sig return type %s is not blittable\n", mono_type_full_name (sig->ret));
+
+ for (int i = 0; i < sig->param_count; ++i) {
+ MonoType *ty = sig->params [i];
+ g_assertf (type_is_blittable (ty), "sig param %d (type %s) is not blittable\n", i, mono_type_full_name (ty));
+ }
+ /* g_assert (every param and return type is blittable) */
+
+ GHashTable *cache = get_cache (&image->wrapper_caches.native_func_wrapper_indirect_cache,
+ (GHashFunc)mono_signature_hash,
+ (GCompareFunc)mono_metadata_signature_equal);
+
+ MonoMethod *res;
+ if ((res = mono_marshal_find_in_cache (cache, sig)))
+ return res;
+
+#if 0
+ fprintf (stderr, "generating wrapper for signature %s\n", mono_signature_full_name (sig));
+#endif
+
+ /* FIXME: better wrapper name */
+ char * name = g_strdup_printf ("wrapper_native_indirect_%p", sig);
+ MonoMethodBuilder *mb = mono_mb_new (caller_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
+ mb->method->save_lmf = 1;
+
+ WrapperInfo *info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NATIVE_FUNC_INDIRECT);
+ info->d.managed_to_native.method = NULL;
+
+ MonoMethodPInvoke *piinfo = NULL;
+ MonoMarshalSpec **mspecs = g_new0 (MonoMarshalSpec *, 1 + sig->param_count);
+ MonoNativeWrapperFlags flags = aot ? EMIT_NATIVE_WRAPPER_AOT : (MonoNativeWrapperFlags)0;
+ flags |= EMIT_NATIVE_WRAPPER_FUNC_PARAM | EMIT_NATIVE_WRAPPER_FUNC_PARAM_UNBOXED;
+ mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, /*func*/NULL, flags);
+ g_free (mspecs);
+
+ MonoMethodSignature *csig = mono_metadata_signature_dup_add_this (image, sig, mono_defaults.int_class);
+ csig->pinvoke = 0;
+
+ MonoMethodSignature *key_sig = mono_metadata_signature_dup_full (image, sig);
+
+ gboolean found;
+ res = mono_mb_create_and_cache_full (cache, key_sig, mb, csig, csig->param_count + 16, info, &found);
+
+ mono_mb_free (mb);
+
+ return res;
+}
+
+/*
* mono_marshal_emit_managed_wrapper:
*
* Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
}
void
-mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans)
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, MonoNativeWrapperFlags flags)
{
- get_marshal_cb ()->emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, aot, check_exceptions, func_param, skip_gc_trans);
+ get_marshal_cb ()->emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, flags);
}
static MonoMarshalCallbacks marshal_cb;
/* Subtypes of MONO_WRAPPER_MANAGED_TO_NATIVE */
WRAPPER_SUBTYPE_ICALL_WRAPPER, // specifically JIT icalls
WRAPPER_SUBTYPE_NATIVE_FUNC_AOT,
+ WRAPPER_SUBTYPE_NATIVE_FUNC_INDIRECT,
WRAPPER_SUBTYPE_PINVOKE,
/* Subtypes of MONO_WRAPPER_OTHER */
WRAPPER_SUBTYPE_SYNCHRONIZED_INNER,
} MonoStelemrefKind;
-#define MONO_MARSHAL_CALLBACKS_VERSION 4
+typedef enum {
+ EMIT_NATIVE_WRAPPER_AOT = 0x01, /* FIXME: what does "aot" mean here */
+ EMIT_NATIVE_WRAPPER_CHECK_EXCEPTIONS = 0x02,
+ EMIT_NATIVE_WRAPPER_FUNC_PARAM = 0x04,
+ EMIT_NATIVE_WRAPPER_FUNC_PARAM_UNBOXED = 0x08,
+ EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS=0x10,
+} MonoNativeWrapperFlags;
+
+G_ENUM_FUNCTIONS(MonoNativeWrapperFlags);
+
+#define MONO_MARSHAL_CALLBACKS_VERSION 5
typedef struct {
int version;
void (*emit_virtual_stelemref) (MonoMethodBuilder *mb, const char **param_names, MonoStelemrefKind kind);
void (*emit_stelemref) (MonoMethodBuilder *mb);
void (*emit_array_address) (MonoMethodBuilder *mb, int rank, int elem_size);
- void (*emit_native_wrapper) (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans);
+ void (*emit_native_wrapper) (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, MonoNativeWrapperFlags flags);
void (*emit_managed_wrapper) (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoGCHandle target_handle);
void (*emit_runtime_invoke_body) (MonoMethodBuilder *mb, const char **param_names, MonoImage *image, MonoMethod *method, MonoMethodSignature *sig, MonoMethodSignature *callsig, gboolean virtual_, gboolean need_direct_wrapper);
void (*emit_runtime_invoke_dynamic) (MonoMethodBuilder *mb);
MonoMethod*
mono_marshal_get_native_func_wrapper_aot (MonoClass *klass);
+MonoMethod*
+mono_marshal_get_native_func_wrapper_indirect (MonoClass *caller_class, MonoMethodSignature *sig,
+ gboolean aot);
+
MonoMethod *
mono_marshal_get_struct_to_ptr (MonoClass *klass);
/* Called from cominterop.c/remoting.c */
void
-mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param, gboolean skip_gc_trans);
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, MonoNativeWrapperFlags flags);
void
mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoGCHandle target_handle);
GHashTable *native_wrapper_aot_check_cache;
GHashTable *native_func_wrapper_aot_cache;
+ GHashTable *native_func_wrapper_indirect_cache; /* Indexed by MonoMethodSignature. Protected by the marshal lock */
GHashTable *remoting_invoke_cache;
GHashTable *synchronized_cache;
GHashTable *unbox_wrapper_cache;
case MONO_CALL_STDCALL:
case MONO_CALL_THISCALL:
case MONO_CALL_FASTCALL:
+ case MONO_CALL_UNMANAGED_MD:
method->pinvoke = 1;
break;
}
MONO_CALL_STDCALL,
MONO_CALL_THISCALL,
MONO_CALL_FASTCALL,
- MONO_CALL_VARARG
+ MONO_CALL_VARARG = 0x05,
+ /* unused, */
+ /* unused, */
+ /* unused, */
+ MONO_CALL_UNMANAGED_MD = 0x09, /* default unmanaged calling convention, with additional attributed encoded in modopts */
} MonoCallConvention;
/* ECMA lamespec: the old spec had more info... */
addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
}
+ if (!method->dynamic && fsig->pinvoke &&
+ !method->wrapper_type) {
+ /* MONO_WRAPPER_DYNAMIC_METHOD dynamic method handled above in the
+ method->dynamic case; for other wrapper types assume the code knows
+ what its doing and added its own GC transitions */
+
+ /* TODO: unmanaged[SuppressGCTransition] call conv will set
+ * skip_gc_trans to TRUE*/
+ gboolean skip_gc_trans = FALSE;
+ if (!skip_gc_trans) {
+#if 0
+ fprintf (stderr, "generating wrapper for calli in method %s with wrapper type %s\n", method->name, mono_wrapper_type_to_str (method->wrapper_type));
+#endif
+ /* Call the wrapper that will do the GC transition instead */
+ MonoMethod *wrapper = mono_marshal_get_native_func_wrapper_indirect (method->klass, fsig, cfg->compile_aot);
+
+ fsig = mono_method_signature_internal (wrapper);
+
+ n = fsig->param_count - 1; /* wrapper has extra fnptr param */
+
+ CHECK_STACK (n);
+
+ /* move the args to allow room for 'this' in the first position */
+ while (n--) {
+ --sp;
+ sp [1] = sp [0];
+ }
+
+ sp[0] = addr; /* n+1 args, first arg is the address of the indirect method to call */
+
+ g_assert (!fsig->hasthis && !fsig->pinvoke);
+
+ gboolean inline_wrapper = cfg->opt & MONO_OPT_INLINE || cfg->compile_aot;
+ if (inline_wrapper) {
+ int costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
+ CHECK_CFG_EXCEPTION;
+ g_assert (costs > 0);
+ cfg->real_offset += 5;
+ inline_costs += costs;
+ ins = sp[0];
+ } else {
+ ins = mono_emit_method_call (cfg, wrapper, /*args*/sp, NULL);
+ }
+ goto calli_end;
+ }
+ }
+
n = fsig->param_count + fsig->hasthis;
CHECK_STACK (n);