paulk-asert opened a new pull request, #2820:
URL: https://github.com/apache/groovy/pull/2820

   ### What this PR is
   
   The GROOVY-12281 investigation branch, opened for review of one shippable 
change plus its
   supporting evidence. **Only `2ab40501e2` ("soft GroovyClassValue mode — soft 
values with
   resurrection (opt-in)") is intended to land on master** — ideally 
cherry-picked or landed
   alone rather than squash-merging the branch. The other commits are 
investigation artifacts
   that should stay on the branch:
   
   - `45e3fc6a56` / `a429dd7415` — the *hybrid* prototype (measured, 
**declined**) and the guide
     update quantifying the existing `=false` escape hatch (the guide change is 
independently
     master-worthy if wanted);
   - `12d59e847b` — the assessment document (v2) and the loader/perf spike 
harnesses:
     
[GROOVY-12281-assessment.html](https://github.com/apache/groovy/blob/groovy12281/GROOVY-12281-assessment.html).
   
   ### Problem
   
   A `java.lang.ClassValue` association lives as long as its key class, so
   `ClassInfo.globalClassValue` entries on immortal platform classes (String, 
Integer, …) hold a
   strong chain to the ClassInfo and through it to Groovy's class loader — 
leaking every Groovy
   copy a container deploys and undeploys (JDK-8136353 / GROOVY-12142). The 
existing remedy,
   `-Dgroovy.use.classvalue=false`, gives up the per-Class fast path for every 
key
   (~4× on the raw lookup, +4.8% geomean on classic dispatch, hot platform 
idioms to 1.38×).
   
   ### Change
   
   `-Dgroovy.use.classvalue=soft` keeps `ClassValue` for all keys but stores 
each value behind a
   bootstrap-loaded `SoftReference`, cutting the only strong chain from 
immortal keys to the
   Groovy island. Three cooperating pieces make that safe (details and file 
references in the
   assessment):
   
   - **Resurrection** — a weak-key/weak-value side map is the identity 
authority: a value still
     reachable anywhere is re-associated, never replaced, so a fresh instance 
can only exist once
     no guard can still observe the old one. Classic call-site version guards 
therefore stay
     sound: legacy-compiled jars using `groovy-callsite` from the classpath are 
unaffected.
   - **Dirty roots** — ClassInfos carrying non-reconstructible state (installed 
MetaClass,
     per-instance MetaClasses, registry-written DGM/extension arrays) are 
strong-rooted
     Groovy-side; `ClassInfo.remove()` unroots, keeping its hard-detach 
undeploy semantics.
   - **Per-Class indy domain continuity** — SwitchPoint domains are keyed by 
`Class` in soft
     mode, so a successor ClassInfo adopts its predecessor's domain and 
mutations
     deterministically retire guards that captured only the SwitchPoint (POJO 
direct dispatch).
     Indy-only; the default mode's behaviour is unchanged.
   
   Default-mode behaviour is byte-identical apart from no-op hook calls; all 
soft-mode structures
   are unallocated unless the flag is set.
   
   ### Evidence
   
   - **Acceptance** (the ticket's point; JDK 17/21/23): a dropped child-loader 
Groovy copy is
     pinned forever under the default and **collected under soft mode** once 
pressure clears
     soft references.
   - **Correctness**: unit tests + a deterministic child-JVM probe 
(resurrection identity/version
     continuity, DGM rooting, EMC/per-instance survival, recreation dispatch, 
classic
     `CallSiteArray` soundness, predecessor-SwitchPoint retirement); a real-GC 
concurrency
     stress probe (128 MB heap, `SoftRefLRUPolicyMSPerMB=0`): 66M dispatches, 
~130 EMC
     generations, 33/36 platform-receiver ClassInfos collected and recreated 
mid-run, zero
     invariant violations; full core suite passes under soft mode (16,800 
tests).
   - **Cost**: raw `getClassInfo` 1.2 → 1.7 ns; compiler harness +0.0%; 
classic-bytecode JMH gate
     0 of 37 significant (geomean +1.7%; the declined map default failed the 
same rule with 12,
     worst 1.38×); classic *polymorphic* miss traffic ≈ +3.7% pooled, flagged 
for the idiom-suite
     sweep before any default-flip discussion.
   
   ### Open questions for review
   
   Assessment §9 consolidates the resulting option landscape 
(`true`/`soft`/`false` ×
   static/dynamic × indy/classic, with guidance); §10 lists the open items: 
adoption path
   (opt-in now — recommended — vs eventual default), whether domain re-homing 
should become
   unconditional rather than soft-gated, and container soak experience. The 
integration guide is
   deliberately untouched until the mode's fate is decided.
   
   JIRA: https://issues.apache.org/jira/browse/GROOVY-12281 (assessment v2 
supersedes v1 in place;
   this prototype responds to the review comments there)
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to