@@ -2998,6 +2998,8 @@ typedef struct {
2998
2998
gpointer * wrapper_arg ;
2999
2999
} RuntimeInvokeInfo ;
3000
3000
3001
+ #define MONO_SIZEOF_DYN_CALL_RET_BUF 256
3002
+
3001
3003
static RuntimeInvokeInfo *
3002
3004
create_runtime_invoke_info (MonoMethod * method , gpointer compiled_method , gboolean callee_gsharedvt , gboolean use_interp , MonoError * error )
3003
3005
{
@@ -3156,8 +3158,9 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
3156
3158
{
3157
3159
MonoMethodSignature * sig = info -> sig ;
3158
3160
MonoObject * (* runtime_invoke ) (MonoObject * this_obj , void * * params , MonoObject * * exc , void * compiled_method );
3161
+ gboolean retval_malloc = FALSE;
3159
3162
gpointer retval_ptr ;
3160
- guint8 retval [256 ];
3163
+ guint8 retval [MONO_SIZEOF_DYN_CALL_RET_BUF ];
3161
3164
int i , pindex ;
3162
3165
3163
3166
error_init (error );
@@ -3184,7 +3187,21 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
3184
3187
if (sig -> hasthis )
3185
3188
args [pindex ++ ] = & obj ;
3186
3189
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 ;
3188
3205
args [pindex ++ ] = & retval_ptr ;
3189
3206
}
3190
3207
for (i = 0 ; i < sig -> param_count ; ++ i ) {
@@ -3234,7 +3251,10 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
3234
3251
if (sig -> ret -> byref ) {
3235
3252
return mono_value_box_checked (info -> ret_box_class , * (gpointer * )retval , error );
3236
3253
} 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 ;
3238
3258
}
3239
3259
} else {
3240
3260
if (sig -> ret -> byref )
@@ -3397,7 +3417,25 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
3397
3417
gpointer * args ;
3398
3418
int i , pindex , buf_size ;
3399
3419
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
+
3401
3439
3402
3440
/* Convert the arguments to the format expected by start_dyn_call () */
3403
3441
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
3433
3471
return NULL ;
3434
3472
}
3435
3473
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
+ }
3440
3499
}
3441
3500
#endif
3442
3501
0 commit comments