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