comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java @ 13983:f46cab39a9a2

Truffle: Updated inlining API. Pushed inlining implementation to the Truffle runtime.
author Christian Humer <christian.humer@gmail.com>
date Thu, 20 Feb 2014 01:21:49 +0100
parents e86d32f4803f
children c5411233cdf8
comparison
equal deleted inserted replaced
13977:39076a984c33 13983:f46cab39a9a2
24 */ 24 */
25 package com.oracle.truffle.api.nodes; 25 package com.oracle.truffle.api.nodes;
26 26
27 import com.oracle.truffle.api.*; 27 import com.oracle.truffle.api.*;
28 import com.oracle.truffle.api.frame.*; 28 import com.oracle.truffle.api.frame.*;
29 import com.oracle.truffle.api.impl.*;
30 29
31 /** 30 /**
32 * This node represents a call to a static {@link CallTarget}. This node should be used whenever a 31 * This node represents a call to a static {@link CallTarget}. This node should be used whenever a
33 * {@link CallTarget} is considered constant at a certain location in the tree. This enables the 32 * {@link CallTarget} is considered constant at a certain location in the tree. This enables the
34 * Truffle runtime to perform inlining or other optimizations for this call-site. 33 * Truffle runtime to perform inlining or other optimizations for this call-site. This class is
34 * intended to be implemented by truffle runtime implementors and not by guest languague
35 * implementors.
35 * 36 *
36 * @see #create(CallTarget) to create a CallNode instance. 37 * @see #create(CallTarget) to create a CallNode instance.
37 */ 38 */
38 public abstract class CallNode extends Node { 39 public abstract class CallNode extends Node {
39 40
40 protected final CallTarget callTarget; 41 protected final CallTarget callTarget;
41 42
42 private CallNode(CallTarget callTarget) { 43 protected CallNode(CallTarget callTarget) {
43 this.callTarget = callTarget; 44 this.callTarget = callTarget;
44 } 45 }
45 46
46 /** 47 /**
47 * @return the constant {@link CallTarget} that is associated with this {@link CallNode}. 48 * @return the constant {@link CallTarget} that is associated with this {@link CallNode}.
57 * @param arguments the arguments that should be passed to the callee 58 * @param arguments the arguments that should be passed to the callee
58 * @return the return result of the call 59 * @return the return result of the call
59 */ 60 */
60 public abstract Object call(PackedFrame caller, Arguments arguments); 61 public abstract Object call(PackedFrame caller, Arguments arguments);
61 62
62 /**
63 * Returns <code>true</code> if the {@link CallTarget} contained in this {@link CallNode} can be
64 * inlined. A {@link CallTarget} is considered inlinable if it was created using
65 * {@link TruffleRuntime#createCallTarget(RootNode)} and if the enclosed {@link RootNode}
66 * returns <code>true</code> for {@link RootNode#isInlinable()}.
67 */
68 public abstract boolean isInlinable(); 63 public abstract boolean isInlinable();
69 64
70 /** 65 /**
71 * @return true if this {@link CallNode} was already inlined. 66 * @return true if this {@link CallNode} was already inlined.
72 */ 67 */
73 public abstract boolean isInlined(); 68 public abstract boolean isInlined();
74 69
75 /** 70 public abstract void inline();
76 * Enforces an inlining optimization on this {@link CallNode} instance. If not performed
77 * manually the Truffle runtime may perform inlining using an heuristic to optimize the
78 * performance of the execution. It is recommended to implement an version of
79 * {@link RootNode#inline()} that adapts the inlining for possible guest language specific
80 * behavior. If the this {@link CallNode} is not inlinable or is already inlined
81 * <code>false</code> is returned.
82 *
83 * @return <code>true</code> if the inlining operation was successful.
84 */
85 public abstract boolean inline();
86 71
87 /** 72 public abstract boolean isSplittable();
88 * Returns the inlined root node if the call node was inlined. If the {@link CallNode} was not 73
89 * inlined <code>null</code> is returned. 74 public abstract boolean split();
90 * 75
91 * @return the inlined root node returned by {@link RootNode#inline()} 76 public abstract CallTarget getSplitCallTarget();
92 */ 77
93 public RootNode getInlinedRoot() { 78 public abstract RootNode getInlinedRoot();
94 return null;
95 }
96 79
97 /** 80 /**
98 * Creates a new {@link CallNode} using a {@link CallTarget}. 81 * Creates a new {@link CallNode} using a {@link CallTarget}.
99 * 82 *
100 * @param target the {@link CallTarget} to call 83 * @param target the {@link CallTarget} to call
101 * @return a call node that calls the provided target 84 * @return a call node that calls the provided target
85 * @deprecated use {@link TruffleRuntime#createCallNode(CallTarget)} instead
102 */ 86 */
87 @Deprecated
103 public static CallNode create(CallTarget target) { 88 public static CallNode create(CallTarget target) {
104 if (isInlinable(target)) { 89 return Truffle.getRuntime().createCallNode(target);
105 return new InlinableCallNode((RootCallTarget) target);
106 } else {
107 return new DefaultCallNode(target);
108 }
109 } 90 }
110 91
111 /** 92 protected final void installParentInlinedCall() {
112 * Warning: this is internal API and may change without notice. 93 getInlinedRoot().addParentInlinedCall(this);
113 */
114 public interface CompilerCallView {
115
116 int getCallCount();
117
118 void resetCallCount();
119
120 void store(Object value);
121
122 Object load();
123 }
124
125 /**
126 * Warning: this is internal API and may change without notice.
127 */
128 public CompilerCallView getCompilerCallView() {
129 return null;
130 }
131
132 private static boolean isInlinable(CallTarget callTarget) {
133 if (callTarget instanceof RootCallTarget) {
134 return (((RootCallTarget) callTarget).getRootNode()).isInlinable();
135 }
136 return false;
137 }
138
139 @Override
140 public String toString() {
141 return getParent() != null ? getParent().toString() : super.toString();
142 }
143
144 static final class DefaultCallNode extends CallNode {
145
146 public DefaultCallNode(CallTarget target) {
147 super(target);
148 }
149
150 @Override
151 public Object call(PackedFrame caller, Arguments arguments) {
152 return callTarget.call(caller, arguments);
153 }
154
155 @Override
156 public boolean inline() {
157 return false;
158 }
159
160 @Override
161 public boolean isInlinable() {
162 return false;
163 }
164
165 @Override
166 public boolean isInlined() {
167 return false;
168 }
169
170 }
171
172 static final class InlinableCallNode extends CallNode implements CompilerCallView {
173
174 private int callCount;
175
176 public InlinableCallNode(RootCallTarget target) {
177 super(target);
178 }
179
180 @Override
181 public Object call(PackedFrame parentFrame, Arguments arguments) {
182 if (CompilerDirectives.inInterpreter()) {
183 callCount++;
184 }
185 return callTarget.call(parentFrame, arguments);
186 }
187
188 @Override
189 public boolean inline() {
190 DefaultCallTarget defaultTarget = (DefaultCallTarget) getCallTarget();
191 RootNode originalRootNode = defaultTarget.getRootNode();
192 if (originalRootNode.isInlinable()) {
193 RootNode inlinedRootNode = defaultTarget.getRootNode().inline();
194 inlinedRootNode.setCallTarget(callTarget);
195 inlinedRootNode.setParentInlinedCall(this);
196 replace(new InlinedCallNode(defaultTarget, inlinedRootNode));
197 return true;
198 }
199 return false;
200 }
201
202 @Override
203 public boolean isInlined() {
204 return false;
205 }
206
207 @Override
208 public boolean isInlinable() {
209 return true;
210 }
211
212 @Override
213 public CompilerCallView getCompilerCallView() {
214 return this;
215 }
216
217 /* Truffle internal API. */
218 public int getCallCount() {
219 return callCount;
220 }
221
222 /* Truffle internal API. */
223 public void resetCallCount() {
224 callCount = 0;
225 }
226
227 private Object storedCompilerInfo;
228
229 public void store(Object value) {
230 this.storedCompilerInfo = value;
231 }
232
233 public Object load() {
234 return storedCompilerInfo;
235 }
236
237 }
238
239 static final class InlinedCallNode extends CallNode {
240
241 private final RootNode inlinedRoot;
242
243 public InlinedCallNode(DefaultCallTarget callTarget, RootNode inlinedRoot) {
244 super(callTarget);
245 this.inlinedRoot = inlinedRoot;
246 }
247
248 @Override
249 public Object call(PackedFrame caller, Arguments arguments) {
250 return inlinedRoot.execute(Truffle.getRuntime().createVirtualFrame(caller, arguments, inlinedRoot.getFrameDescriptor()));
251 }
252
253 @Override
254 public InlinedCallNode copy() {
255 return new InlinedCallNode((DefaultCallTarget) getCallTarget(), NodeUtil.cloneNode(inlinedRoot));
256 }
257
258 @Override
259 public RootNode getInlinedRoot() {
260 return inlinedRoot;
261 }
262
263 @Override
264 public boolean inline() {
265 return false;
266 }
267
268 @Override
269 public boolean isInlinable() {
270 return true;
271 }
272
273 @Override
274 public boolean isInlined() {
275 return true;
276 }
277
278 } 94 }
279 95
280 } 96 }