Native AOT: Implicit F# quotations throw PlatformNotSupportedException in RuntimeHelpers.InitializeArray
メンテナーはふだん 2 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 45/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- fsharp
- 領域
- compilers
調査の方向性
Start with the attached reproduction project and compare the generated IL for the failing List.average quotation with the working List.sum case. Read the linked Native AOT limitation for RuntimeHelpers.InitializeArray and investigate whether the fix belongs in F# quotation code generation or Native AOT handling. Done means both expressions preserve their values and quotation behavior under Native AOT without the exception.
索引モデルが issue の本文から書いたものです。
説明
Description
Implicit F# quotations involving certain expressions, such as List.average, throw System.PlatformNotSupportedException in RuntimeHelpers.InitializeArray when compiled with Native AOT.
The same expressions execute successfully under the JIT, and direct evaluation without implicit quotation also works under Native AOT.
Repro steps
The issue reproduces with .NET 10 on Linux x64.
Environment:
- .NET SDK: 10.0.403
- FSharp.Core: 10.1.403
- Native AOT compiler/runtime pack: 10.0.14
- Target framework:
net10.0 - Runtime identifier:
linux-x64
The attached reproduction project contains the complete source and project file.
The relevant F# code is:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
type Holder() =
member _.Capture([<ReflectedDefinition(true)>] expr: Expr<float>) =
match expr with
| WithValue(value, _, _) -> unbox<float> value
| _ -> -1.0
The reproduction compares direct evaluation with implicit quotation:
run "direct-average" (fun () ->
List.average [1.0; 2.0; 3.0])
run "quoted-average" (fun () ->
holder.Capture(List.average [1.0; 2.0; 3.0]))
Run the attached project using the JIT:
dotnet run -c Release
Then publish and run with Native AOT:
dotnet publish -c Release -r linux-x64 -p:PublishAot=true
./bin/Release/net10.0/linux-x64/publish/MinimalAot
The reproduction catches exceptions and reports them in its output.
Expected behavior
Both expressions should evaluate to 2.0 without throwing an exception.
Implicit quotation should preserve the evaluated value and the corresponding expression tree under Native AOT, as it does under the JIT.
Actual behavior
Under Native AOT:
direct-average|OK|2
quoted-average|ERR|System.PlatformNotSupportedException: Operation is not supported on this platform.
The stack trace identifies:
System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(
System.Array,
System.RuntimeFieldHandle
)
The same reproduction does not encounter this exception under the JIT.
Investigation
The F# compiler generates IL to evaluate the original expression and reconstruct its quotation using serialized expression data.
The quotation deserialization includes an IL sequence resembling:
ldc.i4 <size>
newarr System.Byte
dup
ldtoken <RVA-field>
call RuntimeHelpers.InitializeArray
call Expr.Deserialize40
This sequence also appears in expressions that execute successfully under Native AOT, including the tested List.sum case.
Therefore, the local instruction sequence alone does not explain the failure.
Two experimental IL transformations were tested:
- Spilling the evaluated value: Store the computed result in a local variable before quotation reconstruction, then reload it after deserialization.
- Hoisting array initialization: Move the
newarr,dup,ldtoken, andInitializeArraysequence into a private static helper method returningbyte[].
Both transformations eliminated the original PlatformNotSupportedException.
In a broader test corpus containing 30 quotation expressions, the original generated IL produced 29 expected results and one PlatformNotSupportedException. After the array-initialization sequence was moved into a private helper, all 30 expressions produced their expected results without runtime errors.
These results suggest that the failure depends on the surrounding generated IL and its interaction with Native AOT's intrinsic recognition, rather than on List.average itself.
A nonempty evaluation stack alone does not explain the behavior, since other expressions with nonempty stacks execute successfully.
The exact condition that prevents intrinsic expansion has not yet been identified.
Known workarounds
The experimental IL transformations described above eliminate the exception in the tested cases.
However, they require post-compilation IL rewriting and have not been validated as general-purpose workarounds.
After eliminating the InitializeArray exception, separate quotation metadata-resolution errors may occur under Native AOT. Those are distinct from the issue reported here.
Possible resolution
Two potential approaches are worth investigating:
- F# compiler: Adjust quotation code generation so that serialized byte-array initialization consistently uses an IL structure recognized by Native AOT.
- Native AOT compiler: Improve recognition or handling of valid IL patterns involving
RuntimeHelpers.InitializeArray.
Any change should preserve quotation evaluation semantics, including captured values and expression reconstruction.
It is not yet clear whether the appropriate fix belongs in the F# compiler, the Native AOT compiler, or both.
Related issues
- https://github.com/dotnet/fsharp/issues/20764 — Unpickle a quotation literal once, not on every evaluation. Describes the quotation serialization and deserialization mechanism, but focuses on performance.
- https://github.com/dotnet/runtime/issues/69919 — Documents the Native AOT limitation for
RuntimeHelpers.InitializeArraycalls that cannot be intrinsically expanded. - https://github.com/dotnet/fsharp/issues/13398 — General F# Native AOT and trimming compatibility tracking.
The attached reproduction includes the original F# source, project file, and relevant IL excerpts comparing List.sum and List.average.
- 主要言語
- F#
- スター
- 4.3k
- フォーク
- 883
- 平均マージ
- 3日 4時間
- マージ済み PR(30日)
- 88
環境構築
このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
dotnet/fsharp のほかの issue
-
Needs-Triage
難易度 1/5 1時間未満 初心者へのやさしさ 95/100
メンテナーはふだん 2 日以内に返信
-
Semantic classification cache for opened documents is never populated (written to the unopened-documents cache)対応中かも @xperiandri が 63 日前に担当しました。 オープンNeeds-Triage
難易度 1/5 1時間未満 初心者へのやさしさ 90/100
メンテナーはふだん 2 日以内に返信
-
Needs-Triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
dotnet/fsharp#20265 · コメント 1 件 ·
メンテナーはふだん 2 日以内に返信
-
Bug Needs-Triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 2 日以内に返信
-
Needs-Triage
難易度 4/5 3〜5日 初心者へのやさしさ 42/100
メンテナーはふだん 2 日以内に返信
似ている issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
GaloisInc/llvm-pretty#211 ·
-
crash mlir
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
llvm/llvm-project#239604 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
bug good first issue self-hosted compiler
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
AeroForger/AeroFyl#1 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 63/100
KhronosGroup/SPIRV-LLVM-Translator#4151 ·
メンテナーはふだん 2 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
anthropics/claudes-c-compiler#322 ·