Maybe the annotations was a bad idea since I'm sure you wouldn't want to
have to parse every comment in a system to look for some performance hints.
I read your blog post about the different optimizations that can be done
with Ruby and it looks like there are certain things that can be done with
JRuby, but are not normally safe.  I'm thinking as an developer I just want
ways of marking a method (class?) as obeying some kind of a more strict Ruby
code structure and then tell JRuby that it can make assumptions about my
code that normally wouldn't be allowed.  Could we do something like this?

class MyClassToSpeedUp

  def my_slow_method
    # slow work in here
  end

  allow_unsafe_optimizations :my_slow_method

end

I'm thinking the allow_unsafe_optimizations method would be defined by
JRuby's core and allow it to optimize it in normally unsafe ways.  However
this would also mean that if I wanted to run on MRI I would need to add some
kind of no-op code to get this to work, but I think that would be easy
enough.  Just add:

class Object

  unless defined?(JRUBY_VERSION)
    def allow_unsafe_optimizations
      # do nothing in MRI
    end
  end

end

What I would be looking to do is just to find hot spots in my codebase that
I could optimize for JRuby in a way that would not break its use in MRI.
I'm just a little leary of anything special that would lock my code in to a
particular implementation of Ruby.  I know we complain pretty regularly
about C based extensions, I'd rather not replicate the same issue by using a
Java extension to get speed improvements unless absolutely necessary.  I
hope this is making sense.

Joe


On Mon, Apr 13, 2009 at 4:54 PM, Charles Oliver Nutter <
[email protected]> wrote:

> 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