Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking F# AOT, Trimmability, ILLink #13398

Open
3 of 9 tasks
kant2002 opened this issue Jun 28, 2022 · 6 comments
Open
3 of 9 tasks

Tracking F# AOT, Trimmability, ILLink #13398

kant2002 opened this issue Jun 28, 2022 · 6 comments
Labels

Comments

@kant2002
Copy link
Contributor

kant2002 commented Jun 28, 2022

Note
This is a "meta" issue for tracking purposes, since GitHub does not support special types of issues.
@kant2002 I've converted it to the tracking issue, if you don't mind.

Original description

AOT and trimmability is around the corner, and FSharp has issues with some of these technologies. There visible issues with NativeAOT, but I suspect R2R may AOT less code due to these issues or maybe trimmer keep more code.

Describe the solution you'd like

I would like to create action plan of known issues for NativeAOT and trimmability of generated FSharp code to have smaller steps toward F# ❤️ AOT goal. I would like that reflection-free mode of NativeAOT, as opposed to normal NativeAOT mode where reflection working would be also considered.

Describe alternatives you've considered

Seems to be fsharp/fslang-suggestions#919 reach some conclusion, so I think we should go to action.
Also I consider target just NativeAOT with reflection (default), but seems to be having no-reflection is easy way to uncover issues with trimmability and unnecessary reflection usage in app. I consider that approach more of technique to find issues faster, plus I may have smaller app.

Open issues

@charlesroddie
Copy link
Contributor

I'll make a start on the RFC this weekend (reflection free codegen).

What is the "recursive generics" issue? Does it manifest in non-string-related code? If not, then this issue is a subset of the other one on string functions.

@kant2002
Copy link
Contributor Author

kant2002 commented Jul 3, 2022

@charlesroddie the recursive generic issue can be triggered by printf I suppose, but I can reproduce with Array2D.init 2 3 (fun i j -> i + j) and ILC would print scary warning. Sample which I give, does not crash app, but I maybe I did not put enough efforts into trying. Maybe @MichalStrehovsky can tell us - does issue with recursive generics crash some sample app of him, or not?

@MichalStrehovsky
Copy link
Member

Maybe @MichalStrehovsky can tell us - does issue with recursive generics crash some sample app of him, or not?

You can make generic recursion crash something at runtime. I'm not too keen on fiddling with F# to find it, but here's some C#:

System.Console.WriteLine(Count<int>(3));
System.Console.WriteLine(Count<int>(100));

static int Count<T>(int i) =>
    i switch
    {
        0 => 0,
        _ => 1 + Count<Foo<T>>(i - 1)
    };

struct Foo<T> { }

This will print following warning at compile time:

ILC: AOT analysis warning IL3054: Program.<<Main>$>g__Count|0_0<Foo`1<Foo`1<Foo`1<Foo`1<Int32>>>>>(Int32): Generic expansion to 'Program.<<Main>$>g__Count|0_0<Foo`1<Foo`1<Foo`1<Foo`1<Foo`1<Int32>>>>>>(Int32)' was aborted due to generic recursion. An exception will be thrown at runtime if this codepath is ever reached. Generic recursion also negatively affects compilation speed and the size of the compilation output. It is advisable to remove the source of the generic recursion by restructuring the program around the source of recursion. The source of generic recursion might include: 'Program.<<Main>$>g__Count|0_0<T>(Int32)'

The at runtime, the first call will succeed and print the number (because the depth was sufficiently low), but throws for the second call:

3
Unhandled Exception: System.TypeLoadException: Could not load type 'Program' from assembly 'repro, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null'.
   at Internal.Runtime.CompilerHelpers.ThrowHelpers.ThrowTypeLoadExceptionWithArgument(ExceptionStringID, String, String, String) + 0x42
   at Program.<<Main>$>g__Count|0_0[T](Int32) + 0x29
   at Program.<<Main>$>g__Count|0_0[T](Int32) + 0x3c
   at Program.<<Main>$>g__Count|0_0[T](Int32) + 0x3c
   at Program.<<Main>$>g__Count|0_0[T](Int32) + 0x3c
   at Program.<<Main>$>g__Count|0_0[T](Int32) + 0x3c
   at Program.<Main>$(String[]) + 0x2f

@MichalStrehovsky
Copy link
Member

Interpolated strings like $"{x}" breaks in reflection-free mode.

We don't make any effort in the dotnet/runtime repo to make libraries work with reflection-free mode, besides no-brainer easy fixes that would be accepted even without reflection-free mode. Reflection-free mode things should ideally be separate issues that either have a no-brainer easy fix that would be acceptable even without the NativeAOT reflection-free mode as a motivating scenario, or can be easily Won't fixed as undesirable.

@vzarytovskii vzarytovskii moved this to Not Planned in F# Compiler and Tooling Jul 7, 2022
@vzarytovskii vzarytovskii added this to the Backlog milestone Jul 7, 2022
@vzarytovskii vzarytovskii added the Area-AOT Everything related to AOT label Sep 21, 2022
@vzarytovskii vzarytovskii changed the title F# AOT story Tracking F# AOT story Oct 3, 2022
@vzarytovskii vzarytovskii moved this from Not Planned to Planned in F# Compiler and Tooling Oct 3, 2022
@vzarytovskii vzarytovskii changed the title Tracking F# AOT story Tracking F# AOT, Trimmability, ILLink Oct 6, 2022
@charlesroddie
Copy link
Contributor

charlesroddie commented Sep 14, 2023

Trimming annotations tracked here: #15980

Resolved issues

  • System.ArgumentException when publishing trimmed, self-contained app: resolved with a trimming annotation
  • printf usage requires a lot of rd.xml boilerplate: This is resolved by --reflectionfree (which disallows printf).
  • printf "%А" does not work in reflection-free mode. Same as above

Probably not issues/need more info

  • FSharp.Core.OptimizedClosures.FSharpFunc has recusive generics (?): aside from string functions I don't see an example of this and I don't for example see an ILC warning on Array2D.init.
  • A function calling Assembly.GetExecutingAssembly() gets inlined across assembly boundaries: not AOT-specific
  • Tail opcode being emitted for normal methods, destroys JIT optimizations: not AOT-specific

Remaining issues

  • Hello world uses printf: S to fix
  • Ensure that FSharp.Core is trimmable. Trimming annotations issue here: Annotate FSharp.Core for trimmability #15980
  • Interpolated strings like $"{x}" breaks in reflection-free mode. This is a big one and needs tracking. I can write this up. Currently $"Hello world" also has the problems that it bloats the size of an assembly by several megabytes, and generates ludicrous code with extremely complex generics. I think it's easy to conceive what the solution should be as it's just a matter of properly compiling the code.

@Lanayx
Copy link
Contributor

Lanayx commented Jan 25, 2024

Wanted to add here that PrintfFormat is used not only for string printing, so it shouldn't be regarded as deprecated version of interpolation. For example Giraffe (and Oxpecker) use it for type inference from route to handler where part of route should match parameter handler. So I expect printf to work with non-reflection-free AOT mode as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Planned
Development

No branches or pull requests

5 participants