Closed brettfo closed 3 years ago
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.
Presume codegen for now, and marking as 5.0 pending investigation.
cc @dotnet/jit-contrib
Going to take a preliminary look while waiting for other intermittent bugs to repro.
@dotnet/jit-contrib feel free to jump in and take this one.
Managed stack bactrace at point of overflow...
00000AA618C5710 00007ffa1664ece3 FSharp.Compiler.TypedTreeOps+ExprFolders`1[[System.__Canon, System.Private.CoreLib]].exprF(System.__Canon, Expr) [C:\repos\fsharp\src\fsharp\TypedTreeOps.fs @ 6511]
000000AA618C5790 00007ffa1586f706 Microsoft.FSharp.Collections.ListModule.Fold[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,System.__Canon>>, System.__Canon, Microsoft.FSharp.Collections.FSharpList`1<System.__Canon>) [C:\repos\fsharp\src\fsharp\FSharp.Core\list.fs @ 224]
000000AA618C57E0 00007ffa166511ff ILStubClass.IL_STUB_InstantiatingStub(Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>>>, Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>>>, Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>, Expr, TOp, Microsoft.FSharp.Collections.FSharpList`1, Microsoft.FSharp.Collections.FSharpList`1)
000000AA618C5830 00007ffa16651165 ILStubClass.IL_STUB_CallTailCallTarget(IntPtr, IntPtr, IntPtr)
000000AA618C58C0 00007ffa156e4f06 ILStubClass.IL_STUB_DispatchTailCalls(IntPtr, IntPtr, IntPtr)
000000AA618C5940 00007ffa1664f796 FSharp.Compiler.AutoBox.DecideExpr(cenv, Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>>>, Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>>>, Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1>, Expr) [C:\repos\fsharp\src\fsharp\autobox.fs @ 101]
000000AA618C5A40 00007ffa1664eec8 ILStubClass.IL_STUB_InstantiatingStub(Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2>>>>, Microsoft.FSharp.Core.FSharpFunc`2, Microsoft.FSharp.Core.FSharpFunc`2, Internal.Utilities.Collections.Tagged.Set`2, Expr) [/_/src/libraries/System.Private.CoreLib/src/System/Object.cs @ 27]
000000AA618C5A80 00007ffa1664ee40 ILStubClass.IL_STUB_CallTailCallTarget(IntPtr, IntPtr, IntPtr)
000000AA618C5AF0 00007ffa156e4f06 ILStubClass.IL_STUB_DispatchTailCalls(IntPtr, IntPtr, IntPtr)
000000AA618C5B70 00007ffa1664ed17 FSharp.Compiler.TypedTreeOps+ExprFolders`1[[System.__Canon, System.Private.CoreLib]].exprF(System.__Canon, Expr) [C:\repos\fsharp\src\fsharp\TypedTreeOps.fs @ 6511]
000000AA618C5BF0 00007ffa16650380 FSharp.Compiler.TypedTreeOps+ExprFolders`1[[System.__Canon, System.Private.CoreLib]].exprNoInterceptF(System.__Canon, Expr) [C:\repos\fsharp\src\fsharp\TypedTreeOps.fs @ 6523]
000000AA618C5C70 00007ffa1664eec8 ILStubClass.IL_STUB_InstantiatingStub(Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2>>>>, Microsoft.FSharp.Core.FSharpFunc`2, Microsoft.FSharp.Core.FSharpFunc`2, Internal.Utilities.Collections.Tagged.Set`2, Expr) [/_/src/libraries/System.Private.CoreLib/src/System/Object.cs @ 27]
000000AA618C5CB0 00007ffa1664ee40 ILStubClass.IL_STUB_CallTailCallTarget(IntPtr, IntPtr, IntPtr)
000000AA618C5D20 00007ffa156e4f06 ILStubClass.IL_STUB_DispatchTailCalls(IntPtr, IntPtr, IntPtr)
000000AA618C5DA0 00007ffa1664ed17 FSharp.Compiler.TypedTreeOps+ExprFolders`1[[System.__Canon, System.Private.CoreLib]].exprF(System.__Canon, Expr) [C:\repos\fsharp\src\fsharp\TypedTreeOps.fs @ 6511]
000000AA618C5E20 00007ffa1664eec8 ILStubClass.IL_STUB_InstantiatingStub(Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2>>>>, Microsoft.FSharp.Core.FSharpFunc`2, Microsoft.FSharp.Core.FSharpFunc`2, Internal.Utilities.Collections.Tagged.Set`2, Expr) [/_/src/libraries/System.Private.CoreLib/src/System/Object.cs @ 27]
000000AA618C5E60 00007ffa1664ee40 ILStubClass.IL_STUB_CallTailCallTarget(IntPtr, IntPtr, IntPtr)
000000AA618C5ED0 00007ffa156e4f06 ILStubClass.IL_STUB_DispatchTailCalls(IntPtr, IntPtr, IntPtr)
000000AA618C5F50 00007ffa1664ed17 FSharp.Compiler.TypedTreeOps+ExprFolders`1[[System.__Canon, System.Private.CoreLib]].exprF(System.__Canon, Expr) [C:\repos\fsharp\src\fsharp\TypedTreeOps.fs @ 6511]
000000AA618C5FD0 00007ffa16650380 FSharp.Compiler.TypedTreeOps+ExprFolders`1[[System.__Canon, System.Private.CoreLib]].exprNoInterceptF(System.__Canon, Expr) [C:\repos\fsharp\src\fsharp\TypedTreeOps.fs @ 6523]
000000AA618C6050 00007ffa1664eec8 ILStubClass.IL_STUB_InstantiatingStub(Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.FSharpFunc`2,Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2>>>>, Microsoft.FSharp.Core.FSharpFunc`2, Microsoft.FSharp.Core.FSharpFunc`2, Internal.Utilities.Collections.Tagged.Set`2, Expr) [/_/src/libraries/System.Private.CoreLib/src/System/Object.cs @ 27]
000000AA618C6090 00007ffa1664ee40 ILStubClass.IL_STUB_CallTailCallTarget(IntPtr, IntPtr, IntPtr)
000000AA618C6100 00007ffa156e4f06 ILStubClass.IL_STUB_DispatchTailCalls(IntPtr, IntPtr, IntPtr)
000000AA618C6180 00007ffa1664ed17 FSharp.Compiler.TypedTreeOps+ExprFolders`1[[System.__Canon, System.Private.CoreLib]].exprF(System.__Canon, Expr) [C:\repos\fsharp\src\fsharp\TypedTreeOps.fs @ 6511]
... (frames omitted) ...
000000AA61A3DF70 00007ffa1664ed17 FSharp.Compiler.TypedTreeOps+ExprFolders`1[[System.__Canon, System.Private.CoreLib]].exprF(System.__Canon, Expr) [C:\repos\fsharp\src\fsharp\TypedTreeOps.fs @ 6511]
000000AA61A3DFF0 00007ffa1586f706 Microsoft.FSharp.Collections.ListModule.Fold[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,System.__Canon>>, System.__Canon, Microsoft.FSharp.Collections.FSharpList`1<System.__Canon>) [C:\repos\fsharp\src\fsharp\FSharp.Core\list.fs @ 224]
000000AA61A3E040 00007ffa1586f706 Microsoft.FSharp.Collections.ListModule.Fold[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,System.__Canon>>, System.__Canon, Microsoft.FSharp.Collections.FSharpList`1<System.__Canon>) [C:\repos\fsharp\src\fsharp\FSharp.Core\list.fs @ 224]
000000AA61A3E090 00007ffa1586f706 Microsoft.FSharp.Collections.ListModule.Fold[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,System.__Canon>>, System.__Canon, Microsoft.FSharp.Collections.FSharpList`1<System.__Canon>) [C:\repos\fsharp\src\fsharp\FSharp.Core\list.fs @ 224]
000000AA61A3E0E0 00007ffa1586f706 Microsoft.FSharp.Collections.ListModule.Fold[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,System.__Canon>>, System.__Canon, Microsoft.FSharp.Collections.FSharpList`1<System.__Canon>) [C:\repos\fsharp\src\fsharp\FSharp.Core\list.fs @ 224]
000000AA61A3E130 00007ffa1586f706 Microsoft.FSharp.Collections.ListModule.Fold[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,System.__Canon>>, System.__Canon, Microsoft.FSharp.Collections.FSharpList`1<System.__Canon>) [C:\repos\fsharp\src\fsharp\FSharp.Core\list.fs @ 224]
000000AA61A3E180 00007ffa1664afbd FSharp.Compiler.AutoBox.TransformImplFile(TcGlobals, ImportMap, TypedImplFile) [C:\repos\fsharp\src\fsharp\autobox.fs @ 169]
000000AA61A3E220 00007ffa165d9ce3 FSharp.Compiler.CompileOptions+ApplyAllOptimizations@1726-1.Invoke(TypedImplFile) [C:\repos\fsharp\src\fsharp\CompileOptions.fs @ 1735]
000000AA61A3E460 00007ffa1599f99c Microsoft.FSharp.Primitives.Basics.List.mapFold[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,System.Tuple`2<System.__Canon,System.__Canon>>>, System.__Canon, Microsoft.FSharp.Collections.FSharpList`1<System.__Canon>) [C:\repos\fsharp\src\fsharp\FSharp.Core\local.fs @ 389]
000000AA61A3E580 00007ffa15e860ab Microsoft.FSharp.Collections.ListModule.MapFold[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,System.Tuple`2<System.__Canon,System.__Canon>>>, System.__Canon, Microsoft.FSharp.Collections.FSharpList`1<System.__Canon>) [C:\repos\fsharp\src\fsharp\FSharp.Core\list.fs @ 85]
000000AA61A3E5C0 00007ffa165d8d2b FSharp.Compiler.CompileOptions.ApplyAllOptimizations(TcConfig, TcGlobals, Microsoft.FSharp.Core.FSharpFunc`2<ValRef,Microsoft.FSharp.Core.FSharpFunc`2<ValUseFlag,Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Collections.FSharpList`1,Microsoft.FSharp.Core.FSharpFunc`2<range,System.Tuple`2<Expr,TType>>>>>, System.String, ImportMap, Boolean, IncrementalOptimizationEnv, CcuThunk, Microsoft.FSharp.Collections.FSharpList`1) [C:\repos\fsharp\src\fsharp\CompileOptions.fs @ 1723]
000000AA61A3E6E0 00007ffa15fda3e8 FSharp.Compiler.Driver.main2a[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Args`1<System.Tuple`8<System.__Canon,TcConfig,TcImports,TcImports,System.__Canon,ErrorLogger,CcuThunk,System.Tuple`8<System.String,Microsoft.FSharp.Collections.FSharpList`1,System.__Canon,System.__Canon,System.__Canon,System.__Canon,System.__Canon,System.Tuple`1>>>) [C:\repos\fsharp\src\fsharp\fsc.fs @ 2057]
000000AA61A3E950 00007ffa156db3a4 FSharp.Compiler.Driver.typecheckAndCompile(CompilationThreadToken, System.String[], Resolver, Boolean, ReduceMemoryFlag, CopyFSharpCoreFlag, Exiter, ErrorLoggerProvider, Microsoft.FSharp.Core.FSharpOption`1<Microsoft.FSharp.Core.FSharpFunc`2<TcImports,Microsoft.FSharp.Core.Unit>>, Microsoft.FSharp.Core.FSharpOption`1<Microsoft.FSharp.Core.FSharpFunc`2<System.Tuple`3<TcGlobals,System.String,ILModuleDef>,Microsoft.FSharp.Core.Unit>>) [C:\repos\fsharp\src\fsharp\fsc.fs @ 2209]
000000AA61A3EA20 00007ffa156d9159 FSharp.Compiler.Driver.mainCompile(CompilationThreadToken, System.String[], Resolver, Boolean, ReduceMemoryFlag, CopyFSharpCoreFlag, Exiter, ErrorLoggerProvider, Microsoft.FSharp.Core.FSharpOption`1<Microsoft.FSharp.Core.FSharpFunc`2<TcImports,Microsoft.FSharp.Core.Unit>>, Microsoft.FSharp.Core.FSharpOption`1<Microsoft.FSharp.Core.FSharpFunc`2<System.Tuple`3<TcGlobals,System.String,ILModuleDef>,Microsoft.FSharp.Core.Unit>>) [C:\repos\fsharp\src\fsharp\fsc.fs @ 2227]
000000AA61A3EA80 00007ffa156d8e6b FSharp.Compiler.SourceCodeServices.CompileHelpers+result@168-10.Invoke(Exiter) [C:\repos\fsharp\src\fsharp\service\service.fs @ 169]
000000AA61A3EB10 00007ffa156d52d6 FSharp.Compiler.SourceCodeServices.CompileHelpers.tryCompile(ErrorLogger, Microsoft.FSharp.Core.FSharpFunc`2<Exiter,Microsoft.FSharp.Core.Unit>) [C:\repos\fsharp\src\fsharp\service\service.fs @ 157]
000000AA61A3EBE0 00007ffa156d49a8 FSharp.Compiler.SourceCodeServices.CompileHelpers.compileFromArgs(CompilationThreadToken, System.String[], Resolver, Microsoft.FSharp.Core.FSharpOption`1<Microsoft.FSharp.Core.FSharpFunc`2<TcImports,Microsoft.FSharp.Core.Unit>>, Microsoft.FSharp.Core.FSharpOption`1<Microsoft.FSharp.Core.FSharpFunc`2<System.Tuple`3<TcGlobals,System.String,ILModuleDef>,Microsoft.FSharp.Core.Unit>>) [C:\repos\fsharp\src\fsharp\service\service.fs @ 167]
000000AA61A3EC70 00007ffa156d4394 <StartupCode$FSharp-Compiler-Private>.$Service+Compile@1053-1.Invoke(Microsoft.FSharp.Core.Unit) [C:\repos\fsharp\src\fsharp\service\service.fs @ 1053]
000000AA61A3ECB0 00007ffa156d4318 FSharp.Compiler.AbstractIL.Internal.Library+CancellableModule+delay@741[[System.__Canon, System.Private.CoreLib]].Invoke(System.Threading.CancellationToken) [C:\repos\fsharp\src\absil\illib.fs @ 741]
000000AA61A3ECE0 00007ffa156d3b78 <StartupCode$FSharp-Compiler-Private>.$Reactor+EnqueueAndAwaitOpAsync@185-2[[System.__Canon, System.Private.CoreLib]].Invoke(CompilationThreadToken) [C:\repos\fsharp\src\fsharp\service\Reactor.fs @ 188]
000000AA61A3EE10 00007ffa156d2e48 <StartupCode$FSharp-Compiler-Private>.$Reactor+loop@71-115.Invoke(Microsoft.FSharp.Core.FSharpOption`1<FSharp.Compiler.SourceCodeServices.ReactorCommands>) [C:\repos\fsharp\src\fsharp\service\Reactor.fs @ 82]
000000AA61A3EED0 00007ffa156d021f Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvokeNoHijackCheck[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](Microsoft.FSharp.Control.AsyncActivation`1<System.__Canon>, Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,Microsoft.FSharp.Control.FSharpAsync`1<System.__Canon>>, System.__Canon) [C:\repos\fsharp\src\fsharp\FSharp.Core\async.fs @ 411]
000000AA61A3EF20 00007ffa156d037d <StartupCode$FSharp-Compiler-Private>.$Reactor+loop@61-113.Invoke(Microsoft.FSharp.Control.AsyncActivation`1<Microsoft.FSharp.Core.FSharpOption`1<FSharp.Compiler.SourceCodeServices.ReactorCommands>>) [C:\repos\fsharp\src\fsharp\service\Reactor.fs @ 61]
000000AA61A3EF50 00007ffa156cf504 <StartupCode$FSharp-Core>.$Mailbox+processFirstArrival@303-8[[System.__Canon, System.Private.CoreLib]].Invoke(Microsoft.FSharp.Control.AsyncActivation`1<System.__Canon>) [C:\repos\fsharp\src\fsharp\FSharp.Core\mailbox.fs @ 303]
000000AA61A3EFA0 00007ffa1529a364 Microsoft.FSharp.Control.Trampoline.Execute(Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Control.AsyncReturn>) [C:\repos\fsharp\src\fsharp\FSharp.Core\async.fs @ 104]
000000AA61A3F000 00007ffa15299c00 Microsoft.FSharp.Control.TrampolineHolder.ExecuteWithTrampoline(Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Control.AsyncReturn>) [C:\repos\fsharp\src\fsharp\FSharp.Core\async.fs @ 169]
000000AA61A3F060 00007ffa15299636 <StartupCode$FSharp-Core>.$Async+-ctor@155-1.Invoke(System.Object) [C:\repos\fsharp\src\fsharp\FSharp.Core\async.fs @ 157]
000000AA61A3F0B0 00007ffa731b6de9 System.Threading.QueueUserWorkItemCallback+c.<.cctor>b__6_0(System.Threading.QueueUserWorkItemCallback) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.cs @ 784]
000000AA61A3F0E0 00007ffa731ac88e System.Threading.ExecutionContext.RunForThreadPoolUnsafe[[System.__Canon, System.Private.CoreLib]](System.Threading.ExecutionContext, System.Action`1<System.__Canon>, System.__Canon ByRef) [/_/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs @ 332]
000000AA61A3F120 00007ffa731b6d2f System.Threading.QueueUserWorkItemCallback.Execute() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.cs @ 800]
000000AA61A3F160 00007ffa731b5d2c System.Threading.ThreadPoolWorkQueue.Dispatch() [/_/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.cs @ 641]
000000AA61A3F210 00007ffa731a49aa System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [/_/src/coreclr/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs @ 29]
000000AA61A3F600 00007ffa744ffed3 [DebuggerU2MCatchHandlerFrame: 000000aa61a3f600]
Something goes wrong in the new tail call helpers and we end up not reusing stack frames.
cc @jakobbotsch @erozenfeld
I cannot quite see what segment of the stack is looping in your backtrace. However, it looks like the instantiating stub generated and used by the JIT here also needs to do a tailcall. Since it is leaving a normal frame on the stack the tailcalling mechanism is probably not kicking in. We might be missing tests for this scenario, though it is unclear to me, there are many generic tests around here, and some of them should involve instantiating stubs: https://github.com/dotnet/runtime/blob/f35d747e8d7fe44d7dab76b9683d7c642ec26888/src/tests/JIT/Directed/tailcall/more_tailcalls.cs#L616-L626
I'm not sure how this is normally handled, to me it seems like tail-calling a pointer produced by loadvirtftn
will not guarantee that the stack does not grow since that pointer could be an instantiating stub.
The instantiating stubs for trivial signatures (e.g. where all arguments fit into registers) use regular tail calls. The instantiating stubs for more complex signatures do not tailcall. It is what's causing the problem.
Here's the top of the native stack, frame 0a is one of those complex instantiating stubs
00 00007ffa`743e86b1 : 00000000`00000000 00007ffa`743e8461 00007ffa`15a566f0 00000000`00000000 : coreclr!SigPointer::GetTypeHandleThrowing+0x30 [F:\workspace\_work\1\s\src\coreclr\src\vm\siginfo.cpp @ 993]
01 00007ffa`743e86b1 : 00000000`00000000 00007ffa`00000000 00000000`ffffffe7 00007ffa`15a566f0 : coreclr!SigPointer::GetTypeHandleThrowing+0xde1 [F:\workspace\_work\1\s\src\coreclr\src\vm\siginfo.cpp @ 1379]
02 00007ffa`743e86b1 : 00000000`00000000 00007ffa`743e8461 00007ffa`15a566f0 00000000`02000076 : coreclr!SigPointer::GetTypeHandleThrowing+0xde1 [F:\workspace\_work\1\s\src\coreclr\src\vm\siginfo.cpp @ 1379]
03 00007ffa`7444a72b : 00000000`00000000 00000000`00000003 00007ffa`00000000 000000aa`618c5640 : coreclr!SigPointer::GetTypeHandleThrowing+0xde1 [F:\workspace\_work\1\s\src\coreclr\src\vm\siginfo.cpp @ 1379]
04 00007ffa`7444998e : 0000025e`86367300 00000000`fffffffd 00007ffa`168dd020 00007ffa`743e7019 : coreclr!Dictionary::PopulateEntry+0xafb [F:\workspace\_work\1\s\src\coreclr\src\vm\genericdict.cpp @ 1197]
05 (Inline Function) : --------`-------- --------`-------- --------`-------- --------`-------- : coreclr!JIT_GenericHandleWorker+0x8e [F:\workspace\_work\1\s\src\coreclr\src\vm\jithelpers.cpp @ 3287]
06 00007ffa`744491a8 : 0000025e`8930ffb0 00007ffa`00000006 00000000`00000018 00007ffa`1664e530 : coreclr!JIT_GenericHandle_Framed+0x1a6 [F:\workspace\_work\1\s\src\coreclr\src\vm\jithelpers.cpp @ 3351]
07 00007ffa`1664ece3 : 000000aa`618c5530 00000000`00000003 0000025e`856a33c8 000000aa`618c5820 : coreclr!JIT_GenericHandleClass+0x58 [F:\workspace\_work\1\s\src\coreclr\src\vm\jithelpers.cpp @ 3448]
08 00007ffa`1586f706 : 0000025e`8930ffb0 0000025e`8930ffd8 000000aa`618c5820 000000aa`618c59e0 : FSharp_Compiler_Private!FSharp.Compiler.TypedTreeOps+ExprFolders`1[[System.__Canon, System.Private.CoreLib]].exprF(System.__Canon, Expr)+0x43
09 00007ffa`166511ff : 000000aa`618c5760 00000000`00000003 00007ffa`00000001 00007ffa`00000001 : FSharp_Core!Microsoft.FSharp.Collections.ListModule.Fold[[System.__Canon, System.Private.CoreLib],[FSharp.Compiler.Range+range, FSharp.Compiler.Private]](Microsoft.FSharp.Core.FSharpFunc`2<range,Microsoft.FSharp.Core.FSharpFunc`2<System.__Canon,range>>, range, Microsoft.FSharp.Collections.FSharpList`1<System.__Canon>)+0xffffffff`ffee1aa6
0a 00007ffa`16651165 : 00000001`168cc2e8 00000001`00000000 00001653`092758be 00000001`168edc58 : FSharp_Compiler_Private!ILStubClass.IL_STUB_InstantiatingStub(Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1<Val>>,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1<Val>>>>, Microsoft.FSharp.Core.FSharpFunc`2<Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1<Val>>,Microsoft.FSharp.Core.FSharpFunc`2<Expr,Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1<Val>>>>, Internal.Utilities.Collections.Tagged.Set`2<Val,System.Collections.Generic.IComparer`1<Val>>, Expr, TOp, Microsoft.FSharp.Collections.FSharpList`1<TType>, Microsoft.FSharp.Collections.FSharpList`1<Expr>)+0x4f
0b 00007ffa`156e4f06 : 0000025e`8930ffd8 ffffffff`00000001 0000025e`00000001 00007ffa`1664e530 : System_Diagnostics_Process!ILStubClass.IL_STUB_CallTailCallTarget(IntPtr, IntPtr, IntPtr)+0x75
0c 00007ffa`1664f796 : 000000aa`618c5760 00007ffa`168edcb8 00000000`00000000 00007ffa`168dd020 : System_Private_CoreLib!ILStubClass.IL_STUB_DispatchTailCalls(IntPtr, IntPtr, IntPtr)+0x76
and the code for this stub:
00007ffa`166511b0 55 push rbp
00007ffa`166511b1 4883ec40 sub rsp, 40h
00007ffa`166511b5 488d6c2440 lea rbp, [rsp+40h]
00007ffa`166511ba 488bc2 mov rax, rdx
00007ffa`166511bd 4d8bd0 mov r10, r8
00007ffa`166511c0 4c894c2420 mov qword ptr [rsp+20h], r9
00007ffa`166511c5 488b5530 mov rdx, qword ptr [rbp+30h]
00007ffa`166511c9 4889542428 mov qword ptr [rsp+28h], rdx
00007ffa`166511ce 488b5538 mov rdx, qword ptr [rbp+38h]
00007ffa`166511d2 4889542430 mov qword ptr [rsp+30h], rdx
00007ffa`166511d7 488b5540 mov rdx, qword ptr [rbp+40h]
00007ffa`166511db 4889542438 mov qword ptr [rsp+38h], rdx
00007ffa`166511e0 488bd1 mov rdx, rcx
00007ffa`166511e3 4c8bc0 mov r8, rax
00007ffa`166511e6 4d8bca mov r9, r10
00007ffa`166511e9 48b9c8578e16fa7f0000 mov rcx, 7FFA168E57C8h
00007ffa`166511f3 48b850e56416fa7f0000 mov rax, offset CLRStub[MethodDescPrestub]@7ffa1664e550 (00007ffa`1664e550)
00007ffa`166511fd ffd0 call rax
00007ffa`166511ff 90 nop
00007ffa`16651200 488d6500 lea rsp, [rbp]
00007ffa`16651204 5d pop rbp
00007ffa`16651205 c3 ret
So is the fix it as simple as emitting tail
prefixes for the callis in CreateInstantiatingILStub
and perhaps CreateUnboxingILStubForSharedGenericValueTypeMethods
?
It would introduce very significant performance regression for scenarios that happen to go through these instantiating stubs and do not care about tailcalls.
I think that the best way to solve this is by manually "inlining" the instantiating stub into the tailcall helper: Load address of the actual target + instantiating stub arg in the first tail call helper and match it in the second tail call helper. IIRC, @jakobbotsch tried this, but there were some difficulties with doing that.
Another way to solve this would be to create a tailcalling instantiating stubs (ie slow instantiating stubs that have the tail prefix before the call), but that feels too wide-spread.
I think that the best way to solve this is by manually "inlining" the instantiating stub into the tailcall helper: Load address of the actual target + instantiating stub arg in the first tail call helper and match it in the second tail call helper. IIRC, @jakobbotsch tried this, but there were some difficulties with doing that.
Related comment: https://github.com/dotnet/coreclr/pull/26418#issuecomment-536127958
I think at that time I had been through a few edge cases with VSDs and default interface methods and I was on the path of duplicating all the logic of ldvirtftn
. I'm sure someone with more knowledge of the runtime/type system would not have significant problems doing this, however.
However doing this will still not fix the underlying issue, the symptom being that you cannot robustly tailcall a pointer returned by ldftn
/ldvirtftn
. Even with the suggested fix the F# example still breaks if the target method is first assigned to a delegate before being tail called (right?). But maybe this problem is academic, I suppose the old mechanisms did not handle it either.
Delegates do not make any guarantees about when or whether they internally perform tailcalls.
I was on the path of duplicating all the logic of ldvirtftn
Does the F# example use virtual methods? I think we just need to fix the non-virtual method case for this.
Delegates do not make any guarantees about when or whether they internally perform tailcalls.
What about explicit ldftn
+ tail. calli
? Also, it seems likely to me that F# users are relying on tailcalls via delegates, but maybe I am wrong.
Does the F# example use virtual methods? I think we just need to fix the non-virtual method case for this.
No, but the same problem could occur with virtual methods I presume.
Is it feasible to detect when emitting the instantiating stub whether the target method contains a tail
prefix anywhere in its IL? I'm not sure whether this is feasible due to virtual methods, ReJIT, EnC, just brainstorming...
[edit: had posted the backtrace for the version without IL edits; so updated that part]
Need to dig through what is happening in F# but I think it is non-virtual.
Here's a simple C# repro that overflows... (modified so calls F->G and G->F have a tail
prefix):
using System;
class X
{
static int F<T>(int a, int r, T c, Span<int> d)
{
int result = r;
for (int i = a; i < d.Length; i++)
{
result += d[i];
}
return G(c, a, r, d, result);
}
static int G<T>(T c, int a, int r, Span<int> d, int result)
{
if (a == d.Length) return result;
else return F(a + 1, result, c, d);
}
static int Main()
{
int[] a = new int[1_000_000];
a[99] = 1;
var s = new Span<int>(a);
int r = F<string>(0, 0, "string", a);
Console.WriteLine($"r = {r}");
return r;
}
}
results in
Stack overflow.
Repeat 1732 times:
--------------------------------
at X.G[[System.__Canon, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.__Canon, Int32, Int32, System.Span`1<Int32>, Int32)
at System.Runtime.CompilerServices.RuntimeHelpers.DispatchTailCalls(IntPtr, Void (IntPtr, IntPtr, IntPtr*), IntPtr)
at X.F[[System.__Canon, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](Int32, Int32, System.__Canon, System.Span`1<Int32>)
at System.Runtime.CompilerServices.RuntimeHelpers.DispatchTailCalls(IntPtr, Void (IntPtr, IntPtr, IntPtr*), IntPtr)
--------------------------------
at X.G[[System.__Canon, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.__Canon, Int32, Int32, System.Span`1<Int32>, Int32)
at System.Runtime.CompilerServices.RuntimeHelpers.DispatchTailCalls(IntPtr, Void (IntPtr, IntPtr, IntPtr*), IntPtr)
at X.F[[System.__Canon, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](Int32, Int32, System.__Canon, System.Span`1<Int32>)
at X.Main()
So is the fix it as simple as emitting tail prefixes for the callis in CreateInstantiatingILStub and perhaps CreateUnboxingILStubForSharedGenericValueTypeMethods?
It would introduce very significant performance regression for scenarios that happen to go through these instantiating stubs and do not care about tailcalls.
Is it possible to create special instantiating stubs with tail prefixes that are only used when the caller dispatches a tail-prefixed call?
We could, but I think it is better to deal with it locally by "inlining" the instantiating stub into the tailcall helper: https://github.com/dotnet/runtime/issues/40864#issuecomment-674409519 . It should be local change, with less risk, and it will have better performance compared to introduring new type of instantiating stubs .
New type of instantiating stubs would be a new type system entity. Introducing new type system entities tends to be non-trivial because of they typically have to handled in many places.
Is it feasible to detect when emitting the instantiating stub whether the target method contains a tail prefix anywhere in its IL?
Here is this approach: https://github.com/jakobbotsch/runtime/commit/b1b668aa9e080f67a38924dbca0a41cdf1aac012 It fixes Andy's case above and should be much more pay-for-play than doing it unconditionally. Also, it is pretty self-contained and should work with delegates and virtual calls for free. On the other hand I could not anything similar in the runtime and I don't know if this kind of inspection of the IL will fly.
I agree it will fix this problem. The potential problems with this change:
Also, it may have GC hole for collectible types (not 100% about it). Is the hidden argument going to be reported to GC correctly to keep the collectible type alive when we are inside the tailcall dispatcher?
It introduce performance regression when the instantiating stub is used in situations where tailcalls do not matter (e.g. delegates mentioned above)
IMO, if the target method has explicit tail calls out of it, then the user has already declared that tailcalls do matter and the instantiating stubs should conservative about it. Otherwise it seems we won't be able to support higher order code relying on tailcalls. Again, not sure how academic this problem is.
It may have unpredictable behavior for obfuscated IL that sometimes does not have fully well-formed IL stream
Ok, I see. I don't know how to deal with this.
Also, it may have GC hole for collectible types (not 100% about it). Is the hidden argument going to be reported to GC correctly to keep the collectible type alive when we are inside the tailcall dispatcher?
Hmm, I'm not too familiar with how this works. But I think you are right -- if there is a previous dispatcher then the instantiating stub will return immediately, and since the hidden arg is just a native sized integer in the signature of the calli
it will not be reported to GC. I don't know if we can record in the signature used for the calli
that this is a hidden arg and if the changes are then becoming too infectious.
Would it be feasible for the complex instantiating stubs to detect at runtime if tail calls are pending (say looking at the TLS data) and then have two call sites, one that tail calls (presumably, slowly), the other that does a normal call.
Stubs would get bigger even if we never need the tail call part. Might also have some false positives where we tail call when not needed, but perhaps not too frequent?
Also seems like we could leverage tail call stress (likely with the change to always use helpers for tail calls) plus gc stress to get more gc coverage on these paths.
My guess is that we cannot detect that in general. Consider an example where the target function can do a fast tailcall to an instantiating stub for itself (which has one fewer arguments), while the instantiating stub cannot do a fast tailcall to the target function. Then there won't be any indication in the TLS that we are currently doing tailcalls.
@erozenfeld I take it you may not get around to fixing this.
Should we reassign? cc @JulieLeeMSFT
Yes, at this point I think we should reassign this.
Can I assign this to @jkotas?
I reassigned this issue to @jkotas since he already has a fix.
@jkotas , we are seeing this failure again,the repro is the same as before
Machine: Latest Windows 10 x64
Pre-verification:
On a clean machine install latest VS with the following workloads: .NET desktop development Add optional component F# desktop language support .NET Core cross-platform development Clone https://github.com/dotnet/fsharp and reset to commit 1c1b5ac7eacbbfd79e7277982e15178cecee20b4
Build with .\Build.cmd -c Release
Run test with dotnet test tests\fsharp\FSharpSuite.Tests.fsproj --no-restore --no-build --filter LargeRecordDoesNotStackOverflow -f netcoreapp3.1 -c Release -v n
At this point the test should pass.
Bug repro:
N.b., you may need to alter global.json with the following: { "sdk": { "version": "5.0.200-preview.21075.10" }, "tools": { "dotnet": "3.1.302", "dotnet": "5.0.200-preview.21075.10", ...
The stack overflow happens when running against the net5.0 runtime from : 5.0.200-preview.21075.10
Could you please open a new issue on this and extract the repro into a small program if possible?
I am not able to build using the steps above. I am getting errors like C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets( 131,5): error : Invalid restore input. Invalid target framework 'unsupported'.
Sigh!!! ... I will try
Machine: Latest Windows 10 x64
Pre-verification:
https://github.com/dotnet/fsharp
and reset to commit 1c1b5ac7eacbbfd79e7277982e15178cecee20b4.\Build.cmd -c Release
dotnet test tests\fsharp\FSharpSuite.Tests.fsproj --no-restore --no-build --filter LargeRecordDoesNotStackOverflow -f netcoreapp3.1 -c Release -v n
At this point the test should pass.
Bug repro:
C:\Program Files\dotnet\sdk\3.1.401
C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.7
dotnet --list-sdks
anddotnet --list-runtimes
global.json
with the following:Result: Stack overflow
Possibly related to #40581