Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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 @@ -163,6 +163,10 @@ public static JSTypeInfo CreateJSTypeInfoForTypeSymbol(ITypeSymbol type)
return new JSInvalidTypeInfo();
}
return new JSFunctionTypeInfo(false, signatureTypes);

// struct with inline array attribute
case { TypeKind: TypeKind.Struct } structType when structType.GetAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == "System.Runtime.CompilerServices.InlineArrayAttribute"):
return new JSInvalidTypeInfo();
default:
return new JSInvalidTypeInfo();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,27 @@ internal static partial void InOutRef(
ref int a3
);
}
";

public static readonly string InlineArrayAttributeUnsupported = @"
//InOutRef
using System;
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.CompilerServices;

partial class Basic
{
[InlineArray(42)]
internal struct MyArray
{
byte b;
}

[JSImport(""DoesNotExist"")]
internal static partial void UnsupportedAttribute(
MyArray array
);
}
";

public static readonly string AllUnsupported = @"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public class Fails
"Parameters with 'in', 'out' and 'ref' modifiers are not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'a2'.",
"Parameters with 'in', 'out' and 'ref' modifiers are not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'a3'.",
}, null };
yield return new object?[] { CodeSnippets.InlineArrayAttributeUnsupported, new string[] {
"The type 'Basic.MyArray' is not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'array'.",
}, null };
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public static void AssertPreSourceGeneratorCompilation(Compilation comp, params
"CS0234", // Missing type or namespace - LibraryImportAttribute
"CS0246", // Missing type or namespace - LibraryImportAttribute
"CS8019", // Unnecessary using
"CS0169", // Field is never used
};

foreach (string diagnostic in additionalAllowedDiagnostics)
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/assembly.c
Original file line number Diff line number Diff line change
Expand Up @@ -1785,7 +1785,7 @@ struct HasReferenceAssemblyAttributeIterData {
};

static gboolean
has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, guint32 *cols, gpointer user_data)
{
gboolean stop_scanning = FALSE;
struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/metadata/class-getters.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ MONO_CLASS_GETTER(m_class_is_unicode, gboolean, , MonoClass, unicode)
MONO_CLASS_GETTER(m_class_was_typebuilder, gboolean, , MonoClass, wastypebuilder)
MONO_CLASS_GETTER(m_class_is_array_special_interface, gboolean, , MonoClass, is_array_special_interface)
MONO_CLASS_GETTER(m_class_is_byreflike, gboolean, , MonoClass, is_byreflike)
MONO_CLASS_GETTER(m_class_is_inlinearray, guint, , MonoClass, is_inlinearray)
MONO_CLASS_GETTER(m_class_inlinearray_value, gboolean, , MonoClass, inlinearray_value)
MONO_CLASS_GETTER(m_class_get_min_align, guint8, , MonoClass, min_align)
MONO_CLASS_GETTER(m_class_get_packing_size, guint, , MonoClass, packing_size)
MONO_CLASS_GETTER(m_class_is_ghcimpl, gboolean, , MonoClass, ghcimpl)
Expand Down
124 changes: 85 additions & 39 deletions src/mono/mono/metadata/class-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ static gboolean class_kind_may_contain_generic_instances (MonoTypeKind kind);
static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd);
static int generic_array_methods (MonoClass *klass);
static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
static gboolean class_has_isbyreflike_attribute (MonoClass *klass);
static struct FoundAttrUD class_has_isbyreflike_attribute (MonoClass *klass);
static struct FoundAttrUD class_has_inlinearray_attribute (MonoClass *klass);

static
GENERATE_TRY_GET_CLASS_WITH_CACHE(icollection, "System.Collections.Generic", "ICollection`1");
Expand Down Expand Up @@ -291,6 +292,9 @@ mono_class_setup_fields (MonoClass *klass)
instance_size = MONO_ABI_SIZEOF (MonoObject);
}

if (m_class_is_inlinearray (klass) && m_class_inlinearray_value (klass) <= 0)
mono_class_set_type_load_failure (klass, "Inline array lenght must be greater than 0.");

/* Get the real size */
explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
if (explicit_size)
Expand Down Expand Up @@ -359,6 +363,10 @@ mono_class_setup_fields (MonoClass *klass)
mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
break;
}
if (m_class_is_inlinearray (klass)) {
mono_class_set_type_load_failure (klass, "Inline array struct must not have explicit layout.");
break;
}
}
if (mono_type_has_exceptions (field->type)) {
char *class_name = mono_type_get_full_name (klass);
Expand Down Expand Up @@ -699,9 +707,21 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError
mono_get_runtime_callbacks ()->init_class (klass);

// compute is_byreflike
if (m_class_is_valuetype (klass))
if (class_has_isbyreflike_attribute (klass))
if (m_class_is_valuetype (klass)) {
struct FoundAttrUD attr;
attr = class_has_isbyreflike_attribute (klass);
if (attr.has_attr)
klass->is_byreflike = 1;
attr = class_has_inlinearray_attribute (klass);
if (attr.has_attr) {
klass->is_inlinearray = 1;
if (*(intptr_t*)attr.value > G_MAXUINT32) {
mono_class_set_type_load_failure (klass, "Inline array length > G_MAXUINT32");
goto parent_failure;
}
klass->inlinearray_value = *(guint32*)attr.value;
}
}

mono_loader_unlock ();

Expand Down Expand Up @@ -746,65 +766,75 @@ mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
mono_loader_unlock ();
}

struct FoundAttrUD {
/* inputs */
const char *nspace;
const char *name;
gboolean in_corlib;
/* output */
gboolean has_attr;
};

static gboolean
has_wellknown_attribute_func (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
has_wellknown_attribute_func (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, guint32 *cols, gpointer user_data)
{
struct FoundAttrUD *has_attr = (struct FoundAttrUD *)user_data;
if (!strcmp (name, has_attr->name) && !strcmp (nspace, has_attr->nspace)) {
has_attr->has_attr = TRUE;
return TRUE;
struct FoundAttrUD *attr = (struct FoundAttrUD *)user_data;
if (!strcmp (name, attr->name) && !strcmp (nspace, attr->nspace)) {
attr->has_attr = TRUE;
if (attr->has_value) {
MonoError error;
MonoMethod *ctor = mono_get_method_checked (image, method_token, NULL, NULL, &error);
if (ctor) {
const char *data = mono_metadata_blob_heap (image, cols [MONO_CUSTOM_ATTR_VALUE]);
uint32_t data_size = mono_metadata_decode_value (data, &data);
MonoDecodeCustomAttr *decoded_attr = mono_reflection_create_custom_attr_data_args_noalloc (image, ctor, (guchar*)data, data_size, &error);
mono_error_assert_ok (&error);
attr->value = decoded_attr->typed_args[0]->value.primitive;
} else {
g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, method_token, mono_error_get_message (&error));
}
}
}
/* TODO: use typeref_scope_token to check that attribute comes from
* corlib if in_corlib is TRUE, without triggering an assembly load.
* If we're inside corlib, expect the scope to be
* MONO_RESOLUTION_SCOPE_MODULE I think, if we're outside it'll be an
* MONO_RESOLUTION_SCOPE_ASSEMBLYREF and we'll need to check the
* name.*/
return FALSE;
return attr->has_attr;
}

static gboolean
class_has_wellknown_attribute (MonoClass *klass, const char *nspace, const char *name, gboolean in_corlib)
static struct FoundAttrUD
class_has_wellknown_attribute (MonoClass *klass, const char *nspace, const char *name, gboolean in_corlib, gboolean has_value)
{
struct FoundAttrUD has_attr;
has_attr.nspace = nspace;
has_attr.name = name;
has_attr.in_corlib = in_corlib;
has_attr.has_attr = FALSE;
struct FoundAttrUD attr;
attr.nspace = nspace;
attr.name = name;
attr.in_corlib = in_corlib;
attr.has_attr = FALSE;
attr.has_value = has_value;

mono_class_metadata_foreach_custom_attr (klass, has_wellknown_attribute_func, &has_attr);
mono_class_metadata_foreach_custom_attr (klass, has_wellknown_attribute_func, &attr);

return has_attr.has_attr;
return attr;
}

static gboolean
method_has_wellknown_attribute (MonoMethod *method, const char *nspace, const char *name, gboolean in_corlib)
static struct FoundAttrUD
method_has_wellknown_attribute (MonoMethod *method, const char *nspace, const char *name, gboolean in_corlib, gboolean has_value)
{
struct FoundAttrUD has_attr;
has_attr.nspace = nspace;
has_attr.name = name;
has_attr.in_corlib = in_corlib;
has_attr.has_attr = FALSE;
struct FoundAttrUD attr;
attr.nspace = nspace;
attr.name = name;
attr.in_corlib = in_corlib;
attr.has_value = has_value;

mono_method_metadata_foreach_custom_attr (method, has_wellknown_attribute_func, &has_attr);
mono_method_metadata_foreach_custom_attr (method, has_wellknown_attribute_func, &attr);

return has_attr.has_attr;
return attr;
}


static gboolean
static struct FoundAttrUD
class_has_isbyreflike_attribute (MonoClass *klass)
{
return class_has_wellknown_attribute (klass, "System.Runtime.CompilerServices", "IsByRefLikeAttribute", TRUE);
return class_has_wellknown_attribute (klass, "System.Runtime.CompilerServices", "IsByRefLikeAttribute", TRUE, FALSE);
}

static struct FoundAttrUD
class_has_inlinearray_attribute (MonoClass *klass)
{
return class_has_wellknown_attribute (klass, "System.Runtime.CompilerServices", "InlineArrayAttribute", TRUE, TRUE);
}


Expand All @@ -815,7 +845,8 @@ mono_class_setup_method_has_preserve_base_overrides_attribute (MonoMethod *metho
/* FIXME: implement well known attribute check for dynamic images */
if (image_is_dynamic (image))
return FALSE;
return method_has_wellknown_attribute (method, "System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute", TRUE);
struct FoundAttrUD attr = method_has_wellknown_attribute (method, "System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute", TRUE, FALSE);
return attr.has_attr;
}

static gboolean
Expand Down Expand Up @@ -868,6 +899,8 @@ mono_class_create_generic_inst (MonoGenericClass *gclass)
klass->this_arg.type = m_class_get_byval_arg (klass)->type;
klass->this_arg.data.generic_class = klass->_byval_arg.data.generic_class = gclass;
klass->this_arg.byref__ = TRUE;
klass->is_inlinearray = gklass->is_inlinearray;
klass->inlinearray_value = gklass->inlinearray_value;
klass->enumtype = gklass->enumtype;
klass->valuetype = gklass->valuetype;

Expand Down Expand Up @@ -2184,6 +2217,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
real_size = MONO_ABI_SIZEOF (MonoObject);
}

gboolean is_inlined = FALSE;
for (pass = 0; pass < passes; ++pass) {
for (i = 0; i < top; i++){
gint32 align;
Expand Down Expand Up @@ -2217,6 +2251,15 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
}

size = mono_type_size (field->type, &align);
if (m_class_is_inlinearray (klass)) {
if (!is_inlined) {
size *= m_class_inlinearray_value (klass);
is_inlined = TRUE;
} else {
mono_class_set_type_load_failure (klass, "Inline array struct must have a single field.");
break;
}
}

/* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
align = packing_size ? MIN (packing_size, align): align;
Expand Down Expand Up @@ -2416,6 +2459,9 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_
class_size = field_offsets [i] + size;
}

if (m_class_is_inlinearray (klass) && has_static_fields)
mono_class_set_type_load_failure (klass, "Struct with inline array atribute must have a single field.");

if (has_static_fields && class_size == 0)
/* Simplify code which depends on class_size != 0 if the class has static fields */
class_size = 8;
Expand Down
11 changes: 11 additions & 0 deletions src/mono/mono/metadata/class-init.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@
#include <mono/metadata/metadata.h>
#include <mono/metadata/class-internals.h>

struct FoundAttrUD {
/* inputs */
const char *nspace;
const char *name;
gboolean in_corlib;
gboolean has_value;
/* output */
gboolean has_attr;
gpointer value;
};

MONO_COMPONENT_API gboolean
mono_class_init_internal (MonoClass *klass);

Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/metadata/class-private-definition.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ struct _MonoClass {
guint wastypebuilder : 1; /* class was created at runtime from a TypeBuilder */
guint is_array_special_interface : 1; /* gtd or ginst of once of the magic interfaces that arrays implement */
guint is_byreflike : 1; /* class is a valuetype and has System.Runtime.CompilerServices.IsByRefLikeAttribute */
guint is_inlinearray : 1; /* class is a valuetype and has System.Runtime.CompilerServices.InlineArrayAttribute */
guint inlinearray_value; /* class is a valuetype and has System.Runtime.CompilerServices.InlineArrayAttribute value */

/* next byte */
guint8 min_align;
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/custom-attrs-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ typedef struct _MonoDecodeCustomAttr {
MonoCustomAttrInfo*
mono_custom_attrs_from_builders (MonoImage *alloc_img, MonoImage *image, MonoArray *cattrs);

typedef gboolean (*MonoAssemblyMetadataCustomAttrIterFunc) (MonoImage *image, guint32 typeref_scope_token, const gchar* nspace, const gchar* name, guint32 method_token, gpointer user_data);
typedef gboolean (*MonoAssemblyMetadataCustomAttrIterFunc) (MonoImage *image, guint32 typeref_scope_token, const gchar* nspace, const gchar* name, guint32 method_token, guint32 *cols, gpointer user_data);

void
mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data);
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/custom-attrs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2813,7 +2813,7 @@ metadata_foreach_custom_attr_from_index (MonoImage *image, guint32 idx, MonoAsse
if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
continue;

stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
stop_iterating = func (image, assembly_token, nspace, name, mtoken, cols, user_data);
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/mono/mono/metadata/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,11 @@ compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int
pos += offset;

type = mono_type_get_underlying_type (field->type);

// If a struct has inline array attribute and type is not generic instance, consider it as an array
if (m_class_is_inlinearray (klass) && type->type != MONO_TYPE_GENERICINST && type->type != MONO_TYPE_TYPEDBYREF && type->type != MONO_TYPE_VALUETYPE)
type->type = MONO_TYPE_ARRAY;

switch (type->type) {
case MONO_TYPE_U:
case MONO_TYPE_I:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>Exe</OutputType>
<MonoAotIncompatible>true</MonoAotIncompatible>
</PropertyGroup>
<ItemGroup>
<Compile Include="InlineArrayInvalid.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>Exe</OutputType>
<MonoAotIncompatible>true</MonoAotIncompatible>
</PropertyGroup>
<ItemGroup>
<Compile Include="InlineArrayValid.cs" />
Expand Down
4 changes: 0 additions & 4 deletions src/tests/issues.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1529,10 +1529,6 @@
<Issue>Static virtual methods are not yet implemented in the Mono runtime.</Issue>
</ExcludeList>

<ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/InlineArray/**">
<Issue>https://github.com/dotnet/runtime/issues/80798</Issue>
</ExcludeList>

<ExcludeList Include="$(XunitTestBinBase)/baseservices/exceptions/stackoverflow/stackoverflowtester/**">
<Issue>needs triage</Issue>
</ExcludeList>
Expand Down