2121 */
2222package som .interpreter .nodes ;
2323
24+ import com .oracle .truffle .api .CompilerDirectives ;
2425import com .oracle .truffle .api .frame .VirtualFrame ;
26+ import com .oracle .truffle .api .nodes .NodeInfo ;
27+ import com .oracle .truffle .api .nodes .NodeInfo .Kind ;
2528
2629import som .interpreter .nodes .VariableNode .SuperReadNode ;
2730import som .vm .Universe ;
31+ import som .vmobjects .Class ;
2832import som .vmobjects .Invokable ;
2933import som .vmobjects .Object ;
3034import 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 )
3540public 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