Skip to content

Commit 1defdd7

Browse files
authored
Add supernode for comparing a literal string (#196)
2 parents a33ffee + 3d74296 commit 1defdd7

File tree

10 files changed

+539
-13
lines changed

10 files changed

+539
-13
lines changed

src/trufflesom/src/trufflesom/compiler/MethodGenerationContext.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
import trufflesom.interpreter.nodes.ReturnNonLocalNode;
5656
import trufflesom.interpreter.nodes.ReturnNonLocalNode.CatchNonLocalReturnNode;
5757
import trufflesom.interpreter.nodes.literals.BlockNode;
58-
import trufflesom.interpreter.nodes.specialized.IntIncrementNode;
58+
import trufflesom.interpreter.supernodes.IntIncrementNode;
5959
import trufflesom.primitives.Primitives;
6060
import trufflesom.vmobjects.SClass;
6161
import trufflesom.vmobjects.SInvokable;

src/trufflesom/src/trufflesom/compiler/ParserAst.java

+54-3
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
import trufflesom.bdt.basic.ProgramDefinitionError;
2828
import trufflesom.bdt.inlining.InlinableNodes;
2929
import trufflesom.bdt.tools.structure.StructuralProbe;
30+
import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode;
31+
import trufflesom.interpreter.nodes.ArgumentReadNode.NonLocalArgumentReadNode;
3032
import trufflesom.interpreter.nodes.ExpressionNode;
3133
import trufflesom.interpreter.nodes.FieldNode;
34+
import trufflesom.interpreter.nodes.FieldNode.FieldReadNode;
3235
import trufflesom.interpreter.nodes.GlobalNode;
3336
import trufflesom.interpreter.nodes.MessageSendNode;
3437
import trufflesom.interpreter.nodes.SequenceNode;
@@ -38,9 +41,14 @@
3841
import trufflesom.interpreter.nodes.literals.GenericLiteralNode;
3942
import trufflesom.interpreter.nodes.literals.IntegerLiteralNode;
4043
import trufflesom.interpreter.nodes.literals.LiteralNode;
41-
import trufflesom.interpreter.nodes.specialized.IntIncrementNodeGen;
44+
import trufflesom.interpreter.supernodes.IntIncrementNodeGen;
45+
import trufflesom.interpreter.supernodes.LocalFieldStringEqualsNode;
46+
import trufflesom.interpreter.supernodes.NonLocalFieldStringEqualsNode;
47+
import trufflesom.interpreter.supernodes.StringEqualsNodeGen;
4248
import trufflesom.primitives.Primitives;
4349
import trufflesom.vm.Globals;
50+
import trufflesom.vm.NotYetImplementedException;
51+
import trufflesom.vm.SymbolTable;
4452
import trufflesom.vmobjects.SArray;
4553
import trufflesom.vmobjects.SClass;
4654
import trufflesom.vmobjects.SInvokable;
@@ -255,15 +263,58 @@ protected ExpressionNode binaryMessage(final MethodGenerationContext mgenc,
255263
mgenc.getHolder().getSuperClass(), msg, args, coordWithL);
256264
}
257265

266+
String binSelector = msg.getString();
267+
268+
if (binSelector.equals("=")) {
269+
if (operand instanceof GenericLiteralNode) {
270+
Object literal = operand.executeGeneric(null);
271+
if (literal instanceof String s) {
272+
if (receiver instanceof FieldReadNode fieldRead) {
273+
ExpressionNode self = fieldRead.getSelf();
274+
if (self instanceof LocalArgumentReadNode localSelf) {
275+
return new LocalFieldStringEqualsNode(fieldRead.getFieldIndex(),
276+
localSelf.getArg(), s).initialize(coordWithL);
277+
} else if (self instanceof NonLocalArgumentReadNode arg) {
278+
return new NonLocalFieldStringEqualsNode(fieldRead.getFieldIndex(), arg.getArg(),
279+
arg.getContextLevel(), s).initialize(coordWithL);
280+
} else {
281+
throw new NotYetImplementedException();
282+
}
283+
}
284+
285+
return StringEqualsNodeGen.create(s, receiver).initialize(coordWithL);
286+
}
287+
}
288+
289+
if (receiver instanceof GenericLiteralNode) {
290+
Object literal = receiver.executeGeneric(null);
291+
if (literal instanceof String s) {
292+
if (operand instanceof FieldReadNode fieldRead) {
293+
ExpressionNode self = fieldRead.getSelf();
294+
if (self instanceof LocalArgumentReadNode localSelf) {
295+
return new LocalFieldStringEqualsNode(fieldRead.getFieldIndex(),
296+
localSelf.getArg(), s).initialize(coordWithL);
297+
} else if (self instanceof NonLocalArgumentReadNode arg) {
298+
return new NonLocalFieldStringEqualsNode(fieldRead.getFieldIndex(), arg.getArg(),
299+
arg.getContextLevel(), s).initialize(coordWithL);
300+
} else {
301+
throw new NotYetImplementedException();
302+
}
303+
}
304+
305+
return StringEqualsNodeGen.create(s, operand).initialize(coordWithL);
306+
}
307+
}
308+
}
309+
258310
ExpressionNode inlined =
259311
inlinableNodes.inline(msg, args, mgenc, coordWithL);
260312
if (inlined != null) {
261313
assert !isSuperSend;
262314
return inlined;
263315
}
264316

265-
if (msg.getString().equals("+") && operand instanceof IntegerLiteralNode) {
266-
IntegerLiteralNode lit = (IntegerLiteralNode) operand;
317+
if (msg == SymbolTable.symPlus && operand instanceof IntegerLiteralNode lit) {
267318
if (lit.executeLong(null) == 1) {
268319
return IntIncrementNodeGen.create(receiver);
269320
}

src/trufflesom/src/trufflesom/compiler/Variable.java

-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package trufflesom.compiler;
22

3-
import static com.oracle.truffle.api.CompilerDirectives.transferToInterpreterAndInvalidate;
43
import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPARGUMENT;
54
import static trufflesom.compiler.bc.BytecodeGenerator.emitPOPLOCAL;
65
import static trufflesom.compiler.bc.BytecodeGenerator.emitPUSHARGUMENT;
@@ -116,8 +115,6 @@ public Local splitToMergeIntoOuterScope(final int newSlotIndex) {
116115

117116
@Override
118117
public ExpressionNode getReadNode(final int contextLevel, final long coordinate) {
119-
transferToInterpreterAndInvalidate();
120-
121118
if (contextLevel == 0) {
122119
return new LocalArgumentReadNode(this).initialize(coordinate);
123120
} else {
@@ -128,8 +125,6 @@ public ExpressionNode getReadNode(final int contextLevel, final long coordinate)
128125
@Override
129126
public ExpressionNode getWriteNode(final int contextLevel,
130127
final ExpressionNode valueExpr, final long coordinate) {
131-
transferToInterpreterAndInvalidate();
132-
133128
if (contextLevel == 0) {
134129
return new LocalArgumentWriteNode(this, valueExpr).initialize(coordinate);
135130
} else {
@@ -172,7 +167,6 @@ public void init(final FrameDescriptor desc) {
172167

173168
@Override
174169
public ExpressionNode getReadNode(final int contextLevel, final long coordinate) {
175-
transferToInterpreterAndInvalidate();
176170
if (contextLevel > 0) {
177171
return NonLocalVariableReadNodeGen.create(contextLevel, this).initialize(coordinate);
178172
}
@@ -196,7 +190,6 @@ public Local splitToMergeIntoOuterScope(final int newSlotIndex) {
196190
@Override
197191
public ExpressionNode getWriteNode(final int contextLevel,
198192
final ExpressionNode valueExpr, final long coordinate) {
199-
transferToInterpreterAndInvalidate();
200193
if (contextLevel > 0) {
201194
return NonLocalVariableWriteNodeGen.create(contextLevel, this, valueExpr)
202195
.initialize(coordinate);

src/trufflesom/src/trufflesom/interpreter/nodes/ArgumentReadNode.java

+8
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) {
3939
inliner.updateRead(arg, this, 0);
4040
}
4141

42+
public Argument getArg() {
43+
return arg;
44+
}
45+
4246
@Override
4347
public SSymbol getInvocationIdentifier() {
4448
return arg.name;
@@ -118,6 +122,10 @@ public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) {
118122
inliner.updateRead(arg, this, contextLevel);
119123
}
120124

125+
public Argument getArg() {
126+
return arg;
127+
}
128+
121129
@Override
122130
public SSymbol getInvocationIdentifier() {
123131
return arg.name;

src/trufflesom/src/trufflesom/interpreter/nodes/specialized/IntIncrementNode.java renamed to src/trufflesom/src/trufflesom/interpreter/supernodes/IntIncrementNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package trufflesom.interpreter.nodes.specialized;
1+
package trufflesom.interpreter.supernodes;
22

33
import com.oracle.truffle.api.dsl.NodeChild;
44
import com.oracle.truffle.api.dsl.Specialization;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package trufflesom.interpreter.supernodes;
2+
3+
import com.oracle.truffle.api.CompilerDirectives;
4+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
5+
import com.oracle.truffle.api.frame.VirtualFrame;
6+
import com.oracle.truffle.api.nodes.Node;
7+
import com.oracle.truffle.api.nodes.UnexpectedResultException;
8+
9+
import trufflesom.bdt.inlining.ScopeAdaptationVisitor;
10+
import trufflesom.bdt.inlining.ScopeAdaptationVisitor.ScopeElement;
11+
import trufflesom.compiler.Variable.Argument;
12+
import trufflesom.interpreter.bc.RespecializeException;
13+
import trufflesom.interpreter.nodes.ArgumentReadNode.LocalArgumentReadNode;
14+
import trufflesom.interpreter.nodes.ExpressionNode;
15+
import trufflesom.interpreter.nodes.FieldNode.FieldReadNode;
16+
import trufflesom.interpreter.nodes.GenericMessageSendNode;
17+
import trufflesom.interpreter.nodes.MessageSendNode;
18+
import trufflesom.interpreter.nodes.bc.BytecodeLoopNode;
19+
import trufflesom.interpreter.nodes.literals.GenericLiteralNode;
20+
import trufflesom.interpreter.objectstorage.FieldAccessorNode;
21+
import trufflesom.interpreter.objectstorage.FieldAccessorNode.AbstractReadFieldNode;
22+
import trufflesom.interpreter.objectstorage.ObjectLayout;
23+
import trufflesom.interpreter.objectstorage.StorageLocation;
24+
import trufflesom.vm.SymbolTable;
25+
import trufflesom.vm.VmSettings;
26+
import trufflesom.vm.constants.Nil;
27+
import trufflesom.vmobjects.SObject;
28+
29+
30+
public final class LocalFieldStringEqualsNode extends ExpressionNode {
31+
32+
private final int fieldIdx;
33+
private final String value;
34+
protected final Argument arg;
35+
36+
@Child private AbstractReadFieldNode readFieldNode;
37+
38+
@CompilationFinal private int state;
39+
40+
public LocalFieldStringEqualsNode(final int fieldIdx, final Argument arg,
41+
final String value) {
42+
this.fieldIdx = fieldIdx;
43+
this.arg = arg;
44+
this.value = value;
45+
46+
this.state = 0;
47+
}
48+
49+
@Override
50+
public Object executeGeneric(final VirtualFrame frame) {
51+
try {
52+
SObject rcvr = (SObject) frame.getArguments()[0];
53+
return executeEvaluated(frame, rcvr);
54+
} catch (UnexpectedResultException e) {
55+
return e.getResult();
56+
}
57+
}
58+
59+
@Override
60+
public Object doPreEvaluated(final VirtualFrame frame, final Object[] args) {
61+
try {
62+
return executeEvaluated(frame, (SObject) args[0]);
63+
} catch (UnexpectedResultException e) {
64+
return e.getResult();
65+
}
66+
}
67+
68+
public boolean executeEvaluated(final VirtualFrame frame, final SObject rcvr)
69+
throws UnexpectedResultException {
70+
int currentState = state;
71+
72+
if (state == 0) {
73+
// uninitialized
74+
CompilerDirectives.transferToInterpreterAndInvalidate();
75+
final ObjectLayout layout = rcvr.getObjectLayout();
76+
StorageLocation location = layout.getStorageLocation(fieldIdx);
77+
78+
readFieldNode =
79+
insert(location.getReadNode(fieldIdx, layout,
80+
FieldAccessorNode.createRead(fieldIdx)));
81+
}
82+
83+
Object result = readFieldNode.read(rcvr);
84+
85+
if ((state & 0b1) != 0) {
86+
// we saw a string before
87+
if (result instanceof String) {
88+
return ((String) result).equals(value);
89+
}
90+
}
91+
92+
if ((state & 0b10) != 0) {
93+
// we saw a nil before
94+
if (result == Nil.nilObject) {
95+
return false;
96+
}
97+
}
98+
99+
CompilerDirectives.transferToInterpreterAndInvalidate();
100+
return specialize(frame, result, currentState);
101+
}
102+
103+
@Override
104+
public boolean executeBoolean(final VirtualFrame frame) throws UnexpectedResultException {
105+
SObject rcvr = (SObject) frame.getArguments()[0];
106+
107+
return executeEvaluated(frame, rcvr);
108+
}
109+
110+
private boolean specialize(final VirtualFrame frame, final Object result,
111+
final int currentState) throws UnexpectedResultException {
112+
if (result instanceof String) {
113+
state = currentState | 0b1;
114+
return value.equals(result);
115+
}
116+
117+
if (result == Nil.nilObject) {
118+
state = currentState | 0b10;
119+
return false;
120+
}
121+
122+
Object sendResult =
123+
makeGenericSend(result).doPreEvaluated(frame, new Object[] {result, value});
124+
if (sendResult instanceof Boolean) {
125+
return (Boolean) sendResult;
126+
}
127+
throw new UnexpectedResultException(sendResult);
128+
}
129+
130+
public GenericMessageSendNode makeGenericSend(
131+
@SuppressWarnings("unused") final Object receiver) {
132+
GenericMessageSendNode send =
133+
MessageSendNode.createGeneric(SymbolTable.symbolFor("="),
134+
new ExpressionNode[] {new FieldReadNode(new LocalArgumentReadNode(arg), fieldIdx),
135+
new GenericLiteralNode(value)},
136+
sourceCoord);
137+
138+
if (VmSettings.UseAstInterp) {
139+
replace(send);
140+
send.notifyDispatchInserted();
141+
return send;
142+
}
143+
144+
assert getParent() instanceof BytecodeLoopNode : "This node was expected to be a direct child of a `BytecodeLoopNode`.";
145+
throw new RespecializeException(send);
146+
}
147+
148+
@Override
149+
public void replaceAfterScopeChange(final ScopeAdaptationVisitor inliner) {
150+
ScopeElement<? extends Node> se = inliner.getAdaptedVar(arg);
151+
if (se.var != arg || se.contextLevel < 0) {
152+
Node newNode;
153+
if (se.contextLevel == 0) {
154+
newNode =
155+
new LocalFieldStringEqualsNode(fieldIdx, (Argument) se.var, value).initialize(
156+
fieldIdx);
157+
} else {
158+
newNode = new NonLocalFieldStringEqualsNode(fieldIdx, (Argument) se.var,
159+
se.contextLevel, value).initialize(fieldIdx);
160+
}
161+
162+
replace(newNode);
163+
} else {
164+
assert 0 == se.contextLevel;
165+
}
166+
}
167+
}

0 commit comments

Comments
 (0)