Skip to content

Commit d76f307

Browse files
committed
Handle ref returns in runtime invoke wrappers (case 1076527)
Indirectly load ref return values in invoke wrappers and return by value. Don't share wrappers with ref returns since indirect load is used. Add soft debugger support for methods with ref returns.
1 parent 2195b96 commit d76f307

File tree

4 files changed

+64
-14
lines changed

4 files changed

+64
-14
lines changed

mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ public static int Main (String[] args) {
350350
set_ip ();
351351
step_filters ();
352352
pointers ();
353+
ref_return ();
353354
if (args.Length > 0 && args [0] == "local-reflect")
354355
local_reflect ();
355356
if (args.Length > 0 && args [0] == "domain-test")
@@ -1739,6 +1740,21 @@ public static unsafe void pointers () {
17391740
fixed (int* pa = a)
17401741
pointer_arguments (pa, &s);
17411742
}
1743+
1744+
[MethodImplAttribute (MethodImplOptions.NoInlining)]
1745+
public static void ref_return () {
1746+
1747+
}
1748+
1749+
static int ret_val = 1;
1750+
public static ref int get_ref_int() {
1751+
return ref ret_val;
1752+
}
1753+
1754+
static string ref_return_string = "byref";
1755+
public static ref string get_ref_string() {
1756+
return ref ref_return_string;
1757+
}
17421758
}
17431759

17441760
public class SentinelClass : MarshalByRefObject {

mcs/class/Mono.Debugger.Soft/Test/dtest.cs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4398,15 +4398,31 @@ public void Pointer_GetValue () {
43984398
}
43994399

44004400
[Test]
4401-
public void InvokeGenericMethod () {
4402-
Event e = run_until ("bp1");
4403-
StackFrame frame = e.Thread.GetFrames()[0];
4404-
TypeMirror t = frame.Method.DeclaringType;
4405-
MethodMirror m;
4406-
m = t.GetMethod ("generic_method");
4407-
AssertThrows<ArgumentException> (delegate {
4408-
t.InvokeMethod (e.Thread, m, null);
4409-
});
4410-
}
4401+
public void InvokeGenericMethod () {
4402+
Event e = run_until ("bp1");
4403+
StackFrame frame = e.Thread.GetFrames()[0];
4404+
TypeMirror t = frame.Method.DeclaringType;
4405+
MethodMirror m;
4406+
m = t.GetMethod ("generic_method");
4407+
AssertThrows<ArgumentException> (delegate {
4408+
t.InvokeMethod (e.Thread, m, null);
4409+
});
4410+
}
4411+
4412+
[Test]
4413+
public void InvokeRefReturnMethod () {
4414+
Event e = run_until ("ref_return");
4415+
StackFrame frame = e.Thread.GetFrames()[0];
4416+
TypeMirror t = frame.Method.DeclaringType;
4417+
MethodMirror m;
4418+
4419+
m = t.GetMethod ("get_ref_int");
4420+
var v = t.InvokeMethod (e.Thread, m, null);
4421+
AssertValue (1, v);
4422+
4423+
m = t.GetMethod ("get_ref_string");
4424+
v = t.InvokeMethod (e.Thread, m, null);
4425+
AssertValue ("byref", v);
4426+
}
44114427
} // class DebuggerTests
44124428
} // namespace

mono/metadata/marshal.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3936,6 +3936,11 @@ get_runtime_invoke_type (MonoType *t, gboolean ret)
39363936
if (t->byref) {
39373937
if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
39383938
return t;
3939+
3940+
/* The result needs loaded indirectly */
3941+
if (ret)
3942+
return t;
3943+
39393944
/* Can't share this with 'I' as that needs another indirection */
39403945
return &mono_defaults.int_class->this_arg;
39413946
}
@@ -4143,8 +4148,10 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method,
41434148
}
41444149

41454150
if (sig->ret->byref) {
4146-
/* fixme: */
4147-
g_assert_not_reached ();
4151+
/* perform indirect load and return by value */
4152+
MonoType* ret_byval = &mono_class_from_mono_type (sig->ret)->byval_arg;
4153+
g_assert (!ret_byval->byref);
4154+
mono_mb_emit_byte (mb, mono_type_to_ldind (ret_byval));
41484155
}
41494156

41504157
switch (sig->ret->type) {

mono/mini/debugger-agent.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8366,7 +8366,12 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
83668366
buffer_add_value (buf, &VM_DEFAULTS_VOID_CLASS->byval_arg, NULL, domain);
83678367
}
83688368
} else if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
8369-
buffer_add_value (buf, sig->ret, &res, domain);
8369+
if (sig->ret->byref) {
8370+
MonoType* ret_byval = &mono_class_from_mono_type (sig->ret)->byval_arg;
8371+
buffer_add_value (buf, ret_byval, &res, domain);
8372+
} else {
8373+
buffer_add_value (buf, sig->ret, &res, domain);
8374+
}
83708375
} else if (mono_class_from_mono_type (sig->ret)->valuetype || sig->ret->type == MONO_TYPE_PTR || sig->ret->type == MONO_TYPE_FNPTR) {
83718376
if (mono_class_is_nullable (mono_class_from_mono_type (sig->ret))) {
83728377
MonoClass *k = mono_class_from_mono_type (sig->ret);
@@ -8377,7 +8382,13 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
83778382
buffer_add_value (buf, sig->ret, nullable_buf, domain);
83788383
} else {
83798384
g_assert (res);
8380-
buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain);
8385+
8386+
if (sig->ret->byref) {
8387+
MonoType* ret_byval = &mono_class_from_mono_type (sig->ret)->byval_arg;
8388+
buffer_add_value (buf, ret_byval, mono_object_unbox (res), domain);
8389+
} else {
8390+
buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain);
8391+
}
83818392
}
83828393
} else {
83838394
NOT_IMPLEMENTED;

0 commit comments

Comments
 (0)