FParsec needs --nooptimizationdata to avoid crashes

Issue #16 resolved
Michael Giagnocavo
created an issue

By default the F# compiler will cross-module optimize code, and I'm seeing that it ends up inlining manyChars into the client assembly. manyChars constructs a ManyChars class from FParsecCS. This is an internal class, but InternalsVisibleTo allows FParsec to do so. But, if that call is inlined into the client assembly, a method access violation occurs:

Unhandled Exception: System.MethodAccessException: Attempt by method '<StartupCode$ftest>.$Program.main@()' to access method 'FParsec.ManyChars1<System.__Canon>..ctor(Microsoft.FSharp.Core.FSharpFunc2<FParsec.CharStream1<System.__Canon>,FParsec.Reply1<Char>>, Microsoft.FSharp.Core.FSharpFunc2<FParsec.CharStream1<System.__Canon>,FParsec.Reply`1<Char>>)' failed. at <StartupCode$ftest>.$Program.main@() in C:\Projects\ftest\Program.fs:line 2

Repro: open FParsec (manyChars anyChar) |> ignore

By adding --nooptimizationdata to the FParsec build options, this bug goes away.

Comments (2)

  1. Stephan Tolksdorf

    Michael, thanks a lot for reporting this issue.

    As Don Syme just confirmed, this is a bug in the F# compiler.

    It seems to me that there are two possible workarounds: 1) adding --nooptimizationdata to the FParsec build flags and then explicitly "inline" all small public functions that should be inlined or 2) add [<MethodImplAttribute(MethodImplOptions.NoInlining)>] to all potentially problematic small functions.

    For the moment I'll just add the --nooptimizationdata flag. Later, probably over the weekend, I'll investigate whether implementing 2) makes sense.

  2. Stephan Tolksdorf

    [<MethodImplAttribute(MethodImplOptions.NoInlining)>] has the disadvantage that it also inhibits JIT inlining, so adding the /nooptimizationdata flag is probably the best way to workaround this compiler bug.

    I don't expect any noticable performance impact from this change. Should anyone notice a performance regression, I'd be very interested in the details.

    Note that although the /nooptimizationdata flag improves binary compatibility you should always recompile any F# assembly referencing FParsec.dll after you recompile FParsec.dll.

    Michael, thanks again for reporting the issue.

  3. Log in to comment