[mono][AOT] gsharedvt method calling INumberBase<T>.TryParse fails in aot-only mode

Abierto
#137,120 1 comentario 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
38/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
csharp

Línea de trabajo

Start by tracing Mono full AOT generic sharing for the constrained INumber<T>.TryParse call in BareHolder<T>.Set; the report points to mini-generic-sharing.c and mini_instantiate_gshared_info. Reproduce with the provided iOS AOT setup, comparing the reflection-created closed type with direct construction and interpreter mode. Done when the generic value type parses successfully in AOT-only mode without JIT compilation.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

area-Codegen-AOT-mono untriaged
Description

With Mono full AOT on iOS (UseInterpreter=false), a method on a generic type over a value type that calls T.TryParse(string, NumberStyles, IFormatProvider, out T) fails if the AOT compiler never saw the closed type and it has to run as gsharedvt code. The same method works when the closed type is constructed directly, and with the interpreter.

This came from MudBlazor's slider crashing MAUI Blazor Hybrid apps on iPhone (https://github.com/MudBlazor/MudBlazor/issues/14134). Blazor creates components from a Type and names MudSlider<int> only as a type argument, so the slider always runs as gsharedvt code.

Reproduction Steps

A class library (built with Optimize=true):

using System.Globalization;
using System.Numerics;

public abstract class BareBase
{
    public abstract bool Set(string text);
    public abstract string Text { get; }
}

public sealed class BareHolder<T> : BareBase where T : struct, INumber<T>
{
    private T _value;

    public override string Text => _value.ToString(null, CultureInfo.InvariantCulture);

    public override bool Set(string text)
    {
        if (!T.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
        {
            return false;
        }

        _value = result;
        return true;
    }
}

public static class BareFactory
{
    public static BareBase Create<THolder>() where THolder : BareBase => (BareBase)Activator.CreateInstance(typeof(THolder))!;
}

Called from an iOS app (net10.0-ios, UseInterpreter=false, MtouchLink=SdkOnly):

BareFactory.Create<BareHolder<long>>().Set("181"); // throws
new BareHolder<short>().Set("181");               // works
Expected behavior

Set parses the value, as it does with the interpreter or when the closed type is constructed directly.

Actual behavior
System.ExecutionEngineException: Attempting to JIT compile method 'bool Issue14134.BareHolder`1<long>:Set (string)' while running in aot-only mode.

When the call is inside an async method, the runtime aborts instead:

* Assertion at src/mono/mono/mini/mini-generic-sharing.c:2761, condition `is_ok (error)' not met, function:mini_instantiate_gshared_info, Attempting to JIT compile method 'void Issue14134.SvmAsyncHolder`1/<SetValueTextAsync>d__5<long>:MoveNext ()' while running in aot-only mode.

The reporter's physical iPhone build asserted iface_offset != -1 in mini-generic-sharing.c instead.

Regression?

Unknown.

Known Workarounds
  • Construct the closed type where the AOT compiler sees it, for example new BareHolder<long>() in a method that never runs.
  • Avoid T.TryParse: double.TryParse or decimal.TryParse followed by T.CreateSaturating works in the same gsharedvt context, as do T.Zero, T.One and T.CreateTruncating. MudBlazor does this in https://github.com/MudBlazor/MudBlazor/pull/14136.

Moving T.TryParse into a separate generic method doesn't help. The gsharedvt caller resolves that method on entry and Mono tries to JIT it, even when the call isn't reached.

Configuration

.NET SDK 10.0.403, runtime 10.0.14 (10.0.13 too), iOS workload 27.1.10018, Xcode 27.1, iOS 27.1 arm64 simulator, Debug and Release.

Other information

Possibly related: https://github.com/dotnet/runtime/issues/118697

Lenguaje dominante
C#
Estrellas
18.4k
Forks
5.8k
Merge medio
2 d 12 h
PR fusionados (30 d)
581

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de dotnet/runtime

Todos los issues de dotnet/runtime

Issues similares

Más issues de C#

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.