Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1edbd92c2b86
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ca5578279566
Choose a head ref
  • 2 commits
  • 6 files changed
  • 1 contributor

Commits on Aug 9, 2017

  1. Copy the full SHA
    f11b413 View commit details
  2. Simplify case/when eqq logic and enlist in normal invocation.

    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 Aug 9, 2017
    Copy the full SHA
    ca55782 View commit details
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
@@ -1311,7 +1311,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

Original file line number Diff line number Diff line change
@@ -652,6 +652,13 @@ public static BlockPassType fromIR(ClosureAcceptingInstr callInstr) {
*/
public abstract void prepareBlock(Handle handle, org.jruby.runtime.Signature signature, String className);

/**
* Perform a === call appropriate for a case/when statement.
*
* Stack required: context, case value, when value
*/
public abstract void callEqq(boolean isSplattedValue);

public SkinnyMethodAdapter adapter;
private int variableCount = 0;
private Map<Integer, Type> variableTypes = new HashMap<Integer, Type>();
Original file line number Diff line number Diff line change
@@ -1017,5 +1017,13 @@ public void prepareBlock(Handle handle, org.jruby.runtime.Signature signature, S
invokeIRHelper("prepareBlock", sig(Block.class, ThreadContext.class, IRubyObject.class, DynamicScope.class, BlockBody.class));
}

@Override
public void callEqq(boolean isSplattedValue) {
String siteName = getUniqueSiteName("===");
IRBytecodeAdapter.cacheCallSite(adapter, getClassData().clsName, siteName, "===", CallType.FUNCTIONAL, false);
adapter.ldc(isSplattedValue);
invokeIRHelper("isEQQ", sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, IRubyObject.class, CallSite.class, boolean.class));
}

private final Map<Object, String> cacheFieldNames = new HashMap<>();
}
18 changes: 10 additions & 8 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -1328,14 +1328,16 @@ public void DefineModuleInstr(DefineModuleInstr definemoduleinstr) {

@Override
public void EQQInstr(EQQInstr eqqinstr) {
jvmMethod().loadContext();
visit(eqqinstr.getArg1());
visit(eqqinstr.getArg2());
String siteName = jvmMethod().getUniqueSiteName("===");
IRBytecodeAdapter.cacheCallSite(jvmAdapter(), jvmMethod().getClassData().clsName, siteName, "===", CallType.FUNCTIONAL, false);
jvmAdapter().ldc(eqqinstr.isSplattedValue());
jvmMethod().invokeIRHelper("isEQQ", sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, IRubyObject.class, CallSite.class, boolean.class));
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