Add support for translating between normal and gsharedvt calling conventions in llvmo...
authorZoltan Varga <vargaz@gmail.com>
Wed, 16 Dec 2015 20:08:04 +0000 (15:08 -0500)
committerZoltan Varga <vargaz@gmail.com>
Wed, 16 Dec 2015 20:09:55 +0000 (15:09 -0500)
This is implemented by generating two wrappers for each concrete signature found in the assembly:
* an 'in' wrapper translates from the normal to the gsharedvt signature
* an 'out' wrapper translates from the gsharedvt to the normal signature

The wrappers take an extra argument, which points to a function descriptor, which is an <addr, arg> pair. They
make a call to ADDR which ARG as an extra argument. ADDR/ARG is either a gsharedvt method with an rgctx
argument, or another gsharedvt wrapper with a function descriptor argument.

All calls made out of gsharedvt methods with a variable signature use the gsharedvt calling convention. If the
callee is also gsharedvt, no wrapper is needed. If the callee is not gsharedvt, the call goes thought
a gsharedvt out wrapper.
Calls made from normal methods to gsharedvt methods go though a gsharedvt in wrapper.

    * mini-generic-sharing.c (mini_get_gsharedvt_in_sig_wrapper): New function to generate gsharedvt in
    wrappers as IL code.
    (mini_get_gsharedvt_out_sig_wrapper): Ditto for out wrappers.

    * method-to-ir.c (emit_llvmonly_calli): New helper function to make a call to a function descriptor.
    (mono_method_to_ir): Make some indirect calls to MONO_RGCTX_INFO entries using function descriptors.

    * aot-compiler.c (compile_method): Generate gsharedvt wrappers for the signatures used by the method.

    * aot-runtime.c (decode_method_ref_with_target): Decode gsharedvt wrappers.

    * jit-icalls.c (resolve_vcall): Rewrite this so it can handle gsharedvt as well.
    (resolve_iface_call): Ditto.
    (mono_init_delegate): Ditto.
    (mono_init_delegate_virtual): Ditto.

    * mini-trampolines.c (mini_create_llvmonly_ftndesc): New helper function to create a function descriptor.
    (mini_add_method_wrappers_llvmonly): New helper function to add gsharedvt in/out wrappers, similar
    to mini_add_method_trampolines ().

    * mini-generic-sharing.c (mini_get_gsharedvt_wrapper): Return the newly added wrappers in llvmonly mode.
    (class_type_info): Insert gsharedvt wrappers if needed. Some MONO_RGCTX_INFO types will now resolve to
    function descriptors instead of function addresses.
    (instantiate_info): Ditto.

mono/metadata/marshal.c
mono/metadata/marshal.h
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/jit-icalls.c
mono/mini/jit-icalls.h
mono/mini/method-to-ir.c
mono/mini/mini-generic-sharing.c
mono/mini/mini-runtime.c
mono/mini/mini-trampolines.c
mono/mini/mini.h

index 830434175405988088d7f58a2f85b85de36d5bd9..6bc3217dad194aead099a8c1a9103283b11be047 100644 (file)
@@ -3872,7 +3872,7 @@ emit_runtime_invoke_body (MonoMethodBuilder *mb, MonoClass *target_klass, MonoMe
  * before calling the runtime invoke wrapper. In this case, the wrapper ignores
  * its METHOD argument.
  * If PASS_RGCTX is TRUE, the signature of the called method is changed to include a 'gpointer rgctx' as the
- * first argument (after 'this').
+ * last argument (after 'this').
  */
 MonoMethod *
 mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_, gboolean pass_rgctx)
index 40a23f7e102b1749224d0d97435a0d6470513130..8e3316791c0f5e04e171686b62e849da9c88e133 100644 (file)
@@ -115,7 +115,10 @@ typedef enum {
        WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER,
        /* Subtypes of MONO_WRAPPER_DELEGATE_INVOKE */
        WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL,
-       WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND
+       WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND,
+       /* Subtypes of MONO_WRAPPER_UNKNOWN */
+       WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG,
+       WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG,
 } WrapperSubtype;
 
 typedef struct {
@@ -183,6 +186,10 @@ typedef struct {
        MonoMethod *method;
 } RemotingWrapperInfo;
 
+typedef struct {
+       MonoMethodSignature *sig;
+} GsharedvtWrapperInfo;
+
 /*
  * This structure contains additional information to uniquely identify a given wrapper
  * method. It can be retrieved by mono_marshal_get_wrapper_info () for certain types
@@ -221,6 +228,8 @@ typedef struct {
                UnboxWrapperInfo unbox;
                /* MONO_WRAPPER_REMOTING_INVOKE/MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK/MONO_WRAPPER_XDOMAIN_INVOKE */
                RemotingWrapperInfo remoting;
+               /* GSHAREDVT_IN_SIG/GSHAREDVT_OUT_SIG */
+               GsharedvtWrapperInfo gsharedvt;
        } d;
 } WrapperInfo;
 
index 20a63a6c9279df4832735a4c1d4ca29de7fef459..d343bad54b6e0524d6b0524a5a34bf8db5313a1d 100644 (file)
@@ -178,6 +178,7 @@ typedef struct MonoAotCompile {
        GHashTable *klass_blob_hash;
        /* Maps MonoMethod* -> blob offset */
        GHashTable *method_blob_hash;
+       GHashTable *signatures;
        guint32 *plt_got_info_offsets;
        guint32 got_offset, llvm_got_offset, plt_offset, plt_got_offset_base, nshared_got_entries;
        /* Number of GOT entries reserved for trampolines */
@@ -2840,6 +2841,10 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8
                                encode_method_ref (acfg, info->d.synchronized_inner.method, p, &p);
                        else if (info->subtype == WRAPPER_SUBTYPE_ARRAY_ACCESSOR)
                                encode_method_ref (acfg, info->d.array_accessor.method, p, &p);
+                       else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG)
+                               encode_signature (acfg, info->d.gsharedvt.sig, p, &p);
+                       else if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG)
+                               encode_signature (acfg, info->d.gsharedvt.sig, p, &p);
                        break;
                }
                case MONO_WRAPPER_MANAGED_TO_NATIVE: {
@@ -7121,6 +7126,60 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method)
        if (!cfg->has_got_slots)
                InterlockedIncrement (&acfg->stats.methods_without_got_slots);
 
+       if (!cfg->method->wrapper_type)
+               cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, mono_method_signature (cfg->method));
+
+       /* Add gsharedvt wrappers for signatures used by the method */
+       if (acfg->aot_opts.llvm_only && (acfg->opts & MONO_OPT_GSHAREDVT)) {
+               GSList *l;
+
+               for (l = cfg->signatures; l; l = l->next) {
+                       MonoMethodSignature *sig = mono_metadata_signature_dup ((MonoMethodSignature*)l->data);
+
+                       if (!g_hash_table_lookup (acfg->signatures, sig) && !mini_is_gsharedvt_variable_signature (sig)) {
+                               g_hash_table_insert (acfg->signatures, sig, sig);
+                               if (!sig->has_type_parameters) {
+                                       MonoMethod *wrapper;
+
+                                       //printf ("%s\n", mono_signature_full_name (sig));
+
+                                       wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
+                                       add_extra_method (acfg, wrapper);
+                                       wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
+                                       add_extra_method (acfg, wrapper);
+                               } else {
+                                       /* For signatures creared during generic sharing, convert them to a concrete signature if possible */
+                                       MonoMethodSignature *copy = mono_metadata_signature_dup (sig);
+                                       int i;
+                                       gboolean concrete = TRUE;
+
+                                       //printf ("%s\n", mono_signature_full_name (sig));
+
+                                       copy->ret = mini_get_underlying_type (sig->ret);
+                                       // FIXME: Add more cases
+                                       if (copy->ret->type == MONO_TYPE_VAR || copy->ret->type == MONO_TYPE_MVAR || copy->ret->type == MONO_TYPE_GENERICINST || copy->ret->type == MONO_TYPE_SZARRAY)
+                                               concrete = FALSE;
+                                       for (i = 0; i < sig->param_count; ++i) {
+                                               copy->params [i] = mini_get_underlying_type (sig->params [i]);
+                                               if (copy->params [i]->type == MONO_TYPE_VAR || copy->params [i]->type == MONO_TYPE_MVAR || copy->params [i]->type == MONO_TYPE_GENERICINST || copy->params [i]->type == MONO_TYPE_SZARRAY)
+                                                       concrete = FALSE;
+                                       }
+                                       if (concrete) {
+                                               copy->has_type_parameters = 0;
+                                               sig = copy;
+                                               if (!g_hash_table_lookup (acfg->signatures, sig)) {
+                                                       g_hash_table_insert (acfg->signatures, sig, sig);
+                                                       MonoMethod *wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
+                                                       add_extra_method (acfg, wrapper);
+
+                                                       //printf ("%s\n", mono_method_full_name (wrapper, 1));
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
        /* 
         * FIXME: Instead of this mess, allocate the patches from the aot mempool.
         */
@@ -9020,6 +9079,29 @@ collect_methods (MonoAotCompile *acfg)
                }
        }
 
+       /* gsharedvt in wrappers */
+       /* Generate a wrapper for each generic signature used in the module */
+       if (acfg->aot_opts.llvm_only && (acfg->opts & MONO_OPT_GSHAREDVT)) {
+               // FIXME: Is this needed ?
+               for (mindex = 0; mindex < image->tables [MONO_TABLE_METHODSPEC].rows; ++mindex) {
+                       MonoMethod *method, *wrapper;
+                       MonoMethodSignature *sig;
+                       guint32 token = MONO_TOKEN_METHOD_SPEC | (mindex + 1);
+
+                       method = mono_get_method (acfg->image, token, NULL);
+                       // FIXME:
+                       g_assert (method);
+
+                       sig = mono_method_signature (method);
+                       if (!sig->has_type_parameters) {
+                               wrapper = mini_get_gsharedvt_in_sig_wrapper (sig);
+                               add_extra_method (acfg, wrapper);
+                               wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
+                               add_extra_method (acfg, wrapper);
+                       }
+               }
+       }
+
        add_generic_instances (acfg);
 
        if (mono_aot_mode_is_full (&acfg->aot_opts))
@@ -9314,6 +9396,7 @@ acfg_create (MonoAssembly *ass, guint32 opts)
        acfg->klass_blob_hash = g_hash_table_new (NULL, NULL);
        acfg->method_blob_hash = g_hash_table_new (NULL, NULL);
        acfg->plt_entry_debug_sym_cache = g_hash_table_new (g_str_hash, g_str_equal);
+       acfg->signatures = g_hash_table_new ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal);
        mono_os_mutex_init_recursive (&acfg->mutex);
 
        init_got_info (&acfg->got_info);
index 57d53d55ea46660388b2a34240834d7ac73ba785..1e866c3aa5d8b20336d3bd1a006437d1cb1fa1ef 100644 (file)
@@ -718,7 +718,7 @@ decode_signature_with_target (MonoAotModule *module, MonoMethodSignature *target
 {
        MonoMethodSignature *sig;
        guint32 flags;
-       int i, param_count, call_conv;
+       int i, gen_param_count = 0, param_count, call_conv;
        guint8 *p = buf;
        gboolean hasthis, explicit_this, has_gen_params;
 
@@ -730,7 +730,7 @@ decode_signature_with_target (MonoAotModule *module, MonoMethodSignature *target
        call_conv = flags & 0x0F;
 
        if (has_gen_params)
-               /* gen_param_count = */ decode_value (p, &p);
+               gen_param_count = decode_value (p, &p);
        param_count = decode_value (p, &p);
        if (target && param_count != target->param_count)
                return NULL;
@@ -740,7 +740,7 @@ decode_signature_with_target (MonoAotModule *module, MonoMethodSignature *target
        sig->hasthis = hasthis;
        sig->explicit_this = explicit_this;
        sig->call_convention = call_conv;
-       sig->param_count = param_count;
+       sig->generic_param_count = gen_param_count;
        sig->ret = decode_type (module, p, &p);
        for (i = 0; i < param_count; ++i) {
                if (*p == MONO_TYPE_SENTINEL) {
@@ -971,6 +971,16 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod
                                ref->method = mono_marshal_get_gsharedvt_in_wrapper ();
                        } else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) {
                                ref->method = mono_marshal_get_gsharedvt_out_wrapper ();
+                       } else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG) {
+                               MonoMethodSignature *sig = decode_signature (module, p, &p);
+                               if (!sig)
+                                       return FALSE;
+                               ref->method = mini_get_gsharedvt_in_sig_wrapper (sig);
+                       } else if (subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG) {
+                               MonoMethodSignature *sig = decode_signature (module, p, &p);
+                               if (!sig)
+                                       return FALSE;
+                               ref->method = mini_get_gsharedvt_out_sig_wrapper (sig);
                        } else {
                                g_assert_not_reached ();
                        }
index f5b4e4204fd0efc1ad3e00fbb6d133a9e1f1fec7..e7850d725a1bb851f5033ba8ac61060c3ebdc2b9 100644 (file)
@@ -1328,12 +1328,12 @@ mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
 }
 
 /*
- * mono_resolve_iface_call:
+ * resolve_iface_call:
  *
  *   Return the executable code for the iface method IMT_METHOD called on THIS.
  */
-gpointer
-mono_resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_rgctx_arg)
+static gpointer
+resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
 {
        MonoVTable *vt;
        gpointer *imt, *vtable_slot;
@@ -1356,10 +1356,8 @@ mono_resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_met
        addr = compiled_method = mono_compile_method (impl_method);
        g_assert (addr);
 
-       if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
+       if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
                generic_virtual = imt_method;
-               need_rgctx_tramp = TRUE;
-       }
 
        if (generic_virtual || variant_iface) {
                if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
@@ -1369,7 +1367,7 @@ mono_resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_met
                        need_unbox_tramp = TRUE;
        }
 
-       addr = mini_add_method_trampoline (impl_method, addr, need_rgctx_tramp, need_unbox_tramp);
+       addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
 
        if (generic_virtual || variant_iface) {
                MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
@@ -1381,22 +1379,19 @@ mono_resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_met
 
        *vtable_slot = addr;
 
-       if (need_rgctx_tramp && out_rgctx_arg) {
-               MonoMethod *m = impl_method;
-               MonoJitInfo *ji;
+       return addr;
+}
 
-               /*
-                * The exact compiled method might not be shared so it doesn't have an rgctx arg.
-                */
-               ji = mini_jit_info_table_find (mono_domain_get (), (char *)compiled_method, NULL);
-               if (!ji || (ji && ji->has_generic_jit_info)) {
-                       if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && m->klass->rank && strstr (m->name, "System.Collections.Generic"))
-                               m = mono_aot_get_array_helper_from_wrapper (m);
-                       *out_rgctx_arg = mini_method_get_rgctx (m);
-               }
-       }
+gpointer
+mono_resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
+{
+       return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, FALSE);
+}
 
-       return addr;
+gpointer
+mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
+{
+       return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
 }
 
 static gboolean
@@ -1421,14 +1416,14 @@ is_generic_method_definition (MonoMethod *m)
  *
  *   Return the executable code for calling this_obj->vtable [slot].
  */
-gpointer
-mono_resolve_vcall (MonoObject *this_obj, int slot, MonoMethod *imt_method)
+static gpointer
+resolve_vcall (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
 {
        MonoVTable *vt;
        MonoMethod *m, *generic_virtual = NULL;
        gpointer *vtable_slot;
-       gpointer addr;
-       gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
+       gpointer addr, compiled_method;
+       gboolean need_unbox_tramp = FALSE;
 
        // FIXME: Optimize this
 
@@ -1475,14 +1470,10 @@ mono_resolve_vcall (MonoObject *this_obj, int slot, MonoMethod *imt_method)
 
                m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
                g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
-               /* FIXME: only do this if the method is sharable */
-               // FIXME:
-               //g_assert_not_reached ();
-               //need_rgctx_tramp = TRUE;
        }
 
        if (generic_virtual) {
-               if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
+               if (vt->klass->valuetype)
                        need_unbox_tramp = TRUE;
        } else {
                if (m->klass->valuetype)
@@ -1490,16 +1481,44 @@ mono_resolve_vcall (MonoObject *this_obj, int slot, MonoMethod *imt_method)
        }
 
        // FIXME: This can throw exceptions
-       addr = mono_compile_method (m);
+       addr = compiled_method = mono_compile_method (m);
        g_assert (addr);
 
-       addr = mini_add_method_trampoline (m, addr, need_rgctx_tramp, need_unbox_tramp);
+       addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, out_arg);
+
+       // FIXME: Unify this with mono_resolve_iface_call
 
        *vtable_slot = addr;
 
+       if (gsharedvt) {
+               /*
+                * The callee uses the gsharedvt calling convention, have to add an out wrapper.
+                */
+               g_assert (out_arg);
+               g_assert (*out_arg);
+
+               gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, mono_method_signature (imt_method), NULL, -1, FALSE);
+               gpointer *out_wrapper_arg = mini_create_llvmonly_ftndesc (addr, *out_arg);
+
+               addr = out_wrapper;
+               *out_arg = out_wrapper_arg;
+       }
+
        return addr;
 }
 
+gpointer
+mono_resolve_vcall (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_rgctx_arg)
+{
+       return resolve_vcall (this_obj, slot, imt_method, out_rgctx_arg, FALSE);
+}
+
+gpointer
+mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_rgctx_arg)
+{
+       return resolve_vcall (this_obj, slot, imt_method, out_rgctx_arg, TRUE);
+}
+
 /*
  * mono_init_delegate:
  *
@@ -1512,8 +1531,12 @@ mono_init_delegate (MonoDelegate *del, MonoObject *target, MonoMethod *method)
        MONO_OBJECT_SETREF (del, target, target);
        del->method = method;
        del->method_ptr = mono_compile_method (method);
-       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
-               del->rgctx = mini_method_get_rgctx (method);
+
+       del->method_ptr = mini_add_method_wrappers_llvmonly (method, del->method_ptr, FALSE, FALSE, &del->rgctx);
+       if (!del->rgctx) {
+               if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+                       del->rgctx = mini_method_get_rgctx (method);
+       }
 }
 
 void
@@ -1526,8 +1549,12 @@ mono_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *m
        MONO_OBJECT_SETREF (del, target, target);
        del->method = method;
        del->method_ptr = mono_compile_method (method);
-       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
-               del->rgctx = mini_method_get_rgctx (method);
+
+       del->method_ptr = mini_add_method_wrappers_llvmonly (method, del->method_ptr, FALSE, FALSE, &del->rgctx);
+       if (!del->rgctx) {
+               if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+                       del->rgctx = mini_method_get_rgctx (method);
+       }
 }
 
 MonoObject*
index 7c224995c2b5100b06f2291314ff8d239b424d37..bd7bd4ec7f917a2ff58be3cc2041b7e6c216b84d 100644 (file)
@@ -195,9 +195,13 @@ gpointer mono_fill_class_rgctx (MonoVTable *vtable, int index);
 
 gpointer mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index);
 
-gpointer mono_resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_rgctx_arg);
+gpointer mono_resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg);
 
-gpointer mono_resolve_vcall (MonoObject *this_obj, int slot, MonoMethod *imt_method);
+gpointer mono_resolve_vcall (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg);
+
+gpointer mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg);
+
+gpointer mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg);
 
 void mono_init_delegate (MonoDelegate *del, MonoObject *target, MonoMethod *method);
 
index a09bfe2f4033b09436e6135f96477d4ee69cadba..840e1a8fd68a93aa66b8de4c2a2c0f226a162383 100644 (file)
@@ -2817,6 +2817,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                // FIXME: Vcall optimizations below
                MonoInst *icall_args [16];
                MonoInst *ins;
+               int rgctx_reg;
 
                if (sig->generic_param_count) {
                        /*
@@ -2838,6 +2839,9 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
                        EMIT_NEW_PCONST (cfg, ins, NULL);
                        icall_args [2] = ins;
                }
+               rgctx_reg = alloc_preg (cfg);
+               MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
+               EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
                call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall, icall_args);
        }
 
@@ -3015,6 +3019,68 @@ mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer
        return ins;
 }
 
+static MonoMethodSignature*
+sig_to_rgctx_sig (MonoMethodSignature *sig)
+{
+       // FIXME: memory allocation
+       MonoMethodSignature *res;
+       int i;
+
+       res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
+       memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
+       res->param_count = sig->param_count + 1;
+       for (i = 0; i < sig->param_count; ++i)
+               res->params [i] = sig->params [i];
+       res->params [sig->param_count] = &mono_defaults.int_class->this_arg;
+       return res;
+}
+
+/* Make an indirect call to FSIG passing an additional argument */
+static MonoInst*
+emit_extra_arg_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **orig_args, int arg_reg, MonoInst *call_target)
+{
+       MonoMethodSignature *csig;
+       MonoInst *args_buf [16];
+       MonoInst **args;
+       int i, pindex, tmp_reg;
+
+       /* Make a call with an rgctx/extra arg */
+       if (fsig->param_count + 2 < 16)
+               args = args_buf;
+       else
+               args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
+       pindex = 0;
+       if (fsig->hasthis)
+               args [pindex ++] = orig_args [0];
+       for (i = 0; i < fsig->param_count; ++i)
+               args [pindex ++] = orig_args [fsig->hasthis + i];
+       tmp_reg = alloc_preg (cfg);
+       EMIT_NEW_UNALU (cfg, args [pindex], OP_MOVE, tmp_reg, arg_reg);
+       csig = sig_to_rgctx_sig (fsig);
+       return mono_emit_calli (cfg, csig, args, call_target, NULL, NULL);
+}
+
+/* Emit an indirect call to the function descriptor ADDR */
+static MonoInst*
+emit_llvmonly_calli (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, MonoInst *addr)
+{
+       int addr_reg, arg_reg;
+       MonoInst *call_target;
+
+       g_assert (cfg->llvm_only);
+
+       /*
+        * addr points to a <addr, arg> pair, load both of them, and
+        * make a call to addr, passing arg as an extra arg.
+        */
+       addr_reg = alloc_preg (cfg);
+       EMIT_NEW_LOAD_MEMBASE (cfg, call_target, OP_LOAD_MEMBASE, addr_reg, addr->dreg, 0);
+       arg_reg = alloc_preg (cfg);
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, arg_reg, addr->dreg, sizeof (gpointer));
+
+       return emit_extra_arg_calli (cfg, fsig, args, arg_reg, call_target);
+}
+
 static gboolean
 direct_icalls_enabled (MonoCompile *cfg)
 {
@@ -3986,10 +4052,13 @@ handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int co
                   RGCTX. */
                addr = emit_get_rgctx_method (cfg, context_used, method,
                                                                          MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
+               if (cfg->llvm_only && cfg->gsharedvt) {
+                       return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
+               } else {
+                       rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 
-               rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
-
-               return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
+                       return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
+               }
        } else {
                gboolean pass_vtable, pass_mrgctx;
                MonoInst *rgctx_arg = NULL;
@@ -4118,7 +4187,11 @@ handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
                unbox_sig->ret = &klass->byval_arg;
                unbox_sig->param_count = 1;
                unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
-               unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
+
+               if (cfg->llvm_only)
+                       unbox_call = emit_llvmonly_calli (cfg, unbox_sig, &obj, addr);
+               else
+                       unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
 
                EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
                addr->dreg = addr_reg;
@@ -4240,13 +4313,19 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
                MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
 
                if (context_used) {
-                       /* FIXME: What if the class is shared?  We might not
-                          have to get the method address from the RGCTX. */
-                       MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
-                                                                                                       MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
-                       MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+                       if (cfg->llvm_only && cfg->gsharedvt) {
+                               MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
+                                                                                                               MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
+                               return emit_llvmonly_calli (cfg, mono_method_signature (method), &val, addr);
+                       } else {
+                               /* FIXME: What if the class is shared?  We might not
+                                  have to get the method address from the RGCTX. */
+                               MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
+                                                                                                               MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
+                               MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 
-                       return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
+                               return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
+                       }
                } else {
                        gboolean pass_vtable, pass_mrgctx;
                        MonoInst *rgctx_arg = NULL;
@@ -4322,7 +4401,11 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
                        box_sig->ret = &mono_defaults.object_class->byval_arg;
                        box_sig->param_count = 1;
                        box_sig->params [0] = &klass->byval_arg;
-                       box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
+
+                       if (cfg->llvm_only)
+                               box_call = emit_llvmonly_calli (cfg, box_sig, &val, addr);
+                       else
+                               box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
                        EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
                        res->type = STACK_OBJ;
                        res->klass = klass;
@@ -7734,7 +7817,13 @@ handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fs
                MonoInst *addr;
 
                addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
-               mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
+
+               if (cfg->llvm_only) {
+                       // FIXME: Avoid initializing vtable_arg
+                       emit_llvmonly_calli (cfg, fsig, sp, addr);
+               } else {
+                       mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
+               }
        } else if (context_used &&
                           ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
                                 !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
@@ -7742,10 +7831,16 @@ handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fs
 
                /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
 
-               cmethod_addr = emit_get_rgctx_method (cfg, context_used,
-                                                                                         cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
+               if (cfg->llvm_only) {
+                       MonoInst *addr = emit_get_rgctx_method (cfg, context_used, cmethod,
+                                                                                                       MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
+                       emit_llvmonly_calli (cfg, fsig, sp, addr);
+               } else {
+                       cmethod_addr = emit_get_rgctx_method (cfg, context_used,
+                                                                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
 
-               mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
+                       mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
+               }
        } else {
                INLINE_FAILURE ("ctor call");
                ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
@@ -7790,22 +7885,6 @@ emit_setret (MonoCompile *cfg, MonoInst *val)
        }
 }
 
-static MonoMethodSignature*
-sig_to_rgctx_sig (MonoMethodSignature *sig)
-{
-       // FIXME: memory allocation
-       MonoMethodSignature *res;
-       int i;
-
-       res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
-       memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
-       res->param_count = sig->param_count + 1;
-       for (i = 0; i < sig->param_count; ++i)
-               res->params [i] = sig->params [i];
-       res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
-       return res;
-}
-
 /*
  * mono_method_to_ir:
  *
@@ -8808,6 +8887,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        /* Not tested */
                                        GSHAREDVT_FAILURE (*ip);
 
+                               if (cfg->llvm_only)
+                                       // FIXME:
+                                       GSHAREDVT_FAILURE (*ip);
+
                                addr = emit_get_rgctx_sig (cfg, context_used,
                                                                                          fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
                                ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
@@ -8981,6 +9064,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_CFG_ERROR;
                        }
 
+                       if (cfg->llvm_only && !cfg->method->wrapper_type)
+                               cfg->signatures = g_slist_prepend_mempool (cfg->mempool, cfg->signatures, fsig);
+
                        /* See code below */
                        if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
                                MonoBasicBlock *tbb;
@@ -9418,7 +9504,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         * patching gshared method addresses into a gsharedvt method.
                         */
                        if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
-                               !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
+                               !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY) &&
+                               (!(cfg->llvm_only && virtual_))) {
                                MonoRgctxInfoType info_type;
 
                                if (virtual_) {
@@ -9452,7 +9539,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
                                addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
 
-                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+                               if (cfg->llvm_only) {
+                                       // FIXME: Avoid initializing vtable_arg
+                                       ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
+                               } else {
+                                       ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+                               }
                                goto call_end;
                        }
 
@@ -9484,7 +9576,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
 
                                addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
-                               ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+                               if (cfg->llvm_only) {
+                                       // FIXME: Avoid initializing imt_arg/vtable_arg
+                                       ins = emit_llvmonly_calli (cfg, fsig, sp, addr);
+                               } else {
+                                       ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+                               }
                                goto call_end;
                        }
 
@@ -9631,71 +9728,69 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        /*
-                        * Interface calls in llvm-only mode are complicated becase the callee might need an rgctx arg,
-                        * (i.e. its a vtype method), and there is no way to for the caller to know this at compile time.
-                        * So we make resolve_iface_call return the rgctx, and do two calls with different signatures
-                        * based on whenever there is an rgctx or not.
+                        * Virtual calls in llvm-only mode.
                         */
-                       if (cfg->llvm_only && virtual_ && cmethod && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
-                               MonoInst *args_buf [16], *icall_args [16];
-                               MonoInst **args;
-                               MonoBasicBlock *rgctx_bb, *end_bb;
-                               MonoInst *call1, *call2, *call_target;
-                               MonoMethodSignature *rgctx_sig;
-                               int rgctx_reg, tmp_reg;
+                       if (cfg->llvm_only && virtual_ && cmethod && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
+                               MonoInst *icall_args [16];
+                               MonoInst *call_target;
+                               int arg_reg;
+                               gboolean is_iface = cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE;
 
                                MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
 
-                               NEW_BBLOCK (cfg, rgctx_bb);
-                               NEW_BBLOCK (cfg, end_bb);
-
                                // FIXME: Optimize this
 
-                               guint32 imt_slot = mono_method_get_imt_slot (cmethod);
+                               guint32 slot;
+
+                               if (is_iface)
+                                       slot = mono_method_get_imt_slot (cmethod);
+                               else
+                                       slot = mono_method_get_vtable_index (cmethod);
 
                                icall_args [0] = sp [0];
-                               EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
-                               if (imt_arg) {
+                               EMIT_NEW_ICONST (cfg, icall_args [1], slot);
+
+                               if (fsig->generic_param_count) {
+                                       /* virtual generic call */
+                                       g_assert (!imt_arg);
+                                       /* Same as the virtual generic case above */
+                                       imt_arg = emit_get_rgctx_method (cfg, context_used,
+                                                                                                        cmethod, MONO_RGCTX_INFO_METHOD);
+                                       icall_args [2] = imt_arg;
+                               } else if (imt_arg) {
                                        icall_args [2] = imt_arg;
                                } else {
                                        EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, cmethod);
                                        icall_args [2] = ins;
                                }
 
-                               rgctx_reg = alloc_preg (cfg);
-                               MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
-                               EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
-                               //EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
-
-                               call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
-
-                               // FIXME: Only do this if needed (generic calls)
-
-                               // Check whenever to pass an rgctx
-                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, rgctx_bb);
-                               /* Non rgctx case */
-                               call1 = mono_emit_calli (cfg, fsig, sp, call_target, NULL, vtable_arg);
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-                               /* Rgctx case */
-                               MONO_START_BB (cfg, rgctx_bb);
-                               /* Make a call with an rgctx */
-                               if (fsig->param_count + 2 < 16)
-                                       args = args_buf;
-                               else
-                                       args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
-                               args [0] = sp [0];
-                               for (i = 0; i < fsig->param_count; ++i)
-                                       args [i + 1] = sp [i + 1];
-                               tmp_reg = alloc_preg (cfg);
-                               EMIT_NEW_UNALU (cfg, args [fsig->param_count + 1], OP_MOVE, tmp_reg, rgctx_reg);
-                               rgctx_sig = sig_to_rgctx_sig (fsig);
-                               call2 = mono_emit_calli (cfg, rgctx_sig, args, call_target, NULL, NULL);
-                               call2->dreg = call1->dreg;
-                               MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-                               /* End */
-                               MONO_START_BB (cfg, end_bb);
-                               ins = call1;
+                               // FIXME: For generic virtual calls, avoid computing the rgctx twice
+
+                               arg_reg = alloc_preg (cfg);
+                               MONO_EMIT_NEW_PCONST (cfg, arg_reg, NULL);
+                               EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], arg_reg, &mono_defaults.int_class->byval_arg);
+
+                               if (cfg->gsharedvt && mini_is_gsharedvt_variable_signature (fsig)) {
+                                       /*
+                                        * We handle virtual calls made from gsharedvt methods here instead
+                                        * of the gsharedvt block above.
+                                        */
+                                       if (is_iface)
+                                               call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call_gsharedvt, icall_args);
+                                       else
+                                               call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall_gsharedvt, icall_args);
+                               } else {
+                                       if (is_iface)
+                                               call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
+                                       else
+                                               call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall, icall_args);
+                               }
+
+                               /*
+                                * Pass the extra argument even if the callee doesn't receive it, most calling
+                                * calling conventions allow this.
+                                */
+                               ins = emit_extra_arg_calli (cfg, fsig, sp, arg_reg, call_target);
                                goto call_end;
                        }
 
@@ -12671,7 +12766,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                }
 
                                                /* FIXME: SGEN support */
-                                               if (invoke_context_used == 0) {
+                                               if (invoke_context_used == 0 || cfg->llvm_only) {
                                                        ip += 6;
                                                        if (cfg->verbose_level > 3)
                                                                g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
@@ -13858,6 +13953,11 @@ mono_handle_global_vregs (MonoCompile *cfg)
                        if (mono_arch_is_soft_float ())
                                break;
 
+                       /*
+                       if (var->type == STACK_VTYPE && cfg->gsharedvt && mini_is_gsharedvt_variable_type (var->inst_vtype))
+                               break;
+                       */
+
                        /* Arguments are implicitly global */
                        /* Putting R4 vars into registers doesn't work currently */
                        /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
index 58094823d31f585fcebb0294a2c3ba67e9f9a4c0..aef15370eef385c7d638736a9fe5aad7bb4f763d 100644 (file)
@@ -11,6 +11,7 @@
 #include <config.h>
 
 #include <mono/metadata/class.h>
+#include <mono/metadata/method-builder.h>
 #include <mono/utils/mono-counters.h>
 
 #include "mini.h"
@@ -942,8 +943,10 @@ class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_ty
        case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
        case MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX: {
                MonoMethod *method;
-               gpointer addr;
+               gpointer addr, arg;
                MonoJitInfo *ji;
+               MonoMethodSignature *sig, *gsig;
+               MonoMethod *gmethod;
 
                if (!mono_class_is_nullable (klass))
                        /* This can happen since all the entries in MonoGSharedVtMethodInfo are inflated, even those which are not used */
@@ -955,15 +958,24 @@ class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_ty
                        method = mono_class_get_method_from_name (klass, "Unbox", 1);
 
                addr = mono_compile_method (method);
+
                // The caller uses the gsharedvt call signature
+
+               if (mono_llvm_only) {
+                       /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
+                       gmethod = mini_get_shared_method_full (method, FALSE, TRUE);
+                       sig = mono_method_signature (method);
+                       gsig = mono_method_signature (gmethod);
+
+                       addr = mini_add_method_wrappers_llvmonly (method, addr, TRUE, FALSE, &arg);
+                       return mini_create_llvmonly_ftndesc (addr, arg);
+               }
+
                ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
                g_assert (ji);
                if (mini_jit_info_is_gsharedvt (ji))
                        return mono_create_static_rgctx_trampoline (method, addr);
                else {
-                       MonoMethodSignature *sig, *gsig;
-                       MonoMethod *gmethod;
-
                        /* Need to add an out wrapper */
 
                        /* FIXME: We have no access to the gsharedvt signature/gsctx used by the caller, so have to construct it ourselves */
@@ -1022,6 +1034,257 @@ tramp_info_equal (gconstpointer a, gconstpointer b)
                tramp1->addr == tramp2->addr && tramp1->sig == tramp2->sig && tramp1->gsig == tramp2->gsig;
 }
 
+static MonoType*
+get_wrapper_shared_type (MonoType *t)
+{
+       if (t->byref)
+               return &mono_defaults.int_class->this_arg;
+       t = mini_get_underlying_type (t);
+
+       // FIXME: Merge more types (objref/int etc).
+
+       switch (t->type) {
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_SZARRAY:
+               return &mono_defaults.object_class->byval_arg;
+       case MONO_TYPE_GENERICINST:
+               if (!MONO_TYPE_ISSTRUCT (t))
+                       return &mono_defaults.object_class->byval_arg;
+       default:
+               break;
+       }
+
+       //printf ("%s\n", mono_type_full_name (t));
+
+       return t;
+}
+
+static MonoMethodSignature*
+mini_get_underlying_signature (MonoMethodSignature *sig)
+{
+       MonoMethodSignature *res = mono_metadata_signature_dup (sig);
+       int i;
+
+       res->ret = get_wrapper_shared_type (sig->ret);
+       for (i = 0; i < sig->param_count; ++i)
+               res->params [i] = get_wrapper_shared_type (sig->params [i]);
+
+       return res;
+}
+
+/*
+ * mini_get_gsharedvt_in_sig_wrapper:
+ *
+ *   Return a wrapper to translate between the normal and gsharedvt calling conventions of SIG.
+ * The returned wrapper has a signature of SIG, plus one extra argument, which is an <addr, rgctx> pair.
+ * The extra argument is passed the same way as an rgctx to shared methods.
+ * It calls <addr> using the gsharedvt version of SIG, passing in <rgctx> as an extra argument.
+ */
+MonoMethod*
+mini_get_gsharedvt_in_sig_wrapper (MonoMethodSignature *sig)
+{
+       MonoMethodBuilder *mb;
+       MonoMethod *res;
+       WrapperInfo *info;
+       MonoMethodSignature *csig, *gsharedvt_sig;
+       int i, pindex, retval_var;
+       static GHashTable *cache;
+
+       // FIXME: Memory management
+       sig = mini_get_underlying_signature (sig);
+
+       // FIXME: Normal cache
+       if (!cache)
+               cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
+       // FIXME: Locking
+       res = g_hash_table_lookup (cache, sig);
+       if (res) {
+               g_free (sig);
+               return res;
+       }
+
+       /* Create the signature for the wrapper */
+       // FIXME:
+       csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 1) * sizeof (MonoType*)));
+       memcpy (csig, sig, mono_metadata_signature_size (sig));
+       csig->param_count ++;
+       csig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
+
+       /* Create the signature for the gsharedvt callconv */
+       gsharedvt_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
+       memcpy (gsharedvt_sig, sig, mono_metadata_signature_size (sig));
+       pindex = 0;
+       /* The return value is returned using an explicit vret argument */
+       if (sig->ret->type != MONO_TYPE_VOID) {
+               gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
+               gsharedvt_sig->ret = &mono_defaults.void_class->byval_arg;
+       }
+       for (i = 0; i < sig->param_count; i++) {
+               gsharedvt_sig->params [pindex] = sig->params [i];
+               if (!sig->params [i]->byref) {
+                       gsharedvt_sig->params [pindex] = mono_metadata_type_dup (NULL, gsharedvt_sig->params [pindex]);
+                       gsharedvt_sig->params [pindex]->byref = 1;
+               }
+               pindex ++;
+       }
+       /* Rgctx arg */
+       gsharedvt_sig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
+       gsharedvt_sig->param_count = pindex;
+
+       // FIXME: Use shared signatures
+       mb = mono_mb_new (mono_defaults.object_class, sig->hasthis ? "gsharedvt_in_sig" : "gsharedvt_in_sig_static", MONO_WRAPPER_UNKNOWN);
+
+       if (sig->ret->type != MONO_TYPE_VOID)
+               retval_var = mono_mb_add_local (mb, sig->ret);
+
+       /* Make the call */
+       if (sig->hasthis)
+               mono_mb_emit_ldarg (mb, 0);
+       if (sig->ret->type != MONO_TYPE_VOID)
+               mono_mb_emit_ldloc_addr (mb, retval_var);
+       for (i = 0; i < sig->param_count; i++) {
+               if (sig->params [i]->byref)
+                       mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
+               else
+                       mono_mb_emit_ldarg_addr (mb, i + (sig->hasthis == TRUE));
+       }
+       /* Rgctx arg */
+       mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
+       mono_mb_emit_icon (mb, sizeof (gpointer));
+       mono_mb_emit_byte (mb, CEE_ADD);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       /* Method to call */
+       mono_mb_emit_ldarg (mb, sig->param_count + (sig->hasthis ? 1 : 0));
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_calli (mb, gsharedvt_sig);
+       if (sig->ret->type != MONO_TYPE_VOID)
+               mono_mb_emit_ldloc (mb, retval_var);
+       mono_mb_emit_byte (mb, CEE_RET);
+
+       info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG);
+       info->d.gsharedvt.sig = sig;
+
+       res = mono_mb_create (mb, csig, sig->param_count + 16, info);
+
+       // FIXME: Locking
+       g_hash_table_insert (cache, sig, res);
+
+       return res;
+}
+
+/*
+ * mini_get_gsharedvt_out_sig_wrapper:
+ *
+ *   Same as in_sig_wrapper, but translate between the gsharedvt and normal signatures.
+ */
+MonoMethod*
+mini_get_gsharedvt_out_sig_wrapper (MonoMethodSignature *sig)
+{
+       MonoMethodBuilder *mb;
+       MonoMethod *res;
+       WrapperInfo *info;
+       MonoMethodSignature *normal_sig, *csig;
+       int i, pindex, args_start, ldind_op, stind_op;
+       static GHashTable *cache;
+
+       // FIXME: Memory management
+       sig = mini_get_underlying_signature (sig);
+
+       // FIXME: Normal cache
+       if (!cache)
+               cache = g_hash_table_new_full ((GHashFunc)mono_signature_hash, (GEqualFunc)mono_metadata_signature_equal, NULL, NULL);
+       // FIXME: Locking
+       res = g_hash_table_lookup (cache, sig);
+       if (res) {
+               g_free (sig);
+               return res;
+       }
+
+       /* Create the signature for the wrapper */
+       // FIXME:
+       csig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
+       memcpy (csig, sig, mono_metadata_signature_size (sig));
+       pindex = 0;
+       /* The return value is returned using an explicit vret argument */
+       if (sig->ret->type != MONO_TYPE_VOID) {
+               csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
+               csig->ret = &mono_defaults.void_class->byval_arg;
+       }
+       args_start = pindex;
+       if (sig->hasthis)
+               args_start ++;
+       for (i = 0; i < sig->param_count; i++) {
+               csig->params [pindex] = sig->params [i];
+               if (!sig->params [i]->byref) {
+                       csig->params [pindex] = mono_metadata_type_dup (NULL, csig->params [pindex]);
+                       csig->params [pindex]->byref = 1;
+               }
+               pindex ++;
+       }
+       /* Rgctx arg */
+       csig->params [pindex ++] = &mono_defaults.int_class->byval_arg;
+       csig->param_count = pindex;
+
+       /* Create the signature for the normal callconv */
+       normal_sig = g_malloc0 (MONO_SIZEOF_METHOD_SIGNATURE + ((sig->param_count + 2) * sizeof (MonoType*)));
+       memcpy (normal_sig, sig, mono_metadata_signature_size (sig));
+       normal_sig->param_count ++;
+       normal_sig->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
+
+       // FIXME: Use shared signatures
+       mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out_sig", MONO_WRAPPER_UNKNOWN);
+
+       if (sig->ret->type != MONO_TYPE_VOID)
+               /* Load return address */
+               mono_mb_emit_ldarg (mb, sig->hasthis ? 1 : 0);
+
+       /* Make the call */
+       if (sig->hasthis)
+               mono_mb_emit_ldarg (mb, 0);
+       for (i = 0; i < sig->param_count; i++) {
+               if (sig->params [i]->byref) {
+                       mono_mb_emit_ldarg (mb, args_start + i);
+               } else {
+                       ldind_op = mono_type_to_ldind (sig->params [i]);
+                       mono_mb_emit_ldarg (mb, args_start + i);
+                       // FIXME:
+                       if (ldind_op == CEE_LDOBJ)
+                               mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
+                       else
+                               mono_mb_emit_byte (mb, ldind_op);
+               }
+       }
+       /* Rgctx arg */
+       mono_mb_emit_ldarg (mb, args_start + sig->param_count);
+       mono_mb_emit_icon (mb, sizeof (gpointer));
+       mono_mb_emit_byte (mb, CEE_ADD);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       /* Method to call */
+       mono_mb_emit_ldarg (mb, args_start + sig->param_count);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_calli (mb, normal_sig);
+       if (sig->ret->type != MONO_TYPE_VOID) {
+               /* Store return value */
+               stind_op = mono_type_to_stind (sig->ret);
+               // FIXME:
+               if (stind_op == CEE_STOBJ)
+                       mono_mb_emit_op (mb, CEE_STOBJ, mono_class_from_mono_type (sig->ret));
+               else
+                       mono_mb_emit_byte (mb, stind_op);
+       }
+       mono_mb_emit_byte (mb, CEE_RET);
+
+       info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG);
+       info->d.gsharedvt.sig = sig;
+
+       res = mono_mb_create (mb, csig, sig->param_count + 16, info);
+
+       // FIXME: Locking
+       g_hash_table_insert (cache, sig, res);
+
+       return res;
+}
+
 /*
  * mini_get_gsharedvt_wrapper:
  *
@@ -1043,6 +1306,17 @@ mini_get_gsharedvt_wrapper (gboolean gsharedvt_in, gpointer addr, MonoMethodSign
                inited = TRUE;
        }
 
+       if (mono_llvm_only) {
+               MonoMethod *wrapper;
+
+               if (gsharedvt_in)
+                       wrapper = mini_get_gsharedvt_in_sig_wrapper (normal_sig);
+               else
+                       wrapper = mini_get_gsharedvt_out_sig_wrapper (normal_sig);
+               res = mono_compile_method (wrapper);
+               return res;
+       }
+
        memset (&tinfo, 0, sizeof (tinfo));
        tinfo.is_in = gsharedvt_in;
        tinfo.calli = calli;
@@ -1166,10 +1440,20 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
        case MONO_RGCTX_INFO_METHOD:
                return data;
        case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
+               MonoMethod *m = (MonoMethod*)data;
                gpointer addr;
+               gpointer arg = NULL;
+
+               if (mono_llvm_only) {
+                       addr = mono_compile_method (m);
+                       addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, FALSE, &arg);
 
-               addr = mono_compile_method ((MonoMethod *)data);
-               return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
+                       /* Returns an ftndesc */
+                       return mini_create_llvmonly_ftndesc (addr, arg);
+               } else {
+                       addr = mono_compile_method ((MonoMethod *)data);
+                       return mini_add_method_trampoline ((MonoMethod *)data, addr, mono_method_needs_static_rgctx_invoke ((MonoMethod *)data, FALSE), FALSE);
+               }
        }
        case MONO_RGCTX_INFO_VIRT_METHOD_CODE: {
                MonoJumpInfoVirtMethod *info = (MonoJumpInfoVirtMethod *)data;
@@ -1337,14 +1621,28 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
                        sig = mono_method_signature (method);
                        gsig = call_sig;
 
-                       addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
+                       if (mono_llvm_only) {
+                               if (mini_is_gsharedvt_variable_signature (call_sig)) {
+                                       /* The virtual case doesn't go through this code */
+                                       g_assert (!virtual_);
+
+                                       gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
+                                       gpointer *out_wrapper_arg = mini_create_llvmonly_ftndesc (callee_ji->code_start, mini_method_get_rgctx (method));
+
+                                       /* Returns an ftndesc */
+                                       addr = mini_create_llvmonly_ftndesc (out_wrapper, out_wrapper_arg);
+                               } else {
+                                       addr = mini_create_llvmonly_ftndesc (addr, mini_method_get_rgctx (method));
+                               }
+                       } else {
+                               addr = mini_get_gsharedvt_wrapper (FALSE, addr, sig, gsig, vcall_offset, FALSE);
+                       }
 #if 0
                        if (virtual)
                                printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
                        else
                                printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
 #endif
-                       //              } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && callee_gsharedvt) {
                } else if (callee_gsharedvt) {
                        MonoMethodSignature *sig, *gsig;
 
@@ -1364,7 +1662,33 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
                         * FIXME: Optimize this.
                         */
 
-                       if (call_sig == mono_method_signature (method)) {
+                       if (mono_llvm_only) {
+                               /* Both wrappers receive an extra <addr, rgctx> argument */
+                               sig = mono_method_signature (method);
+                               gsig = mono_method_signature (jinfo_get_method (callee_ji));
+
+                               /* Return a function descriptor */
+
+                               if (mini_is_gsharedvt_variable_signature (call_sig)) {
+                                       /*
+                                        * This is not an optimization, but its needed, since the concrete signature 'sig'
+                                        * might not exist at all in IL, so the AOT compiler cannot generate the wrappers
+                                        * for it.
+                                        */
+                                       addr = mini_create_llvmonly_ftndesc (callee_ji->code_start, mini_method_get_rgctx (method));
+                               } else if (mini_is_gsharedvt_variable_signature (gsig)) {
+                                       gpointer in_wrapper = mini_get_gsharedvt_wrapper (TRUE, callee_ji->code_start, sig, gsig, -1, FALSE);
+
+                                       gpointer in_wrapper_arg = mini_create_llvmonly_ftndesc (callee_ji->code_start, mini_method_get_rgctx (method));
+
+                                       gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, sig, gsig, -1, FALSE);
+                                       gpointer *out_wrapper_arg = mini_create_llvmonly_ftndesc (in_wrapper, in_wrapper_arg);
+
+                                       addr = mini_create_llvmonly_ftndesc (out_wrapper, out_wrapper_arg);
+                               } else {
+                                       addr = mini_create_llvmonly_ftndesc (addr, mini_method_get_rgctx (method));
+                               }
+                       } else if (call_sig == mono_method_signature (method)) {
                        } else {
                                sig = mono_method_signature (method);
                                gsig = mono_method_signature (jinfo_get_method (callee_ji)); 
@@ -2558,6 +2882,8 @@ mini_type_get_underlying_type (MonoType *type)
                return &mono_defaults.byte_class->byval_arg;
        case MONO_TYPE_CHAR:
                return &mono_defaults.uint16_class->byval_arg;
+       case MONO_TYPE_STRING:
+               return &mono_defaults.object_class->byval_arg;
        default:
                return type;
        }
@@ -2638,7 +2964,7 @@ gboolean
 mini_type_var_is_vt (MonoType *type)
 {
        if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
-               return type->data.generic_param->gshared_constraint && type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE;
+               return type->data.generic_param->gshared_constraint && (type->data.generic_param->gshared_constraint->type == MONO_TYPE_VALUETYPE || type->data.generic_param->gshared_constraint->type == MONO_TYPE_GENERICINST);
        } else {
                g_assert_not_reached ();
                return FALSE;
index 9cf0f042c8f0b86759d1dea1ee1e4f5a56cc2b18..3cfe4ef03c2249861a02166b70d136a2d84b3077 100644 (file)
@@ -3474,7 +3474,9 @@ register_icalls (void)
        register_icall (mono_aot_init_gshared_method_rgctx, "mono_aot_init_gshared_method_rgctx", "void ptr int ptr", TRUE);
 
        register_icall_no_wrapper (mono_resolve_iface_call, "mono_resolve_iface_call", "ptr object int ptr ptr");
-       register_icall_no_wrapper (mono_resolve_vcall, "mono_resolve_vcall", "ptr object int ptr");
+       register_icall_no_wrapper (mono_resolve_vcall, "mono_resolve_vcall", "ptr object int ptr ptr");
+       register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
+       register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
        register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE);
        register_icall (mono_init_delegate_virtual, "mono_init_delegate_virtual", "void object object ptr", TRUE);
        register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
index b9790e99681a5d03fe9ef348e7bfb13259910bdc..8c13ef0aa2f7d6b56d480e41bcc16ca20dce7a95 100644 (file)
@@ -328,7 +328,7 @@ mini_add_method_trampoline (MonoMethod *m, gpointer compiled_method, gboolean ad
        addr = compiled_method;
 
        if (add_unbox_tramp) {
-               /* 
+               /*
                 * The unbox trampolines call the method directly, so need to add
                 * an rgctx tramp before them.
                 */
@@ -353,6 +353,8 @@ mini_add_method_trampoline (MonoMethod *m, gpointer compiled_method, gboolean ad
 
                addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, -1, FALSE);
 
+               if (mono_llvm_only)
+                       g_assert_not_reached ();
                //printf ("IN: %s\n", mono_method_full_name (m, TRUE));
        }
 
@@ -375,6 +377,129 @@ mini_add_method_trampoline (MonoMethod *m, gpointer compiled_method, gboolean ad
        return addr;
 }
 
+/*
+ * mini_create_llvmonly_ftndesc:
+ *
+ *   Create a function descriptor of the form <addr, arg>, which
+ * represents a callee ADDR with ARG as the last argument.
+ * This is used for:
+ * - generic sharing (ARG is the rgctx)
+ * - gsharedvt signature wrappers (ARG is a function descriptor)
+ */
+gpointer
+mini_create_llvmonly_ftndesc (gpointer addr, gpointer arg)
+{
+       gpointer *res;
+
+       // FIXME: Memory management
+       res = g_malloc0 (2 * sizeof (gpointer));
+       res [0] = addr;
+       res [1] = arg;
+
+       return res;
+}
+
+/**
+ * mini_add_method_wrappers_llvmonly:
+ *
+ *   Add unbox/gsharedvt wrappers around COMPILED_METHOD if needed. Return the wrapper address or COMPILED_METHOD
+ * if no wrapper is needed. Set OUT_ARG to the rgctx/extra argument needed to be passed to the returned method.
+ */
+gpointer
+mini_add_method_wrappers_llvmonly (MonoMethod *m, gpointer compiled_method, gboolean caller_gsharedvt, gboolean add_unbox_tramp, gpointer *out_arg)
+{
+       gpointer addr = compiled_method;
+       gboolean callee_gsharedvt, callee_array_helper;
+       MonoMethod *jmethod = NULL;
+       MonoJitInfo *ji;
+
+       // FIXME: This loads information from AOT (perf problem)
+       ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
+       callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
+
+       callee_array_helper = FALSE;
+       if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (m);
+
+               /*
+                * generic array helpers.
+                * Have to replace the wrappers with the original generic instances.
+                */
+               if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) {
+                       callee_array_helper = TRUE;
+                       m = info->d.generic_array_helper.method;
+               }
+       } else if (m->wrapper_type == MONO_WRAPPER_UNKNOWN) {
+               WrapperInfo *info = mono_marshal_get_wrapper_info (m);
+
+               /* Same for synchronized inner wrappers */
+               if (info && info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
+                       m = info->d.synchronized_inner.method;
+               }
+       }
+
+       if (callee_gsharedvt)
+               g_assert (m->is_inflated);
+
+       addr = compiled_method;
+
+       if (add_unbox_tramp) {
+               /* 
+                * The unbox trampolines call the method directly, so need to add
+                * an rgctx tramp before them.
+                */
+               if (mono_aot_only) {
+                       addr = mono_aot_get_unbox_trampoline (m);
+               } else {
+                       unbox_trampolines ++;
+                       addr = mono_arch_get_unbox_trampoline (m, addr);
+               }
+       }
+
+       g_assert (mono_llvm_only);
+       g_assert (out_arg);
+
+       if (ji && !ji->is_trampoline)
+               jmethod = jinfo_get_method (ji);
+       if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod))) {
+               MonoMethodSignature *sig, *gsig;
+
+               /* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */
+
+               /* Call from normal/gshared code to gsharedvt code with variable signature */
+               sig = mono_method_signature (m);
+               gsig = mono_method_signature (jmethod);
+
+               addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, -1, FALSE);
+
+               /*
+                * This is a gsharedvt in wrapper, it gets passed a ftndesc for the gsharedvt method as an argument.
+                */
+               *out_arg = mini_create_llvmonly_ftndesc (compiled_method, mini_method_get_rgctx (m));
+               //printf ("IN: %s\n", mono_method_full_name (m, TRUE));
+       }
+
+       if (!(*out_arg) && mono_method_needs_static_rgctx_invoke (m, FALSE))
+               *out_arg = mini_method_get_rgctx (m);
+
+       if (caller_gsharedvt) {
+               /*
+                * The callee uses the gsharedvt calling convention, have to add an out wrapper.
+                */
+               g_assert (*out_arg);
+
+               gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, mono_method_signature (m), NULL, -1, FALSE);
+               gpointer *out_wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
+               out_wrapper_arg [0] = addr;
+               out_wrapper_arg [1] = *out_arg;
+
+               addr = out_wrapper;
+               *out_arg = out_wrapper_arg;
+       }
+
+       return addr;
+}
+
 /**
  * common_call_trampoline:
  *
index c8183d3c7934c6850295320eb9eb60ef830169f6..3bb28e96d2d77d8280c3a41e668975b848103a33 100644 (file)
@@ -1169,6 +1169,7 @@ typedef enum {
        MONO_RGCTX_INFO_TYPE,
        MONO_RGCTX_INFO_REFLECTION_TYPE,
        MONO_RGCTX_INFO_METHOD,
+       /* In llvmonly mode, this is a function descriptor */
        MONO_RGCTX_INFO_GENERIC_METHOD_CODE,
        MONO_RGCTX_INFO_CLASS_FIELD,
        MONO_RGCTX_INFO_METHOD_RGCTX,
@@ -1181,8 +1182,10 @@ typedef enum {
        /* +1 to avoid zero values in rgctx slots */
        MONO_RGCTX_INFO_FIELD_OFFSET,
        /* Either the code for a gsharedvt method, or the address for a gsharedvt-out trampoline for the method */
+       /* In llvmonly mode, this is a function descriptor */
        MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE,
        /* Same for virtual calls */
+       /* In llvmonly mode, this is a function descriptor */
        MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT,
        /* Same for calli, associated with a signature */
        MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI,
@@ -1194,6 +1197,7 @@ typedef enum {
        MONO_RGCTX_INFO_MEMCPY,
        MONO_RGCTX_INFO_BZERO,
        /* The address of Nullable<T>.Box () */
+       /* In llvmonly mode, this is a function descriptor */
        MONO_RGCTX_INFO_NULLABLE_CLASS_BOX,
        MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX,
        /* MONO_PATCH_INFO_VCALL_METHOD */