comparison graal/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/ForeignAccess.java @ 21770:c76742cc2c6f

Polishing inter-operability APIs: Exposing only Message, TruffleObject and ForeignAccess-related classes.
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Mon, 08 Jun 2015 04:50:13 +0200
parents
children
comparison
equal deleted inserted replaced
21769:b6309a7d5a44 21770:c76742cc2c6f
1 /*
2 * Copyright (c) 2014, 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.interop;
26
27 import com.oracle.truffle.api.CallTarget;
28 import com.oracle.truffle.api.frame.Frame;
29 import com.oracle.truffle.api.frame.VirtualFrame;
30 import com.oracle.truffle.api.interop.impl.ReadOnlyArrayList;
31 import com.oracle.truffle.api.nodes.Node;
32 import java.util.List;
33
34 /**
35 * Encapsulates types of access to {@link TruffleObject}. If you want to expose your own objects to
36 * foreign language implementations, you need to implement {@link TruffleObject} and its
37 * {@link TruffleObject#getForeignAccess()} method. To create instance of <code>ForeignAccess</code>
38 * , use one of the factory methods available in this class.
39 */
40 public final class ForeignAccess {
41 private final Factory factory;
42
43 private ForeignAccess(Factory faf) {
44 this.factory = faf;
45 }
46
47 /**
48 * Creates new instance of {@link ForeignAccess} that delegates to provided factory.
49 *
50 * @param baseClass the super class of all {@link TruffleObject}s handled by this factory (if
51 * <code>null</code> than the second interface also needs to implement
52 * {@link Factory})
53 * @param factory the factory that handles access requests to {@link Message}s known as of
54 * version 1.0
55 * @return new instance wrapping <code>factory</code>
56 */
57 public static ForeignAccess create(final Class<? extends TruffleObject> baseClass, final Factory10 factory) {
58 if (baseClass == null) {
59 Factory f = (Factory) factory;
60 assert f != null;
61 }
62 class DelegatingFactory implements Factory {
63 @Override
64 public boolean canHandle(TruffleObject obj) {
65 if (baseClass == null) {
66 return ((Factory) factory).canHandle(obj);
67 }
68 return baseClass.isInstance(obj);
69 }
70
71 @Override
72 public CallTarget accessMessage(Message msg) {
73 if (msg instanceof KnownMessage) {
74 switch (msg.hashCode()) {
75 case Execute.HASH1:
76 return factory.accessInvoke(((Execute) msg).getArity());
77 case Execute.HASH2:
78 return factory.accessExecute(((Execute) msg).getArity());
79 case GetSize.HASH:
80 return factory.accessGetSize();
81 case HasSize.HASH:
82 return factory.accessHasSize();
83 case IsBoxed.HASH:
84 return factory.accessIsBoxed();
85 case IsExecutable.HASH:
86 return factory.accessIsExecutable();
87 case IsNull.HASH:
88 return factory.accessIsNull();
89 case Read.HASH:
90 return factory.accessRead();
91 case Unbox.HASH:
92 return factory.accessUnbox();
93 case Write.HASH:
94 return factory.accessWrite();
95 }
96 }
97 return factory.accessMessage(msg);
98 }
99 }
100 return new ForeignAccess(new DelegatingFactory());
101 }
102
103 /**
104 * Creates new instance of {@link ForeignAccess} that delegates to provided factory.
105 *
106 * @param factory the factory that handles various access requests {@link Message}s.
107 * @return new instance wrapping <code>factory</code>
108 */
109 public static ForeignAccess create(Factory factory) {
110 return new ForeignAccess(factory);
111 }
112
113 /**
114 * Executes {@link Message#createNode() foreign node}.
115 *
116 * @param foreignNode the createNode created by {@link Message#createNode()}
117 * @param frame the call frame
118 * @param receiver foreign object to receive the message passed to {@link Message#createNode()}
119 * method
120 * @param arguments parameters for the receiver
121 * @return return value, if any
122 * @throws ClassCastException if the createNode has not been created by
123 * {@link Message#createNode()} method.
124 */
125 public static Object execute(Node foreignNode, VirtualFrame frame, TruffleObject receiver, Object... arguments) {
126 ForeignObjectAccessHeadNode fn = (ForeignObjectAccessHeadNode) foreignNode;
127 return fn.executeForeign(frame, receiver, arguments);
128 }
129
130 /**
131 * Read only access to foreign call arguments inside of a frame.
132 *
133 * @param frame the frame that was called via
134 * {@link #execute(com.oracle.truffle.api.nodes.Node, com.oracle.truffle.api.frame.VirtualFrame, com.oracle.truffle.api.interop.TruffleObject, java.lang.Object...) }
135 * @return read-only list of parameters passed to the frame
136 */
137 public static List<Object> getArguments(Frame frame) {
138 final Object[] arr = frame.getArguments();
139 return ReadOnlyArrayList.asList(arr, 1, arr.length);
140 }
141
142 /**
143 * The foreign receiver in the frame.
144 *
145 * @param frame the frame that was called via
146 * {@link #execute(com.oracle.truffle.api.nodes.Node, com.oracle.truffle.api.frame.VirtualFrame, com.oracle.truffle.api.interop.TruffleObject, java.lang.Object...) }
147 * @return the receiver used when invoking the frame
148 */
149 public static TruffleObject getReceiver(Frame frame) {
150 return (TruffleObject) frame.getArguments()[ForeignAccessArguments.RECEIVER_INDEX];
151 }
152
153 CallTarget access(Message message) {
154 return factory.accessMessage(message);
155 }
156
157 boolean canHandle(TruffleObject receiver) {
158 return factory.canHandle(receiver);
159 }
160
161 /**
162 * Interface of a factory that produces AST snippets that can access a foreign
163 * {@code TruffleObject}. A Truffle language implementation accesses a {@code TruffleObject} via
164 * a {@code Message}. The {@code TruffleObject} instance provides a {@link ForeignAccess}
165 * instance (built via {@link #create(com.oracle.truffle.api.interop.ForeignAccess.Factory)})
166 * that provides an AST snippet for a given {@link Message}. Rather than using this generic
167 * {@code Factory}, consider implementing {@link Factory10} interface that captures the set of
168 * messages each language should implement as of Truffle version 1.0.
169 */
170 public interface Factory {
171
172 /**
173 * * Checks whether provided {@link TruffleObject} can be accessed using AST snippets
174 * produced by this {@link Factory}.
175 *
176 * @param obj the object to check
177 * @return true, if the object can be processed
178 */
179 boolean canHandle(TruffleObject obj);
180
181 /**
182 * Provides an AST snippet to access a {@code TruffleObject}.
183 *
184 * @param tree the {@code Message} that represents the access to a {@code TruffleObject}.
185 * @return the AST snippet for accessing the {@code TruffleObject}, wrapped as a
186 * {@code CallTarget}.
187 */
188 CallTarget accessMessage(Message tree);
189 }
190
191 /**
192 * Specialized {@link Factory factory} that handles {@link Message messages} known as of release
193 * 1.0 of Truffle API.
194 *
195 */
196 public interface Factory10 {
197 /**
198 * Handles {@link Message#IS_NULL} message.
199 *
200 * @return call target to handle the message or <code>null</code> if this message is not
201 * supported
202 */
203 CallTarget accessIsNull();
204
205 /**
206 * Handles {@link Message#IS_EXECUTABLE} message.
207 *
208 * @return call target to handle the message or <code>null</code> if this message is not
209 * supported
210 */
211 CallTarget accessIsExecutable();
212
213 /**
214 * Handles {@link Message#IS_BOXED} message.
215 *
216 * @return call target to handle the message or <code>null</code> if this message is not
217 * supported
218 */
219 CallTarget accessIsBoxed();
220
221 /**
222 * Handles {@link Message#HAS_SIZE} message.
223 *
224 * @return call target to handle the message or <code>null</code> if this message is not
225 * supported
226 */
227 CallTarget accessHasSize();
228
229 /**
230 * Handles {@link Message#GET_SIZE} message.
231 *
232 * @return call target to handle the message or <code>null</code> if this message is not
233 * supported
234 */
235 CallTarget accessGetSize();
236
237 /**
238 * Handles {@link Message#UNBOX} message.
239 *
240 * @return call target to handle the message or <code>null</code> if this message is not
241 * supported
242 */
243 CallTarget accessUnbox();
244
245 /**
246 * Handles {@link Message#READ} message.
247 *
248 * @return call target to handle the message or <code>null</code> if this message is not
249 * supported
250 */
251 CallTarget accessRead();
252
253 /**
254 * Handles {@link Message#WRITE} message.
255 *
256 * @return call target to handle the message or <code>null</code> if this message is not
257 * supported
258 */
259 CallTarget accessWrite();
260
261 /**
262 * Handles {@link Message#createExecute(int)} messages.
263 *
264 * @param argumentsLength number of parameters the messages has been created for
265 * @return call target to handle the message or <code>null</code> if this message is not
266 * supported
267 */
268 CallTarget accessExecute(int argumentsLength);
269
270 /**
271 * Handles {@link Message#createInvoke(int)} messages.
272 *
273 * @param argumentsLength number of parameters the messages has been created for
274 * @return call target to handle the message or <code>null</code> if this message is not
275 * supported
276 */
277 CallTarget accessInvoke(int argumentsLength);
278
279 /**
280 * Handles request for access to a message not known in version 1.0.
281 *
282 * @param unknown the message
283 * @return call target to handle the message or <code>null</code> if this message is not
284 * supported
285 */
286 CallTarget accessMessage(Message unknown);
287 }
288 }