Implement Array.Initialize in C##77336
Conversation
|
I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label. |
|
Are changes needed in Mono? |
|
The mono changes look ok. |
|
Test failures were caused by a System.Reflection.MetadataLoadContext test that scans all methods on an array type. Since a local variable of function pointer type was added to a method on System.Array, MLC would fail when decoding this local variable. Fortunately, the fix is pretty trivial, since we have a convenient place to move that to. |
| // otherwise this is a no-op. Generally this method is called automatically by the compiler | ||
| [MethodImpl(MethodImplOptions.InternalCall)] | ||
| public extern void Initialize(); | ||
| public unsafe void Initialize() |
There was a problem hiding this comment.
@dotnet/ilc-contrib Should Array.Initialize be marked with RequiresUnreferenceCode, or is the value type default constructor the special-cased by the trimmer and always preserved?
There was a problem hiding this comment.
I think it should:
var b = new ElementType[1];
b.Initialize();
struct ElementType
{
public ElementType()
{
Console.WriteLine(".ctor called");
}
}dotnet run prints out ".ctor called".
But trimmed the app doesn't print out anything.
Related question - what should default do in this case, for example:
var c = new ElementType[1];
c[0] = default; // Should this call the default .ctor?Running it seems like it will NOT call the .ctor - but what does it do?
There was a problem hiding this comment.
Same goes for AOT - published as Native AOT the app above also doesn't print out anything.
There was a problem hiding this comment.
Related question - what should default do in this case, for example:
According to the specification, default ignores the parameterless constructor and generates a zeroed instance.
There was a problem hiding this comment.
Hmmm, adding RequiresUnreferencedCode on Array.Initialize has a ripple effect. It introduces warnings in situations where array type is passed into DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All).
I guess it will need more careful thought.
|
LGTM modulo comments. Thank you! Another 100 lines of manually managed C++ bite the dust. |
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| void | ||
| ves_icall_System_Array_InitializeInternal (MonoObjectHandleOnStack arr_handle, MonoError *error) |
There was a problem hiding this comment.
@reflectronic Are you up for implementing the mono version mostly in C#, too?
I think we can add something like NativeAOT's default constructor -> function pointer icall and then most of this code could be managed.
We don't need to do it in this PR (unless you want to). Just an idea.
There was a problem hiding this comment.
I would have done it like that, but I couldn't quite find the function I wanted (wasn't sure if the thing I was looking at was safe to just call with calli, whether it would try to unbox the argument, etc.). Certainly, I could address it in a follow up.
There was a problem hiding this comment.
@reflectronic I don't think there's an existing icall, but it should be ok to add something like this:
MonoMethod * const method = mono_class_get_method_from_name_checked (element_class, ".ctor", 0, 0, error);
if (!method) {
return NULL;
}
gpointer addr = mono_compile_method_checked (method, error);
if (!is_ok (error)) {
mono_error_cleanup (error);
return NULL;
}
return mono_create_ftnptr(addr);
on the C# side it would look pretty much like the NativeAOT version - cast the icall's IntPtr result to a function pointer type and call it.
wasn't sure if the thing I was looking at was safe to just call with calli, whether it would try to unbox the argument, etc.
I'm pretty certain that it will just work. I believe it should be expecting an unboxed argument.
|
The failure is known nuget infrastructure issue |
|
Thanks for the reviews and feedback |
Implements
Array.Initializefor Mono, moves most of the implementation to managed code for CoreCLR, and adds a test.For those using C++/CLI, your arrays shall now be initialized marginally faster: