This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_5_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_5_0_X by this push:
     new 4782cd733f sync with `master`
4782cd733f is described below

commit 4782cd733fc05361ebb148d1861895d8d787a7e7
Author: Eric Milles <[email protected]>
AuthorDate: Thu Feb 5 16:00:49 2026 -0600

    sync with `master`
---
 .../codehaus/groovy/vmplugin/v8/IndyInterface.java | 227 +++++++++------------
 1 file changed, 98 insertions(+), 129 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 1d789fa574..9b81c9451f 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
@@ -23,7 +23,6 @@ import org.apache.groovy.util.SystemUtil;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.reflection.ClassInfo;
 import org.codehaus.groovy.runtime.GeneratedClosure;
-import org.codehaus.groovy.runtime.NullObject;
 
 import java.lang.invoke.CallSite;
 import java.lang.invoke.ConstantCallSite;
@@ -33,7 +32,6 @@ import java.lang.invoke.MethodType;
 import java.lang.invoke.MutableCallSite;
 import java.lang.invoke.SwitchPoint;
 import java.util.Map;
-import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -53,55 +51,50 @@ public class IndyInterface {
     private static final long INDY_FALLBACK_CUTOFF = 
SystemUtil.getLongSafe("groovy.indy.fallback.cutoff", 100L);
 
     /**
-     * flags for method and property calls
+     * Flags for method and property calls.
      */
-    public static final int
-            SAFE_NAVIGATION = 1, THIS_CALL = 2,
-            GROOVY_OBJECT = 4, IMPLICIT_THIS = 8,
-            SPREAD_CALL = 16, UNCACHED_CALL = 32;
+    public static final int SAFE_NAVIGATION=1, THIS_CALL=2, GROOVY_OBJECT=4, 
IMPLICIT_THIS=8, SPREAD_CALL=16, UNCACHED_CALL=32;
+
     private static final MethodHandleWrapper NULL_METHOD_HANDLE_WRAPPER = 
MethodHandleWrapper.getNullMethodHandleWrapper();
 
     /**
-     * Enum for easy differentiation between call types
+     * Enum for easy differentiation between call types.
      */
     public enum CallType {
         /**
-         * Method invocation type
+         * Method invocation type.
          */
-        METHOD("invoke", 0),
+        METHOD("invoke"),
         /**
-         * Constructor invocation type
+         * Constructor invocation type.
          */
-        INIT("init", 1),
+        INIT("init"),
         /**
-         * Get property invocation type
+         * Get property invocation type.
          */
-        GET("getProperty", 2),
+        GET("getProperty"),
         /**
-         * Set property invocation type
+         * Set property invocation type.
          */
-        SET("setProperty", 3),
+        SET("setProperty"),
         /**
-         * Cast invocation type
+         * Cast invocation type.
          */
-        CAST("cast", 4),
-
+        CAST("cast"),
         /**
-         * call to interface method
+         * Interface method invocation type.
          */
-        INTERFACE("interface", 5);
+        INTERFACE("interface");
 
-        private static final Map<String, CallType> NAME_CALLTYPE_MAP =
-                
Stream.of(CallType.values()).collect(Collectors.toMap(CallType::getCallSiteName,
 Function.identity()));
+        private static final Map<String, CallType> NAME_CALLTYPE_MAP = 
Stream.of(CallType.values())
+            .collect(Collectors.toUnmodifiableMap(CallType::getCallSiteName, 
Function.identity()));
 
         /**
-         * The name of the call site type
+         * The call site type name.
          */
         private final String name;
-        private final int orderNumber;
 
-        CallType(String callSiteName, int orderNumber) {
-            this.orderNumber = orderNumber;
+        CallType(String callSiteName) {
             this.name = callSiteName;
         }
 
@@ -117,16 +110,16 @@ public class IndyInterface {
         }
 
         public int getOrderNumber() {
-            return this.orderNumber;
+            return ordinal();
         }
     }
 
     /**
-     * Logger
+     * Logger.
      */
     protected static final Logger LOG;
     /**
-     * boolean to indicate if logging for indy is enabled
+     * Indicates if indy logging is enabled.
      */
     protected static final boolean LOG_ENABLED;
 
@@ -152,6 +145,11 @@ public class IndyInterface {
      */
     public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 
+    /**
+     * shared invoker for cached method handles
+     */
+    private static final MethodHandle CACHED_INVOKER = 
MethodHandles.exactInvoker(MethodType.methodType(Object.class, Object[].class));
+
     /**
      * handle for the fromCacheHandle method
      */
@@ -162,22 +160,15 @@ public class IndyInterface {
      */
     private static final MethodHandle SELECT_METHOD_HANDLE_METHOD;
 
-    /**
-     * shared invoker for cached method handles
-     */
-    private static final MethodHandle CACHED_INVOKER;
-
     static {
-
         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);
-            SELECT_METHOD_HANDLE_METHOD = 
LOOKUP.findStatic(IndyInterface.class, "selectMethodHandle", handleMt);
+            MethodType mt = 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", mt);
+            SELECT_METHOD_HANDLE_METHOD = 
LOOKUP.findStatic(IndyInterface.class, "selectMethodHandle", mt);
         } catch (Exception e) {
             throw new GroovyBugError(e);
         }
-
-        CACHED_INVOKER = 
MethodHandles.exactInvoker(MethodType.methodType(Object.class, Object[].class));
     }
 
     protected static SwitchPoint switchPoint = new SwitchPoint();
@@ -202,48 +193,40 @@ public class IndyInterface {
     }
 
     /**
-     * bootstrap method for method calls from Groovy compiled code with indy
-     * enabled. This method gets a flags parameter which uses the following
-     * encoding:<ul>
-     * <li>{@value #SAFE_NAVIGATION} is the flag value for safe navigation see 
{@link #SAFE_NAVIGATION}</li>
-     * <li>{@value #THIS_CALL} is the flag value for a call on this see {@link 
#THIS_CALL}</li>
-     * </ul>
+     * Bootstrap method for method calls from Groovy-compiled code with indy.
      *
      * @param caller   - the caller
-     * @param callType - the type of the call
-     * @param type     - the call site type
+     * @param callType - the type of call
+     * @param type     - the parameter(s) and return type specification
      * @param name     - the real method name
-     * @param flags    - call flags
-     * @return the produced CallSite
-     * @since Groovy 2.1.0
+     * @param flags    - call flags <ul>
+     *                   <li>{@value #SAFE_NAVIGATION} is the flag value for 
safe navigation; see {@link #SAFE_NAVIGATION}</li>
+     *                   <li>{@value #THIS_CALL} is the flag value for a call 
on this; see {@link #THIS_CALL}</li>
+     *                   <li>{@value #SPREAD_CALL} is the flag value for a 
spread call; see {@link #SPREAD_CALL}</li>
+     *                   </ul>
+     * @since 2.1.0
      */
-    public static CallSite bootstrap(MethodHandles.Lookup caller, String 
callType, MethodType type, String name, int flags) {
+    public static CallSite bootstrap(final MethodHandles.Lookup caller, final 
String callType, final MethodType type, final String name, final int flags) {
         CallType ct = CallType.fromCallSiteName(callType);
         if (null == ct) throw new GroovyBugError("Unknown call type: " + 
callType);
 
         int callID = ct.getOrderNumber();
-        boolean safe = (flags & SAFE_NAVIGATION) != 0;
-        boolean thisCall = (flags & THIS_CALL) != 0;
-        boolean spreadCall = (flags & SPREAD_CALL) != 0;
+        boolean safe       = (flags & SAFE_NAVIGATION) != 0;
+        boolean thisCall   = (flags & THIS_CALL      ) != 0;
+        boolean spreadCall = (flags & SPREAD_CALL    ) != 0;
 
-        return realBootstrap(caller, name, callID, type, safe, thisCall, 
spreadCall);
-    }
-
-    /**
-     * backing bootstrap method with all parameters
-     */
-    private static CallSite realBootstrap(MethodHandles.Lookup caller, String 
name, int callID, MethodType type, boolean safe, boolean thisCall, boolean 
spreadCall) {
         // first produce a dummy call site, since indy doesn't give the 
runtime types;
         // the site then changes to the target when INDY_OPTIMIZE_THRESHOLD is 
reached
         // that does the method selection including the direct call to the 
real method
-        CacheableCallSite mc = new CacheableCallSite(type, caller);
+        var mc = new CacheableCallSite(type, caller);
         Class<?> sender = caller.lookupClass();
         if (thisCall) {
             while (GeneratedClosure.class.isAssignableFrom(sender)) {
                 sender = sender.getEnclosingClass(); // GROOVY-2433
             }
         }
-        MethodHandle mh = makeAdapter(mc, sender, name, callID, type, safe, 
thisCall, spreadCall);
+        // make an adapter for method selection, i.e. get cached method handle 
(fast path) or fall back
+        MethodHandle mh = makeBootHandle(mc, sender, name, callID, type, safe, 
thisCall, spreadCall, FROM_CACHE_HANDLE_METHOD);
         mc.setTarget(mh);
         mc.setDefaultTarget(mh);
         mc.setFallbackTarget(makeFallBack(mc, sender, name, callID, type, 
safe, thisCall, spreadCall));
@@ -252,42 +235,40 @@ public class IndyInterface {
     }
 
     /**
-     * Makes a fallback method for an invalidated method selection
+     * 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 makeBoothandle(mc, sender, name, callID, type, safeNavigation, 
thisCall, spreadCall, SELECT_METHOD_HANDLE_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 makeBoothandle(mc, sender, name, callID, type, safeNavigation, 
thisCall, spreadCall, FROM_CACHE_HANDLE_METHOD);
-    }
-
-    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
+    private static MethodHandle makeBootHandle(MutableCallSite mc, Class<?> 
sender, String name, int callID, MethodType type, boolean safeNavigation, 
boolean thisCall, boolean spreadCall, MethodHandle fromCacheOrSelectMethod) {
+        final Object dummyReceiver = 1;
+        // Step 1: bind site-constant arguments
+        MethodHandle boundHandle = MethodHandles.insertArguments(
+            fromCacheOrSelectMethod,
+            0, // insert start index
+            mc,
+            sender,
+            name,
+            callID,
+            safeNavigation,
+            thisCall,
+            spreadCall,
+            dummyReceiver
         );
-        // fromCacheBound: (Object receiver, Object[] args) → MethodHandle
+        // boundHandle: (Object receiver, Object[] arguments) ? MethodHandle
 
-        // Step 2: fold into the shared invoker (MethodHandle, Object[]) → 
Object
-        MethodHandle boothandle = MethodHandles.foldArguments(
-            CACHED_INVOKER, // (MethodHandle, Object[]) → Object
-            fromCacheBound  // (Object, Object[]) → MethodHandle
+        // Step 2: fold into the shared invoker (MethodHandle, Object[]) ? 
Object
+        MethodHandle bootHandle = MethodHandles.foldArguments(
+            CACHED_INVOKER, // (MethodHandle, Object[]) ? Object
+            boundHandle  // (Object, Object[]) ? MethodHandle
         );
-        // boothandle: (Object receiver, Object[] args) → Object
+        // bootHandle: (Object receiver, Object[] arguments) ? Object
 
-        // Step 3: adapt to callsite type: collect all arguments into Object[] 
and then asType
-        boothandle = boothandle
-            .asCollector(Object[].class, type.parameterCount())
-            .asType(type);
+        // Step 3: adapt to call site type: collect all arguments into 
Object[] and then asType
+        bootHandle = bootHandle.asCollector(Object[].class, 
type.parameterCount()).asType(type);
 
-        return boothandle;
+        return bootHandle;
     }
 
     private static class FallbackSupplier {
@@ -324,8 +305,8 @@ 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.
+     * 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 {
@@ -334,27 +315,26 @@ public class IndyInterface {
     }
 
     /**
-     * Get the cached methodhandle. if the related methodhandle is not found 
in the inline cache, cache and return it.
+     * 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 =
-                bypassCache(spreadCall, arguments)
-                    ? NULL_METHOD_HANDLE_WRAPPER
-                    : doWithCallSite(
-                            callSite, arguments,
-                            (cs, receiver) ->
-                                    cs.getAndPut(
-                                            receiver.getClass().getName(),
-                                            c -> {
-                                                MethodHandleWrapper fbMhw = 
fallbackSupplier.get();
-                                                return fbMhw.isCanSetTarget() 
? fbMhw : NULL_METHOD_HANDLE_WRAPPER;
-                                            }
-                                    )
-                    );
-
-        if (NULL_METHOD_HANDLE_WRAPPER == mhw) {
+        MethodHandleWrapper mhw;
+        if (bypassCache(spreadCall, arguments)) {
+            mhw = NULL_METHOD_HANDLE_WRAPPER;
+        } else {
+            Object receiver = arguments[0];
+            String receiverClassName = receiver != null ? 
receiver.getClass().getName() : "org.codehaus.groovy.runtime.NullObject";
+
+            mhw = callSite.getAndPut(receiverClassName, (theName) -> {
+                MethodHandleWrapper fallback = fallbackSupplier.get();
+                if (fallback.isCanSetTarget()) return fallback;
+                return NULL_METHOD_HANDLE_WRAPPER;
+            });
+        }
+
+        if (mhw == NULL_METHOD_HANDLE_WRAPPER) {
             mhw = fallbackSupplier.get();
         }
 
@@ -377,13 +357,13 @@ public class IndyInterface {
 
     private static boolean bypassCache(Boolean spreadCall, Object[] arguments) 
{
         if (spreadCall) return true;
-        final Object receiver = arguments[0];
-        return null != receiver && 
ClassInfo.getClassInfo(receiver.getClass()).hasPerInstanceMetaClasses();
+        Object receiver = arguments[0];
+        return receiver != null && 
ClassInfo.getClassInfo(receiver.getClass()).hasPerInstanceMetaClasses();
     }
 
     /**
      * Core method for indy method selection using runtime types.
-     * @deprecated Use the new boothandle-based approach instead.
+     * @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 {
@@ -406,9 +386,11 @@ public class IndyInterface {
         }
 
         if (callSite.getTarget() == defaultTarget) {
-            // correct the stale methodhandle in the inline cache of callsite
+            // correct the stale methodHandle in the inline cache of callsite
             // it is important but impacts the performance somehow when cache 
misses frequently
-            doWithCallSite(callSite, arguments, (cs, receiver) -> 
cs.put(receiver.getClass().getName(), mhw));
+            Object receiver = arguments[0];
+            String key = receiver != null ? receiver.getClass().getName() : 
"org.codehaus.groovy.runtime.NullObject";
+            callSite.put(key, mhw);
         }
 
         return mhw.getCachedMethodHandle();
@@ -425,19 +407,6 @@ public class IndyInterface {
         );
     }
 
-    private static <T> T doWithCallSite(MutableCallSite callSite, Object[] 
arguments, BiFunction<? super CacheableCallSite, ? super Object, ? extends T> 
f) {
-        if (callSite instanceof CacheableCallSite) {
-            CacheableCallSite cacheableCallSite = (CacheableCallSite) callSite;
-            Object receiver = arguments[0];
-
-            if (null == receiver) receiver = NullObject.getNullObject();
-
-            return f.apply(cacheableCallSite, receiver);
-        }
-
-        throw new GroovyBugError("CacheableCallSite is expected, but the 
actual callsite is: " + callSite);
-    }
-
     /**
      * @since 2.5.0
      */

Reply via email to