Skip to content

Commit

Permalink
EQQInstr has added a splattedValue field. This new field is used
Browse files Browse the repository at this point in the history
to differentiate between a single object which happens to be an
array vs an array which happens to represent a set of values we
want to call eqq on.  The discriminator in IRBuilder is whether
we see Args{Cat,Push}Node or SplatNode (at least for when
statements...it is possible we need this for rescue_eqq too?).
enebo committed Jun 15, 2016

Verified

This commit was signed with the committer’s verified signature.
makenowjust Hiroya Fujinami
1 parent 99e11a9 commit 3a37205
Showing 5 changed files with 37 additions and 15 deletions.
10 changes: 4 additions & 6 deletions core/src/main/java/org/jruby/ir/IRBuilder.java
Original file line number Diff line number Diff line change
@@ -1130,13 +1130,11 @@ public Operand buildCase(CaseNode caseNode) {
}
} else {
Operand expression = buildWithOrder(whenNode.getExpressionNodes(), whenNode.containsVariableAssignment());
Node exprNodes = whenNode.getExpressionNodes();
boolean needsSplat = exprNodes instanceof ArgsPushNode || exprNodes instanceof SplatNode || exprNodes instanceof ArgsCatNode;

if (value != UndefinedValue.UNDEFINED) {
addInstr(new EQQInstr(eqqResult, expression, value));
v1 = eqqResult;
} else {
v1 = expression;
}
addInstr(new EQQInstr(eqqResult, expression, value, needsSplat));
v1 = eqqResult;
v2 = manager.getTrue();
}
addInstr(BEQInstr.create(v1, v2, bodyLabel));
27 changes: 23 additions & 4 deletions core/src/main/java/org/jruby/ir/instructions/EQQInstr.java
Original file line number Diff line number Diff line change
@@ -18,13 +18,27 @@
// If v2 is an array, compare v1 with every element of v2 and stop on first match!
public class EQQInstr extends TwoOperandResultBaseInstr implements FixedArityInstr {
private final CallSite callSite;
// This is a splatted value and eqq should compare each element in the array vs
// treating the array as a single value.
private boolean splattedValue;

public EQQInstr(Variable result, Operand v1, Operand v2) {
public EQQInstr(Variable result, Operand v1, Operand v2, boolean splattedValue) {
super(Operation.EQQ, result, v1, v2);

assert result != null: "EQQInstr result is null";

this.callSite = new FunctionalCachingCallSite("===");
this.splattedValue = splattedValue;
}

@Override
public String[] toStringNonOperandArgs() {
return new String[] { "splat: " + splattedValue };
}

@Deprecated
public EQQInstr(Variable result, Operand v1, Operand v2) {
this(result, v1, v2, true);
}

public Operand getArg1() {
@@ -35,27 +49,32 @@ public Operand getArg2() {
return getOperand2();
}

public boolean isSplattedValue() {
return splattedValue;
}

@Override
public Instr clone(CloneInfo ii) {
return new EQQInstr(ii.getRenamedVariable(result), getArg1().cloneForInlining(ii), getArg2().cloneForInlining(ii));
return new EQQInstr(ii.getRenamedVariable(result), getArg1().cloneForInlining(ii), getArg2().cloneForInlining(ii), isSplattedValue());
}

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

public static EQQInstr decode(IRReaderDecoder d) {
return new EQQInstr(d.decodeVariable(), d.decodeOperand(), d.decodeOperand());
return new EQQInstr(d.decodeVariable(), d.decodeOperand(), d.decodeOperand(), d.decodeBoolean());
}

@Override
public Object interpret(ThreadContext context, StaticScope currScope, DynamicScope currDynScope, IRubyObject self, Object[] temp) {
IRubyObject recv = (IRubyObject) getArg1().retrieve(context, self, currScope, currDynScope, temp);
IRubyObject value = (IRubyObject) getArg2().retrieve(context, self, currScope, currDynScope, temp);
return IRRuntimeHelpers.isEQQ(context, recv, value, callSite);
return IRRuntimeHelpers.isEQQ(context, recv, value, callSite, isSplattedValue());
}

@Override
11 changes: 8 additions & 3 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -452,10 +452,10 @@ public static IRubyObject isExceptionHandled(ThreadContext context, IRubyObject
return context.runtime.newBoolean(ret);
}

public static IRubyObject isEQQ(ThreadContext context, IRubyObject receiver, IRubyObject value, CallSite callSite) {
public static IRubyObject isEQQ(ThreadContext context, IRubyObject receiver, IRubyObject value, CallSite callSite, boolean splattedValue) {
boolean isUndefValue = value == UndefinedValue.UNDEFINED;
if (receiver instanceof RubyArray) {
RubyArray testVals = (RubyArray)receiver;
if (splattedValue && receiver instanceof RubyArray) {
RubyArray testVals = (RubyArray) receiver;
for (int i = 0, n = testVals.getLength(); i < n; i++) {
IRubyObject v = testVals.eltInternal(i);
IRubyObject eqqVal = isUndefValue ? v : callSite.call(context, v, v, value);
@@ -467,6 +467,11 @@ public static IRubyObject isEQQ(ThreadContext context, IRubyObject receiver, IRu
}
}

@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);
}
3 changes: 2 additions & 1 deletion core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -1271,7 +1271,8 @@ public void EQQInstr(EQQInstr eqqinstr) {
visit(eqqinstr.getArg2());
String siteName = jvmMethod().getUniqueSiteName("===");
IRBytecodeAdapter.cacheCallSite(jvmAdapter(), jvmMethod().getClassData().clsName, siteName, "===", CallType.FUNCTIONAL, false);
jvmMethod().invokeIRHelper("isEQQ", sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, IRubyObject.class, CallSite.class));
jvmAdapter().ldc(eqqinstr.isSplattedValue());
jvmMethod().invokeIRHelper("isEQQ", sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, IRubyObject.class, CallSite.class, boolean.class));
jvmStoreLocal(eqqinstr.getResult());
}

1 change: 0 additions & 1 deletion test/mri/excludes/TestCase.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
exclude :test_deoptimization, "needs investigation"
exclude :test_deoptimize_nil, "uses refinements (#3548)"
exclude :test_case, "splat issue (unmasked from recent fix)"

0 comments on commit 3a37205

Please sign in to comment.