+2008-05-05 Robert Jordan <robertj@gmx.net>
+
+ * marshal.c (mono_marshal_get_thunk_invoke_wrapper):
+ support for value types. See #386415.
+
+ * object.c: comments.
+
2008-05-05 Martin Baulig <martin@ximian.com>
* debug-mono-symfile.h
csig->call_convention = MONO_CALL_DEFAULT;
if (sig->hasthis) {
- /* "this" of value types is actually a ptr */
- csig->params [0] = klass->valuetype
- ? &mono_ptr_class_get (&klass->byval_arg)->byval_arg
- : &klass->byval_arg;
- /* shift params */
+ /* add "this" */
+ csig->params [0] = &klass->byval_arg;
+ /* move params up by one */
for (i = 0; i < sig->param_count; i++)
csig->params [i + 1] = sig->params [i];
}
csig->params [param_count - 1]->byref = 1;
csig->params [param_count - 1]->attrs = PARAM_ATTRIBUTE_OUT;
+ /* convert struct return to object */
+ if (MONO_TYPE_ISSTRUCT (sig->ret))
+ csig->ret = &mono_defaults.object_class->byval_arg;
+
/* local 0 (temp for exception object) */
mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
clause->try_offset = mono_mb_get_label (mb);
/* push method's args */
- for (i = 0; i < param_count - 1; i++)
+ for (i = 0; i < param_count - 1; i++) {
+ MonoType *type;
+ MonoClass *klass;
+
mono_mb_emit_ldarg (mb, i);
+ /* get the byval type of the param */
+ klass = mono_class_from_mono_type (csig->params [i]);
+ type = &klass->byval_arg;
+
+ /* unbox struct args */
+ if (MONO_TYPE_ISSTRUCT (type)) {
+ mono_mb_emit_op (mb, CEE_UNBOX, klass);
+
+ /* byref args & and the "this" arg must remain a ptr.
+ Otherwise make a copy of the value type */
+ if (!(csig->params [i]->byref || (i == 0 && sig->hasthis)))
+ mono_mb_emit_op (mb, CEE_LDOBJ, klass);
+
+ csig->params [i] = &mono_defaults.object_class->byval_arg;
+ }
+ }
+
/* call */
if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
mono_mb_emit_op (mb, CEE_CALLVIRT, method);
mono_mb_patch_branch (mb, pos_leave);
/* end-try */
- if (!MONO_TYPE_IS_VOID (sig->ret))
+ if (!MONO_TYPE_IS_VOID (sig->ret)) {
mono_mb_emit_ldloc (mb, 1);
+ /* box the return value */
+ if (MONO_TYPE_ISSTRUCT (sig->ret))
+ mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
+ }
+
mono_mb_emit_byte (mb, CEE_RET);
res = mono_mb_create_and_cache (cache, method, mb, csig, param_count + 16);
* The thunk's C signature closely matches the managed signature:
*
* C#: public bool Equals (object obj);
- * C: typedef MonoBoolean (*Equals)(MonoObject *this,
- * MonoObject *obj, MonoException **ex);
+ * C: typedef MonoBoolean (*Equals)(MonoObject*,
+ * MonoObject*, MonoException**);
*
- * The "this" parameter must not be used with static methods:
+ * The 1st ("this") parameter must not be used with static methods:
*
* C#: public static bool ReferenceEquals (object a, object b);
- * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject *a, MonoObject *b,
- * MonoException **ex);
+ * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
+ * MonoException**);
*
* The last argument must be a non-null pointer of a MonoException* pointer.
* It has "out" semantics. After invoking the thunk, *ex will be NULL if no
- * exception has been thrown in managed code. Otherwise, it will point
+ * exception has been thrown in managed code. Otherwise it will point
* to the MonoException* caught by the thunk. In this case, the result of
* the thunk is undefined:
*
* convention. This means that under Windows, C declarations must
* contain the __stdcall attribute:
*
- * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject *this,
- * MonoObject *obj, MonoException **ex);
+ * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
+ * MonoObject*, MonoException**);
+ *
+ * LIMITATIONS
+ *
+ * Value type arguments and return values are treated as they were objects:
+ *
+ * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
+ * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
+ *
+ * Arguments must be properly boxed upon trunk's invocation, while return
+ * values must be unboxed.
*/
gpointer
mono_method_get_unmanaged_thunk (MonoMethod *method)
+2008-05-05 Robert Jordan <robertj@gmx.net>
+
+ * libtest.c, thunks.cs: reworked to match the new struct
+ handling.
+
2008-05-06 Rodrigo Kumpera <rkumpera@novell.com>
* bug-382986.cs. bug-382986-lib.cs: Regression test for
* mono_method_get_unmanaged_thunk tests
*/
-
-#define NATIVE_ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
-#ifdef __GNUC__
-#define MANAGED_ALIGNMENT __alignof__
+#if defined(__GNUC__) && defined(__i386__) && (defined(__linux__) || defined (__APPLE__))
+#define ALIGN(size) __attribute__ ((aligned(size)))
#else
-#define MANAGED_ALIGNMENT NATIVE_ALIGNMENT
+#define ALIGN(size)
#endif
-#define SAME_ALIGNMENT(type) (NATIVE_ALIGNMENT(type) == MANAGED_ALIGNMENT(type))
/* thunks.cs:TestStruct */
typedef struct _TestStruct {
int A;
- double B;
+ double B ALIGN(8); /* align according to mono's struct layout */
} TestStruct;
/* Searches for mono symbols in all loaded modules */
/**
* test_method_thunk:
*
- * @id: the method number
+ * @test_id: the test number
* @test_method_handle: MonoMethod* of the C# test method
* @create_object_method_handle: MonoMethod* of thunks.cs:Test.CreateObject
*/
STDCALL int
-test_method_thunk (int id, gpointer test_method_handle, gpointer create_object_method_handle)
+test_method_thunk (int test_id, gpointer test_method_handle, gpointer create_object_method_handle)
{
gpointer (*mono_method_get_unmanaged_thunk)(gpointer)
= lookup_mono_symbol ("mono_method_get_unmanaged_thunk");
char* (*mono_string_to_utf8)(gpointer)
= lookup_mono_symbol ("mono_string_to_utf8");
+ gpointer (*mono_object_unbox)(gpointer)
+ = lookup_mono_symbol ("mono_object_unbox");
+
gpointer test_method, ex = NULL;
gpointer (STDCALL *CreateObject)(gpointer*);
return 3;
- switch (id) {
+ switch (test_id) {
case 0: {
- /* thunks.cs:Test.Foo0 */
+ /* thunks.cs:Test.Test0 */
void (STDCALL *F)(gpointer*) = test_method;
F (&ex);
break;
}
case 1: {
- /* thunks.cs:Test.Foo1 */
+ /* thunks.cs:Test.Test1 */
int (STDCALL *F)(gpointer*) = test_method;
if (F (&ex) != 42)
return 4;
}
case 2: {
- /* thunks.cs:Test.Foo2 */
+ /* thunks.cs:Test.Test2 */
gpointer (STDCALL *F)(gpointer, gpointer*) = test_method;
gpointer str = mono_string_new_wrapper ("foo");
if (str != F (str, &ex))
}
case 3: {
- /* thunks.cs:Test.Foo3 */
+ /* thunks.cs:Test.Test3 */
gpointer (STDCALL *F)(gpointer, gpointer, gpointer*);
gpointer obj;
gpointer str;
}
case 4: {
- /* thunks.cs:Test.Foo4 */
+ /* thunks.cs:Test.Test4 */
int (STDCALL *F)(gpointer, gpointer, int, gpointer*);
gpointer obj;
gpointer str;
}
case 5: {
- /* thunks.cs:Test.Foo5 */
+ /* thunks.cs:Test.Test5 */
int (STDCALL *F)(gpointer, gpointer, int, gpointer*);
gpointer obj;
gpointer str;
}
case 6: {
- /* thunks.cs:Test.Foo6 */
+ /* thunks.cs:Test.Test6 */
int (STDCALL *F)(gpointer, guint8, gint16, gint32, gint64, float, double,
gpointer, gpointer*);
gpointer obj;
- gpointer str = mono_string_new_wrapper ("Foo6");
+ gpointer str = mono_string_new_wrapper ("Test6");
int res;
F = test_method;
}
case 7: {
- /* thunks.cs:Test.Foo7 */
+ /* thunks.cs:Test.Test7 */
gint64 (STDCALL *F)(gpointer*) = test_method;
if (F (&ex) != G_MAXINT64)
return 4;
}
case 8: {
- /* thunks.cs:Test.Foo8 */
+ /* thunks.cs:Test.Test8 */
void (STDCALL *F)(guint8*, gint16*, gint32*, gint64*, float*, double*,
gpointer*, gpointer*);
a4 == 6789600 &&
(fabs (a5 - 3.1415) < 0.001) &&
(fabs (a6 - 3.1415) < 0.001) &&
- strcmp (mono_string_to_utf8 (a7), "Foo8") == 0))
+ strcmp (mono_string_to_utf8 (a7), "Test8") == 0))
return 5;
break;
}
case 9: {
- /* thunks.cs:Test.Foo9 */
+ /* thunks.cs:Test.Test9 */
void (STDCALL *F)(guint8*, gint16*, gint32*, gint64*, float*, double*,
gpointer*, gpointer*);
}
case 10: {
- /* thunks.cs:Test.Foo10 */
- int (STDCALL *F)(TestStruct, gpointer*);
+ /* thunks.cs:Test.Test10 */
+ void (STDCALL *F)(gpointer*, gpointer*);
- TestStruct a1;
- int res;
+ gpointer obj1, obj2;
- if (!SAME_ALIGNMENT (double))
- break;
-
- a1.A = 42;
- a1.B = 3.1415;
+ obj1 = obj2 = CreateObject (&ex);
+ if (ex)
+ return 4;
F = test_method;
- res = F (a1, &ex);
+ F (&obj1, &ex);
if (ex)
- return 4;
-
- if (!res)
return 5;
+ if (obj1 == obj2)
+ return 6;
+
break;
}
- case 11: {
- /* thunks.cs:Test.Foo11 */
- void (STDCALL *F)(TestStruct*, gpointer*);
+ case 100: {
+ /* thunks.cs:TestStruct.Test0 */
+ int (STDCALL *F)(gpointer*, gpointer*);
- TestStruct a1;
+ gpointer obj;
+ TestStruct *a1;
+ int res;
- if (!SAME_ALIGNMENT (double))
- break;
+ obj = CreateObject (&ex);
+ if (ex)
+ return 4;
+
+ if (!obj)
+ return 5;
+
+ a1 = mono_object_unbox (obj);
+ if (!a1)
+ return 6;
+
+ a1->A = 42;
+ a1->B = 3.1415;
F = test_method;
- F (&a1, &ex);
+ res = F (obj, &ex);
+ if (ex)
+ return 7;
+
+ if (!res)
+ return 8;
+
+ /* check whether the call was really by value */
+ if (a1->A != 42 || a1->B != 3.1415)
+ return 9;
+
+ break;
+ }
+
+ case 101: {
+ /* thunks.cs:TestStruct.Test1 */
+ void (STDCALL *F)(gpointer, gpointer*);
+
+ TestStruct *a1;
+ gpointer obj;
+
+ obj = CreateObject (&ex);
if (ex)
return 4;
- if (!a1.A == 42)
+ if (!obj)
return 5;
- if (!fabs (a1.B - 3.1415) < 0.001)
+ a1 = mono_object_unbox (obj);
+ if (!a1)
return 6;
+ F = test_method;
+
+ F (obj, &ex);
+ if (ex)
+ return 7;
+
+ if (a1->A != 42)
+ return 8;
+
+ if (!fabs (a1->B - 3.1415) < 0.001)
+ return 9;
+
break;
}
- case 12: {
- /* thunks.cs:Test.Foo12 */
- TestStruct (STDCALL *F)(gpointer*);
+ case 102: {
+ /* thunks.cs:TestStruct.Test2 */
+ gpointer (STDCALL *F)(gpointer*);
- TestStruct a1;
-
- if (!SAME_ALIGNMENT (double))
- break;
+ TestStruct *a1;
+ gpointer obj;
F = test_method;
- a1 = F (&ex);
+ obj = F (&ex);
if (ex)
return 4;
- if (!a1.A == 42)
+ if (!obj)
return 5;
- if (!fabs (a1.B - 3.1415) < 0.001)
+ a1 = mono_object_unbox (obj);
+
+ if (a1->A != 42)
+ return 5;
+
+ if (!fabs (a1->B - 3.1415) < 0.001)
return 6;
break;
}
- case 13: {
- /* thunks.cs:TestStruct.Foo13 */
- void (STDCALL *F)(TestStruct*, gpointer*);
+ case 103: {
+ /* thunks.cs:TestStruct.Test3 */
+ void (STDCALL *F)(gpointer, gpointer*);
- TestStruct a1;
+ TestStruct *a1;
+ gpointer obj;
- if (!SAME_ALIGNMENT (double))
- break;
+ obj = CreateObject (&ex);
+ if (ex)
+ return 4;
+
+ if (!obj)
+ return 5;
+
+ a1 = mono_object_unbox (obj);
+
+ if (!a1)
+ return 6;
- a1.A = 42;
- a1.B = 3.1415;
+ a1->A = 42;
+ a1->B = 3.1415;
F = test_method;
- F (&a1, &ex);
+ F (obj, &ex);
if (ex)
return 4;
- if (a1.A != 1)
+ if (a1->A != 1)
return 5;
- if (a1.B != 17)
+ if (a1->B != 17)
return 6;
break;
using System;
+using System.Reflection;
using System.Runtime.InteropServices;
public class Test
{
[DllImport ("libtest")]
- public static extern int test_method_thunk (int id, IntPtr testMethodHandle,
+ public static extern int test_method_thunk (int test_id, IntPtr testMethodHandle,
IntPtr createObjectHandle);
- static int test_method_thunk (int id, Type type)
+ static void RunTests(int series, Type type)
{
- string name = String.Format ("Foo{0}", id);
- return test_method_thunk (
- id,
- type.GetMethod (name).MethodHandle.Value,
- type.GetMethod ("CreateObject").MethodHandle.Value);
+ const string Prefix = "Test";
+ MethodInfo createObjectMethod = type.GetMethod ("CreateObject");
+
+ foreach (MethodInfo mi in type.GetMethods ()) {
+ string name = mi.Name;
+ if (!name.StartsWith (Prefix))
+ continue;
+
+ int id = Convert.ToInt32 (name.Substring (Prefix.Length));
+
+ int res = test_method_thunk (series + id, mi.MethodHandle.Value, createObjectMethod.MethodHandle.Value);
+
+ if (res != 0) {
+ Console.WriteLine ("{0} returned {1}", mi, res);
+ Environment.Exit ((id << 3) + res);
+ }
+ }
}
public static int Main ()
{
- const int MaxClassTests = 13;
- const int MaxStructTests = 1;
-
- // tests of class "Test"
- for (int i = 0; i < MaxClassTests; i++) {
- int res = test_method_thunk (i, typeof (Test));
- if (res != 0)
- return i*10 + res;
- }
-
- // tests of struct "TestStruct"
- for (int i = 0; i < MaxStructTests; i++) {
- int res = test_method_thunk (MaxClassTests + i, typeof (TestStruct));
- if (res != 0)
- return i*10 + res;
- }
-
+ RunTests (0, typeof (Test));
+ RunTests (100, typeof (TestStruct));
return 0;
}
public static object CreateObject ()
{
- Test t = new Test ();
- return t;
+ return new Test ();
}
- public static void Foo0 ()
+ public static void Test0 ()
{
}
- public static int Foo1 ()
+ public static int Test1 ()
{
return 42;
}
- public static string Foo2 (string s)
+ public static string Test2 (string s)
{
return s;
}
- public string Foo3 (string a)
+ public string Test3 (string a)
{
return a;
}
- public int Foo4 (string a, int i)
+ public int Test4 (string a, int i)
{
return i;
}
- public int Foo5 (string a, int i)
+ public int Test5 (string a, int i)
{
throw new NotImplementedException ();
}
- public bool Foo6 (byte a1, short a2, int a3, long a4, float a5, double a6, string a7)
+ public bool Test6 (byte a1, short a2, int a3, long a4, float a5, double a6, string a7)
{
return a1 == 254 &&
a2 == 32700 &&
a4 == 6789600 &&
(Math.Abs (a5 - 3.1415) < 0.001) &&
(Math.Abs (a6 - 3.1415) < 0.001) &&
- a7 == "Foo6";
+ a7 == "Test6";
}
- public static long Foo7 ()
+ public static long Test7 ()
{
return Int64.MaxValue;
}
- public static void Foo8 (ref byte a1, ref short a2, ref int a3, ref long a4, ref float a5, ref double a6, ref string a7)
+ public static void Test8 (ref byte a1, ref short a2, ref int a3, ref long a4, ref float a5, ref double a6, ref string a7)
{
a1 = 254;
a2 = 32700;
a4 = 6789600;
a5 = 3.1415f;
a6 = 3.1415;
- a7 = "Foo8";
+ a7 = "Test8";
}
- public static void Foo9 (ref byte a1, ref short a2, ref int a3, ref long a4, ref float a5, ref double a6, ref string a7)
+ public static void Test9 (ref byte a1, ref short a2, ref int a3, ref long a4, ref float a5, ref double a6, ref string a7)
{
throw new NotImplementedException ();
}
- public static bool Foo10 (TestStruct s)
+ public static void Test10 (ref Test obj)
+ {
+ obj = new Test ();
+ }
+}
+
+
+public struct TestStruct
+{
+ public int A;
+ public double B;
+
+ public static object CreateObject ()
+ {
+ return new TestStruct ();
+ }
+
+ public static bool Test0 (TestStruct s)
{
- return s.A == 42 && Math.Abs (s.B - 3.1415) < 0.001;
+ bool res = s.A == 42 && Math.Abs (s.B - 3.1415) < 0.001;
+
+ /* these changes must not be visible in unmanaged code */
+ s.A = 12;
+ s.B = 13;
+
+ return res;
}
- public static void Foo11 (ref TestStruct s)
+ public static void Test1 (ref TestStruct s)
{
s.A = 42;
s.B = 3.1415;
}
- public static TestStruct Foo12 ()
+ public static TestStruct Test2 ()
{
TestStruct s = new TestStruct ();
s.A = 42;
s.B = 3.1415;
return s;
}
-}
-
-
-public struct TestStruct
-{
- public int A;
- public double B;
-
- public static TestStruct CreateObject ()
- {
- return new TestStruct ();
- }
- public void Foo13 ()
+ public void Test3 ()
{
A = 1;
B = 17;