@@ -2998,6 +2998,8 @@ typedef struct {
29982998 gpointer * wrapper_arg ;
29992999} RuntimeInvokeInfo ;
30003000
3001+ #define MONO_SIZEOF_DYN_CALL_RET_BUF 256
3002+
30013003static RuntimeInvokeInfo *
30023004create_runtime_invoke_info (MonoMethod * method , gpointer compiled_method , gboolean callee_gsharedvt , gboolean use_interp , MonoError * error )
30033005{
@@ -3156,8 +3158,9 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
31563158{
31573159 MonoMethodSignature * sig = info -> sig ;
31583160 MonoObject * (* runtime_invoke ) (MonoObject * this_obj , void * * params , MonoObject * * exc , void * compiled_method );
3161+ gboolean retval_malloc = FALSE;
31593162 gpointer retval_ptr ;
3160- guint8 retval [256 ];
3163+ guint8 retval [MONO_SIZEOF_DYN_CALL_RET_BUF ];
31613164 int i , pindex ;
31623165
31633166 error_init (error );
@@ -3184,7 +3187,21 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
31843187 if (sig -> hasthis )
31853188 args [pindex ++ ] = & obj ;
31863189 if (sig -> ret -> type != MONO_TYPE_VOID ) {
3187- retval_ptr = & retval ;
3190+ if (info -> ret_box_class && !sig -> ret -> byref &&
3191+ (sig -> ret -> type == MONO_TYPE_VALUETYPE ||
3192+ (sig -> ret -> type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (sig -> ret )))) {
3193+ // if the return type is a struct and its too big for the stack buffer, malloc instead
3194+ MonoClass * ret_klass = mono_class_from_mono_type_internal (sig -> ret );
3195+ g_assert (!mono_class_has_failure (ret_klass ));
3196+ int32_t inst_size = mono_class_instance_size (ret_klass );
3197+ if (inst_size > MONO_SIZEOF_DYN_CALL_RET_BUF ) {
3198+ retval_malloc = TRUE;
3199+ retval_ptr = g_new0 (guint8 , inst_size );
3200+ g_assert (retval_ptr );
3201+ }
3202+ }
3203+ if (!retval_malloc )
3204+ retval_ptr = & retval ;
31883205 args [pindex ++ ] = & retval_ptr ;
31893206 }
31903207 for (i = 0 ; i < sig -> param_count ; ++ i ) {
@@ -3234,7 +3251,10 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
32343251 if (sig -> ret -> byref ) {
32353252 return mono_value_box_checked (info -> ret_box_class , * (gpointer * )retval , error );
32363253 } else {
3237- return mono_value_box_checked (info -> ret_box_class , retval , error );
3254+ MonoObject * ret = mono_value_box_checked (info -> ret_box_class , retval_ptr , error );
3255+ if (retval_malloc )
3256+ g_free (retval_ptr );
3257+ return ret ;
32383258 }
32393259 } else {
32403260 if (sig -> ret -> byref )
@@ -3397,7 +3417,25 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
33973417 gpointer * args ;
33983418 int i , pindex , buf_size ;
33993419 guint8 * buf ;
3400- guint8 retval [256 ];
3420+ guint8 retbuf [MONO_SIZEOF_DYN_CALL_RET_BUF ];
3421+ guint8 * retval = & retbuf [0 ];
3422+ gboolean retval_malloc = FALSE;
3423+
3424+ /* if the return value is too big, put it in a dynamically allocated temporary */
3425+ if (info -> ret_box_class && !sig -> ret -> byref &&
3426+ (sig -> ret -> type == MONO_TYPE_VALUETYPE ||
3427+ (sig -> ret -> type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (sig -> ret )))) {
3428+ // if the return type is a struct and its too big for the stack buffer, malloc instead
3429+ MonoClass * ret_klass = mono_class_from_mono_type_internal (sig -> ret );
3430+ g_assert (!mono_class_has_failure (ret_klass ));
3431+ int32_t inst_size = mono_class_instance_size (ret_klass );
3432+ if (inst_size > MONO_SIZEOF_DYN_CALL_RET_BUF ) {
3433+ retval_malloc = TRUE;
3434+ retval = g_new0 (guint8 , inst_size );
3435+ g_assert (retval );
3436+ }
3437+ }
3438+
34013439
34023440 /* Convert the arguments to the format expected by start_dyn_call () */
34033441 args = (void * * )g_alloca ((sig -> param_count + sig -> hasthis ) * sizeof (gpointer ));
@@ -3433,10 +3471,31 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
34333471 return NULL ;
34343472 }
34353473
3436- if (info -> ret_box_class )
3437- return mono_value_box_checked (info -> ret_box_class , retval , error );
3438- else
3439- return * (MonoObject * * )retval ;
3474+ if (sig -> ret -> byref ) {
3475+ if (* (gpointer * )retval == NULL ) {
3476+ MonoClass * klass = mono_class_get_nullbyrefreturn_ex_class ();
3477+ MonoObject * ex = mono_object_new_checked (klass , error );
3478+ mono_error_assert_ok (error );
3479+ mono_error_set_exception_instance (error , (MonoException * )ex );
3480+ return NULL ;
3481+ }
3482+ }
3483+
3484+ if (info -> ret_box_class ) {
3485+ if (sig -> ret -> byref ) {
3486+ return mono_value_box_checked (info -> ret_box_class , * (gpointer * )retval , error );
3487+ } else {
3488+ MonoObject * boxed_ret = mono_value_box_checked (info -> ret_box_class , retval , error );
3489+ if (retval_malloc )
3490+ g_free (retval );
3491+ return boxed_ret ;
3492+ }
3493+ } else {
3494+ if (sig -> ret -> byref )
3495+ return * * (MonoObject * * * )retval ;
3496+ else
3497+ return * (MonoObject * * )retval ;
3498+ }
34403499 }
34413500#endif
34423501
0 commit comments