Attached is a patch that adds the ability to make *static* calls in
compiled code. Basically the compiler sees it and makes it a static
invocation instead of a dynamic one. It's pretty ugly though, since you
need to specify all the Java signature stuff:
To make "n - 2" into a static call against RubyFixnum, you'd use:
__static_call__("org/jruby/RubyFixnum", n, "op_minus",
"(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;",
2)
The compiler would then evaluate n, cast it to RubyFixnum, evaluate the
arguments, and make the call directly.
A better syntax would probably make this more usable, but in my testing
I have not seen it make a substantial performance difference. Our call
pipeline, once compiled, appears to be pretty darn good.
At any rate, the patch is attached for posterity. I'd love to hear about
other ideas for this.
- Charlie
diff --git a/src/org/jruby/compiler/ASTCompiler.java
b/src/org/jruby/compiler/ASTCompiler.java
index 5a75698..5597062 100644
--- a/src/org/jruby/compiler/ASTCompiler.java
+++ b/src/org/jruby/compiler/ASTCompiler.java
@@ -2120,6 +2120,11 @@ public class ASTCompiler {
public void compileFCall(Node node, BodyCompiler context, boolean expr) {
final FCallNode fcallNode = (FCallNode) node;
+ if (fcallNode.getName().equals("__static_call__")) {
+ compileStaticCall(fcallNode, context, expr);
+ return;
+ }
+
ArgumentsCallback argsCallback =
getArgsCallback(fcallNode.getArgsNode());
CompilerCallback closureArg = getBlock(fcallNode.getIterNode());
@@ -2129,6 +2134,35 @@ public class ASTCompiler {
if (!expr) context.consumeCurrentValue();
}
+ public void compileStaticCall(FCallNode fcallNode, BodyCompiler context,
boolean expr) {
+ ArrayNode args = (ArrayNode)fcallNode.getArgsNode();
+
+ // args[0] is the Java type to cast to
+ StrNode type = (StrNode)args.get(0);
+
+ // args[1] is the receiver node
+ final Node receiver = args.get(1);
+
+ // args[2] is the method name
+ StrNode method = (StrNode)args.get(2);
+
+ // args[3] is the signature
+ StrNode signature = (StrNode)args.get(3);
+
+ // args[4] is the expression to produce all arguments
+ final Node callArgs = args.get(4);
+
+ CompilerCallback receiverCallback = new CompilerCallback() {
+ public void call(BodyCompiler context) {
+ compile(receiver, context, true);
+ }
+ };
+
+ ArgumentsCallback argsCallback = getArgsCallback(callArgs);
+
+ context.compileStaticCall(receiverCallback, argsCallback,
type.getValue().toString(), method.getValue().toString(),
signature.getValue().toString());
+ }
+
private CompilerCallback getBlock(Node node) {
if (node == null) {
return null;
@@ -2543,27 +2577,23 @@ public class ASTCompiler {
public void compileIter(Node node, BodyCompiler context) {
final IterNode iterNode = (IterNode) node;
- // create the closure class and instantiate it
final CompilerCallback closureBody = new CompilerCallback() {
+ public void call(BodyCompiler context) {
+ if (iterNode.getBodyNode() != null) {
+ compile(iterNode.getBodyNode(), context, true);
+ } else {
+ context.loadNil();
+ }
+ }
+ };
- public void call(BodyCompiler context) {
- if (iterNode.getBodyNode() != null) {
- compile(iterNode.getBodyNode(), context, true);
- } else {
- context.loadNil();
- }
- }
- };
-
- // create the closure class and instantiate it
final CompilerCallback closureArgs = new CompilerCallback() {
-
- public void call(BodyCompiler context) {
- if (iterNode.getVarNode() != null) {
- compileAssignment(iterNode.getVarNode(), context,
false);
- }
- }
- };
+ public void call(BodyCompiler context) {
+ if (iterNode.getVarNode() != null) {
+ compileAssignment(iterNode.getVarNode(), context, false);
+ }
+ }
+ };
boolean hasMultipleArgsHead = false;
if (iterNode.getVarNode() instanceof MultipleAsgnNode) {
diff --git a/src/org/jruby/compiler/BodyCompiler.java
b/src/org/jruby/compiler/BodyCompiler.java
index 94f501d..65d3213 100644
--- a/src/org/jruby/compiler/BodyCompiler.java
+++ b/src/org/jruby/compiler/BodyCompiler.java
@@ -587,4 +587,6 @@ public interface BodyCompiler {
List<ArgumentsCallback> conditionals,
List<CompilerCallback> bodies,
CompilerCallback fallback);
+
+ public void compileStaticCall(CompilerCallback receiver, ArgumentsCallback
args, String type, String method, String signature);
}
diff --git a/src/org/jruby/compiler/impl/BaseBodyCompiler.java
b/src/org/jruby/compiler/impl/BaseBodyCompiler.java
index 56ab7d2..63fc794 100644
--- a/src/org/jruby/compiler/impl/BaseBodyCompiler.java
+++ b/src/org/jruby/compiler/impl/BaseBodyCompiler.java
@@ -2532,4 +2532,12 @@ public abstract class BaseBodyCompiler implements
BodyCompiler {
getVariableCompiler().releaseTempLocal();
}
+
+ public void compileStaticCall(CompilerCallback receiver, ArgumentsCallback
args, String type, String methodName, String signature) {
+ receiver.call(this);
+ method.checkcast(type);
+ if (signature.startsWith("(Lorg/jruby/runtime/ThreadContext;"))
loadThreadContext();
+ args.call(this);
+ method.invokevirtual(type, methodName, signature);
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email