[llvmonly] Add support for runtime invokes with nullable arguments.
[mono.git] / mono / mini / mini-runtime.c
index 9f62e40fd0dcc5ae65759afac63d8547c34ca03b..91bc9018668a915c7243bc4e08e826015c7cb82a 100644 (file)
@@ -2153,6 +2153,7 @@ typedef struct {
        MonoClass *ret_box_class;
        gboolean needs_rgctx;
        MonoMethodSignature *sig;
+       gboolean gsharedvt_invoke;
        gpointer *wrapper_arg;
 } RuntimeInvokeInfo;
 
@@ -2160,20 +2161,15 @@ gboolean
 mini_gsharedvt_runtime_invoke_supported (MonoMethodSignature *sig)
 {
        gboolean supported = TRUE;
-       int i;
 
-       for (i = 0; i < sig->param_count; ++i) {
-               MonoType *t = sig->params [i];
-
-               if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
-                       supported = FALSE;
-       }
+       if (sig->ret->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (sig->ret)))
+               supported = FALSE;
 
        return supported;
 }
 
 static RuntimeInvokeInfo*
-create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method)
+create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt)
 {
        MonoMethod *invoke;
        RuntimeInvokeInfo *info;
@@ -2271,12 +2267,12 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com
 #ifndef ENABLE_GSHAREDVT
                        supported = FALSE;
 #endif
-
-                       if (supported) {
+                       if (supported && !callee_gsharedvt) {
                                /* Invoke a gsharedvt out wrapper instead */
                                MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
                                MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
 
+                               info->gsharedvt_invoke = TRUE;
                                info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
                                info->wrapper_arg [0] = info->compiled_method;
                                info->wrapper_arg [1] = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
@@ -2286,6 +2282,16 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com
                                g_free (wrapper_sig);
 
                                info->compiled_method = mono_jit_compile_method (wrapper);
+                       } else if (supported) {
+                               /* Gsharedvt methods can be invoked the same way */
+                               /* The out wrapper has the same signature as the compiled gsharedvt method */
+                               MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
+
+                               info->gsharedvt_invoke = TRUE;
+                               info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
+
+                               invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
+                               g_free (wrapper_sig);
                        }
                }
                info->runtime_invoke = mono_jit_compile_method (invoke);
@@ -2309,6 +2315,8 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        MonoDomain *domain = mono_domain_get ();
        MonoJitDomainInfo *domain_info;
        RuntimeInvokeInfo *info, *info2;
+       MonoJitInfo *ji = NULL;
+       gboolean callee_gsharedvt = FALSE;
 
        if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
                g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
@@ -2373,12 +2381,18 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                                }
                        }
 
-                       compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
+                       if (mono_llvm_only) {
+                               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);
+                       }
+
+                       if (!callee_gsharedvt)
+                               compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE);
                } else {
                        compiled_method = NULL;
                }
 
-               info = create_runtime_invoke_info (domain, method, compiled_method);
+               info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt);
 
                mono_domain_lock (domain);
                info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
@@ -2458,7 +2472,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
 
        runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
 
-       if (info->wrapper_arg) {
+       if (info->gsharedvt_invoke) {
                MonoMethodSignature *sig = mono_method_signature (method);
                gpointer *args;
                gpointer retval_ptr;
@@ -2471,6 +2485,8 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                 * The advantage of this is the gsharedvt out wrappers have a reduced set of
                 * signatures, so we only have to generate runtime invoke wrappers for these
                 * signatures.
+                * This code also handles invocation of gsharedvt methods directly, no
+                * out wrappers are used in that case.
                 */
                args = (void **)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
                param_refs = (gpointer*)g_alloca ((sig->param_count + sig->hasthis + 2) * sizeof (gpointer));
@@ -2488,6 +2504,20 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                for (i = 0; i < sig->param_count; ++i) {
                        MonoType *t = sig->params [i];
 
+                       if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+                               MonoClass *klass = mono_class_from_mono_type (t);
+                               guint8 *nullable_buf;
+                               int size;
+
+                               size = mono_class_value_size (klass, NULL);
+                               nullable_buf = g_alloca (size);
+                               g_assert (nullable_buf);
+
+                               /* The argument pointed to by params [i] is either a boxed vtype or null */
+                               mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass);
+                               params [i] = nullable_buf;
+                       }
+
                        if (MONO_TYPE_IS_REFERENCE (t)) {
                                param_refs [i] = params [i];
                                params [i] = &(param_refs [i]);
@@ -2499,7 +2529,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                runtime_invoke (NULL, args, exc, info->compiled_method);
 
                if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
-                               return mono_value_box (domain, info->ret_box_class, retval);
+                       return mono_value_box (domain, info->ret_box_class, retval);
                else
                        return *(MonoObject**)retval;
        }
@@ -2993,7 +3023,7 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met
        is_interface = method->klass->flags & TYPE_ATTRIBUTE_INTERFACE ? TRUE : FALSE;
        load_imt_reg = is_virtual_generic || is_interface;
 
-       if (is_interface && !is_virtual_generic)
+       if (is_interface)
                offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
        else
                offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));