Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/cominterop.c
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,7 @@ cominterop_get_native_wrapper_adjusted (MonoMethod *method)
}
}

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);

Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/metadata/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -2493,6 +2493,7 @@ mono_wrapper_caches_free (MonoWrapperCaches *cache)
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);
Expand Down
16 changes: 12 additions & 4 deletions src/mono/mono/metadata/marshal-ilgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1995,13 +1995,19 @@ gc_safe_transition_builder_cleanup (GCSafeTransitionBuilder *builder)
* \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;
Comment thread
lambdageek marked this conversation as resolved.
Outdated
gboolean skip_gc_trans = (flags & EMIT_NATIVE_WRAPPER_SKIP_GC_TRANS) != 0;
EmitMarshalContext m;
MonoMethodSignature *csig;
MonoClass *klass;
Expand Down Expand Up @@ -2139,9 +2145,11 @@ emit_native_wrapper_ilgen (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSi
/* 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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/marshal-noilgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ emit_thunk_invoke_wrapper_noilgen (MonoMethodBuilder *mb, MonoMethod *method, Mo
}

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)
{
}

Expand Down
88 changes: 83 additions & 5 deletions src/mono/mono/metadata/marshal.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "Sys
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)
{
Expand Down Expand Up @@ -3518,7 +3520,11 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
}
#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;

Expand Down Expand Up @@ -3573,7 +3579,7 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig
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;
Expand Down Expand Up @@ -3636,7 +3642,7 @@ mono_marshal_get_native_func_wrapper_aot (MonoClass *klass)
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;
Expand All @@ -3658,6 +3664,78 @@ mono_marshal_get_native_func_wrapper_aot (MonoClass *klass)
return res;
}

/*
* 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

Comment thread
lambdageek marked this conversation as resolved.
/* 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:
*
Expand Down Expand Up @@ -6383,9 +6461,9 @@ mono_marshal_lookup_pinvoke (MonoMethod *method)
}

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;
Expand Down
21 changes: 18 additions & 3 deletions src/mono/mono/metadata/marshal.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ typedef enum {
/* 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,
Expand Down Expand Up @@ -300,7 +301,17 @@ typedef enum {
} 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;
Expand All @@ -325,7 +336,7 @@ typedef struct {
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);
Expand Down Expand Up @@ -473,6 +484,10 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig
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);

Expand Down Expand Up @@ -668,7 +683,7 @@ mono_signature_no_pinvoke (MonoMethod *method);
/* 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);
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/metadata/metadata-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ typedef struct {
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;
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/metadata/metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -2355,6 +2355,7 @@ mono_metadata_parse_method_signature_full (MonoImage *m, MonoGenericContainer *c
case MONO_CALL_STDCALL:
case MONO_CALL_THISCALL:
case MONO_CALL_FASTCALL:
case MONO_CALL_UNMANAGED_MD:
method->pinvoke = 1;
break;
}
Expand Down
6 changes: 5 additions & 1 deletion src/mono/mono/metadata/metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ typedef enum {
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... */
Expand Down
47 changes: 47 additions & 0 deletions src/mono/mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -7065,6 +7065,53 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
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);
Comment thread
vargaz marked this conversation as resolved.
cfg->real_offset += 5;
inline_costs += costs;
ins = sp[0];
} else {
Comment thread
vargaz marked this conversation as resolved.
ins = mono_emit_method_call (cfg, wrapper, /*args*/sp, NULL);
}
goto calli_end;
}
}

n = fsig->param_count + fsig->hasthis;

CHECK_STACK (n);
Expand Down