Ver código fonte

Merge pull request #23097 from neikeq/aa

 C#: Optimize struct marshalling
Ignacio Etcheverry 7 anos atrás
pai
commit
b550f93cfd

+ 0 - 3
modules/mono/SCsub

@@ -88,9 +88,6 @@ vars.Update(env_mono)
 if env_mono['mono_glue']:
     env_mono.Append(CPPDEFINES=['MONO_GLUE_ENABLED'])
 
-if ARGUMENTS.get('yolo_copy', False):
-    env_mono.Append(CPPDEFINES=['YOLO_COPY'])
-
 # Configure TLS checks
 
 import tls_configure

+ 48 - 39
modules/mono/editor/bindings_generator.cpp

@@ -97,7 +97,7 @@
 #define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
 #define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
 
-#define BINDINGS_GENERATOR_VERSION UINT32_C(3)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(4)
 
 const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n";
 
@@ -646,8 +646,11 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
 	List<String> output;
 
 	output.push_back("using System;\n"); // IntPtr
+	output.push_back("using System.Diagnostics;\n"); // DebuggerBrowsable
+
 	output.push_back("\n#pragma warning disable CS1591 // Disable warning: "
 					 "'Missing XML comment for publicly visible type or member'\n");
+
 	output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
 
 	const DocData::ClassDoc *class_doc = itype.class_doc;
@@ -1086,7 +1089,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
 	// Generate method
 	{
 		if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
-			p_output.push_back(MEMBER_BEGIN "private static IntPtr ");
+			p_output.push_back(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static IntPtr ");
 			p_output.push_back(method_bind_field + " = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
 			p_output.push_back(p_imethod.name);
 			p_output.push_back("\");\n");
@@ -1990,18 +1993,18 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
 
 	TypeInterface itype;
 
-#define INSERT_STRUCT_TYPE(m_type, m_type_in)                                                         \
-	{                                                                                                 \
-		itype = TypeInterface::create_value_type(String(#m_type));                                    \
-		itype.c_in = "\tMARSHALLED_IN(" #m_type ", %1, %1_in);\n";                                    \
-		itype.c_out = "\tMARSHALLED_OUT(" #m_type ", %1, ret_out)\n"                                  \
-					  "\treturn mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(%2), ret_out);\n"; \
-		itype.c_arg_in = "&%s_in";                                                                    \
-		itype.c_type_in = m_type_in;                                                                  \
-		itype.cs_in = "ref %s";                                                                       \
-		itype.cs_out = "return (%1)%0;";                                                              \
-		itype.im_type_out = "object";                                                                 \
-		builtin_types.insert(itype.cname, itype);                                                     \
+#define INSERT_STRUCT_TYPE(m_type, m_type_in)                          \
+	{                                                                  \
+		itype = TypeInterface::create_value_type(String(#m_type));     \
+		itype.c_in = "\t%0 %1_in = MARSHALLED_IN(" #m_type ", %1);\n"; \
+		itype.c_out = "\treturn MARSHALLED_OUT(" #m_type ", %1);\n";   \
+		itype.c_arg_in = "&%s_in";                                     \
+		itype.c_type_in = "GDMonoMarshal::M_" #m_type "*";             \
+		itype.c_type_out = "GDMonoMarshal::M_" #m_type;                \
+		itype.cs_in = "ref %s";                                        \
+		itype.cs_out = "return (%1)%0;";                               \
+		itype.im_type_out = itype.cs_type;                             \
+		builtin_types.insert(itype.cname, itype);                      \
 	}
 
 	INSERT_STRUCT_TYPE(Vector2, "real_t*")
@@ -2019,26 +2022,31 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
 
 	// bool
 	itype = TypeInterface::create_value_type(String("bool"));
-	itype.c_arg_in = "&%s_in";
-	// /* MonoBoolean <---> bool
-	itype.c_in = "\t%0 %1_in = (%0)%1;\n";
-	itype.c_out = "\treturn (%0)%1;\n";
-	itype.c_type = "bool";
-	// */
-	itype.c_type_in = "MonoBoolean";
-	itype.c_type_out = itype.c_type_in;
+
+	{
+		// MonoBoolean <---> bool
+		itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+		itype.c_out = "\treturn (%0)%1;\n";
+		itype.c_type = "bool";
+		itype.c_type_in = "MonoBoolean";
+		itype.c_type_out = itype.c_type_in;
+		itype.c_arg_in = "&%s_in";
+	}
 	itype.im_type_in = itype.name;
 	itype.im_type_out = itype.name;
 	builtin_types.insert(itype.cname, itype);
 
 	// int
+	// C interface is the same as that of enums. Remember to apply any
+	// changes done here to TypeInterface::postsetup_enum_type as well
 	itype = TypeInterface::create_value_type(String("int"));
 	itype.c_arg_in = "&%s_in";
-	// /* ptrcall only supports int64_t and uint64_t
-	itype.c_in = "\t%0 %1_in = (%0)%1;\n";
-	itype.c_out = "\treturn (%0)%1;\n";
-	itype.c_type = "int64_t";
-	// */
+	{
+		// The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
+		itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+		itype.c_out = "\treturn (%0)%1;\n";
+		itype.c_type = "int64_t";
+	}
 	itype.c_type_in = "int32_t";
 	itype.c_type_out = itype.c_type_in;
 	itype.im_type_in = itype.name;
@@ -2047,21 +2055,22 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
 
 	// real_t
 	itype = TypeInterface();
+	itype.name = "float"; // The name is always "float" in Variant, even with REAL_T_IS_DOUBLE.
+	itype.cname = itype.name;
 #ifdef REAL_T_IS_DOUBLE
-	itype.name = "double";
+	itype.proxy_name = "double";
 #else
-	itype.name = "float";
+	itype.proxy_name = "float";
 #endif
-	itype.cname = itype.name;
-	itype.proxy_name = itype.name;
-	itype.c_arg_in = "&%s_in";
-	//* ptrcall only supports double
-	itype.c_in = "\t%0 %1_in = (%0)%1;\n";
-	itype.c_out = "\treturn (%0)%1;\n";
-	itype.c_type = "double";
-	//*/
-	itype.c_type_in = "real_t";
-	itype.c_type_out = "real_t";
+	{
+		// The expected type for parameters and return value in ptrcall is 'double'.
+		itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+		itype.c_out = "\treturn (%0)%1;\n";
+		itype.c_type = "double";
+		itype.c_type_in = "real_t";
+		itype.c_type_out = "real_t";
+		itype.c_arg_in = "&%s_in";
+	}
 	itype.cs_type = itype.proxy_name;
 	itype.im_type_in = itype.proxy_name;
 	itype.im_type_out = itype.proxy_name;

+ 14 - 7
modules/mono/editor/bindings_generator.h

@@ -223,7 +223,7 @@ class BindingsGenerator {
 		String c_in;
 
 		/**
-		 * Determines the name of the variable that will be passed as argument to a ptrcall.
+		 * Determines the expression that will be passed as argument to ptrcall.
 		 * By default the value equals the name of the parameter,
 		 * this varies for types that require special manipulation via [c_in].
 		 * Formatting elements:
@@ -333,8 +333,6 @@ class BindingsGenerator {
 			itype.proxy_name = itype.name;
 
 			itype.c_type = itype.name;
-			itype.c_type_in = "void*";
-			itype.c_type_out = "MonoObject*";
 			itype.cs_type = itype.proxy_name;
 			itype.im_type_in = "ref " + itype.proxy_name;
 			itype.im_type_out = itype.proxy_name;
@@ -385,10 +383,19 @@ class BindingsGenerator {
 		}
 
 		static void postsetup_enum_type(TypeInterface &r_enum_itype) {
-			r_enum_itype.c_arg_in = "&%s";
-			r_enum_itype.c_type = "int";
-			r_enum_itype.c_type_in = "int";
-			r_enum_itype.c_type_out = "int";
+			// C interface is the same as that of 'int'. Remember to apply any
+			// changes done here to the 'int' type interface as well
+
+			r_enum_itype.c_arg_in = "&%s_in";
+			{
+				// The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
+				r_enum_itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+				r_enum_itype.c_out = "\treturn (%0)%1;\n";
+				r_enum_itype.c_type = "int64_t";
+			}
+			r_enum_itype.c_type_in = "int32_t";
+			r_enum_itype.c_type_out = r_enum_itype.c_type_in;
+
 			r_enum_itype.cs_type = r_enum_itype.proxy_name;
 			r_enum_itype.cs_in = "(int)%s";
 			r_enum_itype.cs_out = "return (%1)%0;";

+ 226 - 90
modules/mono/mono_gd/gd_mono_field.cpp

@@ -40,65 +40,71 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
 }
 
 void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) {
-#define SET_FROM_STRUCT_AND_BREAK(m_type)                \
-	{                                                    \
-		const m_type &val = p_value.operator ::m_type(); \
-		MARSHALLED_OUT(m_type, val, raw);                \
-		mono_field_set_value(p_object, mono_field, raw); \
-		break;                                           \
+#define SET_FROM_STRUCT(m_type)                                                               \
+	{                                                                                         \
+		GDMonoMarshal::M_##m_type from = MARSHALLED_OUT(m_type, p_value.operator ::m_type()); \
+		mono_field_set_value(p_object, mono_field, &from);                                    \
 	}
 
-#define SET_FROM_PRIMITIVE(m_type)                        \
-	{                                                     \
-		m_type val = p_value.operator m_type();           \
-		mono_field_set_value(p_object, mono_field, &val); \
-		break;                                            \
-	}
-
-#define SET_FROM_ARRAY_AND_BREAK(m_type)                                                       \
-	{                                                                                          \
-		MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator m_type()); \
-		mono_field_set_value(p_object, mono_field, &managed);                                  \
-		break;                                                                                 \
+#define SET_FROM_ARRAY(m_type)                                                                   \
+	{                                                                                            \
+		MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \
+		mono_field_set_value(p_object, mono_field, &managed);                                    \
 	}
 
 	switch (type.type_encoding) {
 		case MONO_TYPE_BOOLEAN: {
-			SET_FROM_PRIMITIVE(bool);
+			MonoBoolean val = p_value.operator bool();
+			mono_field_set_value(p_object, mono_field, &val);
+		} break;
+
+		case MONO_TYPE_CHAR: {
+			int16_t val = p_value.operator unsigned short();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 
 		case MONO_TYPE_I1: {
-			SET_FROM_PRIMITIVE(signed char);
+			int8_t val = p_value.operator signed char();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 		case MONO_TYPE_I2: {
-			SET_FROM_PRIMITIVE(signed short);
+			int16_t val = p_value.operator signed short();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 		case MONO_TYPE_I4: {
-			SET_FROM_PRIMITIVE(signed int);
+			int32_t val = p_value.operator signed int();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 		case MONO_TYPE_I8: {
-			SET_FROM_PRIMITIVE(int64_t);
+			int64_t val = p_value.operator int64_t();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 
 		case MONO_TYPE_U1: {
-			SET_FROM_PRIMITIVE(unsigned char);
+			uint8_t val = p_value.operator unsigned char();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 		case MONO_TYPE_U2: {
-			SET_FROM_PRIMITIVE(unsigned short);
+			uint16_t val = p_value.operator unsigned short();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 		case MONO_TYPE_U4: {
-			SET_FROM_PRIMITIVE(unsigned int);
+			uint32_t val = p_value.operator unsigned int();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 		case MONO_TYPE_U8: {
-			SET_FROM_PRIMITIVE(uint64_t);
+			uint64_t val = p_value.operator uint64_t();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 
 		case MONO_TYPE_R4: {
-			SET_FROM_PRIMITIVE(float);
+			float val = p_value.operator float();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 
 		case MONO_TYPE_R8: {
-			SET_FROM_PRIMITIVE(double);
+			double val = p_value.operator double();
+			mono_field_set_value(p_object, mono_field, &val);
 		} break;
 
 		case MONO_TYPE_STRING: {
@@ -109,38 +115,115 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 		case MONO_TYPE_VALUETYPE: {
 			GDMonoClass *tclass = type.type_class;
 
-			if (tclass == CACHED_CLASS(Vector2))
-				SET_FROM_STRUCT_AND_BREAK(Vector2);
+			if (tclass == CACHED_CLASS(Vector2)) {
+				SET_FROM_STRUCT(Vector2);
+				break;
+			}
 
-			if (tclass == CACHED_CLASS(Rect2))
-				SET_FROM_STRUCT_AND_BREAK(Rect2);
+			if (tclass == CACHED_CLASS(Rect2)) {
+				SET_FROM_STRUCT(Rect2);
+				break;
+			}
 
-			if (tclass == CACHED_CLASS(Transform2D))
-				SET_FROM_STRUCT_AND_BREAK(Transform2D);
+			if (tclass == CACHED_CLASS(Transform2D)) {
+				SET_FROM_STRUCT(Transform2D);
+				break;
+			}
 
-			if (tclass == CACHED_CLASS(Vector3))
-				SET_FROM_STRUCT_AND_BREAK(Vector3);
+			if (tclass == CACHED_CLASS(Vector3)) {
+				SET_FROM_STRUCT(Vector3);
+				break;
+			}
 
-			if (tclass == CACHED_CLASS(Basis))
-				SET_FROM_STRUCT_AND_BREAK(Basis);
+			if (tclass == CACHED_CLASS(Basis)) {
+				SET_FROM_STRUCT(Basis);
+				break;
+			}
 
-			if (tclass == CACHED_CLASS(Quat))
-				SET_FROM_STRUCT_AND_BREAK(Quat);
+			if (tclass == CACHED_CLASS(Quat)) {
+				SET_FROM_STRUCT(Quat);
+				break;
+			}
 
-			if (tclass == CACHED_CLASS(Transform))
-				SET_FROM_STRUCT_AND_BREAK(Transform);
+			if (tclass == CACHED_CLASS(Transform)) {
+				SET_FROM_STRUCT(Transform);
+				break;
+			}
 
-			if (tclass == CACHED_CLASS(AABB))
-				SET_FROM_STRUCT_AND_BREAK(AABB);
+			if (tclass == CACHED_CLASS(AABB)) {
+				SET_FROM_STRUCT(AABB);
+				break;
+			}
 
-			if (tclass == CACHED_CLASS(Color))
-				SET_FROM_STRUCT_AND_BREAK(Color);
+			if (tclass == CACHED_CLASS(Color)) {
+				SET_FROM_STRUCT(Color);
+				break;
+			}
 
-			if (tclass == CACHED_CLASS(Plane))
-				SET_FROM_STRUCT_AND_BREAK(Plane);
+			if (tclass == CACHED_CLASS(Plane)) {
+				SET_FROM_STRUCT(Plane);
+				break;
+			}
 
-			if (mono_class_is_enum(tclass->get_mono_ptr()))
-				SET_FROM_PRIMITIVE(signed int);
+			if (mono_class_is_enum(tclass->get_mono_ptr())) {
+				MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
+				switch (mono_type_get_type(enum_basetype)) {
+					case MONO_TYPE_BOOLEAN: {
+						MonoBoolean val = p_value.operator bool();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					case MONO_TYPE_CHAR: {
+						uint16_t val = p_value.operator unsigned short();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					case MONO_TYPE_I1: {
+						int8_t val = p_value.operator signed char();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					case MONO_TYPE_I2: {
+						int16_t val = p_value.operator signed short();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					case MONO_TYPE_I4: {
+						int32_t val = p_value.operator signed int();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					case MONO_TYPE_I8: {
+						int64_t val = p_value.operator int64_t();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					case MONO_TYPE_U1: {
+						uint8_t val = p_value.operator unsigned char();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					case MONO_TYPE_U2: {
+						uint16_t val = p_value.operator unsigned short();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					case MONO_TYPE_U4: {
+						uint32_t val = p_value.operator unsigned int();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					case MONO_TYPE_U8: {
+						uint64_t val = p_value.operator uint64_t();
+						mono_field_set_value(p_object, mono_field, &val);
+						break;
+					}
+					default: {
+						ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
+						ERR_FAIL();
+					}
+				}
+			}
 
 			ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + tclass->get_name());
 			ERR_FAIL();
@@ -150,29 +233,45 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 		case MONO_TYPE_SZARRAY: {
 			MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
 
-			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
-				SET_FROM_ARRAY_AND_BREAK(Array);
+			if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
+				SET_FROM_ARRAY(Array);
+				break;
+			}
 
-			if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
-				SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
+			if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
+				SET_FROM_ARRAY(PoolByteArray);
+				break;
+			}
 
-			if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
-				SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
+			if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
+				SET_FROM_ARRAY(PoolIntArray);
+				break;
+			}
 
-			if (array_type->eklass == REAL_T_MONOCLASS)
-				SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
+			if (array_type->eklass == REAL_T_MONOCLASS) {
+				SET_FROM_ARRAY(PoolRealArray);
+				break;
+			}
 
-			if (array_type->eklass == CACHED_CLASS_RAW(String))
-				SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
+			if (array_type->eklass == CACHED_CLASS_RAW(String)) {
+				SET_FROM_ARRAY(PoolStringArray);
+				break;
+			}
 
-			if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
-				SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
+			if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
+				SET_FROM_ARRAY(PoolVector2Array);
+				break;
+			}
 
-			if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
-				SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
+			if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
+				SET_FROM_ARRAY(PoolVector3Array);
+				break;
+			}
 
-			if (array_type->eklass == CACHED_CLASS_RAW(Color))
-				SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
+			if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
+				SET_FROM_ARRAY(PoolColorArray);
+				break;
+			}
 
 			ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type.");
 			ERR_FAIL();
@@ -220,32 +319,56 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 			// Variant
 			switch (p_value.get_type()) {
 				case Variant::BOOL: {
-					SET_FROM_PRIMITIVE(bool);
+					MonoBoolean val = p_value.operator bool();
+					mono_field_set_value(p_object, mono_field, &val);
 				} break;
 				case Variant::INT: {
-					SET_FROM_PRIMITIVE(int);
+					int32_t val = p_value.operator signed int();
+					mono_field_set_value(p_object, mono_field, &val);
 				} break;
 				case Variant::REAL: {
 #ifdef REAL_T_IS_DOUBLE
-					SET_FROM_PRIMITIVE(double);
+					double val = p_value.operator double();
+					mono_field_set_value(p_object, mono_field, &val);
 #else
-					SET_FROM_PRIMITIVE(float);
+					float val = p_value.operator float();
+					mono_field_set_value(p_object, mono_field, &val);
 #endif
 				} break;
 				case Variant::STRING: {
 					MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
 					mono_field_set_value(p_object, mono_field, mono_string);
 				} break;
-				case Variant::VECTOR2: SET_FROM_STRUCT_AND_BREAK(Vector2);
-				case Variant::RECT2: SET_FROM_STRUCT_AND_BREAK(Rect2);
-				case Variant::VECTOR3: SET_FROM_STRUCT_AND_BREAK(Vector3);
-				case Variant::TRANSFORM2D: SET_FROM_STRUCT_AND_BREAK(Transform2D);
-				case Variant::PLANE: SET_FROM_STRUCT_AND_BREAK(Plane);
-				case Variant::QUAT: SET_FROM_STRUCT_AND_BREAK(Quat);
-				case Variant::AABB: SET_FROM_STRUCT_AND_BREAK(AABB);
-				case Variant::BASIS: SET_FROM_STRUCT_AND_BREAK(Basis);
-				case Variant::TRANSFORM: SET_FROM_STRUCT_AND_BREAK(Transform);
-				case Variant::COLOR: SET_FROM_STRUCT_AND_BREAK(Color);
+				case Variant::VECTOR2: {
+					SET_FROM_STRUCT(Vector2);
+				} break;
+				case Variant::RECT2: {
+					SET_FROM_STRUCT(Rect2);
+				} break;
+				case Variant::VECTOR3: {
+					SET_FROM_STRUCT(Vector3);
+				} break;
+				case Variant::TRANSFORM2D: {
+					SET_FROM_STRUCT(Transform2D);
+				} break;
+				case Variant::PLANE: {
+					SET_FROM_STRUCT(Plane);
+				} break;
+				case Variant::QUAT: {
+					SET_FROM_STRUCT(Quat);
+				} break;
+				case Variant::AABB: {
+					SET_FROM_STRUCT(AABB);
+				} break;
+				case Variant::BASIS: {
+					SET_FROM_STRUCT(Basis);
+				} break;
+				case Variant::TRANSFORM: {
+					SET_FROM_STRUCT(Transform);
+				} break;
+				case Variant::COLOR: {
+					SET_FROM_STRUCT(Color);
+				} break;
 				case Variant::NODE_PATH: {
 					MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
 					mono_field_set_value(p_object, mono_field, managed);
@@ -267,14 +390,27 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 					MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
 					mono_field_set_value(p_object, mono_field, managed);
 				} break;
-				case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
-				case Variant::POOL_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
-				case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
-				case Variant::POOL_STRING_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
-				case Variant::POOL_VECTOR2_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
-				case Variant::POOL_VECTOR3_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
-				case Variant::POOL_COLOR_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
-#undef SET_FROM_ARRAY_AND_BREAK
+				case Variant::POOL_BYTE_ARRAY: {
+					SET_FROM_ARRAY(PoolByteArray);
+				} break;
+				case Variant::POOL_INT_ARRAY: {
+					SET_FROM_ARRAY(PoolIntArray);
+				} break;
+				case Variant::POOL_REAL_ARRAY: {
+					SET_FROM_ARRAY(PoolRealArray);
+				} break;
+				case Variant::POOL_STRING_ARRAY: {
+					SET_FROM_ARRAY(PoolStringArray);
+				} break;
+				case Variant::POOL_VECTOR2_ARRAY: {
+					SET_FROM_ARRAY(PoolVector2Array);
+				} break;
+				case Variant::POOL_VECTOR3_ARRAY: {
+					SET_FROM_ARRAY(PoolVector3Array);
+				} break;
+				case Variant::POOL_COLOR_ARRAY: {
+					SET_FROM_ARRAY(PoolColorArray);
+				} break;
 				default: break;
 			}
 		} break;
@@ -312,8 +448,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 		} break;
 	}
 
+#undef SET_FROM_ARRAY_AND_BREAK
 #undef SET_FROM_STRUCT_AND_BREAK
-#undef SET_FROM_PRIMITIVE
 }
 
 MonoObject *GDMonoField::get_value(MonoObject *p_object) {

+ 0 - 10
modules/mono/mono_gd/gd_mono_header.h

@@ -55,14 +55,4 @@ struct ManagedType {
 	}
 };
 
-typedef union {
-	uint32_t _uint32;
-	float _float;
-} mono_float;
-
-typedef union {
-	uint64_t _uint64;
-	float _double;
-} mono_double;
-
 #endif // GD_MONO_HEADER_H

+ 193 - 124
modules/mono/mono_gd/gd_mono_marshal.cpp

@@ -35,20 +35,6 @@
 
 namespace GDMonoMarshal {
 
-#define RETURN_BOXED_STRUCT(m_t, m_var_in)                                    \
-	{                                                                         \
-		const m_t &m_in = m_var_in->operator ::m_t();                         \
-		MARSHALLED_OUT(m_t, m_in, raw);                                       \
-		return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_t), raw); \
-	}
-
-#define RETURN_UNBOXED_STRUCT(m_t, m_var_in)               \
-	{                                                      \
-		float *raw = (float *)mono_object_unbox(m_var_in); \
-		MARSHALLED_IN(m_t, raw, ret);                      \
-		return ret;                                        \
-	}
-
 Variant::Type managed_to_variant_type(const ManagedType &p_type) {
 	switch (p_type.type_encoding) {
 		case MONO_TYPE_BOOLEAN:
@@ -252,16 +238,21 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 			return BOX_BOOLEAN(val);
 		}
 
+		case MONO_TYPE_CHAR: {
+			uint16_t val = p_var->operator unsigned short();
+			return BOX_UINT16(val);
+		}
+
 		case MONO_TYPE_I1: {
-			char val = p_var->operator signed char();
+			int8_t val = p_var->operator signed char();
 			return BOX_INT8(val);
 		}
 		case MONO_TYPE_I2: {
-			short val = p_var->operator signed short();
+			int16_t val = p_var->operator signed short();
 			return BOX_INT16(val);
 		}
 		case MONO_TYPE_I4: {
-			int val = p_var->operator signed int();
+			int32_t val = p_var->operator signed int();
 			return BOX_INT32(val);
 		}
 		case MONO_TYPE_I8: {
@@ -270,15 +261,15 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 		}
 
 		case MONO_TYPE_U1: {
-			char val = p_var->operator unsigned char();
+			uint8_t val = p_var->operator unsigned char();
 			return BOX_UINT8(val);
 		}
 		case MONO_TYPE_U2: {
-			short val = p_var->operator unsigned short();
+			uint16_t val = p_var->operator unsigned short();
 			return BOX_UINT16(val);
 		}
 		case MONO_TYPE_U4: {
-			int val = p_var->operator unsigned int();
+			uint32_t val = p_var->operator unsigned int();
 			return BOX_UINT32(val);
 		}
 		case MONO_TYPE_U8: {
@@ -302,39 +293,105 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 		case MONO_TYPE_VALUETYPE: {
 			GDMonoClass *tclass = p_type.type_class;
 
-			if (tclass == CACHED_CLASS(Vector2))
-				RETURN_BOXED_STRUCT(Vector2, p_var);
+			if (tclass == CACHED_CLASS(Vector2)) {
+				GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
+			}
 
-			if (tclass == CACHED_CLASS(Rect2))
-				RETURN_BOXED_STRUCT(Rect2, p_var);
+			if (tclass == CACHED_CLASS(Rect2)) {
+				GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
+			}
 
-			if (tclass == CACHED_CLASS(Transform2D))
-				RETURN_BOXED_STRUCT(Transform2D, p_var);
+			if (tclass == CACHED_CLASS(Transform2D)) {
+				GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
+			}
 
-			if (tclass == CACHED_CLASS(Vector3))
-				RETURN_BOXED_STRUCT(Vector3, p_var);
+			if (tclass == CACHED_CLASS(Vector3)) {
+				GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
+			}
 
-			if (tclass == CACHED_CLASS(Basis))
-				RETURN_BOXED_STRUCT(Basis, p_var);
+			if (tclass == CACHED_CLASS(Basis)) {
+				GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
+			}
 
-			if (tclass == CACHED_CLASS(Quat))
-				RETURN_BOXED_STRUCT(Quat, p_var);
+			if (tclass == CACHED_CLASS(Quat)) {
+				GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
+			}
 
-			if (tclass == CACHED_CLASS(Transform))
-				RETURN_BOXED_STRUCT(Transform, p_var);
+			if (tclass == CACHED_CLASS(Transform)) {
+				GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
+			}
 
-			if (tclass == CACHED_CLASS(AABB))
-				RETURN_BOXED_STRUCT(AABB, p_var);
+			if (tclass == CACHED_CLASS(AABB)) {
+				GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
+			}
 
-			if (tclass == CACHED_CLASS(Color))
-				RETURN_BOXED_STRUCT(Color, p_var);
+			if (tclass == CACHED_CLASS(Color)) {
+				GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
+			}
 
-			if (tclass == CACHED_CLASS(Plane))
-				RETURN_BOXED_STRUCT(Plane, p_var);
+			if (tclass == CACHED_CLASS(Plane)) {
+				GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
+				return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
+			}
 
 			if (mono_class_is_enum(tclass->get_mono_ptr())) {
-				int val = p_var->operator signed int();
-				return BOX_ENUM(tclass->get_mono_ptr(), val);
+				MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
+				MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype);
+				switch (mono_type_get_type(enum_basetype)) {
+					case MONO_TYPE_BOOLEAN: {
+						MonoBoolean val = p_var->operator bool();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					case MONO_TYPE_CHAR: {
+						uint16_t val = p_var->operator unsigned short();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					case MONO_TYPE_I1: {
+						int8_t val = p_var->operator signed char();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					case MONO_TYPE_I2: {
+						int16_t val = p_var->operator signed short();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					case MONO_TYPE_I4: {
+						int32_t val = p_var->operator signed int();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					case MONO_TYPE_I8: {
+						int64_t val = p_var->operator int64_t();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					case MONO_TYPE_U1: {
+						uint8_t val = p_var->operator unsigned char();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					case MONO_TYPE_U2: {
+						uint16_t val = p_var->operator unsigned short();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					case MONO_TYPE_U4: {
+						uint32_t val = p_var->operator unsigned int();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					case MONO_TYPE_U8: {
+						uint64_t val = p_var->operator uint64_t();
+						return BOX_ENUM(enum_baseclass, val);
+					}
+					default: {
+						ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
+						ERR_FAIL_V(NULL);
+					}
+				}
 			}
 		} break;
 
@@ -402,7 +459,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 					return BOX_BOOLEAN(val);
 				}
 				case Variant::INT: {
-					int val = p_var->operator signed int();
+					int32_t val = p_var->operator signed int();
 					return BOX_INT32(val);
 				}
 				case Variant::REAL: {
@@ -416,33 +473,52 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 				}
 				case Variant::STRING:
 					return (MonoObject *)mono_string_from_godot(p_var->operator String());
-				case Variant::VECTOR2:
-					RETURN_BOXED_STRUCT(Vector2, p_var);
-				case Variant::RECT2:
-					RETURN_BOXED_STRUCT(Rect2, p_var);
-				case Variant::VECTOR3:
-					RETURN_BOXED_STRUCT(Vector3, p_var);
-				case Variant::TRANSFORM2D:
-					RETURN_BOXED_STRUCT(Transform2D, p_var);
-				case Variant::PLANE:
-					RETURN_BOXED_STRUCT(Plane, p_var);
-				case Variant::QUAT:
-					RETURN_BOXED_STRUCT(Quat, p_var);
-				case Variant::AABB:
-					RETURN_BOXED_STRUCT(AABB, p_var);
-				case Variant::BASIS:
-					RETURN_BOXED_STRUCT(Basis, p_var);
-				case Variant::TRANSFORM:
-					RETURN_BOXED_STRUCT(Transform, p_var);
-				case Variant::COLOR:
-					RETURN_BOXED_STRUCT(Color, p_var);
+				case Variant::VECTOR2: {
+					GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
+				}
+				case Variant::RECT2: {
+					GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
+				}
+				case Variant::VECTOR3: {
+					GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
+				}
+				case Variant::TRANSFORM2D: {
+					GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
+				}
+				case Variant::PLANE: {
+					GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
+				}
+				case Variant::QUAT: {
+					GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
+				}
+				case Variant::AABB: {
+					GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
+				}
+				case Variant::BASIS: {
+					GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
+				}
+				case Variant::TRANSFORM: {
+					GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
+				}
+				case Variant::COLOR: {
+					GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
+					return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
+				}
 				case Variant::NODE_PATH:
 					return GDMonoUtils::create_managed_from(p_var->operator NodePath());
 				case Variant::_RID:
 					return GDMonoUtils::create_managed_from(p_var->operator RID());
-				case Variant::OBJECT: {
+				case Variant::OBJECT:
 					return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
-				}
 				case Variant::DICTIONARY:
 					return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
 				case Variant::ARRAY:
@@ -512,6 +588,9 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 		case MONO_TYPE_BOOLEAN:
 			return (bool)unbox<MonoBoolean>(p_obj);
 
+		case MONO_TYPE_CHAR:
+			return unbox<uint16_t>(p_obj);
+
 		case MONO_TYPE_I1:
 			return unbox<int8_t>(p_obj);
 		case MONO_TYPE_I2:
@@ -545,34 +624,34 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 			GDMonoClass *tclass = type.type_class;
 
 			if (tclass == CACHED_CLASS(Vector2))
-				RETURN_UNBOXED_STRUCT(Vector2, p_obj);
+				return MARSHALLED_IN(Vector2, (GDMonoMarshal::M_Vector2 *)mono_object_unbox(p_obj));
 
 			if (tclass == CACHED_CLASS(Rect2))
-				RETURN_UNBOXED_STRUCT(Rect2, p_obj);
+				return MARSHALLED_IN(Rect2, (GDMonoMarshal::M_Rect2 *)mono_object_unbox(p_obj));
 
 			if (tclass == CACHED_CLASS(Transform2D))
-				RETURN_UNBOXED_STRUCT(Transform2D, p_obj);
+				return MARSHALLED_IN(Transform2D, (GDMonoMarshal::M_Transform2D *)mono_object_unbox(p_obj));
 
 			if (tclass == CACHED_CLASS(Vector3))
-				RETURN_UNBOXED_STRUCT(Vector3, p_obj);
+				return MARSHALLED_IN(Vector3, (GDMonoMarshal::M_Vector3 *)mono_object_unbox(p_obj));
 
 			if (tclass == CACHED_CLASS(Basis))
-				RETURN_UNBOXED_STRUCT(Basis, p_obj);
+				return MARSHALLED_IN(Basis, (GDMonoMarshal::M_Basis *)mono_object_unbox(p_obj));
 
 			if (tclass == CACHED_CLASS(Quat))
-				RETURN_UNBOXED_STRUCT(Quat, p_obj);
+				return MARSHALLED_IN(Quat, (GDMonoMarshal::M_Quat *)mono_object_unbox(p_obj));
 
 			if (tclass == CACHED_CLASS(Transform))
-				RETURN_UNBOXED_STRUCT(Transform, p_obj);
+				return MARSHALLED_IN(Transform, (GDMonoMarshal::M_Transform *)mono_object_unbox(p_obj));
 
 			if (tclass == CACHED_CLASS(AABB))
-				RETURN_UNBOXED_STRUCT(AABB, p_obj);
+				return MARSHALLED_IN(AABB, (GDMonoMarshal::M_AABB *)mono_object_unbox(p_obj));
 
 			if (tclass == CACHED_CLASS(Color))
-				RETURN_UNBOXED_STRUCT(Color, p_obj);
+				return MARSHALLED_IN(Color, (GDMonoMarshal::M_Color *)mono_object_unbox(p_obj));
 
 			if (tclass == CACHED_CLASS(Plane))
-				RETURN_UNBOXED_STRUCT(Plane, p_obj);
+				return MARSHALLED_IN(Plane, (GDMonoMarshal::M_Plane *)mono_object_unbox(p_obj));
 
 			if (mono_class_is_enum(tclass->get_mono_ptr()))
 				return unbox<int32_t>(p_obj);
@@ -708,13 +787,13 @@ Array mono_array_to_Array(MonoArray *p_array) {
 	return ret;
 }
 
-// TODO Optimize reading/writing from/to PoolArrays
-
 MonoArray *PoolIntArray_to_mono_array(const PoolIntArray &p_array) {
+	PoolIntArray::Read r = p_array.read();
+
 	MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), p_array.size());
 
 	for (int i = 0; i < p_array.size(); i++) {
-		mono_array_set(ret, int32_t, i, p_array[i]);
+		mono_array_set(ret, int32_t, i, r[i]);
 	}
 
 	return ret;
@@ -726,19 +805,22 @@ PoolIntArray mono_array_to_PoolIntArray(MonoArray *p_array) {
 		return ret;
 	int length = mono_array_length(p_array);
 	ret.resize(length);
+	PoolIntArray::Write w = ret.write();
+
 	for (int i = 0; i < length; i++) {
-		int32_t elem = mono_array_get(p_array, int32_t, i);
-		ret.set(i, elem);
+		w[i] = mono_array_get(p_array, int32_t, i);
 	}
 
 	return ret;
 }
 
 MonoArray *PoolByteArray_to_mono_array(const PoolByteArray &p_array) {
+	PoolByteArray::Read r = p_array.read();
+
 	MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), p_array.size());
 
 	for (int i = 0; i < p_array.size(); i++) {
-		mono_array_set(ret, uint8_t, i, p_array[i]);
+		mono_array_set(ret, uint8_t, i, r[i]);
 	}
 
 	return ret;
@@ -750,20 +832,22 @@ PoolByteArray mono_array_to_PoolByteArray(MonoArray *p_array) {
 		return ret;
 	int length = mono_array_length(p_array);
 	ret.resize(length);
+	PoolByteArray::Write w = ret.write();
 
 	for (int i = 0; i < length; i++) {
-		uint8_t elem = mono_array_get(p_array, uint8_t, i);
-		ret.set(i, elem);
+		w[i] = mono_array_get(p_array, uint8_t, i);
 	}
 
 	return ret;
 }
 
 MonoArray *PoolRealArray_to_mono_array(const PoolRealArray &p_array) {
+	PoolRealArray::Read r = p_array.read();
+
 	MonoArray *ret = mono_array_new(mono_domain_get(), REAL_T_MONOCLASS, p_array.size());
 
 	for (int i = 0; i < p_array.size(); i++) {
-		mono_array_set(ret, real_t, i, p_array[i]);
+		mono_array_set(ret, real_t, i, r[i]);
 	}
 
 	return ret;
@@ -775,20 +859,22 @@ PoolRealArray mono_array_to_PoolRealArray(MonoArray *p_array) {
 		return ret;
 	int length = mono_array_length(p_array);
 	ret.resize(length);
+	PoolRealArray::Write w = ret.write();
 
 	for (int i = 0; i < length; i++) {
-		real_t elem = mono_array_get(p_array, real_t, i);
-		ret.set(i, elem);
+		w[i] = mono_array_get(p_array, real_t, i);
 	}
 
 	return ret;
 }
 
 MonoArray *PoolStringArray_to_mono_array(const PoolStringArray &p_array) {
+	PoolStringArray::Read r = p_array.read();
+
 	MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), p_array.size());
 
 	for (int i = 0; i < p_array.size(); i++) {
-		MonoString *boxed = mono_string_from_godot(p_array[i]);
+		MonoString *boxed = mono_string_from_godot(r[i]);
 		mono_array_set(ret, MonoString *, i, boxed);
 	}
 
@@ -801,29 +887,24 @@ PoolStringArray mono_array_to_PoolStringArray(MonoArray *p_array) {
 		return ret;
 	int length = mono_array_length(p_array);
 	ret.resize(length);
+	PoolStringArray::Write w = ret.write();
 
 	for (int i = 0; i < length; i++) {
 		MonoString *elem = mono_array_get(p_array, MonoString *, i);
-		ret.set(i, mono_string_to_godot(elem));
+		w[i] = mono_string_to_godot(elem);
 	}
 
 	return ret;
 }
 
 MonoArray *PoolColorArray_to_mono_array(const PoolColorArray &p_array) {
+	PoolColorArray::Read r = p_array.read();
+
 	MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), p_array.size());
 
 	for (int i = 0; i < p_array.size(); i++) {
-#ifdef YOLOCOPY
-		mono_array_set(ret, Color, i, p_array[i]);
-#else
-		real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 4, i);
-		const Color &elem = p_array[i];
-		raw[0] = elem.r;
-		raw[1] = elem.g;
-		raw[2] = elem.b;
-		raw[3] = elem.a;
-#endif
+		M_Color *raw = (M_Color *)mono_array_addr_with_size(ret, sizeof(M_Color), i);
+		*raw = MARSHALLED_OUT(Color, r[i]);
 	}
 
 	return ret;
@@ -835,28 +916,23 @@ PoolColorArray mono_array_to_PoolColorArray(MonoArray *p_array) {
 		return ret;
 	int length = mono_array_length(p_array);
 	ret.resize(length);
+	PoolColorArray::Write w = ret.write();
 
 	for (int i = 0; i < length; i++) {
-		real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 4, i);
-		MARSHALLED_IN(Color, raw_elem, elem);
-		ret.set(i, elem);
+		w[i] = MARSHALLED_IN(Color, (M_Color *)mono_array_addr_with_size(p_array, sizeof(M_Color), i));
 	}
 
 	return ret;
 }
 
 MonoArray *PoolVector2Array_to_mono_array(const PoolVector2Array &p_array) {
+	PoolVector2Array::Read r = p_array.read();
+
 	MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), p_array.size());
 
 	for (int i = 0; i < p_array.size(); i++) {
-#ifdef YOLOCOPY
-		mono_array_set(ret, Vector2, i, p_array[i]);
-#else
-		real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 2, i);
-		const Vector2 &elem = p_array[i];
-		raw[0] = elem.x;
-		raw[1] = elem.y;
-#endif
+		M_Vector2 *raw = (M_Vector2 *)mono_array_addr_with_size(ret, sizeof(M_Vector2), i);
+		*raw = MARSHALLED_OUT(Vector2, r[i]);
 	}
 
 	return ret;
@@ -868,29 +944,23 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array) {
 		return ret;
 	int length = mono_array_length(p_array);
 	ret.resize(length);
+	PoolVector2Array::Write w = ret.write();
 
 	for (int i = 0; i < length; i++) {
-		real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 2, i);
-		MARSHALLED_IN(Vector2, raw_elem, elem);
-		ret.set(i, elem);
+		w[i] = MARSHALLED_IN(Vector2, (M_Vector2 *)mono_array_addr_with_size(p_array, sizeof(M_Vector2), i));
 	}
 
 	return ret;
 }
 
 MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array) {
+	PoolVector3Array::Read r = p_array.read();
+
 	MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), p_array.size());
 
 	for (int i = 0; i < p_array.size(); i++) {
-#ifdef YOLOCOPY
-		mono_array_set(ret, Vector3, i, p_array[i]);
-#else
-		real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 3, i);
-		const Vector3 &elem = p_array[i];
-		raw[0] = elem.x;
-		raw[1] = elem.y;
-		raw[2] = elem.z;
-#endif
+		M_Vector3 *raw = (M_Vector3 *)mono_array_addr_with_size(ret, sizeof(M_Vector3), i);
+		*raw = MARSHALLED_OUT(Vector3, r[i]);
 	}
 
 	return ret;
@@ -902,11 +972,10 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) {
 		return ret;
 	int length = mono_array_length(p_array);
 	ret.resize(length);
+	PoolVector3Array::Write w = ret.write();
 
 	for (int i = 0; i < length; i++) {
-		real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 3, i);
-		MARSHALLED_IN(Vector3, raw_elem, elem);
-		ret.set(i, elem);
+		w[i] = MARSHALLED_IN(Vector3, (M_Vector3 *)mono_array_addr_with_size(p_array, sizeof(M_Vector3), i));
 	}
 
 	return ret;

+ 239 - 46
modules/mono/mono_gd/gd_mono_marshal.h

@@ -147,78 +147,271 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array);
 MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
 PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array);
 
-#ifdef YOLO_COPY
-#define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in;
-#define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in);
+// Structures
+
+namespace InteropLayout {
+
+enum {
+	MATCHES_float = (sizeof(float) == sizeof(uint32_t)),
+
+	MATCHES_double = (sizeof(double) == sizeof(uint64_t)),
+
+#ifdef REAL_T_IS_DOUBLE
+	MATCHES_real_t = (sizeof(real_t) == sizeof(uint64_t)),
 #else
+	MATCHES_real_t = (sizeof(real_t) == sizeof(uint32_t)),
+#endif
 
-// Expects m_in to be of type float*
+	MATCHES_Vector2 = (MATCHES_real_t && (sizeof(Vector2) == (sizeof(real_t) * 2)) &&
+					   offsetof(Vector2, x) == (sizeof(real_t) * 0) &&
+					   offsetof(Vector2, y) == (sizeof(real_t) * 1)),
 
-#define MARSHALLED_OUT(m_t, m_in, m_out) MARSHALLED_OUT_##m_t(m_in, m_out)
-#define MARSHALLED_IN(m_t, m_in, m_out) MARSHALLED_IN_##m_t(m_in, m_out)
+	MATCHES_Rect2 = (MATCHES_Vector2 && (sizeof(Rect2) == (sizeof(Vector2) * 2)) &&
+					 offsetof(Rect2, position) == (sizeof(Vector2) * 0) &&
+					 offsetof(Rect2, size) == (sizeof(Vector2) * 1)),
 
-// Vector2
+	MATCHES_Transform2D = (MATCHES_Vector2 && (sizeof(Transform2D) == (sizeof(Vector2) * 3))), // No field offset required, it stores an array
 
-#define MARSHALLED_OUT_Vector2(m_in, m_out) real_t m_out[2] = { m_in.x, m_in.y };
-#define MARSHALLED_IN_Vector2(m_in, m_out) Vector2 m_out(m_in[0], m_in[1]);
+	MATCHES_Vector3 = (MATCHES_real_t && (sizeof(Vector3) == (sizeof(real_t) * 3)) &&
+					   offsetof(Vector3, x) == (sizeof(real_t) * 0) &&
+					   offsetof(Vector3, y) == (sizeof(real_t) * 1) &&
+					   offsetof(Vector3, z) == (sizeof(real_t) * 2)),
 
-// Rect2
+	MATCHES_Basis = (MATCHES_Vector3 && (sizeof(Basis) == (sizeof(Vector3) * 3))), // No field offset required, it stores an array
 
-#define MARSHALLED_OUT_Rect2(m_in, m_out) real_t m_out[4] = { m_in.position.x, m_in.position.y, m_in.size.width, m_in.size.height };
-#define MARSHALLED_IN_Rect2(m_in, m_out) Rect2 m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+	MATCHES_Quat = (MATCHES_real_t && (sizeof(Quat) == (sizeof(real_t) * 4)) &&
+					offsetof(Quat, x) == (sizeof(real_t) * 0) &&
+					offsetof(Quat, y) == (sizeof(real_t) * 1) &&
+					offsetof(Quat, z) == (sizeof(real_t) * 2) &&
+					offsetof(Quat, w) == (sizeof(real_t) * 3)),
 
-// Transform2D
+	MATCHES_Transform = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform) == (sizeof(Basis) + sizeof(Vector3))) &&
+						 offsetof(Transform, basis) == 0 &&
+						 offsetof(Transform, origin) == sizeof(Basis)),
 
-#define MARSHALLED_OUT_Transform2D(m_in, m_out) real_t m_out[6] = { m_in[0].x, m_in[0].y, m_in[1].x, m_in[1].y, m_in[2].x, m_in[2].y };
-#define MARSHALLED_IN_Transform2D(m_in, m_out) Transform2D m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5]);
+	MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) &&
+					offsetof(AABB, position) == (sizeof(Vector3) * 0) &&
+					offsetof(AABB, size) == (sizeof(Vector3) * 1)),
 
-// Vector3
+	MATCHES_Color = (MATCHES_float && (sizeof(Color) == (sizeof(float) * 4)) &&
+					 offsetof(Color, r) == (sizeof(float) * 0) &&
+					 offsetof(Color, g) == (sizeof(float) * 1) &&
+					 offsetof(Color, b) == (sizeof(float) * 2) &&
+					 offsetof(Color, a) == (sizeof(float) * 3)),
+
+	MATCHES_Plane = (MATCHES_Vector3 && MATCHES_real_t && (sizeof(Plane) == (sizeof(Vector3) + sizeof(real_t))) &&
+					 offsetof(Plane, normal) == 0 &&
+					 offsetof(Plane, d) == sizeof(Vector3))
+};
+
+// In the future we may force this if we want to ref return these structs
+#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
+// Sometimes clang-format can be an ass
+GD_STATIC_ASSERT(MATCHES_Vector2 &&MATCHES_Rect2 &&MATCHES_Transform2D &&MATCHES_Vector3 &&
+				MATCHES_Basis &&MATCHES_Quat &&MATCHES_Transform &&MATCHES_AABB &&MATCHES_Color &&MATCHES_Plane);
+#endif
 
-#define MARSHALLED_OUT_Vector3(m_in, m_out) real_t m_out[3] = { m_in.x, m_in.y, m_in.z };
-#define MARSHALLED_IN_Vector3(m_in, m_out) Vector3 m_out(m_in[0], m_in[1], m_in[2]);
+} // namespace InteropLayout
 
-// Basis
+#pragma pack(push, 1)
 
-#define MARSHALLED_OUT_Basis(m_in, m_out) real_t m_out[9] = { \
-	m_in[0].x, m_in[0].y, m_in[0].z,                          \
-	m_in[1].x, m_in[1].y, m_in[1].z,                          \
-	m_in[2].x, m_in[2].y, m_in[2].z                           \
+struct M_Vector2 {
+	real_t x, y;
+
+	static _FORCE_INLINE_ Vector2 convert_to(const M_Vector2 &p_from) {
+		return Vector2(p_from.x, p_from.y);
+	}
+
+	static _FORCE_INLINE_ M_Vector2 convert_from(const Vector2 &p_from) {
+		M_Vector2 ret = { p_from.x, p_from.y };
+		return ret;
+	}
 };
-#define MARSHALLED_IN_Basis(m_in, m_out) Basis m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]);
 
-// Quat
+struct M_Rect2 {
+	M_Vector2 position;
+	M_Vector2 size;
 
-#define MARSHALLED_OUT_Quat(m_in, m_out) real_t m_out[4] = { m_in.x, m_in.y, m_in.z, m_in.w };
-#define MARSHALLED_IN_Quat(m_in, m_out) Quat m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+	static _FORCE_INLINE_ Rect2 convert_to(const M_Rect2 &p_from) {
+		return Rect2(M_Vector2::convert_to(p_from.position),
+				M_Vector2::convert_to(p_from.size));
+	}
 
-// Transform
+	static _FORCE_INLINE_ M_Rect2 convert_from(const Rect2 &p_from) {
+		M_Rect2 ret = { M_Vector2::convert_from(p_from.position), M_Vector2::convert_from(p_from.size) };
+		return ret;
+	}
+};
 
-#define MARSHALLED_OUT_Transform(m_in, m_out) real_t m_out[12] = { \
-	m_in.basis[0].x, m_in.basis[0].y, m_in.basis[0].z,             \
-	m_in.basis[1].x, m_in.basis[1].y, m_in.basis[1].z,             \
-	m_in.basis[2].x, m_in.basis[2].y, m_in.basis[2].z,             \
-	m_in.origin.x, m_in.origin.y, m_in.origin.z                    \
+struct M_Transform2D {
+	M_Vector2 elements[3];
+
+	static _FORCE_INLINE_ Transform2D convert_to(const M_Transform2D &p_from) {
+		return Transform2D(p_from.elements[0].x, p_from.elements[0].y,
+				p_from.elements[1].x, p_from.elements[1].y,
+				p_from.elements[2].x, p_from.elements[2].y);
+	}
+
+	static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) {
+		M_Transform2D ret = {
+			M_Vector2::convert_from(p_from.elements[0]),
+			M_Vector2::convert_from(p_from.elements[1]),
+			M_Vector2::convert_from(p_from.elements[2])
+		};
+		return ret;
+	}
 };
-#define MARSHALLED_IN_Transform(m_in, m_out) Transform m_out(                                   \
-		Basis(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]), \
-		Vector3(m_in[9], m_in[10], m_in[11]));
 
-// AABB
+struct M_Vector3 {
+	real_t x, y, z;
+
+	static _FORCE_INLINE_ Vector3 convert_to(const M_Vector3 &p_from) {
+		return Vector3(p_from.x, p_from.y, p_from.z);
+	}
 
-#define MARSHALLED_OUT_AABB(m_in, m_out) real_t m_out[6] = { m_in.position.x, m_in.position.y, m_in.position.z, m_in.size.x, m_in.size.y, m_in.size.z };
-#define MARSHALLED_IN_AABB(m_in, m_out) AABB m_out(Vector3(m_in[0], m_in[1], m_in[2]), Vector3(m_in[3], m_in[4], m_in[5]));
+	static _FORCE_INLINE_ M_Vector3 convert_from(const Vector3 &p_from) {
+		M_Vector3 ret = { p_from.x, p_from.y, p_from.z };
+		return ret;
+	}
+};
 
-// Color
+struct M_Basis {
+	M_Vector3 elements[3];
+
+	static _FORCE_INLINE_ Basis convert_to(const M_Basis &p_from) {
+		return Basis(M_Vector3::convert_to(p_from.elements[0]),
+				M_Vector3::convert_to(p_from.elements[1]),
+				M_Vector3::convert_to(p_from.elements[2]));
+	}
+
+	static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) {
+		M_Basis ret = {
+			M_Vector3::convert_from(p_from.elements[0]),
+			M_Vector3::convert_from(p_from.elements[1]),
+			M_Vector3::convert_from(p_from.elements[2])
+		};
+		return ret;
+	}
+};
 
-#define MARSHALLED_OUT_Color(m_in, m_out) real_t m_out[4] = { m_in.r, m_in.g, m_in.b, m_in.a };
-#define MARSHALLED_IN_Color(m_in, m_out) Color m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+struct M_Quat {
+	real_t x, y, z, w;
 
-// Plane
+	static _FORCE_INLINE_ Quat convert_to(const M_Quat &p_from) {
+		return Quat(p_from.x, p_from.y, p_from.z, p_from.w);
+	}
 
-#define MARSHALLED_OUT_Plane(m_in, m_out) real_t m_out[4] = { m_in.normal.x, m_in.normal.y, m_in.normal.z, m_in.d };
-#define MARSHALLED_IN_Plane(m_in, m_out) Plane m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+	static _FORCE_INLINE_ M_Quat convert_from(const Quat &p_from) {
+		M_Quat ret = { p_from.x, p_from.y, p_from.z, p_from.w };
+		return ret;
+	}
+};
 
-#endif
+struct M_Transform {
+	M_Basis basis;
+	M_Vector3 origin;
+
+	static _FORCE_INLINE_ Transform convert_to(const M_Transform &p_from) {
+		return Transform(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin));
+	}
+
+	static _FORCE_INLINE_ M_Transform convert_from(const Transform &p_from) {
+		M_Transform ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) };
+		return ret;
+	}
+};
+
+struct M_AABB {
+	M_Vector3 position;
+	M_Vector3 size;
+
+	static _FORCE_INLINE_ AABB convert_to(const M_AABB &p_from) {
+		return AABB(M_Vector3::convert_to(p_from.position), M_Vector3::convert_to(p_from.size));
+	}
+
+	static _FORCE_INLINE_ M_AABB convert_from(const AABB &p_from) {
+		M_AABB ret = { M_Vector3::convert_from(p_from.position), M_Vector3::convert_from(p_from.size) };
+		return ret;
+	}
+};
+
+struct M_Color {
+	float r, g, b, a;
+
+	static _FORCE_INLINE_ Color convert_to(const M_Color &p_from) {
+		return Color(p_from.r, p_from.g, p_from.b, p_from.a);
+	}
+
+	static _FORCE_INLINE_ M_Color convert_from(const Color &p_from) {
+		M_Color ret = { p_from.r, p_from.g, p_from.b, p_from.a };
+		return ret;
+	}
+};
+
+struct M_Plane {
+	M_Vector3 normal;
+	real_t d;
+
+	static _FORCE_INLINE_ Plane convert_to(const M_Plane &p_from) {
+		return Plane(M_Vector3::convert_to(p_from.normal), p_from.d);
+	}
+
+	static _FORCE_INLINE_ M_Plane convert_from(const Plane &p_from) {
+		M_Plane ret = { M_Vector3::convert_from(p_from.normal), p_from.d };
+		return ret;
+	}
+};
+
+#pragma pack(pop)
+
+#define DECL_TYPE_MARSHAL_TEMPLATES(m_type)                                             \
+	template <int>                                                                      \
+	_FORCE_INLINE_ m_type marshalled_in_##m_type##_impl(const M_##m_type *p_from);      \
+                                                                                        \
+	template <>                                                                         \
+	_FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<0>(const M_##m_type *p_from) {  \
+		return M_##m_type::convert_to(*p_from);                                         \
+	}                                                                                   \
+                                                                                        \
+	template <>                                                                         \
+	_FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<1>(const M_##m_type *p_from) {  \
+		return *reinterpret_cast<const m_type *>(p_from);                               \
+	}                                                                                   \
+                                                                                        \
+	_FORCE_INLINE_ m_type marshalled_in_##m_type(const M_##m_type *p_from) {            \
+		return marshalled_in_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from);  \
+	}                                                                                   \
+                                                                                        \
+	template <int>                                                                      \
+	_FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl(const m_type &p_from);     \
+                                                                                        \
+	template <>                                                                         \
+	_FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<0>(const m_type &p_from) { \
+		return M_##m_type::convert_from(p_from);                                        \
+	}                                                                                   \
+                                                                                        \
+	template <>                                                                         \
+	_FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<1>(const m_type &p_from) { \
+		return *reinterpret_cast<const M_##m_type *>(&p_from);                          \
+	}                                                                                   \
+                                                                                        \
+	_FORCE_INLINE_ M_##m_type marshalled_out_##m_type(const m_type &p_from) {           \
+		return marshalled_out_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \
+	}
+
+DECL_TYPE_MARSHAL_TEMPLATES(Vector2)
+DECL_TYPE_MARSHAL_TEMPLATES(Rect2)
+DECL_TYPE_MARSHAL_TEMPLATES(Transform2D)
+DECL_TYPE_MARSHAL_TEMPLATES(Vector3)
+DECL_TYPE_MARSHAL_TEMPLATES(Basis)
+DECL_TYPE_MARSHAL_TEMPLATES(Quat)
+DECL_TYPE_MARSHAL_TEMPLATES(Transform)
+DECL_TYPE_MARSHAL_TEMPLATES(AABB)
+DECL_TYPE_MARSHAL_TEMPLATES(Color)
+DECL_TYPE_MARSHAL_TEMPLATES(Plane)
+
+#define MARSHALLED_IN(m_type, m_from_ptr) (GDMonoMarshal::marshalled_in_##m_type(m_from_ptr))
+#define MARSHALLED_OUT(m_type, m_from) (GDMonoMarshal::marshalled_out_##m_type(m_from))
 
 } // namespace GDMonoMarshal
 

+ 9 - 0
modules/mono/utils/macros.h

@@ -33,6 +33,15 @@
 
 // noreturn
 
+#if __cpp_static_assert
+#define GD_STATIC_ASSERT(m_cond) static_assert((m_cond), "Condition '" #m_cond "' failed")
+#else
+#define _GD_STATIC_ASSERT_VARNAME_CONCAT_B(m_ignore, m_name) m_name
+#define _GD_STATIC_ASSERT_VARNAME_CONCAT_A(m_a, m_b) GD_STATIC_ASSERT_VARNAME_CONCAT_B(hello there, m_a##m_b)
+#define _GD_STATIC_ASSERT_VARNAME_CONCAT(m_a, m_b) GD_STATIC_ASSERT_VARNAME_CONCAT_A(m_a, m_b)
+#define GD_STATIC_ASSERT(m_cond) typedef int GD_STATIC_ASSERT_VARNAME_CONCAT(godot_static_assert_, __COUNTER__)[((m_cond) ? 1 : -1)]
+#endif
+
 #undef _NO_RETURN_
 
 #ifdef __GNUC__