Skip to content

Commit 29371d9

Browse files
committed
Fix #2409: Splat --> BuildSplatInstr + Splat (for use in call args)
* Splat operand is now a BuildSplatInstr to represent splats seen in ruby code. These can throw exceptions. * Splat operand is now only used in call args and will always extract its args and is guaranteed to have a RubyArray for its operand. These cannot throw exceptions. * This will ungreen master since my jit fixes seem to be incomplete -- Charlie will take over those fixes.
1 parent 8ced6d2 commit 29371d9

File tree

11 files changed

+127
-27
lines changed

11 files changed

+127
-27
lines changed

core/src/main/java/org/jruby/ir/IRBuilder.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -577,11 +577,11 @@ protected Operand buildAttrAssignCallArgs(List<Operand> argsList, Node args, IRS
577577
Operand rhs = build(argsPushNode.getSecondNode(), s);
578578
Variable res = s.createTemporaryVariable();
579579
addInstr(s, new BuildCompoundArrayInstr(res, lhs, rhs, true));
580-
argsList.add(new Splat(res, true));
580+
argsList.add(new Splat(res));
581581
return rhs;
582582
}
583583
case SPLATNODE: { // a[1] = *b
584-
Splat rhs = new Splat(build(((SplatNode)args).getValue(), s), true);
584+
Splat rhs = new Splat(buildSplat((SplatNode)args, s));
585585
argsList.add(rhs);
586586
return rhs;
587587
}
@@ -594,7 +594,7 @@ protected Operand[] buildCallArgs(Node args, IRScope s) {
594594
switch (args.getNodeType()) {
595595
case ARGSCATNODE:
596596
case ARGSPUSHNODE:
597-
return new Operand[] { new Splat(build(args, s), true) };
597+
return new Operand[] { new Splat(build(args, s)) };
598598
case ARRAYNODE: {
599599
List<Node> children = args.childNodes();
600600
int numberOfArgs = children.size();
@@ -606,7 +606,7 @@ protected Operand[] buildCallArgs(Node args, IRScope s) {
606606
return builtArgs;
607607
}
608608
case SPLATNODE:
609-
return new Operand[] { new Splat(build(((SplatNode) args).getValue(), s), true) };
609+
return new Operand[] { new Splat(buildSplat((SplatNode)args, s)) };
610610
}
611611

612612
throw new NotCompilableException("Invalid node for call args: " + args.getClass().getSimpleName() + ":" + args.getPosition());
@@ -3269,9 +3269,9 @@ public Operand buildSelf(IRScope s) {
32693269
}
32703270

32713271
public Operand buildSplat(SplatNode splatNode, IRScope s) {
3272-
// SSS: Since splats can only occur in call argument lists, no need to copyAndReturnValue(...)
3273-
// Verify with Tom / Charlie
3274-
return new Splat(build(splatNode.getValue(), s));
3272+
Variable res = s.createTemporaryVariable();
3273+
addInstr(s, new BuildSplatInstr(res, build(splatNode.getValue(), s)));
3274+
return res;
32753275
}
32763276

32773277
public Operand buildStr(StrNode strNode, IRScope s) {

core/src/main/java/org/jruby/ir/IRClosure.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ public void addInstr(Instr i) {
195195
// FIXME: This lost encoding information when name was converted to string earlier in IRBuilder
196196
keywordArgs.add(new KeyValuePair<Operand, Operand>(new Symbol(rkai.argName, USASCIIEncoding.INSTANCE), rkai.getResult()));
197197
} else if (i instanceof ReceiveRestArgInstr) {
198-
blockArgs.add(new Splat(((ReceiveRestArgInstr)i).getResult(), true));
198+
blockArgs.add(new Splat(((ReceiveRestArgInstr)i).getResult()));
199199
} else if (i instanceof ReceiveArgBase) {
200200
blockArgs.add(((ReceiveArgBase) i).getResult());
201201
}

core/src/main/java/org/jruby/ir/IRMethod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public void addInstr(Instr i) {
9797
// FIXME: This lost encoding information when name was converted to string earlier in IRBuilder
9898
keywordArgs.add(new KeyValuePair<Operand, Operand>(new Symbol(rkai.argName, USASCIIEncoding.INSTANCE), rkai.getResult()));
9999
} else if (i instanceof ReceiveRestArgInstr) {
100-
callArgs.add(new Splat(((ReceiveRestArgInstr)i).getResult(), true));
100+
callArgs.add(new Splat(((ReceiveRestArgInstr)i).getResult()));
101101
} else if (i instanceof ReceiveArgBase) {
102102
callArgs.add(((ReceiveArgBase) i).getResult());
103103
}

core/src/main/java/org/jruby/ir/IRVisitor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ private void error(Object object) {
4545
public void BuildCompoundStringInstr(BuildCompoundStringInstr instr) { error(instr); }
4646
public void BuildDynRegExpInstr(BuildDynRegExpInstr instr) { error(instr); }
4747
public void BuildRangeInstr(BuildRangeInstr instr) { error(instr); }
48+
public void BuildSplatInstr(BuildSplatInstr instr) { error(instr); }
4849
public void CallInstr(CallInstr callinstr) { error(callinstr); }
4950
public void CheckArgsArrayArityInstr(CheckArgsArrayArityInstr checkargsarrayarityinstr) { error(checkargsarrayarityinstr); }
5051
public void CheckArityInstr(CheckArityInstr checkarityinstr) { error(checkarityinstr); }

core/src/main/java/org/jruby/ir/Operation.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ public enum Operation {
143143
BUILD_COMPOUND_STRING(OpFlags.f_can_raise_exception),
144144
BUILD_DREGEXP(OpFlags.f_can_raise_exception),
145145
BUILD_RANGE(OpFlags.f_can_raise_exception),
146+
BUILD_SPLAT(OpFlags.f_can_raise_exception),
146147
BACKTICK_STRING(OpFlags.f_can_raise_exception),
147148
CHECK_ARGS_ARRAY_ARITY(OpFlags.f_can_raise_exception),
148149
CHECK_ARITY(OpFlags.f_is_book_keeping_op | OpFlags.f_can_raise_exception),
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package org.jruby.ir.instructions;
2+
3+
import org.jruby.ir.IRVisitor;
4+
import org.jruby.ir.Operation;
5+
import org.jruby.ir.operands.Operand;
6+
import org.jruby.ir.operands.Variable;
7+
import org.jruby.ir.runtime.IRRuntimeHelpers;
8+
import org.jruby.ir.transformations.inlining.CloneInfo;
9+
import org.jruby.parser.StaticScope;
10+
import org.jruby.runtime.DynamicScope;
11+
import org.jruby.runtime.ThreadContext;
12+
import org.jruby.runtime.builtin.IRubyObject;
13+
14+
import java.util.Map;
15+
16+
// Represents a splat value in Ruby code: *array
17+
public class BuildSplatInstr extends Instr implements ResultInstr {
18+
private Variable result;
19+
private Operand array;
20+
21+
public BuildSplatInstr(Variable result, Operand array) {
22+
super(Operation.BUILD_SPLAT);
23+
this.result = result;
24+
this.array = array;
25+
}
26+
27+
@Override
28+
public String toString() {
29+
return result + " = *" + array;
30+
}
31+
32+
@Override
33+
public Variable getResult() {
34+
return result;
35+
}
36+
37+
@Override
38+
public void updateResult(Variable v) {
39+
this.result = v;
40+
}
41+
42+
public Operand getArray() {
43+
return array;
44+
}
45+
46+
@Override
47+
public Operand[] getOperands() {
48+
return new Operand[] { array };
49+
}
50+
51+
@Override
52+
public void simplifyOperands(Map<Operand, Operand> valueMap, boolean force) {
53+
array = array.getSimplifiedOperand(valueMap, force);
54+
}
55+
56+
@Override
57+
public Instr clone(CloneInfo ii) {
58+
return new BuildSplatInstr(ii.getRenamedVariable(result), array.cloneForInlining(ii));
59+
}
60+
61+
@Override
62+
public Object interpret(ThreadContext context, StaticScope currScope, DynamicScope currDynScope, IRubyObject self, Object[] temp) {
63+
IRubyObject arrayVal = (IRubyObject) array.retrieve(context, self, currScope, currDynScope, temp);
64+
return IRRuntimeHelpers.irSplat(context, arrayVal);
65+
}
66+
67+
@Override
68+
public void visit(IRVisitor visitor) {
69+
visitor.BuildSplatInstr(this);
70+
}
71+
}

core/src/main/java/org/jruby/ir/instructions/CallBase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ public String toString() {
402402

403403
public static boolean containsArgSplat(Operand[] arguments) {
404404
for (Operand argument : arguments) {
405-
if (argument instanceof Splat && ((Splat)argument).unsplatArgs) return true;
405+
if (argument instanceof Splat) return true;
406406
}
407407

408408
return false;

core/src/main/java/org/jruby/ir/operands/Splat.java

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,15 @@
1717
// Further down the line, it could get converted to calls that implement splat semantics
1818
public class Splat extends Operand implements DepthCloneable {
1919
final private Operand array;
20-
final public boolean unsplatArgs;
2120

22-
public Splat(Operand array, boolean unsplatArgs) {
21+
public Splat(Operand array) {
2322
super(OperandType.SPLAT);
2423
this.array = array;
25-
this.unsplatArgs = unsplatArgs;
26-
}
27-
28-
public Splat(Operand array) {
29-
this(array, false);
3024
}
3125

3226
@Override
3327
public String toString() {
34-
return (unsplatArgs ? "*(unsplat)" : "*") + array;
28+
return "*(unsplat)" + array;
3529
}
3630

3731
@Override
@@ -46,7 +40,7 @@ public Operand getArray() {
4640
@Override
4741
public Operand getSimplifiedOperand(Map<Operand, Operand> valueMap, boolean force) {
4842
Operand newArray = array.getSimplifiedOperand(valueMap, force);
49-
return (newArray == array) ? this : new Splat(newArray, unsplatArgs);
43+
return (newArray == array) ? this : new Splat(newArray);
5044
}
5145

5246
/** Append the list of variables used in this operand to the input list */
@@ -57,19 +51,31 @@ public void addUsedVariables(List<Variable> l) {
5751

5852
/** When fixing up splats in nested closure we need to tweak the operand if it is a LocalVariable */
5953
public Operand cloneForDepth(int n) {
60-
return array instanceof LocalVariable ? new Splat(((LocalVariable) array).cloneForDepth(n), unsplatArgs) : this;
54+
return array instanceof LocalVariable ? new Splat(((LocalVariable) array).cloneForDepth(n)) : this;
6155
}
6256

6357
@Override
6458
public Operand cloneForInlining(CloneInfo ii) {
65-
return hasKnownValue() ? this : new Splat(array.cloneForInlining(ii), unsplatArgs);
59+
return hasKnownValue() ? this : new Splat(array.cloneForInlining(ii));
6660
}
6761

6862
@Override
6963
public Object retrieve(ThreadContext context, IRubyObject self, StaticScope currScope, DynamicScope currDynScope, Object[] temp) {
70-
IRubyObject arrayVal = (IRubyObject) array.retrieve(context, self, currScope, currDynScope, temp);
71-
// SSS FIXME: Some way to specialize this code?
72-
return IRRuntimeHelpers.irSplat(context, arrayVal);
64+
// Splat is now only used in call arg lists where it is guaranteed that
65+
// the splat-arg is an array.
66+
//
67+
// It is:
68+
// - either a result of a args-cat/args-push (which generate an array),
69+
// - or a result of a BuildSplatInstr (which also generates an array),
70+
// - or a rest-arg that has been received (which also generates an array)
71+
// and is being passed via zsuper.
72+
//
73+
// In addition, since this only shows up in call args, the array itself is
74+
// never modified. The array elements are extracted out and inserted into
75+
// a java array. So, a dup is not required either.
76+
//
77+
// So, besides retrieving the array, nothing more to be done here!
78+
return (IRubyObject) array.retrieve(context, self, currScope, currDynScope, temp);
7379
}
7480

7581
@Override

core/src/main/java/org/jruby/ir/persistence/OperandDecoderMap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public Operand decode(OperandType type) {
5050
case REGEXP: return decodeRegexp();
5151
case SCOPE_MODULE: return new ScopeModule(d.decodeInt());
5252
case SELF: return Self.SELF;
53-
case SPLAT: return new Splat(d.decodeOperand(), d.decodeBoolean());
53+
case SPLAT: return new Splat(d.decodeOperand());
5454
case STANDARD_ERROR: return new StandardError();
5555
case STRING_LITERAL: return new StringLiteral(d.decodeString());
5656
case SVALUE: return new SValue(d.decodeOperand());

core/src/main/java/org/jruby/ir/persistence/OperandEncoderMap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public void encode(Operand operand) {
9393

9494
@Override public void Self(Self self) {} // No data
9595

96-
@Override public void Splat(Splat splat) { encode(splat.getArray()); encoder.encode(splat.unsplatArgs); }
96+
@Override public void Splat(Splat splat) { encode(splat.getArray()); }
9797

9898
@Override public void StandardError(StandardError standarderror) {} // No data
9999

0 commit comments

Comments
 (0)