fix(scripts): memoize missing-assembly resolution on the site compile path
This commit is contained in:
@@ -89,9 +89,21 @@ public class ScriptCompilationService
|
|||||||
/// <c>ScriptAnalysisService.DefaultOptions</c> and
|
/// <c>ScriptAnalysisService.DefaultOptions</c> and
|
||||||
/// <c>ScriptTrustPolicy.DefaultReferences</c> already follow this pattern.
|
/// <c>ScriptTrustPolicy.DefaultReferences</c> already follow this pattern.
|
||||||
/// </para>
|
/// </para>
|
||||||
|
///
|
||||||
|
/// <para>
|
||||||
|
/// Static options alone are NOT enough: every <c>script.Compile()</c> binds the
|
||||||
|
/// transitive closure of these references, and Roslyn's default resolver
|
||||||
|
/// re-resolves that closure through <c>MetadataReference.CreateFromFile</c> on
|
||||||
|
/// EVERY compile (~74–105 fresh native metadata copies per compiled script,
|
||||||
|
/// confirmed live post-5a781c70 on 2026-08-12: 21 scripts held 6,640
|
||||||
|
/// AssemblyMetadata/PEReader/MetadataImageReference objects). The shared
|
||||||
|
/// <see cref="CachingScriptMetadataResolver"/> memoizes those resolutions
|
||||||
|
/// process-wide; see its doc for the full mechanism.
|
||||||
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly ScriptOptions SharedScriptOptions = ScriptOptions.Default
|
private static readonly ScriptOptions SharedScriptOptions = ScriptOptions.Default
|
||||||
.WithReferences(ScriptAssemblies)
|
.WithReferences(ScriptAssemblies)
|
||||||
|
.WithMetadataResolver(CachingScriptMetadataResolver.Instance)
|
||||||
.WithImports(
|
.WithImports(
|
||||||
"System",
|
"System",
|
||||||
"System.Collections.Generic",
|
"System.Collections.Generic",
|
||||||
|
|||||||
+15
@@ -251,4 +251,19 @@ public class ScriptCompilationServiceTests
|
|||||||
// The options object itself is cached, so it must not be rebuilt either.
|
// The options object itself is cached, so it must not be rebuilt either.
|
||||||
Assert.Same(first.CompiledScript.Options, second.CompiledScript.Options);
|
Assert.Same(first.CompiledScript.Options, second.CompiledScript.Options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compile_UsesProcessWideCachingMetadataResolver()
|
||||||
|
{
|
||||||
|
SiteScriptCompileCache.Clear();
|
||||||
|
var result = _service.Compile("resolver-pin", "return 41 + 1;");
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
// Without the shared caching resolver, EVERY compile re-resolves the
|
||||||
|
// transitive assembly closure via MetadataReference.CreateFromFile —
|
||||||
|
// ~74+ fresh native metadata copies per compiled script (2026-08-12 dump).
|
||||||
|
Assert.Same(
|
||||||
|
ZB.MOM.WW.ScadaBridge.ScriptAnalysis.CachingScriptMetadataResolver.Instance,
|
||||||
|
result.CompiledScript!.Options.MetadataResolver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user