+static RuntimeInvokeInfo*
+create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt)
+{
+ MonoMethod *invoke;
+ RuntimeInvokeInfo *info;
+
+ info = g_new0 (RuntimeInvokeInfo, 1);
+ info->compiled_method = compiled_method;
+ info->sig = mono_method_signature (method);
+
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+ info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
+ g_assert (info->vtable);
+
+ MonoMethodSignature *sig = mono_method_signature (method);
+ MonoType *ret_type;
+
+ /*
+ * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
+ * in full-aot mode, so we use a slower, but more generic wrapper if
+ * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
+ */
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+ if (!mono_llvm_only && (mono_aot_only || debug_options.dyn_runtime_invoke)) {
+ gboolean supported = TRUE;
+ int i;
+
+ if (method->string_ctor)
+ sig = mono_marshal_get_string_ctor_signature (method);
+
+ 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 (mono_class_is_contextbound (method->klass) || !info->compiled_method)
+ supported = FALSE;
+
+ if (supported)
+ info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
+ }
+#endif
+
+ ret_type = sig->ret;
+ switch (ret_type->type) {
+ case MONO_TYPE_VOID:
+ break;
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ info->ret_box_class = mono_class_from_mono_type (ret_type);
+ break;
+ case MONO_TYPE_PTR:
+ info->ret_box_class = mono_defaults.int_class;
+ break;
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_OBJECT:
+ break;
+ case MONO_TYPE_GENERICINST:
+ if (!MONO_TYPE_IS_REFERENCE (ret_type))
+ info->ret_box_class = mono_class_from_mono_type (ret_type);
+ break;
+ case MONO_TYPE_VALUETYPE:
+ info->ret_box_class = mono_class_from_mono_type (ret_type);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (!info->dyn_call_info) {
+ if (mono_llvm_only) {
+#ifndef ENABLE_GSHAREDVT
+ g_assert_not_reached ();
+#endif
+ info->gsharedvt_invoke = TRUE;
+ if (!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->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
+ info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
+
+ /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
+ invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
+ g_free (wrapper_sig);
+
+ info->compiled_method = mono_jit_compile_method (wrapper);
+ } else {
+ /* 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->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);
+ }
+
+ return info;
+}
+
+static MonoObject*
+mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc)
+{
+ MonoMethodSignature *sig = info->sig;
+ MonoDomain *domain = mono_domain_get ();
+ MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
+ gpointer *args;
+ gpointer retval_ptr;
+ guint8 retval [256];
+ gpointer *param_refs;
+ int i, pindex;
+
+ g_assert (info->gsharedvt_invoke);
+
+ /*
+ * Instead of invoking the method directly, we invoke a gsharedvt out wrapper.
+ * 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));
+ pindex = 0;
+ /*
+ * The runtime invoke wrappers expects pointers to primitive types, so have to
+ * use indirections.
+ */
+ if (sig->hasthis)
+ args [pindex ++] = &obj;
+ if (sig->ret->type != MONO_TYPE_VOID) {
+ retval_ptr = (gpointer)&retval;
+ args [pindex ++] = &retval_ptr;
+ }
+ 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 (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
+ param_refs [i] = params [i];
+ params [i] = &(param_refs [i]);
+ }
+ args [pindex ++] = ¶ms [i];
+ }
+ /* The gsharedvt out wrapper has an extra argument which contains the method to call */
+ args [pindex ++] = &info->wrapper_arg;
+
+ runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
+
+ 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);
+ else
+ return *(MonoObject**)retval;
+}
+