Skip to content

Commit

Permalink
Simplify case/when eqq logic and enlist in normal invocation.
Browse files Browse the repository at this point in the history
Most case/when will have neither an undefined case value (for bare
case statements) nor multiple values for a given when (splatted)
so in those cases we can simply do a plain eqq call + isTrue. The
unusual cases will still go to the old isEQQ logic, so there may
be value in optimizing that path later.

The main logic in isEQQ is the processing of a splatted array of
when values in sequence, and a small bit of logic that simply
checks truthiness of the when value for a bare case statement.

This change reduces the bytecode for all case/when, and by more
than half for the typical form. It also allows the === call to be
optimized with invokedynamic like a normal call.
headius committed Oct 10, 2017
1 parent 49be9b5 commit d455523
Showing 4 changed files with 12 additions and 12 deletions.
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -1321,7 +1321,7 @@ public int compare(Map.Entry<Integer, Label> o1, Map.Entry<Integer, Label> o2) {
expression = ((StringLiteral) expression).frozenString;
}

addInstr(new EQQInstr(eqqResult, expression, value, true));
addInstr(new EQQInstr(eqqResult, expression, value, false));
v1 = eqqResult;
v2 = manager.getTrue();
}
5 changes: 0 additions & 5 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -408,11 +408,6 @@ public static IRubyObject isEQQ(ThreadContext context, IRubyObject receiver, IRu
return isUndefValue ? receiver : callSite.call(context, receiver, receiver, value);
}

@Deprecated
public static IRubyObject isEQQ(ThreadContext context, IRubyObject receiver, IRubyObject value, CallSite callSite) {
return isEQQ(context, receiver, value, callSite, true);
}

public static IRubyObject newProc(Ruby runtime, Block block) {
return (block == Block.NULL_BLOCK) ? runtime.getNil() : runtime.newProc(Block.Type.PROC, block);
}
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/targets/Bootstrap.java
Original file line number Diff line number Diff line change
@@ -485,7 +485,7 @@ static MethodHandle buildJittedHandle(InvokeSite site, DynamicMethod method, boo
// Temporary fix for missing kwargs dup+splitting logic from frobnicate, called by CompiledIRMethod but
// skipped by indy's direct binding.
if (compiledIRMethod.hasKwargs()) return null;

// attempt IR direct binding
// TODO: this will have to expand when we start specializing arities

15 changes: 10 additions & 5 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -1328,11 +1328,16 @@ public void DefineModuleInstr(DefineModuleInstr definemoduleinstr) {

@Override
public void EQQInstr(EQQInstr eqqinstr) {
jvmMethod().loadContext();
visit(eqqinstr.getArg1());
visit(eqqinstr.getArg2());
jvmMethod().callEqq(eqqinstr.isSplattedValue());
jvmStoreLocal(eqqinstr.getResult());
if (!eqqinstr.isSplattedValue() && !(eqqinstr.getArg2() instanceof UndefinedValue)) {
// FIXME: eqq for case/when can be refined but we don't handle that
compileCallCommon(jvmMethod(), "===", Helpers.arrayOf(eqqinstr.getArg2()), eqqinstr.getArg1(), 1, null, BlockPassType.NONE, CallType.FUNCTIONAL, eqqinstr.getResult(), false);
} else {
jvmMethod().loadContext();
visit(eqqinstr.getArg1());
visit(eqqinstr.getArg2());
jvmMethod().callEqq(eqqinstr.isSplattedValue());
jvmStoreLocal(eqqinstr.getResult());
}
}

@Override

0 comments on commit d455523

Please sign in to comment.