Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 54 additions & 3 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,48 @@ stackval_to_data (MonoType *type, stackval *val, void *data, gboolean pinvoke)
}
}

static void
stackval_to_data_sign_ext (MonoType *type, stackval *val, void *data, gboolean pinvoke)
{
switch (type->type) {
case MONO_TYPE_I1: {
mono_i *p = (mono_i*)data;
*p = (mono_i)((gint8)val->data.i);
break;
}
case MONO_TYPE_U1: {
mono_u *p = (mono_u*)data;
*p = (mono_u)((guint8)val->data.i);
break;
}
case MONO_TYPE_I2: {
mono_i *p = (mono_i*)data;
*p = (mono_i)((gint16)val->data.i);
break;
}
case MONO_TYPE_U2: {
mono_u *p = (mono_u*)data;
*p = (mono_u)((guint16)val->data.i);
break;
}
#if SIZEOF_VOID_P == 8
case MONO_TYPE_I4: {
mono_i *p = (mono_i*)data;
*p = (mono_i)(val->data.i);
break;
}
case MONO_TYPE_U4: {
mono_u *p = (mono_u*)data;
*p = (mono_u)((guint32)val->data.i);
break;
}
#endif
default:
stackval_to_data (type, val, data, pinvoke);
break;
}
}

typedef struct {
MonoException *ex;
MonoContext *ctx;
Expand Down Expand Up @@ -1651,7 +1693,7 @@ interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig,

// If index == -1, we finished executing an InterpFrame and the result is at retval.
if (index == -1)
stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke && !sig->marshalling_disabled);
stackval_to_data_sign_ext (sig->ret, iframe->retval, data, sig->pinvoke && !sig->marshalling_disabled);
else if (sig->hasthis && index == 0)
*(gpointer*)data = iframe->stack->data.p;
else
Expand Down Expand Up @@ -2353,8 +2395,17 @@ interp_entry (InterpEntryData *data)

// The return value is at the bottom of the stack, after the locals space
type = rmethod->rtype;
if (type->type != MONO_TYPE_VOID)
stackval_to_data (type, frame.stack, data->res, FALSE);
if (type->type != MONO_TYPE_VOID) {
// interp entry is called either from a interp_in wrapper or a gsharedvt_in_sig wrapper
// interp_in wrappers always return intptr (they are more aggresively shared) while the
// gsharedvt_in_sig wrapper returns the actual type. This check follows the logic in
// interp_create_method_pointer_llvmonly and interp_create_method_pointer so we do the
// return sign extension only when called from the interp_in wrapper.
if (!mono_llvm_only || sig->param_count > MAX_INTERP_ENTRY_ARGS)
stackval_to_data_sign_ext (type, frame.stack, data->res, FALSE);
else
stackval_to_data (type, frame.stack, data->res, FALSE);
}
}

static void
Expand Down
Loading