Skip to content

[mono] Support copying arrays of compatible pointers #104611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -1599,7 +1599,6 @@ public static void Copy_SourceAndDestinationNeverConvertible_ThrowsArrayTypeMism
}

[Fact]
[SkipOnMono("https://github.com/dotnet/runtime/issues/104197")]
public static unsafe void Copy_CompatiblePointers()
{
// Can copy between compatible pointers
Expand Down
11 changes: 4 additions & 7 deletions src/mono/mono/metadata/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -3582,6 +3582,7 @@ mono_class_is_subclass_of_internal (MonoClass *klass, MonoClass *klassc,
gboolean check_interfaces)
{
MONO_REQ_GC_UNSAFE_MODE;

/* FIXME test for interfaces with variant generic arguments */
if (check_interfaces) {
mono_class_init_internal (klass);
Expand Down Expand Up @@ -4284,13 +4285,9 @@ mono_class_is_assignable_from_general (MonoClass *klass, MonoClass *oklass, gboo

MonoClass *eclass;
MonoClass *eoclass;
if (signature_assignment) {
eclass = composite_type_to_reduced_element_type (klass);
eoclass = composite_type_to_reduced_element_type (oklass);
} else {
eclass = m_class_get_cast_class (klass);
eoclass = m_class_get_cast_class (oklass);
}

eclass = composite_type_to_reduced_element_type (klass);
eoclass = composite_type_to_reduced_element_type (oklass);

*result = (eclass == eoclass);
return;
Expand Down
24 changes: 11 additions & 13 deletions src/mono/mono/metadata/icall.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,7 @@ ves_icall_System_Array_GetValueImpl (MonoObjectHandleOnStack array_handle, MonoO
MonoClass * const array_class = mono_object_class (array);
MonoClass * const element_class = m_class_get_element_class (array_class);

if (m_class_is_native_pointer (element_class)) {
mono_error_set_not_supported (error, NULL);
return;
}

if (m_class_is_valuetype (element_class)) {
if (m_class_is_valuetype (element_class) || mono_class_is_pointer (element_class)) {
gsize element_size = mono_array_element_size (array_class);
gpointer element_address = mono_array_addr_with_size_fast (array, element_size, (gsize)pos);
MonoObject *res = mono_value_box_checked (element_class, element_address, error);
Expand Down Expand Up @@ -872,13 +867,16 @@ ves_icall_System_Array_FastCopy (MonoObjectHandleOnStack source_handle, int sour
if (m_class_is_valuetype (dest_class) || m_class_is_enumtype (dest_class) ||
m_class_is_valuetype (src_class) || m_class_is_valuetype (src_class))
return FALSE;

/* It's only safe to copy between arrays if we can ensure the source will always have a subtype of the destination. We bail otherwise. */
if (!mono_class_is_subclass_of_internal (src_class, dest_class, FALSE))
return FALSE;

if (m_class_is_native_pointer (src_class) || m_class_is_native_pointer (dest_class))
return FALSE;

if (mono_class_is_pointer (dest_class) || mono_class_is_pointer (src_class)) {
/* if we're copying between at least one array of pointers, only allow it if both dest_class is assignable from src_class (checked above, and src_class is assignable from dest_class). This should only be true if both src_class and dest_class have a common cast_class. (for example: int*[] and uint*[] are ok, but void*[] and int*[] are not)). */
if (!mono_class_is_assignable_from_internal (dest_class, src_class))
return FALSE;
} else {
/* It's only safe to copy between arrays if we can ensure the source will always have a subtype of the destination. We bail otherwise. */
if (!mono_class_is_subclass_of_internal (src_class, dest_class, FALSE))
return FALSE;
}
}

if (m_class_is_valuetype (dest_class)) {
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -6529,7 +6529,7 @@ mono_value_box_handle (MonoClass *klass, gpointer value, MonoError *error)

error_init (error);

g_assert (m_class_is_valuetype (klass));
g_assert (m_class_is_valuetype (klass) || mono_class_is_pointer (klass));
g_assert (value != NULL);
if (G_UNLIKELY (m_class_is_byreflike (klass))) {
char *full_name = mono_type_get_full_name (klass);
Expand Down
Loading