Skip to content

Commit 482ccaa

Browse files
committed
Complete refactoring of execution strategy to utilize Truffle DSL
This is a major rewrite of the Truffle-based execution system. Instead of relying on a general MessageNode, we need to introduce Unary, Binary, and Ternary nodes to use the Truffle DSL specialization features properly. For variable arguments, we still keep the KeywordMessage nodes around. However, the specific node types are needed to have a specialization down to the argument level of execution methods of a node. For instance, an addition needs to get the receiver and the argument evaluated properly. That's not supported by the DSL otherwise. The NodeFactory should now be used for all 'higher-level'/'higher-complexity' node creations. (Refactoring needs to be completed still) #if* and #while* related nodes have be split into classes for each selector. Primitives are rewritten so that each primitive node class represents one operation (i.e., selector) and implementers all variants for all types. Not yet clear is whether this is going to work well for primitives. Especially since we still want to enable classes to override primitives in subclasses, and since we need to handle polymorphism in a way that works. Also need to avoid primitives becoming polymorphic sends when it is not necessary! TODO: * Cloning for inlining needs to be implemented * Move all 'complex' node creation stuff into NodeFactory * Primitives can be further optimized by using primitive types, avoid boxing, using ExactMath, etc. * verify polymorphism works properly with new Primitive design [TODO-REPORT: give an overview of the final node type hierarchy, and the transitions between optimization states] Signed-off-by: Stefan Marr <git@stefan-marr.de>
1 parent 7037294 commit 482ccaa

File tree

75 files changed

+2634
-2074
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+2634
-2074
lines changed

src/som/compiler/Parser.java

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,20 @@
6363
import java.util.List;
6464

6565
import som.compiler.SourcecodeCompiler.Source;
66+
import som.interpreter.nodes.AbstractMessageNode;
6667
import som.interpreter.nodes.ArgumentEvaluationNode;
68+
import som.interpreter.nodes.BinaryMessageNode;
69+
import som.interpreter.nodes.BinaryMessageNodeFactory;
6770
import som.interpreter.nodes.ExpressionNode;
6871
import som.interpreter.nodes.FieldNode.FieldReadNode;
6972
import som.interpreter.nodes.FieldNode.FieldWriteNode;
7073
import som.interpreter.nodes.GlobalNode.GlobalReadNode;
71-
import som.interpreter.nodes.MessageNode;
72-
import som.interpreter.nodes.MessageNodeFactory;
74+
import som.interpreter.nodes.KeywordMessageNodeFactory;
7375
import som.interpreter.nodes.ReturnNonLocalNode;
7476
import som.interpreter.nodes.SequenceNode;
77+
import som.interpreter.nodes.TernaryMessageNodeFactory;
78+
import som.interpreter.nodes.UnaryMessageNode;
79+
import som.interpreter.nodes.UnaryMessageNodeFactory;
7580
import som.interpreter.nodes.VariableNode.SelfReadNode;
7681
import som.interpreter.nodes.VariableNode.SuperReadNode;
7782
import som.interpreter.nodes.VariableNode.VariableReadNode;
@@ -527,9 +532,9 @@ private String variable() {
527532
return identifier();
528533
}
529534

530-
private MessageNode messages(final MethodGenerationContext mgenc,
535+
private AbstractMessageNode messages(final MethodGenerationContext mgenc,
531536
final ExpressionNode receiver) {
532-
MessageNode msg;
537+
AbstractMessageNode msg;
533538
if (sym == Identifier) {
534539
msg = unaryMessage(receiver);
535540

@@ -560,24 +565,21 @@ private MessageNode messages(final MethodGenerationContext mgenc,
560565
return msg;
561566
}
562567

563-
private MessageNode unaryMessage(final ExpressionNode receiver) {
568+
private UnaryMessageNode unaryMessage(final ExpressionNode receiver) {
564569
SourceCoordinate coord = getCoordinate();
565570
SSymbol selector = unarySelector();
566-
MessageNode msg = MessageNodeFactory.create(selector, universe, receiver, new ArgumentEvaluationNode());
571+
UnaryMessageNode msg = UnaryMessageNodeFactory.create(selector, universe, receiver);
567572
assignSource(msg, coord);
568573
return msg;
569574
}
570575

571-
private MessageNode binaryMessage(final MethodGenerationContext mgenc,
576+
private BinaryMessageNode binaryMessage(final MethodGenerationContext mgenc,
572577
final ExpressionNode receiver) {
573578
SourceCoordinate coord = getCoordinate();
574579
SSymbol msg = binarySelector();
575-
ExpressionNode operand = binaryOperand(mgenc);
576-
577-
ArgumentEvaluationNode args =
578-
new ArgumentEvaluationNode(new ExpressionNode[] {operand});
580+
ExpressionNode operand = binaryOperand(mgenc);
579581

580-
MessageNode msgNode = MessageNodeFactory.create(msg, universe, receiver, args);
582+
BinaryMessageNode msgNode = BinaryMessageNodeFactory.create(msg, universe, receiver, operand);
581583
assignSource(msgNode, coord);
582584
return msgNode;
583585
}
@@ -594,7 +596,7 @@ private ExpressionNode binaryOperand(final MethodGenerationContext mgenc) {
594596
return operand;
595597
}
596598

597-
private MessageNode keywordMessage(final MethodGenerationContext mgenc,
599+
private AbstractMessageNode keywordMessage(final MethodGenerationContext mgenc,
598600
final ExpressionNode receiver) {
599601
SourceCoordinate coord = getCoordinate();
600602
List<ExpressionNode> arguments = new ArrayList<ExpressionNode>();
@@ -608,10 +610,18 @@ private MessageNode keywordMessage(final MethodGenerationContext mgenc,
608610

609611
SSymbol msg = universe.symbolFor(kw.toString());
610612

611-
ArgumentEvaluationNode args =
612-
new ArgumentEvaluationNode(arguments.toArray(new ExpressionNode[0]));
613+
AbstractMessageNode msgNode;
614+
int numArgs = msg.getNumberOfSignatureArguments();
615+
if (numArgs == 2) {
616+
msgNode = BinaryMessageNodeFactory.create(msg, universe, receiver, arguments.get(0));
617+
} else if (numArgs == 3) {
618+
msgNode = TernaryMessageNodeFactory.create(msg, universe, receiver, arguments.get(0), arguments.get(1));
619+
} else {
620+
ArgumentEvaluationNode args =
621+
new ArgumentEvaluationNode(arguments.toArray(new ExpressionNode[0]));
622+
msgNode = KeywordMessageNodeFactory.create(msg, universe, receiver, args);
623+
}
613624

614-
MessageNode msgNode = MessageNodeFactory.create(msg, universe, receiver, args);
615625
assignSource(msgNode, coord);
616626
return msgNode;
617627
}

src/som/interpreter/Method.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ protected static SAbstractObject messageSendExecution(final FrameOnStackMarker m
6969
do {
7070
restart = false;
7171
try {
72-
result = expr.executeGeneric(frame);
72+
result = (SAbstractObject) expr.executeGeneric(frame); // TODO: work out whether there is another way than this cast!
7373
} catch (ReturnException e) {
7474
if (!e.reachedTarget(marker)) {
7575
marker.frameNoLongerOnStack();

src/som/interpreter/Primitive.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package som.interpreter;
22

33
import som.interpreter.nodes.ExpressionNode;
4-
import som.interpreter.nodes.PrimitiveNode;
54
import som.vmobjects.SAbstractObject;
65

76
import com.oracle.truffle.api.frame.FrameDescriptor;
@@ -12,7 +11,7 @@
1211

1312
public class Primitive extends Invokable {
1413

15-
public Primitive(final PrimitiveNode primitive,
14+
public Primitive(final ExpressionNode primitive,
1615
final FrameSlot selfSlot, final FrameSlot[] arugmentSlots,
1716
final FrameDescriptor frameDescriptor) {
1817
super(primitive, selfSlot, arugmentSlots, frameDescriptor);
@@ -43,7 +42,7 @@ protected void initializeFrame(final VirtualFrame frame) {
4342
public SAbstractObject executeInlined(final VirtualFrame frame,
4443
final ExpressionNode exp) {
4544
initializeFrame(frame);
46-
return exp.executeGeneric(frame);
45+
return (SAbstractObject) exp.executeGeneric(frame); // TODO: Work out whether there is another way than this cast!
4746
}
4847

4948
@Override

src/som/interpreter/nodes/AbstractMessageNode.java

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,8 @@
77
import som.vmobjects.SMethod;
88
import som.vmobjects.SSymbol;
99

10-
import com.oracle.truffle.api.dsl.NodeChild;
11-
import com.oracle.truffle.api.dsl.NodeChildren;
1210
import com.oracle.truffle.api.frame.VirtualFrame;
1311

14-
15-
@NodeChildren({
16-
@NodeChild(value = "receiver", type = ExpressionNode.class),
17-
@NodeChild(value = "arguments", type = ArgumentEvaluationNode.class)
18-
})
1912
public abstract class AbstractMessageNode extends ExpressionNode {
2013

2114
protected final SSymbol selector;
@@ -26,14 +19,10 @@ public AbstractMessageNode(final SSymbol selector, final Universe universe) {
2619
this.universe = universe;
2720
}
2821

29-
public AbstractMessageNode(final MessageNode node) {
22+
public AbstractMessageNode(final AbstractMessageNode node) {
3023
this(node.selector, node.universe);
3124
}
3225

33-
// TODO: document this getter idiom
34-
public abstract ExpressionNode getReceiver();
35-
public abstract ArgumentEvaluationNode getArguments();
36-
3726
protected SClass classOfReceiver(final SAbstractObject rcvr, final ExpressionNode receiver) {
3827
SClass rcvrClass = rcvr.getSOMClass(universe);
3928

@@ -44,17 +33,18 @@ protected SClass classOfReceiver(final SAbstractObject rcvr, final ExpressionNod
4433
return rcvrClass;
4534
}
4635

47-
protected boolean hasOneArgument(final Object receiver, final Object arguments) {
48-
return (arguments != null && ((SAbstractObject[]) arguments).length == 1);
49-
}
50-
51-
protected boolean hasTwoArguments(final Object receiver, final Object arguments) {
52-
return (arguments != null && ((SAbstractObject[]) arguments).length == 2);
36+
protected boolean isBooleanReceiver(final SAbstractObject receiver) {
37+
return receiver == universe.trueObject || receiver == universe.falseObject;
5338
}
5439

55-
protected boolean isBooleanReceiver(final SAbstractObject receiver) {
56-
SClass rcvrClass = classOfReceiver(receiver, getReceiver());
57-
return rcvrClass == universe.trueClass || rcvrClass == universe.falseClass;
40+
/**
41+
* Guard for system primitives.
42+
* TODO: make sure system primitives do not trigger on any other kind of object
43+
* @param receiver
44+
* @return
45+
*/
46+
protected boolean receiverIsSystemObject(final SAbstractObject receiver) {
47+
return receiver == universe.systemObject;
5848
}
5949

6050
protected SAbstractObject doFullSend(final VirtualFrame frame, final SAbstractObject rcvr,
@@ -68,4 +58,8 @@ protected SAbstractObject doFullSend(final VirtualFrame frame, final SAbstractOb
6858
return rcvr.sendDoesNotUnderstand(selector, args, universe, frame.pack());
6959
}
7060
}
61+
62+
protected static final SAbstractObject[] noArgs = new SAbstractObject[0];
63+
64+
public static final int PriorityMonomorphicCase = 9999;
7165
}

src/som/interpreter/nodes/ArgumentEvaluationNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public SAbstractObject[] doArray(final VirtualFrame frame) {
3131
SAbstractObject[] result = new SAbstractObject[arguments.length];
3232

3333
for (int i = 0; i < arguments.length; i++) {
34-
result[i] = arguments[i].executeGeneric(frame);
34+
result[i] = (SAbstractObject) arguments[i].executeGeneric(frame); // TODO: Work out whether there is another way than this cast!
3535
}
3636

3737
return result;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package som.interpreter.nodes;
2+
3+
import som.interpreter.nodes.messages.BinaryMonomorphicNode;
4+
import som.vm.Universe;
5+
import som.vmobjects.SAbstractObject;
6+
import som.vmobjects.SClass;
7+
import som.vmobjects.SMethod;
8+
import som.vmobjects.SSymbol;
9+
10+
import com.oracle.truffle.api.CompilerDirectives;
11+
import com.oracle.truffle.api.dsl.NodeChild;
12+
import com.oracle.truffle.api.dsl.NodeChildren;
13+
import com.oracle.truffle.api.dsl.Specialization;
14+
import com.oracle.truffle.api.frame.VirtualFrame;
15+
16+
17+
@NodeChildren({
18+
@NodeChild(value = "receiver", type = ExpressionNode.class),
19+
@NodeChild(value = "argument", type = ExpressionNode.class)
20+
})
21+
public abstract class BinaryMessageNode extends AbstractMessageNode {
22+
23+
public BinaryMessageNode(final SSymbol selector, final Universe universe) {
24+
super(selector, universe);
25+
}
26+
27+
public BinaryMessageNode(final BinaryMessageNode node) {
28+
this(node.selector, node.universe);
29+
}
30+
31+
// TODO: document this getter idiom
32+
public abstract ExpressionNode getReceiver();
33+
public abstract ExpressionNode getArgument();
34+
public abstract Object executeEvaluated(final VirtualFrame frame, final Object receiver, Object argument);
35+
36+
// TODO: want to use @Generic here!
37+
@Specialization
38+
public Object doGeneric(final VirtualFrame frame,
39+
final Object rcvr,
40+
final Object arg) {
41+
CompilerDirectives.transferToInterpreter();
42+
43+
SAbstractObject receiver = (SAbstractObject) rcvr;
44+
SAbstractObject argument = (SAbstractObject) arg;
45+
46+
SClass rcvrClass = classOfReceiver(receiver, getReceiver());
47+
SMethod invokable = rcvrClass.lookupInvokable(selector);
48+
49+
if (invokable != null) {
50+
BinaryMonomorphicNode node = NodeFactory.createBinaryMonomorphicNode(selector, universe, rcvrClass, invokable, getReceiver(), getReceiver());
51+
// BinaryMonomorphicNodeFactory.create(selector, universe, rcvrClass, invokable, getReceiver(), getArgument());
52+
return replace(node, "Be optimisitic and do a monomorphic lookup cache, or a primitive inline.").executeEvaluated(frame, receiver, argument);
53+
} else {
54+
SAbstractObject[] args = new SAbstractObject[] {argument};
55+
return doFullSend(frame, receiver, args, rcvrClass);
56+
}
57+
}
58+
59+
@Override
60+
public ExpressionNode cloneForInlining() {
61+
// TODO: test whether this is problematic
62+
return (ExpressionNode) this.copy();
63+
}
64+
}

src/som/interpreter/nodes/FieldNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ public FieldWriteNode(final int fieldIndex,
8080
@Override
8181
public SAbstractObject executeGeneric(final VirtualFrame frame) {
8282
MaterializedFrame ctx = determineContext(frame.materialize());
83-
SAbstractObject value = exp.executeGeneric(frame);
84-
SObject self = getSelfFromMaterialized(ctx);
83+
SAbstractObject value = (SAbstractObject) exp.executeGeneric(frame); // TODO: Work out whether there is another way than this cast!
84+
SObject self = getSelfFromMaterialized(ctx);
8585

8686
self.setField(fieldIndex, value);
8787
return value;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* Copyright (c) 2013 Stefan Marr, stefan.marr@vub.ac.be
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
* THE SOFTWARE.
21+
*/
22+
package som.interpreter.nodes;
23+
24+
import som.interpreter.nodes.messages.KeywordMonomorphicNode;
25+
import som.vm.Universe;
26+
import som.vmobjects.SAbstractObject;
27+
import som.vmobjects.SClass;
28+
import som.vmobjects.SMethod;
29+
import som.vmobjects.SSymbol;
30+
31+
import com.oracle.truffle.api.CompilerDirectives;
32+
import com.oracle.truffle.api.dsl.NodeChild;
33+
import com.oracle.truffle.api.dsl.NodeChildren;
34+
import com.oracle.truffle.api.dsl.Specialization;
35+
import com.oracle.truffle.api.frame.VirtualFrame;
36+
37+
@NodeChildren({
38+
@NodeChild(value = "receiver", type = ExpressionNode.class),
39+
@NodeChild(value = "arguments", type = ArgumentEvaluationNode.class)
40+
})
41+
public abstract class KeywordMessageNode extends AbstractMessageNode {
42+
43+
public KeywordMessageNode(final SSymbol selector, final Universe universe) {
44+
super(selector, universe);
45+
}
46+
47+
public KeywordMessageNode(final KeywordMessageNode node) {
48+
this(node.selector, node.universe);
49+
}
50+
51+
public abstract ExpressionNode getReceiver();
52+
public abstract ArgumentEvaluationNode getArguments();
53+
public abstract Object executeEvaluated(final VirtualFrame frame, final Object receiver, Object arguments);
54+
55+
// TODO: want to use @Generic here!
56+
@Specialization
57+
public Object doGeneric(final VirtualFrame frame, final Object rcvr,
58+
final Object arguments) {
59+
CompilerDirectives.transferToInterpreter();
60+
61+
SAbstractObject receiver = (SAbstractObject) rcvr;
62+
63+
SClass rcvrClass = classOfReceiver(receiver, getReceiver());
64+
SMethod invokable = rcvrClass.lookupInvokable(selector);
65+
66+
if (invokable != null) {
67+
KeywordMonomorphicNode node = NodeFactory.createKeywordMonomorphicNode(selector, universe, rcvrClass, invokable, getReceiver(), getArguments());
68+
return replace(node, "Be optimisitic and do a monomorphic lookup cache, or a primitive inline.").
69+
executeEvaluated(frame, receiver, arguments);
70+
} else {
71+
SAbstractObject[] args = (SAbstractObject[]) arguments;
72+
return doFullSend(frame, receiver, args, rcvrClass);
73+
}
74+
}
75+
76+
@Override
77+
public ExpressionNode cloneForInlining() {
78+
// TODO: test whether this is problematic
79+
return (ExpressionNode) this.copy();
80+
//return NodeFactory.createKeywordMessageNode(selector, universe, getReceiver(), getArguments());
81+
}
82+
}

0 commit comments

Comments
 (0)