The GitHub Actions job "Code Style" on grails-core.git/grails8-groovy6-canary has failed. Run started by GitHub user jamesfredley (triggered by jamesfredley).
Head commit for run: ddc7ea20c6f783a66a684603e298c85c3a461ce2 / James Fredley <[email protected]> fix: serialise GSP compilation under Groovy 6 to dodge ListHashMap race Every CI job that compiled GSPs against Groovy 6.0.0-SNAPSHOT failed with a Groovy compiler stack like: General error during instruction selection: Index 3 out of bounds for length 3 java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3 at org.codehaus.groovy.util.ListHashMap.toMap(ListHashMap.java:207) at org.codehaus.groovy.util.ListHashMap.put(ListHashMap.java:146) at java.base/java.util.Map.computeIfAbsent(Map.java:1067) at org.codehaus.groovy.ast.NodeMetaDataHandler.getNodeMetaData(NodeMetaDataHandler.java:65) at org.codehaus.groovy.ast.AnnotationNode.isTargetAllowed(AnnotationNode.java:168) at org.codehaus.groovy.classgen.ExtendedVerifier.visitAnnotations(ExtendedVerifier.java:354) at org.codehaus.groovy.classgen.ExtendedVerifier.visitConstructor(ExtendedVerifier.java:216) ... at org.grails.web.pages.GroovyPageForkedCompiler.main(GroovyPageForkedCompiler.groovy:106) `AnnotationNode.isTargetAllowed` was added in Groovy 6 (GROOVY-11838) to honour the new default annotation targets and uses `NodeMetaDataHandler.getNodeMetaData` (a `Map.computeIfAbsent` over an internal `ListHashMap`) on shared `Annotation*` AST nodes. That cache is touched concurrently by the Grails `GroovyPageCompiler` thread pool (`Executors.newFixedThreadPool(availableProcessors() * 2)`) once shared annotations like `@Inject`, `@CompileStatic`, etc. are seen by more than one GSP compile at the same time, which is exactly the case for test apps that pull in Spring/Grails compiled output. `ListHashMap` is not designed for concurrent mutation, so the resize fails with an `ArrayIndexOutOfBoundsException` and the entire GSP compile aborts. Replace the unconditional `availableProcessors() * 2` thread pool with a small `computeGspCompilerParallelism()` helper that: * defaults to 1 worker on Groovy 6 (eliminates the race), * defaults to `availableProcessors() * 2` on Groovy 5 and earlier (preserves prior behaviour), * honours `-Dgrails.gsp.compiler.parallelism=N` so callers can opt back into parallel GSP compilation once Groovy 6 fixes the race (or experimentally tune it down on Groovy 5). Trade-off: a small wall-clock increase on Groovy 6 GSP compilation in exchange for deterministic behaviour. The control knob is a single system property, so this is easy to revert once the upstream Groovy fix is available. Verified locally: ./gradlew :grails-gsp-core:compileGroovy --rerun-tasks -> BUILD SUCCESSFUL Assisted-by: claude-code:claude-opus-4-7 Report URL: https://github.com/apache/grails-core/actions/runs/24934605888 With regards, GitHub Actions via GitBox
