Skip to content

Commit a1769ac

Browse files
committed
Added specialized MessageNodes
- a monomorphic message node is the first specialization and caches the invokable of the first message send - a polymorphic message node caches 8 elements - the megamorphic node is used if there are more than 8 receiver classes encountered, it does the complete lookup and send and is the most general state [TODO: not yet properly working, there are issues with the Bounce and Queen benchmarks] Signed-off-by: Stefan Marr <git@stefan-marr.de>
1 parent 52d5612 commit a1769ac

File tree

1 file changed

+166
-9
lines changed

1 file changed

+166
-9
lines changed

src/som/interpreter/nodes/MessageNode.java

Lines changed: 166 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,29 @@
2121
*/
2222
package som.interpreter.nodes;
2323

24+
import com.oracle.truffle.api.CompilerDirectives;
2425
import com.oracle.truffle.api.frame.VirtualFrame;
26+
import com.oracle.truffle.api.nodes.NodeInfo;
27+
import com.oracle.truffle.api.nodes.NodeInfo.Kind;
2528

2629
import som.interpreter.nodes.VariableNode.SuperReadNode;
2730
import som.vm.Universe;
31+
import som.vmobjects.Class;
2832
import som.vmobjects.Invokable;
2933
import som.vmobjects.Object;
3034
import som.vmobjects.Symbol;
3135

3236
// @NodeChildren({
3337
// @NodeChild(value = "receiver", type = ExpressionNode.class),
3438
// @NodeChild(value = "arguments", type = ExpressionNode[].class)})
39+
@NodeInfo(kind = Kind.UNINITIALIZED)
3540
public class MessageNode extends ExpressionNode {
3641

3742
@Child protected final ExpressionNode receiver;
3843
@Children protected final ExpressionNode[] arguments;
3944

40-
private final Symbol selector;
41-
private final Universe universe;
45+
protected final Symbol selector;
46+
protected final Universe universe;
4247

4348
public MessageNode(final ExpressionNode receiver,
4449
final ExpressionNode[] arguments,
@@ -50,34 +55,186 @@ public MessageNode(final ExpressionNode receiver,
5055
this.universe = universe;
5156
}
5257

53-
@Override
54-
public Object executeGeneric(VirtualFrame frame) {
55-
// evaluate all the expressions: first determine receiver
56-
Object rcvr = receiver.executeGeneric(frame);
58+
protected Object[] determineArguments(final VirtualFrame frame) {
5759
int numArgs = (arguments == null) ? 0 : arguments.length;
5860

59-
// then determine the arguments
6061
Object[] args = new Object[numArgs];
6162

6263
for (int i = 0; i < numArgs; i++) {
6364
args[i] = arguments[i].executeGeneric(frame);
6465
}
6566

66-
// now start lookup
67-
som.vmobjects.Class rcvrClass = rcvr.getSOMClass();
67+
return args;
68+
}
69+
70+
protected Object doFullSend(final VirtualFrame frame, final Object rcvr,
71+
final Object[] args, final Class rcvrClass) {
72+
// now lookup selector
73+
Invokable invokable = rcvrClass.lookupInvokable(selector);
74+
75+
if (invokable != null) {
76+
return invokable.invoke(frame.pack(), rcvr, args);
77+
} else {
78+
return rcvr.sendDoesNotUnderstand(selector, args, universe, frame.pack());
79+
}
80+
}
81+
82+
protected static Class classOfReceiver(final Object rcvr, final ExpressionNode receiver) {
83+
Class rcvrClass = rcvr.getSOMClass();
6884

6985
// first determine whether it is a normal, or super send
7086
if (receiver instanceof SuperReadNode) {
7187
rcvrClass = rcvrClass.getSuperClass();
7288
}
7389

90+
return rcvrClass;
91+
}
92+
93+
@Override
94+
public Object executeGeneric(VirtualFrame frame) {
95+
// evaluate all the expressions: first determine receiver
96+
Object rcvr = receiver.executeGeneric(frame);
97+
98+
// then determine the arguments
99+
Object[] args = determineArguments(frame);
100+
101+
// now start lookup
102+
Class rcvrClass = classOfReceiver(rcvr, receiver);
103+
74104
// now lookup selector
75105
Invokable invokable = rcvrClass.lookupInvokable(selector);
76106

77107
if (invokable != null) {
108+
CompilerDirectives.transferToInterpreter();
109+
110+
// First let's rewrite this node
111+
MonomorpicMessageNode mono = new MonomorpicMessageNode(receiver, arguments, selector, universe, rcvrClass, invokable);
112+
this.replace(mono, "Let's assume it is a monomorphic send site.");
113+
114+
// Then execute the invokable, because it can exit this method with
115+
// control flow exceptions (non-local returns), which would leave node
116+
// unspecialized.
78117
return invokable.invoke(frame.pack(), rcvr, args);
79118
} else {
80119
return rcvr.sendDoesNotUnderstand(selector, args, universe, frame.pack());
81120
}
82121
}
122+
123+
@NodeInfo(kind = Kind.SPECIALIZED)
124+
public static class MonomorpicMessageNode extends MessageNode {
125+
126+
private final Class rcvrClass;
127+
private final Invokable invokable;
128+
129+
public MonomorpicMessageNode(final ExpressionNode receiver,
130+
final ExpressionNode[] arguments, final Symbol selector,
131+
final Universe universe, final Class rcvrClass,
132+
final Invokable invokable) {
133+
super(receiver, arguments, selector, universe);
134+
this.rcvrClass = rcvrClass;
135+
this.invokable = invokable;
136+
}
137+
138+
@Override
139+
public Object executeGeneric(VirtualFrame frame) {
140+
// evaluate all the expressions: first determine receiver
141+
Object rcvr = receiver.executeGeneric(frame);
142+
143+
// then determine the arguments
144+
Object[] args = determineArguments(frame);
145+
146+
Class currentRcvrClass = classOfReceiver(rcvr, receiver);
147+
148+
if (currentRcvrClass == rcvrClass) {
149+
return invokable.invoke(frame.pack(), rcvr, args);
150+
} else {
151+
CompilerDirectives.transferToInterpreter();
152+
// So, it might just be a polymorphic send site.
153+
PolymorpicMessageNode poly = new PolymorpicMessageNode(receiver,
154+
arguments, selector, universe, rcvrClass, invokable, currentRcvrClass);
155+
this.replace(poly, "It is not a monomorpic send.");
156+
return doFullSend(frame, rcvr, args, currentRcvrClass);
157+
}
158+
}
159+
}
160+
161+
@NodeInfo(kind = Kind.SPECIALIZED)
162+
public static class PolymorpicMessageNode extends MessageNode {
163+
private static final int CACHE_SIZE = 8;
164+
165+
private final Class[] rcvrClasses;
166+
private final Invokable[] invokables;
167+
168+
private int cacheEntries;
169+
170+
public PolymorpicMessageNode(final ExpressionNode receiver,
171+
final ExpressionNode[] arguments, final Symbol selector,
172+
final Universe universe, final Class firstRcvrClass,
173+
final Invokable firstInvokable,
174+
final Class secondRcvrClass) {
175+
super(receiver, arguments, selector, universe);
176+
rcvrClasses = new Class[CACHE_SIZE];
177+
invokables = new Invokable[CACHE_SIZE];
178+
179+
rcvrClasses[0] = firstRcvrClass;
180+
invokables[0] = firstInvokable;
181+
rcvrClasses[1] = secondRcvrClass;
182+
invokables[1] = secondRcvrClass.lookupInvokable(selector);
183+
cacheEntries = 2;
184+
}
185+
186+
@Override
187+
public Object executeGeneric(VirtualFrame frame) {
188+
// evaluate all the expressions: first determine receiver
189+
Object rcvr = receiver.executeGeneric(frame);
190+
191+
// then determine the arguments
192+
Object[] args = determineArguments(frame);
193+
194+
Class currentRcvrClass = classOfReceiver(rcvr, receiver);
195+
196+
int i;
197+
for (i = 0; i < cacheEntries; i++) {
198+
if (rcvrClasses[i] == currentRcvrClass) {
199+
return invokables[i].invoke(frame.pack(), rcvr, args);
200+
}
201+
}
202+
203+
if (i < CACHE_SIZE) { // we got still room in this polymorphic inline cache
204+
rcvrClasses[cacheEntries] = currentRcvrClass;
205+
invokables[cacheEntries] = currentRcvrClass.lookupInvokable(selector);
206+
return invokables[i].invoke(frame.pack(), rcvr, args);
207+
} else {
208+
CompilerDirectives.transferToInterpreter();
209+
// So, it might just be a megamorphic send site.
210+
MegamorphicMessageNode mega = new MegamorphicMessageNode(receiver, arguments, selector, universe);
211+
this.replace(mega, "It is not a monomorpic send.");
212+
return doFullSend(frame, rcvr, args, currentRcvrClass);
213+
}
214+
}
215+
}
216+
217+
@NodeInfo(kind = Kind.GENERIC)
218+
public static class MegamorphicMessageNode extends MessageNode {
219+
220+
public MegamorphicMessageNode(final ExpressionNode receiver,
221+
final ExpressionNode[] arguments, final Symbol selector,
222+
final Universe universe) {
223+
super(receiver, arguments, selector, universe);
224+
}
225+
226+
@Override
227+
public Object executeGeneric(VirtualFrame frame) {
228+
// evaluate all the expressions: first determine receiver
229+
Object rcvr = receiver.executeGeneric(frame);
230+
231+
// then determine the arguments
232+
Object[] args = determineArguments(frame);
233+
234+
// now start lookup
235+
Class rcvrClass = classOfReceiver(rcvr, receiver);
236+
237+
return doFullSend(frame, rcvr, args, rcvrClass);
238+
}
239+
}
83240
}

0 commit comments

Comments
 (0)