$NetBSD$

--- mono/metadata/object.c.orig	2009-10-26 20:44:10.000000000 +0000
+++ mono/metadata/object.c
@@ -3353,6 +3353,135 @@ mono_install_runtime_invoke (MonoInvokeF
 	default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
 }
 
+/*
+ * is_widen_compatible:
+ * 
+ * Tests if @candidate can be used in place of @type by means of a widening conversion.
+ * This means, for example, that a byte can be widened to an int and be used as argument in
+ * a reflection call. 
+ * 
+ * Returns true if @candidate can be widened to @type.
+ */
+static gboolean
+is_widen_compatible (MonoType * type, MonoType *candidate)
+{
+	if (type->type == candidate->type)
+		return TRUE;
+
+	switch (candidate->type) {
+	case MONO_TYPE_U1:
+		switch (type->type) {
+		case MONO_TYPE_U2:
+		case MONO_TYPE_I2:
+		case MONO_TYPE_CHAR:
+		case MONO_TYPE_U:
+		case MONO_TYPE_I:
+		case MONO_TYPE_U4:
+		case MONO_TYPE_I4:
+		case MONO_TYPE_U8:
+		case MONO_TYPE_I8:
+		case MONO_TYPE_R4:
+		case MONO_TYPE_R8:
+			return TRUE;
+		}
+		return FALSE;
+	case MONO_TYPE_I1:
+		switch (type->type) {
+		case MONO_TYPE_I2:
+		case MONO_TYPE_I:
+		case MONO_TYPE_I4:
+		case MONO_TYPE_I8:
+		case MONO_TYPE_R4:
+		case MONO_TYPE_R8:
+			return TRUE;
+		}
+	case MONO_TYPE_BOOLEAN:
+		return type->type == MONO_TYPE_BOOLEAN;
+	case MONO_TYPE_U2:
+		switch (type->type) {
+		case MONO_TYPE_U2:
+		case MONO_TYPE_U:
+		case MONO_TYPE_I:
+		case MONO_TYPE_U4:
+		case MONO_TYPE_I4:
+		case MONO_TYPE_U8:
+		case MONO_TYPE_I8:
+		case MONO_TYPE_R4:
+		case MONO_TYPE_R8:
+			return TRUE;
+		}
+		return FALSE;
+	case MONO_TYPE_I2:
+		switch (type->type) {
+		case MONO_TYPE_I:
+		case MONO_TYPE_I4:
+		case MONO_TYPE_I8:
+		case MONO_TYPE_R4:
+		case MONO_TYPE_R8:
+			return TRUE;
+		}
+		return FALSE;
+	case MONO_TYPE_CHAR:
+		switch (type->type) {
+		case MONO_TYPE_U2:
+		case MONO_TYPE_U:
+		case MONO_TYPE_I:
+		case MONO_TYPE_U4:
+		case MONO_TYPE_I4:
+		case MONO_TYPE_U8:
+		case MONO_TYPE_I8:
+		case MONO_TYPE_R4:
+		case MONO_TYPE_R8:
+			return TRUE;
+		}
+		return FALSE;
+	case MONO_TYPE_U:
+		switch (type->type) {
+		case MONO_TYPE_U4:
+		case MONO_TYPE_U8:
+		case MONO_TYPE_R4:
+		case MONO_TYPE_R8:
+			return TRUE;
+		}
+		return FALSE;
+	case MONO_TYPE_I:
+		switch (type->type) {
+		case MONO_TYPE_I:
+		case MONO_TYPE_I8:
+		case MONO_TYPE_R4:
+		case MONO_TYPE_R8:
+			return TRUE;
+		}
+		return FALSE;
+	case MONO_TYPE_U4:
+		switch (type->type) {
+		case MONO_TYPE_U:
+		case MONO_TYPE_U8:
+		case MONO_TYPE_I8:
+		case MONO_TYPE_R4:
+		case MONO_TYPE_R8:
+			return TRUE;
+		}
+		return FALSE;
+	case MONO_TYPE_I4:
+		switch (type->type) {
+		case MONO_TYPE_I:
+		case MONO_TYPE_I8:
+		case MONO_TYPE_R4:
+		case MONO_TYPE_R8:
+			return TRUE;
+		}
+		return FALSE;
+	case MONO_TYPE_U8:
+	case MONO_TYPE_I8:
+		return type->type == MONO_TYPE_R4 || type->type == MONO_TYPE_R8;
+	case MONO_TYPE_R4:
+		return type->type == MONO_TYPE_R8;
+	case MONO_TYPE_R8:
+		break;
+	}
+	return FALSE;
+}
 
 /**
  * mono_runtime_invoke_array:
@@ -3405,6 +3534,8 @@ mono_runtime_invoke_array (MonoMethod *m
 		pa = alloca (sizeof (gpointer) * mono_array_length (params));
 		for (i = 0; i < mono_array_length (params); i++) {
 			MonoType *t = sig->params [i];
+			MonoClass *par_class = mono_class_from_mono_type (t);
+			MonoObject *pao;
 
 		again:
 			switch (t->type) {
@@ -3429,9 +3560,16 @@ mono_runtime_invoke_array (MonoMethod *m
 					if (t->byref)
 						has_byref_nullables = TRUE;
 				} else {
+					pao = mono_array_get (params, MonoObject*, i);
 					/* MS seems to create the objects if a null is passed in */
-					if (!mono_array_get (params, MonoObject*, i))
-						mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]))); 
+					if (pao) {
+						if ((t->type == MONO_TYPE_VALUETYPE && pao->vtable->klass != par_class) ||
+							(t->type != MONO_TYPE_VALUETYPE && !is_widen_compatible (t, &pao->vtable->klass->byval_arg)))
+							mono_raise_exception (mono_get_exception_argument ("", "Incompatible type passed"));
+					} else {
+						pao = mono_object_new (mono_domain_get (), par_class);
+						mono_array_setref (params, i, pao);
+					}
 
 					if (t->byref) {
 						/*
@@ -3441,12 +3579,13 @@ mono_runtime_invoke_array (MonoMethod *m
 						 * object, pass that to the callee, and replace the original
 						 * boxed object in the arg array with the copy.
 						 */
-						MonoObject *orig = mono_array_get (params, MonoObject*, i);
+						MonoObject *orig = pao;
 						MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
 						mono_array_setref (params, i, copy);
+						pao = copy;
 					}
 						
-					pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
+					pa [i] = mono_object_unbox (pao);
 				}
 				break;
 			case MONO_TYPE_STRING:
@@ -3454,11 +3593,19 @@ mono_runtime_invoke_array (MonoMethod *m
 			case MONO_TYPE_CLASS:
 			case MONO_TYPE_ARRAY:
 			case MONO_TYPE_SZARRAY:
-				if (t->byref)
+				if (t->byref) {
 					pa [i] = mono_array_addr (params, MonoObject*, i);
 					// FIXME: I need to check this code path
-				else
-					pa [i] = mono_array_get (params, MonoObject*, i);
+				} else {
+					pao = mono_array_get (params, MonoObject*, i);
+					pa [i] = pao;
+					
+					if (pao != NULL && !mono_class_is_assignable_from (par_class, pao->vtable->klass) &&
+						(pao->vtable->klass == mono_defaults.transparent_proxy_class &&
+							!mono_class_is_assignable_from (par_class, ((MonoTransparentProxy*)pao)->remote_class->proxy_class))) {
+						mono_raise_exception (mono_get_exception_argument ("", "Incompatible type passed"));
+					}
+				}
 				break;
 			case MONO_TYPE_GENERICINST:
 				if (t->byref)
