From fae421bd9a51e5044202281d18e05a2e554804e8 Mon Sep 17 00:00:00 2001 From: Jochen Theodorou Date: Tue, 19 May 2026 08:44:23 +0200 Subject: [PATCH 1/3] GROOVY-12022: replace indy code for array access in static compilation mode with existing code in BytecodeInterface8 and deprecate now surplus IndyStaticTypesMultiTypeDispatcher. Performance wise there is no gain to use indy here and it simplifies code paths and JIT work --- .../asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java | 2 ++ .../classgen/asm/sc/StaticTypesWriterController.java | 8 +------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java b/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java index d58f253a20d..577020185c4 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java @@ -36,7 +36,9 @@ * Multi type dispatcher for binary expression backend combining indy and static compilation * * @since 2.5.0 + * @deprecated 6.0.0 */ +@Deprecated(since = "6.0.0") public class IndyStaticTypesMultiTypeDispatcher extends StaticTypesBinaryExpressionMultiTypeDispatcher { /** * Creates a dispatcher that combines static compilation and indy array access. diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java index 5ec8a558b9c..4878fbdf117 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java @@ -42,8 +42,6 @@ import org.codehaus.groovy.classgen.asm.TypeChooser; import org.codehaus.groovy.classgen.asm.UnaryExpressionHelper; import org.codehaus.groovy.classgen.asm.WriterController; -import org.codehaus.groovy.classgen.asm.indy.sc.IndyStaticTypesMultiTypeDispatcher; -import org.codehaus.groovy.control.CompilerConfiguration; import org.objectweb.asm.ClassVisitor; import static org.codehaus.groovy.transform.sc.StaticCompilationVisitor.isStaticallyCompiled; @@ -91,11 +89,7 @@ public void init(final AsmClassGenerator asmClassGenerator, final GeneratorConte this.lambdaWriter = new StaticTypesLambdaWriter(this); this.methodReferenceExpressionWriter = new StaticTypesMethodReferenceExpressionWriter(this); this.unaryExpressionHelper = new StaticTypesUnaryExpressionHelper(this); - - CompilerConfiguration config = cn.getCompileUnit().getConfig(); - this.binaryExpressionHelper = config.isIndyEnabled() - ? new IndyStaticTypesMultiTypeDispatcher(this) - : new StaticTypesBinaryExpressionMultiTypeDispatcher(this); + this.binaryExpressionHelper = new StaticTypesBinaryExpressionMultiTypeDispatcher(this); } /** {@inheritDoc} */ From b2cb3f235fb6fd2b3927f9d259f39165e9fe1601 Mon Sep 17 00:00:00 2001 From: Jochen Theodorou Date: Tue, 19 May 2026 17:00:01 +0200 Subject: [PATCH 2/3] GROOVY-12022: fixing tests, since BytecodeInterface8 is now used, the old invokedynamic instruction is no longer valid --- ...ombinedIndyAndStaticCompilationTest.groovy | 54 ++++++++++++++----- .../asm/sc/StaticCompilationTest.groovy | 6 +-- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/CombinedIndyAndStaticCompilationTest.groovy b/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/CombinedIndyAndStaticCompilationTest.groovy index ffdc43183bf..0b7a6985ab9 100644 --- a/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/CombinedIndyAndStaticCompilationTest.groovy +++ b/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/CombinedIndyAndStaticCompilationTest.groovy @@ -21,6 +21,7 @@ package org.codehaus.groovy.classgen.asm.sc import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource import org.junit.jupiter.params.provider.ValueSource import static org.codehaus.groovy.control.CompilerConfiguration.DEFAULT as config @@ -32,41 +33,59 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue final class CombinedIndyAndStaticCompilationTest extends AbstractBytecodeTestCase { @ParameterizedTest - @ValueSource(strings=['byte','short','int','long','float','double','boolean','char']) - void testArrayRead(String type) { + @CsvSource([ + 'byte, bArray, B', + 'short, sArray, S', + 'int, intArray, I', + 'long, lArray, J', + 'float, fArray, F', + 'double, dArray, D', + 'boolean, zArray, Z', + 'char, cArray, C', + 'Object, objectArray, Ljava/lang/Object;']) + void testArrayRead(String typeSource, String namePart, String typeByteCode) { assumeTrue config.indyEnabled def bytecode = compile method:'test', """ @groovy.transform.CompileStatic void test() { - ${type}[] array = new ${type}[10] - ${type} x = array[0] + ${typeSource}[] array = new ${typeSource}[10] + ${typeSource} x = array[0] } """ int offset = bytecode.indexOf('--BEGIN--') + 4 - assert bytecode.indexOf('INVOKEDYNAMIC', offset) > offset - assert bytecode.indexOf('INVOKEDYNAMIC', offset) < bytecode.indexOf('--END--') + assert bytecode.indexOf(createGetter(typeByteCode, namePart), offset) > offset + assert bytecode.indexOf(createGetter(typeByteCode, namePart), offset) < bytecode.indexOf('--END--') } @ParameterizedTest - @ValueSource(strings=['byte','short','int','long','float','double','boolean','char']) - void testArrayWrite(String type) { + @CsvSource([ + 'byte, bArray, B', + 'short, sArray, S', + 'int, intArray, I', + 'long, lArray, J', + 'float, fArray, F', + 'double, dArray, D', + 'boolean, zArray, Z', + 'char, cArray, C', + 'Object, objectArray, Ljava/lang/Object;']) + void testArrayWrite(String typeSource, String namePart, String typeByteCode) { assumeTrue config.indyEnabled def bytecode = compile method:'test', """ @groovy.transform.CompileStatic void test() { - ${type}[] array = new ${type}[10] + ${typeSource}[] array = new ${typeSource}[10] array[0] = 1 } """ int offset = bytecode.indexOf('--BEGIN--') + 4 - assert bytecode.indexOf('INVOKEDYNAMIC', offset) > offset - assert bytecode.indexOf('INVOKEDYNAMIC', offset) < bytecode.indexOf('--END--') + assert bytecode.indexOf(createSetter(typeByteCode, namePart), offset) > offset + assert bytecode.indexOf(createSetter(typeByteCode, namePart), offset) < bytecode.indexOf('--END--') } @ParameterizedTest - @ValueSource(strings=['byte','short','int','long','float','double','char']) + @ValueSource(strings=['byte','short','int','long','float','double','char','Object']) void testNegativeIndex(String type) { assertScript """ @groovy.transform.CompileStatic @@ -149,4 +168,15 @@ final class CombinedIndyAndStaticCompilationTest extends AbstractBytecodeTestCas assert bytecode.indexOf('INVOKESTATIC ', offset) > offset assert bytecode.indexOf('INVOKESTATIC ', offset) < bytecode.indexOf('RETURN', offset) } + + private String createSetter(String typeByteCode, String namePart) { + return "INVOKESTATIC org/codehaus/groovy/runtime/BytecodeInterface8." + + namePart + "Set ([" + typeByteCode + "I" + typeByteCode + ")V" + } + + private String createGetter(String typeByteCode, String namePart) { + return "INVOKESTATIC org/codehaus/groovy/runtime/BytecodeInterface8." + + namePart + "Get ([" + typeByteCode + "I)" + typeByteCode + + } } diff --git a/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy b/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy index bea51d253c6..f2450f94b37 100644 --- a/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy +++ b/src/test/groovy/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy @@ -266,11 +266,7 @@ final class StaticCompilationTest extends AbstractBytecodeTestCase { 'ALOAD 1', 'ICONST_0', 'ILOAD 2', - 'INVOKEDYNAMIC set([III)V [', - '// handle kind 0x6 : INVOKESTATIC', - 'org/codehaus/groovy/vmplugin/v8/IndyInterface.staticArrayAccess', - '// arguments: none', - ']', + 'INVOKESTATIC org/codehaus/groovy/runtime/BytecodeInterface8.intArraySet ([III)V', 'L1', 'LINENUMBER 4', 'RETURN' From 1c2bd18da29721b2ec0611dc5d2aa04e97d75506 Mon Sep 17 00:00:00 2001 From: Jochen Theodorou Date: Sat, 23 May 2026 11:34:31 +0200 Subject: [PATCH 3/3] Applying suggested GroovyDoc fix from Co-Pilot Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java b/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java index 577020185c4..78a2cb7b4c6 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java @@ -36,7 +36,8 @@ * Multi type dispatcher for binary expression backend combining indy and static compilation * * @since 2.5.0 - * @deprecated 6.0.0 + * @deprecated Since 6.0.0, use {@link StaticTypesBinaryExpressionMultiTypeDispatcher} instead; + * indy array access is no longer used in static compilation. */ @Deprecated(since = "6.0.0") public class IndyStaticTypesMultiTypeDispatcher extends StaticTypesBinaryExpressionMultiTypeDispatcher {