Mercurial > hg > graal-jvmci-8
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java @ 13803:e076c87ab175
Truffle: refactored inlining interfaces to a more compact CallNode.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Fri, 24 Jan 2014 15:55:41 +0100 |
parents | |
children | 3840d61e0e68 |
comparison
equal
deleted
inserted
replaced
13750:a03cb658e68e | 13803:e076c87ab175 |
---|---|
1 /* | |
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. Oracle designates this | |
8 * particular file as subject to the "Classpath" exception as provided | |
9 * by Oracle in the LICENSE file that accompanied this code. | |
10 * | |
11 * This code is distributed in the hope that it will be useful, but WITHOUT | |
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 * version 2 for more details (a copy is included in the LICENSE file that | |
15 * accompanied this code). | |
16 * | |
17 * You should have received a copy of the GNU General Public License version | |
18 * 2 along with this work; if not, write to the Free Software Foundation, | |
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
20 * | |
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
22 * or visit www.oracle.com if you need additional information or have any | |
23 * questions. | |
24 */ | |
25 package com.oracle.truffle.api.nodes; | |
26 | |
27 import com.oracle.truffle.api.*; | |
28 import com.oracle.truffle.api.frame.*; | |
29 import com.oracle.truffle.api.impl.*; | |
30 | |
31 /** | |
32 * This node represents a call to a constant {@link CallTarget} in the Truffle AST. This node should | |
33 * be used whenever a {@link CallTarget} is considered constant at a certain location. This enables | |
34 * the Truffle runtime to perform inlining or other optimizations for this call-site. | |
35 * | |
36 * @see #create(CallTarget) to create a CallNode instance. | |
37 */ | |
38 public abstract class CallNode extends Node { | |
39 | |
40 protected final CallTarget callTarget; | |
41 | |
42 private CallNode(CallTarget callTarget) { | |
43 this.callTarget = callTarget; | |
44 } | |
45 | |
46 /** | |
47 * Returns the constant {@link CallTarget} that is associated with this {@link CallNode}. | |
48 */ | |
49 public CallTarget getCallTarget() { | |
50 return callTarget; | |
51 } | |
52 | |
53 /** | |
54 * Calls this constant target passing a caller frame and arguments. | |
55 * | |
56 * @param caller the caller frame | |
57 * @param arguments the arguments that should be passed to the callee | |
58 * @return the return result of the call | |
59 */ | |
60 public abstract Object call(PackedFrame caller, Arguments arguments); | |
61 | |
62 /** | |
63 * Returns <code>true</code> if this {@link CallNode} can be inlined. A {@link CallTarget} is | |
64 * 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 boolean isInlinable() { | |
69 return false; | |
70 } | |
71 | |
72 /** | |
73 * Returns true if this {@link CallNode} was already inlined. | |
74 */ | |
75 public boolean isInlined() { | |
76 return false; | |
77 } | |
78 | |
79 /** | |
80 * Enforces an inlining optimization on this {@link CallNode} instance. If not performed | |
81 * manually the Truffle runtime may perform inlining using an heuristic to optimize the | |
82 * performance of the execution. It is recommended to implement an optimized version of | |
83 * {@link RootNode#inline()}. | |
84 * | |
85 * @return true if the inlining operation was successful. | |
86 * @throws IllegalStateException if {@link #isInlinable()} is false. | |
87 */ | |
88 public boolean inline() { | |
89 CompilerDirectives.transferToInterpreter(); | |
90 if (!isInlinable()) { | |
91 throw new IllegalStateException("Invoked inline on a non inlinable CallNode."); | |
92 } | |
93 assert !isInlined(); | |
94 return false; | |
95 } | |
96 | |
97 /** | |
98 * Creates a new {@link CallNode} using a constant {@link CallTarget}. | |
99 * | |
100 * @param target the {@link CallTarget} the {@link CallNode} should call | |
101 * @return a call node that calls the provided target | |
102 */ | |
103 public static CallNode create(CallTarget target) { | |
104 if (isInlinable(target)) { | |
105 return new InlinableCallNode(target); | |
106 } else { | |
107 return new DefaultCallNode(target); | |
108 } | |
109 } | |
110 | |
111 /** | |
112 * Warning: this is internal API and may change without notice. | |
113 */ | |
114 public static int internalGetCallCount(CallNode callNode) { | |
115 if (callNode.isInlinable()) { | |
116 return ((InlinableCallNode) callNode).getCallCount(); | |
117 } | |
118 throw new UnsupportedOperationException(); | |
119 } | |
120 | |
121 /** | |
122 * Warning: this is internal API and may change without notice. | |
123 */ | |
124 public static void internalResetCallCount(CallNode callNode) { | |
125 if (callNode.isInlinable()) { | |
126 ((InlinableCallNode) callNode).resetCallCount(); | |
127 return; | |
128 } | |
129 throw new UnsupportedOperationException(); | |
130 } | |
131 | |
132 private static boolean isInlinable(CallTarget callTarget) { | |
133 if (callTarget instanceof DefaultCallTarget) { | |
134 return (((DefaultCallTarget) callTarget).getRootNode()).isInlinable(); | |
135 } | |
136 return false; | |
137 } | |
138 | |
139 static final class DefaultCallNode extends CallNode { | |
140 | |
141 public DefaultCallNode(CallTarget target) { | |
142 super(target); | |
143 } | |
144 | |
145 @Override | |
146 public Object call(PackedFrame caller, Arguments arguments) { | |
147 return callTarget.call(caller, arguments); | |
148 } | |
149 | |
150 } | |
151 | |
152 static final class InlinableCallNode extends CallNode { | |
153 | |
154 private int callCount; | |
155 | |
156 public InlinableCallNode(CallTarget target) { | |
157 super(target); | |
158 } | |
159 | |
160 @Override | |
161 public Object call(PackedFrame parentFrame, Arguments arguments) { | |
162 if (CompilerDirectives.inInterpreter()) { | |
163 callCount++; | |
164 } | |
165 return callTarget.call(parentFrame, arguments); | |
166 } | |
167 | |
168 @Override | |
169 public boolean inline() { | |
170 super.inline(); | |
171 DefaultCallTarget defaultTarget = (DefaultCallTarget) getCallTarget(); | |
172 RootNode originalRootNode = defaultTarget.getRootNode(); | |
173 boolean inlined = false; | |
174 if (originalRootNode.isInlinable()) { | |
175 RootNode inlinedRootNode = defaultTarget.getRootNode().inline(); | |
176 replace(new InlinedCallNode(defaultTarget, inlinedRootNode)); | |
177 inlined = true; | |
178 } | |
179 return inlined; | |
180 } | |
181 | |
182 @Override | |
183 public boolean isInlinable() { | |
184 return true; | |
185 } | |
186 | |
187 /* Truffle internal API. */ | |
188 int getCallCount() { | |
189 return callCount; | |
190 } | |
191 | |
192 /* Truffle internal API. */ | |
193 void resetCallCount() { | |
194 callCount = 0; | |
195 } | |
196 | |
197 } | |
198 | |
199 static final class InlinedCallNode extends CallNode { | |
200 | |
201 private final RootNode inlinedRoot; | |
202 | |
203 public InlinedCallNode(DefaultCallTarget callTarget, RootNode inlinedRoot) { | |
204 super(callTarget); | |
205 this.inlinedRoot = inlinedRoot; | |
206 } | |
207 | |
208 @Override | |
209 public Object call(PackedFrame caller, Arguments arguments) { | |
210 return inlinedRoot.execute(Truffle.getRuntime().createVirtualFrame(caller, arguments, inlinedRoot.getFrameDescriptor())); | |
211 } | |
212 | |
213 @Override | |
214 public InlinedCallNode copy() { | |
215 return new InlinedCallNode((DefaultCallTarget) getCallTarget(), NodeUtil.cloneNode(inlinedRoot)); | |
216 } | |
217 | |
218 @Override | |
219 public boolean isInlinable() { | |
220 return false; | |
221 } | |
222 | |
223 @Override | |
224 public boolean isInlined() { | |
225 return true; | |
226 } | |
227 | |
228 } | |
229 | |
230 } |