[loader] Init MonoClass:sizes.element_size lazily (Fixes #43563) (#5559)
* [loader] If signaling recursive type initialize, don't double free
If we detect that a recursive type initialization is happening, we should leave
without removing the class from the init_pending_tld_id list. Otherwise we get
a double-free when the outer recursive call finally finishes and tries to
remove the same element.
Also re-load the init_list from TLS since a recursive call to mono_class_init could
have modified it between the time the current mono_class_init call started and
when it is finishing.
* [loader] Improve error message when a field's type is a failed class
Add the class failure to the field failure error message.
* [tests] Check that runtime can represent recursive structs
Regression tests for https://bugzilla.xamarin.com/show_bug.cgi?id=43563
* [loader] Init MonoClass:sizes.element_size lazily (Fixes #43563)
Originally mono_bounded_array_class_get () would populate
MonoClass:sizes.element_size as soon as the MonoClass for the array was needed.
This is a problem because we cannot call mono_class_array_element_size () on
the element class on a valuetype until mono_class_layout_fields () finishes
initializing it.
That means that structs which contain an array of themselves would hit the
recursive initialization check in mono_class_setup_fields and the MonoClass for
the element class would be marked as failed to load.
Instead we rely on the MonoClass:size_inited bit to tell us whether the array
class has been initialized and if not, we set the array element size in
mono_class_layout_fields.
This is possible because MonoClass:sizes.element_size is only really needed to
know how to allocate space for an array. When laying out a class that contains
an array we don't need the element size - they array is just a reference type.
Example:
```csharp
struct S {
static S[][] foo;
}
```
Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=43563