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 }