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

未关闭
#137,120 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
38/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
csharp

调研方向

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.

由索引模型根据 Issue 内容生成。

描述

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

主要语言
C#
星标
18.4k
派生
5.8k
平均合并
2 天 12 小时
30 天内合并 PR
581

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

dotnet/runtime 的其他 Issue

查看 dotnet/runtime 的全部 Issue

相似的 Issue

更多 C# Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。