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

ifesdjeen pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/cassandra-simulator.git

commit cb0a026027e1a4e6126740489d5c318b02745565
Author: Alex Petrov <[email protected]>
AuthorDate: Thu Jul 23 19:10:29 2026 +0200

    Avoid gating by global methods
---
 .../cassandra/simulator/asm/ClassTransformer.java  |  8 ++-
 .../simulator/asm/GlobalMethodTransformer.java     | 10 ++--
 .../cassandra/simulator/asm/InterceptClasses.java  |  3 +-
 .../cassandra/simulator/asm/InterceptRule.java     |  5 ++
 ...ethodOverrideOutsideConfiguredPackagesTest.java | 67 ++++++++++++++++++++++
 5 files changed, 85 insertions(+), 8 deletions(-)

diff --git 
a/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/ClassTransformer.java
 
b/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/ClassTransformer.java
index 856f88d..e2f5209 100644
--- 
a/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/ClassTransformer.java
+++ 
b/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/ClassTransformer.java
@@ -212,7 +212,8 @@ class ClassTransformer extends ClassVisitor implements 
MethodWriterSink
             visitEachRefType(descriptor, dependentTypes);
 
         EnumSet<Flag> flags = this.flags;
-        if (flags.isEmpty() || ((access & ACC_SYNTHETIC) != 0 && 
(name.endsWith("$unsync") || name.endsWith("$catch") || 
name.endsWith("$nemesis"))))
+        if ((flags.isEmpty() && customRules.isEmpty())
+            || ((access & ACC_SYNTHETIC) != 0 && (name.endsWith("$unsync") || 
name.endsWith("$catch") || name.endsWith("$nemesis"))))
         {
             MethodVisitor visitor = super.visitMethod(access, name, 
descriptor, signature, exceptions);
             if (dependentTypes != null && (access & (ACC_STATIC | 
ACC_SYNTHETIC)) != 0 && (name.equals("<clinit>") || name.startsWith("lambda$")))
@@ -253,7 +254,10 @@ class ClassTransformer extends ClassVisitor implements 
MethodWriterSink
             visitor = new MonitorEnterExitParkTransformer(this, api, visitor, 
className, monitorDelayChance);
         if (isToString)
             visitor = deterministicToString(visitor);
-        if (flags.contains(GLOBAL_METHODS) || 
flags.contains(Flag.LOCK_SUPPORT) || flags.contains(Flag.DETERMINISTIC))
+        if (flags.contains(GLOBAL_METHODS)
+            || flags.contains(Flag.LOCK_SUPPORT)
+            || flags.contains(Flag.DETERMINISTIC)
+            || !customRules.isEmpty())
             visitor = new GlobalMethodTransformer(flags, this, api, name, 
visitor, customRules);
         if (flags.contains(NEMESIS))
             visitor = new NemesisTransformer(this, api, name, visitor, 
nemesis, nemesisFieldSelector);
diff --git 
a/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/GlobalMethodTransformer.java
 
b/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/GlobalMethodTransformer.java
index 7f1de1e..0153473 100644
--- 
a/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/GlobalMethodTransformer.java
+++ 
b/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/GlobalMethodTransformer.java
@@ -49,8 +49,8 @@ class GlobalMethodTransformer extends MethodVisitor
     private final ClassTransformer transformer;
     private final String methodName;
     private final Set<InterceptRule> customRules;
-    /** Enables the bulk of redirects: Thread.start, Executors, UUID, Unsafe, 
Uninterruptibles,
-     *  TimeUnit.sleep, Future.get, @Intercept factory/constructor rules. */
+    /** Enables the bulk of built-in redirects: Thread.start, Executors, UUID, 
Unsafe,
+     *  Uninterruptibles, TimeUnit.sleep, and Future.get. */
     private boolean globalMethods;
     /** TimeUtils#timestampMicros -> 
SimulatedTime$Global.nextGlobalMonotonicMicros(). */
     private boolean globalClock;
@@ -113,7 +113,7 @@ class GlobalMethodTransformer extends MethodVisitor
             super.visitMethodInsn(Opcodes.INVOKESTATIC, 
"org/apache/cassandra/simulator/systems/InterceptorOfSystemMethods$Global", 
name, descriptor, false);
         }
         // TimeUnit#sleep(long) [INVOKEVIRTUAL, ~globalMethods] -> 
InterceptorOfSystemMethods$Global.sleep(TimeUnit, long)
-        else if (owner.equals("java/util/concurrent/TimeUnit") && 
name.equals("sleep"))
+        else if ((lockSupport || deterministic) && 
owner.equals("java/util/concurrent/TimeUnit") && name.equals("sleep"))
         {
             transformer.witness(GLOBAL_METHOD);
             super.visitMethodInsn(Opcodes.INVOKESTATIC, 
"org/apache/cassandra/simulator/systems/InterceptorOfSystemMethods$Global", 
"sleep", "(Ljava/util/concurrent/TimeUnit;J)V", false);
@@ -174,7 +174,7 @@ class GlobalMethodTransformer extends MethodVisitor
             else
                 super.visitMethodInsn(opcode, owner, name, descriptor, 
isInterface);
         }
-        else if (globalMethods && applyMethodRule(opcode, owner, name, 
descriptor, isFirstMethodInsn))
+        else if (!customRules.isEmpty() && applyMethodRule(opcode, owner, 
name, descriptor, isFirstMethodInsn))
         {
             // emitted by the matching rule
         }
@@ -284,7 +284,7 @@ class GlobalMethodTransformer extends MethodVisitor
     @Override
     public void visitTypeInsn(int opcode, String type)
     {
-        if (globalMethods)
+        if (!customRules.isEmpty() && opcode == Opcodes.NEW)
         {
             for (InterceptRule rule : customRules)
             {
diff --git 
a/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/InterceptClasses.java
 
b/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/InterceptClasses.java
index 433fa5a..f3bc092 100644
--- 
a/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/InterceptClasses.java
+++ 
b/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/InterceptClasses.java
@@ -51,6 +51,7 @@ public class InterceptClasses implements BiFunction<String, 
byte[], byte[]>
     public static final int BYTECODE_VERSION = Opcodes.ASM9;
 
     // TODO (cleanup): use annotations
+    // TODO (alexp, cleanup): this should be redundant by now; we need to 
slowly migrate off to use global method transformer / new InterceptRule API
     private static final Pattern MONITORS = Pattern.compile( 
"org[/.]apache[/.]cassandra[/.]utils[/.]concurrent[/.].*" +
                                                             
"|org[/.]apache[/.]cassandra[/.]concurrent[/.].*" +
                                                             
"|org[/.]apache[/.]cassandra[/.]simulator[/.]test.*" +
@@ -264,7 +265,7 @@ public class InterceptClasses implements BiFunction<String, 
byte[], byte[]>
             flags.add(Flag.NEMESIS);
         }
 
-        if (flags.isEmpty() && hashcode == null)
+        if (flags.isEmpty() && hashcode == null && customRules.isEmpty())
         {
             cache.put(internalName, peerGroup.unmodified);
             return input;
diff --git 
a/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/InterceptRule.java
 
b/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/InterceptRule.java
index d911b44..d41262d 100644
--- 
a/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/InterceptRule.java
+++ 
b/simulator-asm/src/main/java/org/apache/cassandra/simulator/asm/InterceptRule.java
@@ -71,6 +71,11 @@ public abstract class InterceptRule
             this.descriptor = descriptor;
         }
 
+        public static FactoryMethod make(String fromClass, String methodName, 
String descriptor)
+        {
+            return new FactoryMethod(fromClass, methodName, descriptor);
+        }
+
         @Override
         public boolean match(int opcode, String owner, String name, String 
descriptor)
         {
diff --git 
a/simulator-core/src/test/java/com/example/MethodOverrideOutsideConfiguredPackagesTest.java
 
b/simulator-core/src/test/java/com/example/MethodOverrideOutsideConfiguredPackagesTest.java
new file mode 100644
index 0000000..b5f4688
--- /dev/null
+++ 
b/simulator-core/src/test/java/com/example/MethodOverrideOutsideConfiguredPackagesTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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 com.example;
+
+import org.apache.cassandra.simulator.Simulator;
+import 
org.apache.cassandra.simulator.context.IIsolatedExecutor.SerializableRunnable;
+import org.apache.cassandra.simulator.context.SharedTestState;
+import org.apache.cassandra.simulator.utils.Intercept;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class MethodOverrideOutsideConfiguredPackagesTest
+{
+    @BeforeEach
+    void reset()
+    {
+        SharedTestState.reset();
+    }
+
+    @Test
+    void redirectsCallSiteOutsideConfiguredPackages()
+    {
+        try (Simulator simulator = new Simulator(42L))
+        {
+            simulator.interceptMethods(Source.class, Redirects.class);
+            simulator.simulate((SerializableRunnable) () ->
+                SharedTestState.value1.set(new Source().value()));
+        }
+
+        assertEquals(2, SharedTestState.value1.get());
+    }
+
+    public static class Source
+    {
+        public int value()
+        {
+            return 1;
+        }
+    }
+
+    public static class Redirects
+    {
+        @Intercept
+        public static int value(Source receiver)
+        {
+            return 2;
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to