Well I'm starting to lean toward needing a nice pluggable compile phase. So essentially the current compiler would allow plugging in either Java or Ruby code in the compiler toolchain so that you could define your own "pragmas" that do something special.

Putting stuff in comments can work, but we've been trying to get the parser as fast as possible...part of that has been removing awareness/preservation of comments. If there were some standard formats for comment-based annotation, it would be a strong case to add it back in. We also could overload existing syntax that would have no impact on regular Ruby, similar to the "bare hash" annotation I used in early versions of the Duby compiler.

What sort of stuff do you want to speed up? I think we can do a lot with only a handful of annotations.

Joseph Athman wrote:
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] <mailto:[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




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

   http://xircles.codehaus.org/manage_email


Reply via email to