JamesNK / Newtonsoft.Json

Json.NET is a popular high-performance JSON framework for .NET
https://www.newtonsoft.com/json
MIT License
10.71k stars 3.24k forks source link

Avoid LINQ expression trees on .NET 6+. #2902

Closed filipnavara closed 11 months ago

filipnavara commented 11 months ago

The condition was changed in https://github.com/JamesNK/Newtonsoft.Json/pull/2678 and it looks like an accidental search and replace rather than intentional change. Other similar code path uses the reflection on .NET 6 builds.

Notably, the LINQ expression trees are broken for many scenarios on iOS for .NET 6 and 7. This was tracked by https://github.com/dotnet/runtime/issues/69410 and fixed in .NET 8 with refactoring of several switches in the LINQ expression implementation but the changes were not back-ported to older .NET releases. The suggested workaround (using Mono interpreter) unfortunately hits a different unrelated issue (https://github.com/dotnet/runtime/issues/89359) which was also fixed in .NET 8 only.

All the unit tests still pass locally for me with this change. I have also confirmed that it resolves the following crash on our iOS application:

System.ExecutionEngineException: Attempting to JIT compile method '(wrapper delegate-invoke) System.Collections.Generic.IList`1<Google.Apis.Gmail.v1.Data.Label> <Module>:invoke_callvirt_IList`1<Label>_ListLabelsResponse (Google.Apis.Gmail.v1.Data.ListLabelsResponse)' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.

   at System.Linq.Expressions.Interpreter.FuncCallInstruction`2[[Google.Apis.Gmail.v1.Data.ListLabelsResponse, Google.Apis.Gmail.v1, Version=1.62.0.3105, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab],[System.Collections.Generic.IList`1[[Google.Apis.Gmail.v1.Data.Label, Google.Apis.Gmail.v1, Version=1.62.0.3105, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab]], System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Run(InterpretedFrame )
   at System.Linq.Expressions.Interpreter.Interpreter.Run(InterpretedFrame )
   at System.Linq.Expressions.Interpreter.LightLambda.Run(Object[] )
   at System.Dynamic.Utils.DelegateHelpers.FuncThunk1[Object,Object](Func`2 handler, Object t1)
   at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)
JamesNK commented 11 months ago

Good find. Thanks.