comparison graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java @ 13338:652f24858aad

SL: simplified call nodes. aligned builtin inlining with user function inlining.
author Christian Humer <christian.humer@gmail.com>
date Sun, 15 Dec 2013 23:32:41 +0100
parents 06afa0db90b3
children c2ed2ce2cfe0
comparison
equal deleted inserted replaced
13337:ecf152c6bd16 13338:652f24858aad
32 public abstract class CallNode extends TypedNode { 32 public abstract class CallNode extends TypedNode {
33 33
34 private static final int INLINE_CACHE_SIZE = 2; 34 private static final int INLINE_CACHE_SIZE = 2;
35 35
36 @Child protected TypedNode functionNode; 36 @Child protected TypedNode functionNode;
37 37 @Child protected ArgumentsNode argumentsNode;
38 private CallNode(TypedNode functionNode) { 38
39 public CallNode(TypedNode functionNode, ArgumentsNode argumentsNode) {
39 this.functionNode = adoptChild(functionNode); 40 this.functionNode = adoptChild(functionNode);
40 } 41 this.argumentsNode = adoptChild(argumentsNode);
41 42 }
42 private CallTarget executeCallTargetNode(VirtualFrame frame) { 43
44 @Override
45 public final Object executeGeneric(VirtualFrame frame) {
46 CallTarget function;
43 try { 47 try {
44 return functionNode.executeCallTarget(frame); 48 function = functionNode.executeCallTarget(frame);
45 } catch (UnexpectedResultException e) { 49 } catch (UnexpectedResultException e) {
46 throw new UnsupportedOperationException("Call to " + e.getMessage() + " not supported."); 50 throw new UnsupportedOperationException("Call to " + e.getMessage() + " not supported.");
47 } 51 }
48 } 52 Object[] arguments = argumentsNode.executeArray(frame);
49 53 return executeCall(frame, function, arguments);
50 @Override 54 }
51 public final Object executeGeneric(VirtualFrame frame) { 55
52 return executeGeneric(frame, executeCallTargetNode(frame)); 56 public abstract Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments);
53 }
54
55 public abstract Object executeGeneric(VirtualFrame frame, CallTarget function);
56 57
57 public static CallNode create(TypedNode function, TypedNode[] arguments) { 58 public static CallNode create(TypedNode function, TypedNode[] arguments) {
58 return new UninitializedCallNode(function, new ArgumentsNode(arguments), 0); 59 return new UninitializedCallNode(function, new ArgumentsNode(arguments), 0);
59 } 60 }
60 61
61 private static final class CachedCallNode extends CallNode {
62
63 @Child protected CallNode nextNode;
64 @Child protected TypedNode currentNode;
65 private final CallTarget cachedFunction;
66
67 public CachedCallNode(TypedNode function, TypedNode current, CallNode next, CallTarget cachedFunction) {
68 super(function);
69 this.currentNode = adoptChild(current);
70 this.nextNode = adoptChild(next);
71 this.cachedFunction = cachedFunction;
72 }
73
74 @Override
75 public Object executeGeneric(VirtualFrame frame, CallTarget function) {
76 if (this.cachedFunction == function) {
77 return currentNode.executeGeneric(frame);
78 }
79 return nextNode.executeGeneric(frame, function);
80 }
81 }
82
83 private static final class UninitializedCallNode extends CallNode { 62 private static final class UninitializedCallNode extends CallNode {
84 63
85 @Child protected ArgumentsNode uninitializedArgs;
86 protected final int depth; 64 protected final int depth;
87 65
88 UninitializedCallNode(TypedNode function, ArgumentsNode args, int depth) { 66 UninitializedCallNode(TypedNode function, ArgumentsNode args, int depth) {
89 super(function); 67 super(function, args);
90 this.uninitializedArgs = adoptChild(args);
91 this.depth = depth; 68 this.depth = depth;
92 } 69 }
93 70
94 UninitializedCallNode(UninitializedCallNode copy) { 71 UninitializedCallNode(UninitializedCallNode copy) {
95 super(null); 72 super(null, null);
96 this.uninitializedArgs = adoptChild(copy.uninitializedArgs);
97 this.depth = copy.depth + 1; 73 this.depth = copy.depth + 1;
98 } 74 }
99 75
100 @Override 76 @Override
101 public Object executeGeneric(VirtualFrame frame, CallTarget function) { 77 public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) {
102 CompilerDirectives.transferToInterpreter(); 78 CompilerDirectives.transferToInterpreter();
103 return specialize(function).executeGeneric(frame, function); 79 return specialize(function).executeCall(frame, function, arguments);
104 } 80 }
105 81
106 private CallNode specialize(CallTarget function) { 82 private CallNode specialize(CallTarget function) {
107 CompilerAsserts.neverPartOfCompilation(); 83 CompilerAsserts.neverPartOfCompilation();
108 84
109 if (depth < INLINE_CACHE_SIZE) { 85 if (depth < INLINE_CACHE_SIZE) {
110 TypedNode current = createCacheNode(function); 86 DefaultCallTarget callTarget = (DefaultCallTarget) function;
87 FunctionRootNode root = (FunctionRootNode) callTarget.getRootNode();
111 CallNode next = new UninitializedCallNode(this); 88 CallNode next = new UninitializedCallNode(this);
112 return replace(new CachedCallNode(this.functionNode, current, next, function)); 89 InlinableDirectCallNode directCall = new InlinableDirectCallNode(functionNode, argumentsNode, next, callTarget);
90 replace(directCall);
91 if (root.isInlineImmediatly()) {
92 return directCall.inlineImpl();
93 } else {
94 return directCall;
95 }
113 } else { 96 } else {
114 CallNode topMost = (CallNode) getTopNode(); 97 CallNode topMost = (CallNode) NodeUtil.getNthParent(this, depth);
115 return topMost.replace(new GenericCallNode(topMost.functionNode, uninitializedArgs)); 98 return topMost.replace(new GenericCallNode(topMost.functionNode, topMost.argumentsNode));
116 } 99 }
117 } 100 }
118 101
119 protected Node getTopNode() { 102 }
120 Node parentNode = this; 103
121 for (int i = 0; i < depth; i++) { 104 private abstract static class DirectCallNode extends CallNode {
122 parentNode = parentNode.getParent(); 105
123 } 106 protected final DefaultCallTarget cachedFunction;
124 return parentNode; 107
125 } 108 @Child protected CallNode nextNode;
126 109
127 protected TypedNode createCacheNode(CallTarget function) { 110 public DirectCallNode(TypedNode function, ArgumentsNode arguments, DefaultCallTarget cachedFunction, CallNode next) {
128 ArgumentsNode clonedArgs = NodeUtil.cloneNode(uninitializedArgs); 111 super(function, arguments);
129 112 this.cachedFunction = cachedFunction;
130 if (function instanceof DefaultCallTarget) { 113 this.nextNode = adoptChild(next);
131 DefaultCallTarget defaultFunction = (DefaultCallTarget) function; 114 }
132 RootNode rootNode = defaultFunction.getRootNode(); 115
133 if (rootNode instanceof FunctionRootNode) { 116 @Override
134 FunctionRootNode root = (FunctionRootNode) rootNode; 117 public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) {
135 if (root.isAlwaysInline()) { 118 if (this.cachedFunction == function) {
136 TypedNode inlinedCall = root.inline(clonedArgs); 119 return executeCurrent(frame, arguments);
137 if (inlinedCall != null) { 120 }
138 return inlinedCall; 121 return nextNode.executeCall(frame, function, arguments);
139 } 122 }
140 } 123
141 return new InlinableCallNode((DefaultCallTarget) function, clonedArgs); 124 protected abstract Object executeCurrent(VirtualFrame frame, Object[] arguments);
142 } 125
143 // got a call target that is not inlinable (should not occur for SL) 126 }
144 return new DispatchedCallNode(defaultFunction, clonedArgs); 127
145 } else { 128 private static final class InlinableDirectCallNode extends DirectCallNode implements InlinableCallSite {
146 throw new AssertionError();
147 }
148
149 }
150 }
151
152 private static final class InlinableCallNode extends DispatchedCallNode implements InlinableCallSite {
153 129
154 @CompilationFinal private int callCount; 130 @CompilationFinal private int callCount;
155 131
156 InlinableCallNode(DefaultCallTarget function, ArgumentsNode arguments) { 132 InlinableDirectCallNode(TypedNode function, ArgumentsNode arguments, CallNode next, DefaultCallTarget cachedFunction) {
157 super(function, arguments); 133 super(function, arguments, cachedFunction, next);
134 }
135
136 @Override
137 public Object executeCurrent(VirtualFrame frame, Object[] arguments) {
138 if (CompilerDirectives.inInterpreter()) {
139 callCount++;
140 }
141 return cachedFunction.call(frame.pack(), new SLArguments(arguments));
142 }
143
144 InlinedDirectCallNode inlineImpl() {
145 CompilerAsserts.neverPartOfCompilation();
146 RootNode root = cachedFunction.getRootNode();
147 TypedNode inlinedNode = ((FunctionRootNode) root).inline();
148 assert inlinedNode != null;
149 return replace(new InlinedDirectCallNode(this, inlinedNode), "Inlined " + root);
150 }
151
152 @Override
153 public boolean inline(FrameFactory factory) {
154 inlineImpl();
155 /* SL is always able to inline if required. */
156 return true;
158 } 157 }
159 158
160 @Override 159 @Override
161 public int getCallCount() { 160 public int getCallCount() {
162 return callCount; 161 return callCount;
167 callCount = 0; 166 callCount = 0;
168 } 167 }
169 168
170 @Override 169 @Override
171 public Node getInlineTree() { 170 public Node getInlineTree() {
172 RootNode root = function.getRootNode(); 171 RootNode root = cachedFunction.getRootNode();
173 if (root instanceof FunctionRootNode) { 172 if (root instanceof FunctionRootNode) {
174 return ((FunctionRootNode) root).getUninitializedBody(); 173 return ((FunctionRootNode) root).getUninitializedBody();
175 } 174 }
176 return null; 175 return null;
177 } 176 }
178 177
179 @Override 178 @Override
180 public boolean inline(FrameFactory factory) {
181 CompilerAsserts.neverPartOfCompilation();
182 TypedNode functionCall = null;
183
184 RootNode root = function.getRootNode();
185 if (root instanceof FunctionRootNode) {
186 functionCall = ((FunctionRootNode) root).inline(NodeUtil.cloneNode(args));
187 }
188 if (functionCall != null) {
189 this.replace(functionCall);
190 return true;
191 } else {
192 return false;
193 }
194 }
195
196 @Override
197 public Object executeGeneric(VirtualFrame frame) {
198 if (CompilerDirectives.inInterpreter()) {
199 callCount++;
200 }
201 return super.executeGeneric(frame);
202 }
203
204 @Override
205 public CallTarget getCallTarget() { 179 public CallTarget getCallTarget() {
206 return function; 180 return cachedFunction;
207 } 181 }
208 182
209 } 183 }
210 184
211 private static class DispatchedCallNode extends TypedNode { 185 private static class InlinedDirectCallNode extends DirectCallNode implements InlinedCallSite {
212 186
213 @Child protected ArgumentsNode args; 187 private final FrameDescriptor descriptor;
214 protected final DefaultCallTarget function; 188 @Child private TypedNode inlinedBody;
215 189
216 DispatchedCallNode(DefaultCallTarget function, ArgumentsNode arguments) { 190 InlinedDirectCallNode(InlinableDirectCallNode prev, TypedNode inlinedBody) {
217 this.args = adoptChild(arguments); 191 super(prev.functionNode, prev.argumentsNode, prev.cachedFunction, prev.nextNode);
218 this.function = function; 192 this.descriptor = cachedFunction.getFrameDescriptor();
219 } 193 this.inlinedBody = adoptChild(inlinedBody);
220 194 }
221 @Override 195
222 public Object executeGeneric(VirtualFrame frame) { 196 @Override
223 SLArguments argsObject = new SLArguments(args.executeArray(frame)); 197 public Object executeCurrent(VirtualFrame frame, Object[] arguments) {
224 return function.call(frame.pack(), argsObject); 198 SLArguments slArguments = new SLArguments(arguments);
225 } 199 VirtualFrame newFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), slArguments, descriptor);
200 return inlinedBody.executeGeneric(newFrame);
201 }
202
203 @Override
204 public CallTarget getCallTarget() {
205 return cachedFunction;
206 }
207
226 } 208 }
227 209
228 private static final class GenericCallNode extends CallNode { 210 private static final class GenericCallNode extends CallNode {
229 211
230 @Child protected ArgumentsNode args;
231
232 GenericCallNode(TypedNode functionNode, ArgumentsNode arguments) { 212 GenericCallNode(TypedNode functionNode, ArgumentsNode arguments) {
233 super(functionNode); 213 super(functionNode, arguments);
234 this.args = adoptChild(arguments); 214 }
235 } 215
236 216 @Override
237 @Override 217 public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) {
238 public Object executeGeneric(VirtualFrame frame, CallTarget function) { 218 return function.call(frame.pack(), new SLArguments(arguments));
239 SLArguments argsObject = new SLArguments(args.executeArray(frame));
240 return function.call(frame.pack(), argsObject);
241 } 219 }
242 } 220 }
243 221
244 } 222 }