Am I right that the goal of this would be to allow for specific Ruby calls
to be sped up by skipping a lot of the dynamic nature of the language?
Assuming that's true, what I was hoping for would be a non-invasive way of
adding functionality like to without breaking my ability to still run the
code on MRI.  In my ideal world I would be able to add "hints" to JRuby to
speed things up in a normally unsafe way, but not have to change the actual
code so that if I still wanted to run on MRI I could, these special
optimizations would just not be used.  Maybe something in a comment?

Joe

On Sun, Apr 12, 2009 at 2:15 AM, Charles Oliver Nutter <
[email protected]> wrote:

> 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
>
>

Reply via email to