Mercurial > hg > truffle
comparison graal/Runtime/src/com/sun/hotspot/c1x/InvocationSocket.java @ 2297:099e697d8934
Renaming c1x4hotspotsrc => graal and HotSpotVM => Runtime
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Fri, 22 Apr 2011 15:08:53 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2296:34354e2e40a3 | 2297:099e697d8934 |
---|---|
1 /* | |
2 * Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved. | |
3 * | |
4 * Sun Microsystems, Inc. has intellectual property rights relating to technology embodied in the product | |
5 * that is described in this document. In particular, and without limitation, these intellectual property | |
6 * rights may include one or more of the U.S. patents listed at http://www.sun.com/patents and one or | |
7 * more additional patents or pending patent applications in the U.S. and in other countries. | |
8 * | |
9 * U.S. Government Rights - Commercial software. Government users are subject to the Sun | |
10 * Microsystems, Inc. standard license agreement and applicable provisions of the FAR and its | |
11 * supplements. | |
12 * | |
13 * Use is subject to license terms. Sun, Sun Microsystems, the Sun logo, Java and Solaris are trademarks or | |
14 * registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries. All SPARC trademarks | |
15 * are used under license and are trademarks or registered trademarks of SPARC International, Inc. in the | |
16 * U.S. and other countries. | |
17 * | |
18 * UNIX is a registered trademark in the U.S. and other countries, exclusively licensed through X/Open | |
19 * Company, Ltd. | |
20 */ | |
21 package com.sun.hotspot.c1x; | |
22 | |
23 import java.io.*; | |
24 import java.lang.reflect.*; | |
25 import java.util.*; | |
26 | |
27 import com.sun.hotspot.c1x.logging.*; | |
28 | |
29 /** | |
30 * A collection of java.lang.reflect proxies that communicate over a socket connection. | |
31 * | |
32 * Calling a method sends the method name and the parameters through the socket. Afterwards this class waits for a | |
33 * result. While waiting for a result three types of objects can arrive through the socket: a method invocation, a | |
34 * method result or an exception. Method invocation can thus be recursive. | |
35 * | |
36 * @author Lukas Stadler | |
37 */ | |
38 public class InvocationSocket { | |
39 | |
40 private static final boolean DEBUG = false; | |
41 private static final boolean COUNT_CALLS = false; | |
42 | |
43 private static final HashSet<String> cachedMethodNames = new HashSet<String>(); | |
44 private static final HashSet<String> forbiddenMethodNames = new HashSet<String>(); | |
45 | |
46 static { | |
47 cachedMethodNames.add("name"); | |
48 cachedMethodNames.add("kind"); | |
49 cachedMethodNames.add("isResolved"); | |
50 cachedMethodNames.add("getVMEntries"); | |
51 cachedMethodNames.add("exactType"); | |
52 cachedMethodNames.add("isInitialized"); | |
53 forbiddenMethodNames.add("javaClass"); | |
54 } | |
55 | |
56 private final ObjectOutputStream output; | |
57 private final ObjectInputStream input; | |
58 | |
59 private final Map<String, Integer> counts = new HashMap<String, Integer>(); | |
60 | |
61 public InvocationSocket(ObjectOutputStream output, ObjectInputStream input) { | |
62 this.output = output; | |
63 this.input = input; | |
64 | |
65 if (COUNT_CALLS) { | |
66 Runtime.getRuntime().addShutdownHook(new Thread() { | |
67 @Override | |
68 public void run() { | |
69 SortedMap<Integer, String> sorted = new TreeMap<Integer, String>(); | |
70 for (Map.Entry<String, Integer> entry : counts.entrySet()) { | |
71 sorted.put(entry.getValue(), entry.getKey()); | |
72 } | |
73 for (Map.Entry<Integer, String> entry : sorted.entrySet()) { | |
74 System.out.println(entry.getKey() + ": " + entry.getValue()); | |
75 } | |
76 } | |
77 }); | |
78 } | |
79 } | |
80 | |
81 /** | |
82 * Represents one invocation of a method that is transferred via the socket connection. | |
83 * | |
84 * @author Lukas Stadler | |
85 */ | |
86 private static class Invocation implements Serializable { | |
87 | |
88 public Object receiver; | |
89 public String methodName; | |
90 public Object[] args; | |
91 | |
92 public Invocation(Object receiver, String methodName, Object[] args) { | |
93 this.receiver = receiver; | |
94 this.methodName = methodName; | |
95 this.args = args; | |
96 } | |
97 } | |
98 | |
99 /** | |
100 * Represents the result of an invocation that is transferred via the socket connection. | |
101 * | |
102 * @author Lukas Stadler | |
103 */ | |
104 private static class Result implements Serializable { | |
105 | |
106 public Object result; | |
107 | |
108 public Result(Object result) { | |
109 this.result = result; | |
110 } | |
111 } | |
112 | |
113 private void incCount(String name, Object[] args) { | |
114 if (COUNT_CALLS) { | |
115 name = name + (args == null ? 0 : args.length); | |
116 if (counts.get(name) != null) { | |
117 counts.put(name, counts.get(name) + 1); | |
118 } else { | |
119 counts.put(name, 1); | |
120 } | |
121 } | |
122 } | |
123 | |
124 /** | |
125 * Each instance of this class handles remote invocations for one instance of a Remote class. It will forward all | |
126 * interface methods to the other end of the socket and cache the results of calls to certain methods. | |
127 * | |
128 * @author Lukas Stadler | |
129 */ | |
130 public class Handler implements InvocationHandler { | |
131 | |
132 private final Object receiver; | |
133 private final HashMap<String, Object> cache = new HashMap<String, Object>(); | |
134 | |
135 public Handler(Object receiver) { | |
136 this.receiver = receiver; | |
137 } | |
138 | |
139 @Override | |
140 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |
141 // only interface methods can be transferred, java.lang.Object methods | |
142 if (method.getDeclaringClass() == Object.class) { | |
143 return method.invoke(receiver, args); | |
144 } | |
145 String methodName = method.getName(); | |
146 // check if the result of this zero-arg method was cached | |
147 if (args == null || args.length == 0) { | |
148 if (cache.containsKey(methodName)) { | |
149 return cache.get(methodName); | |
150 } | |
151 } | |
152 if (forbiddenMethodNames.contains(methodName)) { | |
153 throw new IllegalAccessException(methodName + " not allowed"); | |
154 } | |
155 Object result = null; | |
156 try { | |
157 if (DEBUG) { | |
158 Logger.startScope("invoking remote " + methodName); | |
159 } | |
160 incCount(methodName, args); | |
161 | |
162 output.writeObject(new Invocation(receiver, methodName, args)); | |
163 output.flush(); | |
164 result = waitForResult(false); | |
165 | |
166 // result caching for selected methods | |
167 if ((args == null || args.length == 0) && cachedMethodNames.contains(methodName)) { | |
168 cache.put(methodName, result); | |
169 } | |
170 return result; | |
171 } catch (Throwable t) { | |
172 t.printStackTrace(); | |
173 throw t; | |
174 } finally { | |
175 if (DEBUG) { | |
176 Logger.endScope(" = " + result); | |
177 } | |
178 } | |
179 } | |
180 } | |
181 | |
182 /** | |
183 * Waits for the result of a remote method invocation. Invocations that should be executed in this VM might arrive | |
184 * while waiting for the result, and these invocations will be executed before again waiting fort he result. | |
185 */ | |
186 public Object waitForResult(boolean eofExpected) throws IOException, ClassNotFoundException { | |
187 while (true) { | |
188 Object in; | |
189 try { | |
190 in = input.readObject(); | |
191 } catch(EOFException e) { | |
192 if (eofExpected) { | |
193 return null; | |
194 } | |
195 throw e; | |
196 } | |
197 if (in instanceof Result) { | |
198 return ((Result) in).result; | |
199 } else if (in instanceof RuntimeException) { | |
200 throw (RuntimeException) in; | |
201 } else if (in instanceof Throwable) { | |
202 throw new RuntimeException((Throwable) in); | |
203 } | |
204 | |
205 Invocation invoke = (Invocation) in; | |
206 Method method = null; | |
207 for (Class<?> clazz = invoke.receiver.getClass(); clazz != null; clazz = clazz.getSuperclass()) { | |
208 for (Method m : clazz.getDeclaredMethods()) { | |
209 if (invoke.methodName.equals(m.getName())) { | |
210 method = m; | |
211 break; | |
212 } | |
213 } | |
214 } | |
215 if (method == null) { | |
216 Exception e = new UnsupportedOperationException("unknown method " + invoke.methodName); | |
217 e.printStackTrace(); | |
218 output.writeObject(e); | |
219 output.flush(); | |
220 } else { | |
221 Object result = null; | |
222 try { | |
223 if (invoke.args == null) { | |
224 if (DEBUG) { | |
225 Logger.startScope("invoking local " + invoke.methodName); | |
226 } | |
227 result = method.invoke(invoke.receiver); | |
228 } else { | |
229 if (Logger.ENABLED && DEBUG) { | |
230 StringBuilder str = new StringBuilder(); | |
231 str.append("invoking local " + invoke.methodName + "("); | |
232 for (int i = 0; i < invoke.args.length; i++) { | |
233 str.append(i == 0 ? "" : ", "); | |
234 str.append(Logger.pretty(invoke.args[i])); | |
235 } | |
236 str.append(")"); | |
237 Logger.startScope(str.toString()); | |
238 } | |
239 result = method.invoke(invoke.receiver, invoke.args); | |
240 } | |
241 result = new Result(result); | |
242 } catch (IllegalArgumentException e) { | |
243 System.out.println("error while invoking " + invoke.methodName); | |
244 e.getCause().printStackTrace(); | |
245 result = e.getCause(); | |
246 } catch (InvocationTargetException e) { | |
247 System.out.println("error while invoking " + invoke.methodName); | |
248 e.getCause().printStackTrace(); | |
249 result = e.getCause(); | |
250 } catch (IllegalAccessException e) { | |
251 System.out.println("error while invoking " + invoke.methodName); | |
252 e.getCause().printStackTrace(); | |
253 result = e.getCause(); | |
254 } finally { | |
255 if (DEBUG) { | |
256 if (result instanceof Result) { | |
257 Logger.endScope(" = " + ((Result)result).result); | |
258 } else { | |
259 Logger.endScope(" = " + result); | |
260 } | |
261 } | |
262 } | |
263 output.writeObject(result); | |
264 output.flush(); | |
265 } | |
266 } | |
267 } | |
268 | |
269 /** | |
270 * Sends a result without invoking a method, used by CompilationServer startup code. | |
271 */ | |
272 public void sendResult(Object obj) throws IOException { | |
273 output.writeObject(new Result(obj)); | |
274 output.flush(); | |
275 } | |
276 } |