Hi,

I've implemented caching of the implementer in CallAdapter. Take a look and see what you think. It improves invocation of included Module methods high in larger hierarchies by about 10% while not adding any noticeable penalty to other invocations.

Cheers

--
Ola Bini (http://ola-bini.blogspot.com) JRuby Core Developer
Developer, ThoughtWorks Studios (http://studios.thoughtworks.com)
Practical JRuby on Rails (http://apress.com/book/view/9781590598818)

"Yields falsehood when quined" yields falsehood when quined.


Index: src/org/jruby/runtime/CallAdapter.java
===================================================================
--- src/org/jruby/runtime/CallAdapter.java      (revision 4415)
+++ src/org/jruby/runtime/CallAdapter.java      (working copy)
@@ -34,6 +34,7 @@
 import org.jruby.exceptions.JumpException;
 import org.jruby.internal.runtime.methods.DynamicMethod;
 import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.javasupport.util.CompilerHelpers;
 
 /**
  *
@@ -69,6 +70,7 @@
         byte[] cachedTable;
         DynamicMethod cachedMethod;
         RubyClass cachedType;
+        RubyModule cachedImpl;
         
         public DefaultCallAdapter(String methodName, CallType callType) {
             super(MethodIndex.getIndex(methodName), methodName, callType);
@@ -140,12 +142,13 @@
                     byte[] cTable = this.cachedTable;
                     DynamicMethod cMethod = this.cachedMethod;
                     RubyModule cType = this.cachedType;
+                    RubyModule cImpl = this.cachedImpl;
 
                     if (cType == selfType && cachedTable != null) {
                         if (cTable.length > methodID && cTable[methodID] != 0) 
{
                             return 
selfType.getDispatcher().callMethod(context, self, selfType, methodID, 
methodName, args, callType, block);
                         } else if (cMethod != null) {
-                            return cMethod.call(context, self, selfType, 
methodName, args, block);
+                            return cMethod.call(context, self, cType, 
methodName, args, block);
                         }
                     }
 
@@ -166,10 +169,11 @@
                     cachedMethod = method;
                     cachedType = selfType;
                     cachedTable = table;
+                    cachedImpl = 
CompilerHelpers.findImplementerIfNecessary(selfType, 
cachedMethod.getRealMethod().getImplementationClass());
 
                     selfType.getRuntime().getCacheMap().add(method, this);
 
-                    return method.call(context, self, selfType, methodName, 
args, block);
+                    return method.call(context, self, cachedType, cachedImpl, 
methodName, args, block);
                 } catch (JumpException.BreakJump bj) {
                     // JRUBY-530, Kernel#loop case:
                     if (bj.isBreakInKernelLoop()) {
@@ -191,6 +195,7 @@
         public void removeCachedMethod() {
             cachedType = null;
             cachedMethod = null;
+            cachedImpl = null;
         }
     }
 }
Index: src/org/jruby/internal/runtime/methods/RubiniusMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/RubiniusMethod.java  (revision 4414)
+++ src/org/jruby/internal/runtime/methods/RubiniusMethod.java  (working copy)
@@ -57,7 +57,7 @@
         this.arity = Arity.optional();
     }
 
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, String name, IRubyObject[] args, Block block) {
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, RubyModule impl, String name, IRubyObject[] args, Block 
block) {
        assert args != null;
         //        System.err.println("--- entering " + cmethod.name);
         Ruby runtime = context.getRuntime();
Index: src/org/jruby/internal/runtime/methods/UndefinedMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/UndefinedMethod.java (revision 4414)
+++ src/org/jruby/internal/runtime/methods/UndefinedMethod.java (working copy)
@@ -50,7 +50,7 @@
     }
 
     
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, String name, IRubyObject[] args, Block block) {
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, RubyModule impl, String name, IRubyObject[] args, Block 
block) {
         throw new UnsupportedOperationException();
     }
 
Index: src/org/jruby/internal/runtime/methods/InvocationMethodFactory.java
===================================================================
--- src/org/jruby/internal/runtime/methods/InvocationMethodFactory.java 
(revision 4416)
+++ src/org/jruby/internal/runtime/methods/InvocationMethodFactory.java 
(working copy)
@@ -55,7 +55,7 @@
     public final static CodegenUtils cg = CodegenUtils.cg;
     private final static String COMPILED_SUPER_CLASS = 
CompiledMethod.class.getName().replace('.','/');
     private final static String COMPILED_CALL_SIG = cg.sig(IRubyObject.class,
-            cg.params(ThreadContext.class, IRubyObject.class, 
RubyModule.class, String.class, IRubyObject[].class, Block.class));
+            cg.params(ThreadContext.class, IRubyObject.class, 
RubyModule.class, RubyModule.class, String.class, IRubyObject[].class, 
Block.class));
     private final static String COMPILED_SUPER_SIG = cg.sig(Void.TYPE, 
cg.params(RubyModule.class, Arity.class, Visibility.class, StaticScope.class, 
Object.class));
 
     private JRubyClassLoader classLoader;
@@ -129,9 +129,10 @@
     public static final int THREADCONTEXT_INDEX = 1;
     public static final int RECEIVER_INDEX = 2;
     public static final int CLASS_INDEX = 3;
-    public static final int NAME_INDEX = 4;
-    public static final int ARGS_INDEX = 5;
-    public static final int BLOCK_INDEX = 6;
+    public static final int IMPL_INDEX = 4;
+    public static final int NAME_INDEX = 5;
+    public static final int ARGS_INDEX = 6;
+    public static final int BLOCK_INDEX = 7;
 
     private DynamicMethod getCompleteMethod(RubyModule implementationClass, 
String method, Arity arity, Visibility visibility, StaticScope scope, String 
sup, Object scriptObject) {
         Class scriptClass = scriptObject.getClass();
@@ -154,11 +155,7 @@
                 mv.aload(THREADCONTEXT_INDEX); // tc
                 mv.aload(RECEIVER_INDEX); // self
                 
-                // determine the appropriate class, for super calls to work 
right
-                mv.aload(CLASS_INDEX); // klazz
-                mv.aload(0);
-                mv.invokevirtual(cg.p(CompiledMethod.class), 
"getImplementationClass", cg.sig(RubyModule.class));
-                mv.invokestatic(cg.p(CompilerHelpers.class), 
"findImplementerIfNecessary", cg.sig(RubyModule.class, RubyModule.class, 
RubyModule.class));
+                mv.aload(IMPL_INDEX); // klazz
                 
                 mv.aload(0);
                 mv.getfield(cg.p(CompiledMethod.class), "arity", 
cg.ci(Arity.class)); // arity
Index: src/org/jruby/internal/runtime/methods/ProcMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/ProcMethod.java      (revision 4414)
+++ src/org/jruby/internal/runtime/methods/ProcMethod.java      (working copy)
@@ -60,7 +60,7 @@
     /**
      * @see org.jruby.runtime.ICallable#call(Ruby, IRubyObject, String, 
IRubyObject[], boolean)
      */
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, String name, IRubyObject[] args, Block block) {
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, RubyModule impl, String name, IRubyObject[] args, Block 
block) {
         context.preMethodCall(implementationClass, klazz, self, name, args, 
getArity().required(), block, this);
         
         try {
Index: src/org/jruby/internal/runtime/methods/SimpleCallbackMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/SimpleCallbackMethod.java    
(revision 4414)
+++ src/org/jruby/internal/runtime/methods/SimpleCallbackMethod.java    
(working copy)
@@ -52,7 +52,7 @@
         this.callback = callback;
     }
 
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, String name, IRubyObject[] args, Block block) {
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, RubyModule impl, String name, IRubyObject[] args, Block 
block) {
        assert args != null;
         Ruby runtime = context.getRuntime();
         
Index: src/org/jruby/internal/runtime/methods/WrapperMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/WrapperMethod.java   (revision 4414)
+++ src/org/jruby/internal/runtime/methods/WrapperMethod.java   (working copy)
@@ -50,8 +50,8 @@
         this.method = method;
     }
     
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, String name, IRubyObject[] args, Block block) {
-        return method.call(context, self, klazz, name, args, block);
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, RubyModule impl, String name, IRubyObject[] args, Block 
block) {
+        return method.call(context, self, klazz, impl, name, args, block);
     }
     
     public DynamicMethod dup() {
Index: src/org/jruby/internal/runtime/methods/MethodMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/MethodMethod.java    (revision 4414)
+++ src/org/jruby/internal/runtime/methods/MethodMethod.java    (working copy)
@@ -58,7 +58,7 @@
     /**
      * @see org.jruby.runtime.ICallable#call(Ruby, IRubyObject, String, 
IRubyObject[], boolean)
      */
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, String name, IRubyObject[] args, Block block) {
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, RubyModule impl, String name, IRubyObject[] args, Block 
block) {
         context.preMethodCall(implementationClass, klazz, self, name, args, 0, 
block, this);
         
         try {
Index: src/org/jruby/internal/runtime/methods/YARVMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/YARVMethod.java      (revision 4414)
+++ src/org/jruby/internal/runtime/methods/YARVMethod.java      (working copy)
@@ -72,7 +72,7 @@
         }
     }
 
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, String name, IRubyObject[] args, Block block) {
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, RubyModule impl, String name, IRubyObject[] args, Block 
block) {
        assert args != null;
         
         Ruby runtime = context.getRuntime();
Index: src/org/jruby/internal/runtime/methods/DynamicMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/DynamicMethod.java   (revision 4414)
+++ src/org/jruby/internal/runtime/methods/DynamicMethod.java   (working copy)
@@ -36,6 +36,7 @@
 import org.jruby.runtime.ThreadContext;
 import org.jruby.runtime.Visibility;
 import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.javasupport.util.CompilerHelpers;
 
 /**
  *
@@ -57,8 +58,13 @@
      * @param context is the thread-specific information that this method is 
being invoked on
      * @param receiver 
      */
-    public abstract IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule clazz, 
+    public abstract IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule clazz, RubyModule implementer,
             String name, IRubyObject[] args, Block block);
+
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, String name, IRubyObject[] args, Block block) {
+        return call(context, self, klazz, 
CompilerHelpers.findImplementerIfNecessary(klazz, 
getRealMethod().getImplementationClass()), name, args, block);
+    }
+
     public abstract DynamicMethod dup();
 
     public boolean isCallableFrom(IRubyObject caller, CallType callType) {
Index: src/org/jruby/internal/runtime/methods/DefaultMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/DefaultMethod.java   (revision 4416)
+++ src/org/jruby/internal/runtime/methods/DefaultMethod.java   (working copy)
@@ -92,11 +92,9 @@
     /**
      * @see AbstractCallable#call(Ruby, IRubyObject, String, IRubyObject[], 
boolean)
      */
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule clazz, String name, IRubyObject[] args, Block block) {
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule clazz, RubyModule implementer, String name, IRubyObject[] args, 
Block block) {
         assert args != null;
 
-        RubyModule implementer = 
CompilerHelpers.findImplementerIfNecessary(clazz, getImplementationClass());
-        
         Ruby runtime = context.getRuntime();
 
         if (runtime.getInstanceConfig().isJitEnabled()) {
Index: src/org/jruby/internal/runtime/methods/FullFunctionCallbackMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/FullFunctionCallbackMethod.java      
(revision 4414)
+++ src/org/jruby/internal/runtime/methods/FullFunctionCallbackMethod.java      
(working copy)
@@ -54,7 +54,7 @@
         this.callback = callback;
     }
 
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule clazz, String name, IRubyObject[] args, Block block) {
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule clazz, RubyModule impl, String name, IRubyObject[] args, Block 
block) {
         try {
             callConfig.pre(context, self, clazz, getArity(), name, args, 
block, null, this);
             
Index: src/org/jruby/internal/runtime/methods/AliasMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/AliasMethod.java     (revision 4414)
+++ src/org/jruby/internal/runtime/methods/AliasMethod.java     (working copy)
@@ -56,8 +56,8 @@
         this.oldMethod = oldMethod;
     }
     
-    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule clazz, String name, IRubyObject[] args, Block block) {
-        return oldMethod.call(context, self, clazz, oldName, args, block);
+    public IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule clazz, RubyModule impl, String name, IRubyObject[] args, Block 
block) {
+        return oldMethod.call(context, self, clazz, impl, oldName, args, 
block);
     }
 
     public DynamicMethod dup() {
Index: src/org/jruby/internal/runtime/methods/CompiledMethod.java
===================================================================
--- src/org/jruby/internal/runtime/methods/CompiledMethod.java  (revision 4416)
+++ src/org/jruby/internal/runtime/methods/CompiledMethod.java  (working copy)
@@ -47,7 +47,7 @@
         this.$scriptObject = scriptObject;
     }
 
-    public abstract IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, String name, IRubyObject[] args, boolean noSuper, Block 
block);
+    public abstract IRubyObject call(ThreadContext context, IRubyObject self, 
RubyModule klazz, RubyModule impl, String name, IRubyObject[] args, boolean 
noSuper, Block block);
     
     public DynamicMethod dup() {
         try {

---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply via email to