Skip to content

Commit

Permalink
Use pure-Ruby Enumerable#inject with new block arg instr.
Browse files Browse the repository at this point in the history
This is a modified version of the same inject used in Truffle,
but with a different form for the "single block arg" instruction.

With the previous (broken) version of this code using |o,|, I saw
a significant improvement in the performance of rubykon's bench
"full_playout.rb". Unfortunately with this new fixed version, that
improvement has disappeared and I have not figured out why. It is
possible that the addition of the fixed path, which allocates an
Array for more than two args passed, has now taken all the gains
back again.
headius committed Feb 3, 2016
1 parent 5f715f0 commit 85eb21c
Showing 9 changed files with 135 additions and 0 deletions.
7 changes: 7 additions & 0 deletions core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -3442,6 +3442,13 @@ public Operand buildVAlias(VAliasNode valiasNode) {
}

public Operand buildVCall(VCallNode node) {
// Intrinsic for processing possibly-multiple block args into one
if (node.getName().equals("__single_block_arg__")) {
Variable result = createTemporaryVariable();
addInstr(new ReceiveSingleBlockArgInstr(result));
return result;
}

return addResultInstr(CallInstr.create(scope, CallType.VARIABLE, createTemporaryVariable(),
node.getName(), buildSelf(), NO_ARGS, null));
}
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ir/IRVisitor.java
Original file line number Diff line number Diff line change
@@ -113,6 +113,7 @@ private void error(Object object) {
public void ReceivePreReqdArgInstr(ReceivePreReqdArgInstr receiveprereqdarginstr) { error(receiveprereqdarginstr); }
public void ReceiveRestArgInstr(ReceiveRestArgInstr receiverestarginstr) { error(receiverestarginstr); }
public void ReceiveSelfInstr(ReceiveSelfInstr receiveselfinstr) { error(receiveselfinstr); }
public void ReceiveSingleBlockArgInstr(ReceiveSingleBlockArgInstr receivesingleblockarg) { error(receivesingleblockarg); }
public void RecordEndBlockInstr(RecordEndBlockInstr recordendblockinstr) { error(recordendblockinstr); }
public void ReqdArgMultipleAsgnInstr(ReqdArgMultipleAsgnInstr reqdargmultipleasgninstr) { error(reqdargmultipleasgninstr); }
public void RescueEQQInstr(RescueEQQInstr rescueeqqinstr) { error(rescueeqqinstr); }
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ir/Operation.java
Original file line number Diff line number Diff line change
@@ -52,6 +52,7 @@ public enum Operation {
RECV_RUBY_EXC(OpFlags.f_is_arg_receive),
RECV_JRUBY_EXC(OpFlags.f_is_arg_receive),
LOAD_IMPLICIT_CLOSURE(OpFlags.f_is_arg_receive),
RECV_SINGLE_BLOCK_ARG(OpFlags.f_is_arg_receive),

/** Instruction to reify an passed-in block to a Proc for def foo(&b) */
REIFY_CLOSURE(0),
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.jruby.ir.instructions;

import org.jruby.ir.IRVisitor;
import org.jruby.ir.Operation;
import org.jruby.ir.operands.Operand;
import org.jruby.ir.operands.Variable;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.persistence.IRWriterEncoder;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

public class ReceiveSingleBlockArgInstr extends ReceiveArgBase implements FixedArityInstr {
public ReceiveSingleBlockArgInstr(Variable result) {
super(Operation.RECV_SINGLE_BLOCK_ARG, result, -1);
}

@Override
public String[] toStringNonOperandArgs() {
return new String[] {};
}

@Override
public Instr clone(CloneInfo info) {
return this;
}

@Override
public void encode(IRWriterEncoder e) {
super.encode(e);
}

@Override
public Operand[] getOperands() {
return Operand.EMPTY_ARRAY;
}

@Override
public void setOperand(int i, Operand operand) {
}

public static ReceiveSingleBlockArgInstr decode(IRReaderDecoder d) {
return new ReceiveSingleBlockArgInstr(d.decodeVariable());
}

@Override
public void visit(IRVisitor visitor) {
visitor.ReceiveSingleBlockArgInstr(this);
}

@Override
public IRubyObject receiveArg(ThreadContext context, IRubyObject[] args, boolean acceptsKeywordArguments) {
return IRRuntimeHelpers.receiveSingleBlockArg(context, args);
}
}
Original file line number Diff line number Diff line change
@@ -285,6 +285,9 @@ protected static void receiveArg(ThreadContext context, Instr i, Operation opera
case LOAD_IMPLICIT_CLOSURE:
setResult(temp, currDynScope, instr.getResult(), blockArg);
return;
case RECV_SINGLE_BLOCK_ARG:
setResult(temp, currDynScope, instr.getResult(), IRRuntimeHelpers.receiveSingleBlockArg(context, args));
break;
default:
result = ((ReceiveArgBase)instr).receiveArg(context, args, acceptsKeywordArgument);
setResult(temp, currDynScope, instr.getResult(), result);
Original file line number Diff line number Diff line change
@@ -238,6 +238,8 @@ public IRubyObject interpret(ThreadContext context, Block block, IRubyObject sel
putField.getValue().retrieve(context, self, currScope, currDynScope, temp));
break;
}
case RECV_SINGLE_BLOCK_ARG:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), arg1);

case BUILD_COMPOUND_STRING: case CONST_MISSING:
default:
@@ -440,6 +442,8 @@ public IRubyObject interpret(ThreadContext context, Block block, IRubyObject sel
putField.getValue().retrieve(context, self, currScope, currDynScope, temp));
break;
}
case RECV_SINGLE_BLOCK_ARG:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), IRRuntimeHelpers.receiveSingleBlockArg(context, arg1, arg2));

case BUILD_COMPOUND_STRING: case CONST_MISSING:
default:
@@ -643,6 +647,8 @@ public IRubyObject interpret(ThreadContext context, Block block, IRubyObject sel
putField.getValue().retrieve(context, self, currScope, currDynScope, temp));
break;
}
case RECV_SINGLE_BLOCK_ARG:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), IRRuntimeHelpers.receiveSingleBlockArg(context, arg1, arg2, arg3));

case BUILD_COMPOUND_STRING: case CONST_MISSING:
default:
@@ -847,6 +853,8 @@ public IRubyObject interpret(ThreadContext context, Block block, IRubyObject sel
putField.getValue().retrieve(context, self, currScope, currDynScope, temp));
break;
}
case RECV_SINGLE_BLOCK_ARG:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), IRRuntimeHelpers.receiveSingleBlockArg(context, arg1, arg2, arg3, arg4));

case BUILD_COMPOUND_STRING: case CONST_MISSING:
default:
@@ -1043,6 +1051,8 @@ public IRubyObject interpret(ThreadContext context, Block block, IRubyObject sel
putField.getValue().retrieve(context, self, currScope, currDynScope, temp));
break;
}
case RECV_SINGLE_BLOCK_ARG:
setResult(temp, currDynScope, ((ResultInstr) instr).getResult(), context.nil);

case BUILD_COMPOUND_STRING: case CONST_MISSING:
default:
7 changes: 7 additions & 0 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -1737,4 +1737,11 @@ public static Block prepareBlock(ThreadContext context, IRubyObject self, Dynami

return block;
}

@JIT @Interp
public static IRubyObject receiveSingleBlockArg(ThreadContext context, IRubyObject... args) {
if (args.length == 0) return context.nil;
if (args.length == 1) return args[0];
return context.runtime.newArrayNoCopy(args);
}
}
8 changes: 8 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -1696,6 +1696,14 @@ public void ReceiveSelfInstr(ReceiveSelfInstr receiveselfinstr) {
// noop...self is passed in
}

@Override
public void ReceiveSingleBlockArgInstr(ReceiveSingleBlockArgInstr receivesingleblockarg) {
jvmMethod().loadContext();
jvmMethod().loadArgs();
jvmMethod().invokeIRHelper("receiveSingleBlockArg", sig(IRubyObject.class, ThreadContext.class, IRubyObject[].class));
jvmStoreLocal(receivesingleblockarg.getResult());
}

@Override
public void RecordEndBlockInstr(RecordEndBlockInstr recordEndBlockInstr) {
jvmMethod().loadContext();
42 changes: 42 additions & 0 deletions core/src/main/ruby/jruby/kernel/enumerable.rb
Original file line number Diff line number Diff line change
@@ -105,4 +105,46 @@ def lazy
klass = Enumerator::Lazy::LAZY_WITH_NO_BLOCK # Note: class_variable_get is private in 1.8
Enumerator::Lazy.new(klass.new(self, :each, []))
end

# Enumerable#inject is modified from Rubinius

Undefined = Object.new
private_constant :Undefined

def inject(initial=Undefined, sym=Undefined)
if !block_given? or !(undefined_sym = Undefined.equal?(sym))
if undefined_sym
sym = initial
initial = Undefined
end

# Do the sym version

sym = sym.to_sym

each do
o = __single_block_arg__

if Undefined.equal? initial
initial = o
else
initial = initial.__send__(sym, o)
end
end

# Block version
else
each do
o = __single_block_arg__

if Undefined.equal? initial
initial = o
else
initial = yield(initial, o)
end
end
end

Undefined.equal?(initial) ? nil : initial
end
end

0 comments on commit 85eb21c

Please sign in to comment.