-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Description
Description
I have an application built using .NET 4.8 that makes extensive use of LINQ CompileToMethod to precompile lots of scripts to managed binaries. This works great on .NET 4.8 and almost works right on .NET 9 using a runtimeconfig + dotnet exec to run the application.
I'm using the runtimeconfig trick to identify .NET core compatibility issues before trying to roll the whole application forward, and considering using the runtimeconfig trick to deploy the application itself. (Rolling it forward as-is is difficult because its script compiler relies on LINQ CompileToMethod and AssemblyBuilder.Save.)
The problem appears to be a missing redirect for CompilerServices.Closure and maybe also StrongBox`1. The rest of the application seems to work fine.
Reproduction Steps
- Compile a LINQ expression containing a closure using LINQ CompileToMethod on .NET 4.8
- Invoke the compiled method on modern .NET
I can share a build of the application that will repro the issue, but for licensing reasons (middleware fees not yet paid) I can't distribute it publicly yet. Just email me.
An example DLL containing problematic references to Closure is here:
action.zip
It was generated using the BCL's LINQ CompileToMethod and AssemblyBuilder.Save.
Expected behavior
System.Runtime.CompilerServices.Closure should resolve to System.Linq.Expressions.dll since that seems to be where it lives now.
Actual behavior
> ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
> ---> System.TypeLoadException: Could not load type 'System.Runtime.CompilerServices.Closure' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
> at System.Signature.GetSignature(Void* pCorSig, Int32 cCorSig, RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo methodHandle, RuntimeType declaringType)
> at System.Reflection.RuntimeMethodInfo.<get_Signature>g__LazyCreateSignature|25_0()
> at System.Reflection.RuntimeMethodInfo.get_ReturnType()
It appears that there's no redirect/forwarding from System.Core to Closure's new home.
Regression?
It worked in .NET Framework, but I don't think this is a regression compared to a previous version of .NET Core
Known Workarounds
- Use .NET Framework
- Patch the DLLs, maybe?
Configuration
.NET 9.0.6 on Windows 11 x64
Other information
Some sample IL of a method that fails:
.method public static
class [mscorlib]System.Threading.Tasks.Task l40c5_decl (
class [HeavenLens]HeavenLens.Combat.ActionScriptContext context
) cil managed
{
// Method begins at RVA 0x153dc
// Header size: 12
// Code size: 95 (0x5f)
.maxstack 6
.locals init (
[0] object[]
)
IL_0000: ldc.i4.1
IL_0001: newarr [mscorlib]System.Object
IL_0006: dup
IL_0007: ldc.i4.0
IL_0008: ldarg.0
IL_0009: newobj instance void class [System.Core]System.Runtime.CompilerServices.StrongBox`1<class [HeavenLens]HeavenLens.Combat.ActionScriptContext>::.ctor(!0)
IL_000e: stelem.ref
IL_000f: stloc.0
IL_0010: nop
IL_0011: nop
IL_0012: ldloc.0
IL_0013: ldc.i4.0
IL_0014: ldelem.ref
IL_0015: castclass class [System.Core]System.Runtime.CompilerServices.StrongBox`1<class [HeavenLens]HeavenLens.Combat.ActionScriptContext>
IL_001a: ldfld !0 class [System.Core]System.Runtime.CompilerServices.StrongBox`1<class [HeavenLens]HeavenLens.Combat.ActionScriptContext>::Value
IL_001f: ldstr "Power"
IL_0024: nop
IL_0025: ldloc.0
IL_0026: ldc.i4.0
IL_0027: ldelem.ref
IL_0028: castclass class [System.Core]System.Runtime.CompilerServices.StrongBox`1<class [HeavenLens]HeavenLens.Combat.ActionScriptContext>
IL_002d: ldfld !0 class [System.Core]System.Runtime.CompilerServices.StrongBox`1<class [HeavenLens]HeavenLens.Combat.ActionScriptContext>::Value
IL_0032: castclass class [HeavenLens]HeavenLens.HLBaseScriptContext`1<class [HeavenLens]HeavenLens.Combat.ActionScriptContext>
IL_0037: ldnull
IL_0038: ldloc.0
IL_0039: newobj instance void [System.Core]System.Runtime.CompilerServices.Closure::.ctor(object[], object[])
IL_003e: ldftn float64 attack_gun.Statements::'<ExpressionCompilerImplementationDetails>{163}lambda_method'(class [System.Core]System.Runtime.CompilerServices.Closure)
IL_0044: newobj instance void class [mscorlib]System.Func`1<float64>::.ctor(object, native int)
IL_0049: newobj instance void valuetype [HeavenLens.Data]HeavenLens.Scripts.ValueOrClosure`1<float64>::.ctor(class [mscorlib]System.Func`1<!0>)
IL_004e: ldstr "Power"
IL_0053: callvirt instance class [HeavenLens]HeavenLens.RuntimeExpression class [HeavenLens]HeavenLens.HLBaseScriptContext`1<class [HeavenLens]HeavenLens.Combat.ActionScriptContext>::Expr(valuetype [HeavenLens.Data]HeavenLens.Scripts.ValueOrClosure`1<float64>, string)
IL_0058: callvirt instance void [HeavenLens.Data]HeavenLens.Scripts.IScriptContext::InitializeConstant<class [HeavenLens]HeavenLens.RuntimeExpression>(string, !!0)
IL_005d: ldnull
IL_005e: ret
} // end of method Statements::l40c5_decl