You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by bl...@apache.org on 2026/01/17 04:44:09 UTC
(groovy) branch indy_experiment_2 created (now 821b53893e)
This is an automated email from the ASF dual-hosted git repository.
blackdrag pushed a change to branch indy_experiment_2
in repository https://gitbox.apache.org/repos/asf/groovy.git
at 821b53893e IndyUsageTest will no longer work since there will be no IndyInterface lines in the trace anymore
This branch includes the following new commits:
new 871627098f ensure the first call of invokedynamic is not polluting the stack trace
new 821b53893e IndyUsageTest will no longer work since there will be no IndyInterface lines in the trace anymore
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(groovy) 02/02: IndyUsageTest will no longer work since there will be no IndyInterface lines in the trace anymore
Posted by bl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
blackdrag pushed a commit to branch indy_experiment_2
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 821b53893e288178ec18fefe73660809da9009ec
Author: Jochen Theodorou <bl...@gmx.org>
AuthorDate: Sat Jan 17 05:20:07 2026 +0100
IndyUsageTest will no longer work since there will be no IndyInterface lines in the trace anymore
---
src/test/groovy/indy/IndyUsageTest.groovy | 40 -------------------------------
1 file changed, 40 deletions(-)
diff --git a/src/test/groovy/indy/IndyUsageTest.groovy b/src/test/groovy/indy/IndyUsageTest.groovy
deleted file mode 100644
index 5e95ca7724..0000000000
--- a/src/test/groovy/indy/IndyUsageTest.groovy
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package indy
-
-import org.junit.Test
-
-import static groovy.test.GroovyAssert.assertScript
-
-final class IndyUsageTest {
-
- @Test
- void testIndyIsUsedNested() {
- assertScript '''
- def foo() {
- throw new Exception('blah')
- }
- try {
- foo()
- } catch (e) {
- assert e.stackTrace.find { it.className == 'org.codehaus.groovy.vmplugin.v8.IndyInterface' }
- }
- '''
- }
-}
(groovy) 01/02: ensure the first call of invokedynamic is not polluting the stack trace
Posted by bl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
blackdrag pushed a commit to branch indy_experiment_2
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 871627098f43005bed05d096e21db36c379a1daf
Author: Jochen Theodorou <bl...@gmx.org>
AuthorDate: Sat Jan 17 04:23:10 2026 +0100
ensure the first call of invokedynamic is not polluting the stack trace
---
.../codehaus/groovy/vmplugin/v8/IndyInterface.java | 85 ++++++++++++++++++++--
1 file changed, 78 insertions(+), 7 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
index e813e3217f..48c5ba0be5 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
@@ -162,6 +162,21 @@ public class IndyInterface {
*/
private static final MethodHandle SELECT_METHOD;
+ /**
+ * handle for the fromCacheHandle method
+ */
+ private static final MethodHandle FROM_CACHE_HANDLE_METHOD;
+
+ /**
+ * handle for the selectMethodHandle method
+ */
+ private static final MethodHandle SELECT_METHOD_HANDLE_METHOD;
+
+ /**
+ * shared invoker for cached method handles
+ */
+ private static final MethodHandle CACHED_INVOKER;
+
static {
try {
@@ -177,6 +192,22 @@ public class IndyInterface {
} catch (Exception e) {
throw new GroovyBugError(e);
}
+
+ try {
+ MethodType handleMt = MethodType.methodType(MethodHandle.class, CacheableCallSite.class, Class.class, String.class, int.class, Boolean.class, Boolean.class, Boolean.class, Object.class, Object[].class);
+ FROM_CACHE_HANDLE_METHOD = LOOKUP.findStatic(IndyInterface.class, "fromCacheHandle", handleMt);
+ } catch (Exception e) {
+ throw new GroovyBugError(e);
+ }
+
+ try {
+ MethodType handleMt = MethodType.methodType(MethodHandle.class, CacheableCallSite.class, Class.class, String.class, int.class, Boolean.class, Boolean.class, Boolean.class, Object.class, Object[].class);
+ SELECT_METHOD_HANDLE_METHOD = LOOKUP.findStatic(IndyInterface.class, "selectMethodHandle", handleMt);
+ } catch (Exception e) {
+ throw new GroovyBugError(e);
+ }
+
+ CACHED_INVOKER = MethodHandles.exactInvoker(MethodType.methodType(Object.class, Object[].class));
}
protected static SwitchPoint switchPoint = new SwitchPoint();
@@ -254,19 +285,39 @@ public class IndyInterface {
* Makes a fallback method for an invalidated method selection
*/
protected static MethodHandle makeFallBack(MutableCallSite mc, Class<?> sender, String name, int callID, MethodType type, boolean safeNavigation, boolean thisCall, boolean spreadCall) {
- return make(mc, sender, name, callID, type, safeNavigation, thisCall, spreadCall, SELECT_METHOD);
+ return makeBoothandle(mc, sender, name, callID, type, safeNavigation, thisCall, spreadCall, SELECT_METHOD_HANDLE_METHOD);
}
/**
* Makes an adapter method for method selection, i.e. get the cached methodhandle(fast path) or fallback
*/
private static MethodHandle makeAdapter(MutableCallSite mc, Class<?> sender, String name, int callID, MethodType type, boolean safeNavigation, boolean thisCall, boolean spreadCall) {
- return make(mc, sender, name, callID, type, safeNavigation, thisCall, spreadCall, FROM_CACHE_METHOD);
+ return makeBoothandle(mc, sender, name, callID, type, safeNavigation, thisCall, spreadCall, FROM_CACHE_HANDLE_METHOD);
}
- private static MethodHandle make(MutableCallSite mc, Class<?> sender, String name, int callID, MethodType type, boolean safeNavigation, boolean thisCall, boolean spreadCall, MethodHandle originalMH) {
- MethodHandle mh = MethodHandles.insertArguments(originalMH, 0, mc, sender, name, callID, safeNavigation, thisCall, spreadCall, /*dummy receiver:*/ 1);
- return mh.asCollector(Object[].class, type.parameterCount()).asType(type);
+ private static MethodHandle makeBoothandle(MutableCallSite mc, Class<?> sender, String name, int callID, MethodType type, boolean safeNavigation, boolean thisCall, boolean spreadCall, MethodHandle handleReturningMh) {
+ // Step 1: bind site-constant arguments (incl dummy receiver marker)
+ MethodHandle fromCacheBound = MethodHandles.insertArguments(
+ handleReturningMh,
+ 0, mc, sender, name, callID,
+ safeNavigation, thisCall, spreadCall,
+ /*dummy receiver*/ 1
+ );
+ // fromCacheBound: (Object receiver, Object[] args) → MethodHandle
+
+ // Step 2: fold into the shared invoker (MethodHandle, Object[]) → Object
+ MethodHandle boothandle = MethodHandles.foldArguments(
+ CACHED_INVOKER, // (MethodHandle, Object[]) → Object
+ fromCacheBound // (Object, Object[]) → MethodHandle
+ );
+ // boothandle: (Object receiver, Object[] args) → Object
+
+ // Step 3: adapt to callsite type: collect all arguments into Object[] and then asType
+ boothandle = boothandle
+ .asCollector(Object[].class, type.parameterCount())
+ .asType(type);
+
+ return boothandle;
}
private static class FallbackSupplier {
@@ -304,8 +355,18 @@ public class IndyInterface {
/**
* Get the cached methodhandle. if the related methodhandle is not found in the inline cache, cache and return it.
+ * @deprecated Use the new boothandle-based approach instead.
*/
+ @Deprecated
public static Object fromCache(CacheableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) throws Throwable {
+ MethodHandle mh = fromCacheHandle(callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
+ return mh.invokeExact(arguments);
+ }
+
+ /**
+ * Get the cached methodhandle. if the related methodhandle is not found in the inline cache, cache and return it.
+ */
+ private static MethodHandle fromCacheHandle(CacheableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) throws Throwable {
FallbackSupplier fallbackSupplier = new FallbackSupplier(callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
MethodHandleWrapper mhw =
@@ -341,7 +402,7 @@ public class IndyInterface {
mhw.resetLatestHitCount();
}
- return mhw.getCachedMethodHandle().invokeExact(arguments);
+ return mhw.getCachedMethodHandle();
}
private static boolean bypassCache(Boolean spreadCall, Object[] arguments) {
@@ -352,8 +413,18 @@ public class IndyInterface {
/**
* Core method for indy method selection using runtime types.
+ * @deprecated Use the new boothandle-based approach instead.
*/
+ @Deprecated
public static Object selectMethod(CacheableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) throws Throwable {
+ MethodHandle mh = selectMethodHandle(callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
+ return mh.invokeExact(arguments);
+ }
+
+ /**
+ * Core method for indy method selection using runtime types.
+ */
+ private static MethodHandle selectMethodHandle(CacheableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) throws Throwable {
MethodHandleWrapper mhw = fallback(callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
MethodHandle defaultTarget = callSite.getDefaultTarget();
@@ -370,7 +441,7 @@ public class IndyInterface {
doWithCallSite(callSite, arguments, (cs, receiver) -> cs.put(receiver.getClass().getName(), mhw));
}
- return mhw.getCachedMethodHandle().invokeExact(arguments);
+ return mhw.getCachedMethodHandle();
}
private static MethodHandleWrapper fallback(CacheableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) {