comparison graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java @ 12752:71991b7a0f14

SL: Enhanced SimpleLanguage with support for if statements, function calls, function caching + inlining and builtins.
author Christian Humer <christian.humer@gmail.com>
date Mon, 11 Nov 2013 21:34:44 +0100
parents
children 06afa0db90b3
comparison
equal deleted inserted replaced
12712:882a0aadfed6 12752:71991b7a0f14
1 /*
2 * Copyright (c) 2012, 2012, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.oracle.truffle.sl.nodes;
24
25 import com.oracle.truffle.api.*;
26 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
27 import com.oracle.truffle.api.frame.*;
28 import com.oracle.truffle.api.impl.*;
29 import com.oracle.truffle.api.nodes.*;
30 import com.oracle.truffle.sl.runtime.*;
31
32 public abstract class CallNode extends TypedNode {
33
34 private static final int INLINE_CACHE_SIZE = 2;
35
36 @Child protected TypedNode functionNode;
37
38 private CallNode(TypedNode functionNode) {
39 this.functionNode = adoptChild(functionNode);
40 }
41
42 private CallTarget executeCallTargetNode(VirtualFrame frame) {
43 try {
44 return functionNode.executeCallTarget(frame);
45 } catch (UnexpectedResultException e) {
46 throw new UnsupportedOperationException("Call to " + e.getMessage() + " not supported.");
47 }
48 }
49
50 @Override
51 public final Object executeGeneric(VirtualFrame frame) {
52 return executeGeneric(frame, executeCallTargetNode(frame));
53 }
54
55 public abstract Object executeGeneric(VirtualFrame frame, CallTarget function);
56
57 public static CallNode create(TypedNode function, TypedNode[] arguments) {
58 return new UninitializedCallNode(function, new ArgumentsNode(arguments), 0);
59 }
60
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 {
84
85 @Child protected ArgumentsNode uninitializedArgs;
86 protected final int depth;
87
88 UninitializedCallNode(TypedNode function, ArgumentsNode args, int depth) {
89 super(function);
90 this.uninitializedArgs = adoptChild(args);
91 this.depth = depth;
92 }
93
94 UninitializedCallNode(UninitializedCallNode copy) {
95 super(null);
96 this.uninitializedArgs = adoptChild(copy.uninitializedArgs);
97 this.depth = copy.depth + 1;
98 }
99
100 @Override
101 public Object executeGeneric(VirtualFrame frame, CallTarget function) {
102 CompilerDirectives.transferToInterpreter();
103 return specialize(function).executeGeneric(frame, function);
104 }
105
106 private CallNode specialize(CallTarget function) {
107 CompilerAsserts.neverPartOfCompilation();
108
109 if (depth < INLINE_CACHE_SIZE) {
110 TypedNode current = createCacheNode(function);
111 CallNode next = new UninitializedCallNode(this);
112 return replace(new CachedCallNode(this.functionNode, current, next, function));
113 } else {
114 CallNode topMost = (CallNode) getTopNode();
115 return topMost.replace(new GenericCallNode(topMost.functionNode, uninitializedArgs));
116 }
117 }
118
119 protected Node getTopNode() {
120 Node parentNode = this;
121 for (int i = 0; i < depth; i++) {
122 parentNode = parentNode.getParent();
123 }
124 return parentNode;
125 }
126
127 protected TypedNode createCacheNode(CallTarget function) {
128 ArgumentsNode clonedArgs = NodeUtil.cloneNode(uninitializedArgs);
129
130 if (function instanceof DefaultCallTarget) {
131 DefaultCallTarget defaultFunction = (DefaultCallTarget) function;
132 RootNode rootNode = defaultFunction.getRootNode();
133 if (rootNode instanceof FunctionRootNode) {
134 FunctionRootNode root = (FunctionRootNode) rootNode;
135 if (root.isAlwaysInline()) {
136 TypedNode inlinedCall = root.inline(clonedArgs);
137 if (inlinedCall != null) {
138 return inlinedCall;
139 }
140 }
141 return new InlinableCallNode((DefaultCallTarget) function, clonedArgs);
142 }
143 }
144
145 // got a call target that is not inlinable (should not occur for SL)
146 return new DispatchedCallNode(function, clonedArgs);
147 }
148 }
149
150 private static final class InlinableCallNode extends DispatchedCallNode implements InlinableCallSite {
151
152 private final DefaultCallTarget inlinableTarget;
153
154 @CompilationFinal private int callCount;
155
156 InlinableCallNode(DefaultCallTarget function, ArgumentsNode arguments) {
157 super(function, arguments);
158 this.inlinableTarget = function;
159 }
160
161 @Override
162 public int getCallCount() {
163 return callCount;
164 }
165
166 @Override
167 public void resetCallCount() {
168 callCount = 0;
169 }
170
171 @Override
172 public Node getInlineTree() {
173 RootNode root = inlinableTarget.getRootNode();
174 if (root instanceof FunctionRootNode) {
175 return ((FunctionRootNode) root).getUninitializedBody();
176 }
177 return null;
178 }
179
180 @Override
181 public boolean inline(FrameFactory factory) {
182 CompilerAsserts.neverPartOfCompilation();
183 TypedNode functionCall = null;
184
185 RootNode root = inlinableTarget.getRootNode();
186 if (root instanceof FunctionRootNode) {
187 functionCall = ((FunctionRootNode) root).inline(NodeUtil.cloneNode(args));
188 }
189 if (functionCall != null) {
190 this.replace(functionCall);
191 return true;
192 } else {
193 return false;
194 }
195 }
196
197 @Override
198 public Object executeGeneric(VirtualFrame frame) {
199 if (CompilerDirectives.inInterpreter()) {
200 callCount++;
201 }
202 return super.executeGeneric(frame);
203 }
204
205 @Override
206 public CallTarget getCallTarget() {
207 return inlinableTarget;
208 }
209
210 }
211
212 private static class DispatchedCallNode extends TypedNode {
213
214 @Child protected ArgumentsNode args;
215 protected final CallTarget function;
216
217 DispatchedCallNode(CallTarget function, ArgumentsNode arguments) {
218 this.args = adoptChild(arguments);
219 this.function = function;
220 }
221
222 @Override
223 public Object executeGeneric(VirtualFrame frame) {
224 SLArguments argsObject = new SLArguments(args.executeArray(frame));
225 return function.call(frame.pack(), argsObject);
226 }
227 }
228
229 private static final class GenericCallNode extends CallNode {
230
231 @Child protected ArgumentsNode args;
232
233 GenericCallNode(TypedNode functionNode, ArgumentsNode arguments) {
234 super(functionNode);
235 this.args = adoptChild(arguments);
236 }
237
238 @Override
239 public Object executeGeneric(VirtualFrame frame, CallTarget function) {
240 SLArguments argsObject = new SLArguments(args.executeArray(frame));
241 return function.call(frame.pack(), argsObject);
242 }
243 }
244
245 }