Make Function.prototype.toString() source text retention opt-in (#2560)#2562
Merged
Conversation
…stienros#2560) Since v4.9.0 (sebastienros#2394) every parsed function node pins the entire source string (Node.UserData = ctx.Input) so Function.prototype.toString() can return the original source, released only lazily on the first toString() call. Applications that cache many large prepared scripts and never call toString() therefore retain hundreds of MB of duplicated source strings (issue sebastienros#2560: ~250 MB, the same ~500 KB string per engine). Add an opt-in RetainFunctionSourceText parsing option (default false) plus an engine-level Options.RetainFunctionSourceText toggle. When disabled (the default) the source text is not retained and toString() returns the "function name() { [native code] }" placeholder. - RetainFunctionSourceText on IParsingOptions + ScriptParsingOptions/ModuleParsingOptions - ApplyTo wires OnNode conditionally; prepared path passes null/ctx.Input in AstAnalyzer - Options.RetainFunctionSourceText + fluent extension; engine default parser honors it - Test262 harness and the sebastienros#2394 source-asserting tests opt in to keep conformance green - Retained-memory regression test: 25 cached ~800 KB scripts retain 20.1 MB vs 1.8 MB Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bf1LESD4X8dMNPwLKJCAh9
lahma
enabled auto-merge (squash)
July 2, 2026 13:59
This was referenced Jul 3, 2026
Contributor
|
Can't we just keep the source text once, have the node store its own slice position, and only create the string slice from the source text based on the position when calling |
Collaborator
Author
|
You can always propose a PR, but sounds that we are still pinning the source string. |
8 tasks
This was referenced Jul 6, 2026
This was referenced Jul 10, 2026
This was referenced Jul 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2560.
Problem
Since v4.9.0 (#2394),
Function.prototype.toString()returns the real source text of user functions. To support this, every parsed function node pins the entire source string (Node.UserData = ctx.Input), released only lazily on the firsttoString()call. Applications that cache many large prepared scripts and never calltoString()therefore retain the full source for the lifetime of the cache — the reporter observed ~250 MB of duplicated source strings (the same ~500 KB string retained once per engine).Fix
Add an opt-in
RetainFunctionSourceTextoption, defaultfalse:IParsingOptions.RetainFunctionSourceTextonScriptParsingOptions/ModuleParsingOptions— controls per-parse retention (prepared and non-prepared).Options.RetainFunctionSourceText(+ fluentoptions.RetainFunctionSourceText()) — engine-level toggle for the default parser, so bareengine.Execute(string)can opt in without passing parsing options.When retention is disabled (the default), source text is not kept and
toString()returns the pre-4.9function name() { [native code] }placeholder. When enabled, real source is returned exactly as before.Verification
EngineLimitTests.ShouldAllowReasonableCallStackDepth, which crashes on unmodifiedmainhere too).built-ins/Function/prototype/toString/*conformance tests stay green via the harness opt-in.GarbageCollectionTests.PreparedScriptsDoNotRetainSourceTextByDefault): holding 25 distinct ~800 KB cached prepared scripts retains 20.1 MB with retention on vs 1.8 MB off — ~18.3 MB / 91% freed.The secondary env-pooling suspect (#2413) is left for a separate, benchmarked PR; it is a bounded, self-healing-under-load retention, unlike the quantified source-string regression fixed here.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Bf1LESD4X8dMNPwLKJCAh9