Mercurial > hg > truffle
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 } |