Mercurial > hg > truffle
diff c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/InvocationSocket.java @ 2295:160aacf936ad
removed last instances of RiType.javaClass, small changes to InvocationSocket and ReplacingStreams to make remote compilation work
author | Lukas Stadler <lukas.stadler@jku.at> |
---|---|
date | Tue, 12 Apr 2011 16:58:56 +0200 |
parents | 6190d20bd6d6 |
children | 34354e2e40a3 |
line wrap: on
line diff
--- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/InvocationSocket.java Mon Apr 11 18:01:44 2011 +0200 +++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/InvocationSocket.java Tue Apr 12 16:58:56 2011 +0200 @@ -22,28 +22,67 @@ import java.io.*; import java.lang.reflect.*; +import java.util.*; import com.sun.hotspot.c1x.logging.*; /** - * A java.lang.reflect proxy that communicates over a socket connection. + * A collection of java.lang.reflect proxies that communicate over a socket connection. * - * Calling a method sends the method name and the parameters through the socket. Afterwards this class waits for a result. - * While waiting for a result three types of objects can arrive through the socket: a method invocation, a method result or an exception. - * Method invocation can thus be recursive. + * Calling a method sends the method name and the parameters through the socket. Afterwards this class waits for a + * result. While waiting for a result three types of objects can arrive through the socket: a method invocation, a + * method result or an exception. Method invocation can thus be recursive. * * @author Lukas Stadler */ public class InvocationSocket { + private static final boolean DEBUG = false; + private static final boolean COUNT_CALLS = false; + + private static final HashSet<String> cachedMethodNames = new HashSet<String>(); + private static final HashSet<String> forbiddenMethodNames = new HashSet<String>(); + + static { + cachedMethodNames.add("name"); + cachedMethodNames.add("kind"); + cachedMethodNames.add("isResolved"); + cachedMethodNames.add("getVMEntries"); + cachedMethodNames.add("exactType"); + cachedMethodNames.add("isInitialized"); + forbiddenMethodNames.add("javaClass"); + } + private final ObjectOutputStream output; private final ObjectInputStream input; + private final Map<String, Integer> counts = new HashMap<String, Integer>(); + public InvocationSocket(ObjectOutputStream output, ObjectInputStream input) { this.output = output; this.input = input; + + if (COUNT_CALLS) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + SortedMap<Integer, String> sorted = new TreeMap<Integer, String>(); + for (Map.Entry<String, Integer> entry : counts.entrySet()) { + sorted.put(entry.getValue(), entry.getKey()); + } + for (Map.Entry<Integer, String> entry : sorted.entrySet()) { + System.out.println(entry.getKey() + ": " + entry.getValue()); + } + } + }); + } } + /** + * Represents one invocation of a method that is transferred via the socket connection. + * + * @author Lukas Stadler + */ private static class Invocation implements Serializable { public Object receiver; @@ -57,6 +96,11 @@ } } + /** + * Represents the result of an invocation that is transferred via the socket connection. + * + * @author Lukas Stadler + */ private static class Result implements Serializable { public Object result; @@ -66,8 +110,27 @@ } } + private void incCount(String name, Object[] args) { + if (COUNT_CALLS) { + name = name + (args == null ? 0 : args.length); + if (counts.get(name) != null) { + counts.put(name, counts.get(name) + 1); + } else { + counts.put(name, 1); + } + } + } + + /** + * Each instance of this class handles remote invocations for one instance of a Remote class. It will forward all + * interface methods to the other end of the socket and cache the results of calls to certain methods. + * + * @author Lukas Stadler + */ public class Handler implements InvocationHandler { - private Object receiver; + + private final Object receiver; + private final HashMap<String, Object> cache = new HashMap<String, Object>(); public Handler(Object receiver) { this.receiver = receiver; @@ -75,23 +138,50 @@ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (!method.getDeclaringClass().isInterface()) { + // only interface methods can be transferred, java.lang.Object methods + if (method.getDeclaringClass() == Object.class) { return method.invoke(receiver, args); } + String methodName = method.getName(); + // check if the result of this zero-arg method was cached + if (args == null || args.length == 0) { + if (cache.containsKey(methodName)) { + return cache.get(methodName); + } + } + if (forbiddenMethodNames.contains(methodName)) { + throw new IllegalAccessException(methodName + " not allowed"); + } try { - Logger.startScope("invoking remote " + method.getName()); - output.writeObject(new Invocation(receiver, method.getName(), args)); + if (DEBUG) { + Logger.startScope("invoking remote " + methodName); + } + incCount(methodName, args); + + output.writeObject(new Invocation(receiver, methodName, args)); output.flush(); - return waitForResult(); + Object result = waitForResult(); + + // result caching for selected methods + if ((args == null || args.length == 0) && cachedMethodNames.contains(methodName)) { + cache.put(methodName, result); + } + return result; } catch (Throwable t) { t.printStackTrace(); throw t; } finally { - Logger.endScope(""); + if (DEBUG) { + Logger.endScope(""); + } } } } + /** + * Waits for the result of a remote method invocation. Invocations that should be executed in this VM might arrive + * while waiting for the result, and these invocations will be executed before again waiting fort he result. + */ public Object waitForResult() throws IOException, ClassNotFoundException { while (true) { Object in = input.readObject(); @@ -122,10 +212,12 @@ Object result; try { if (invoke.args == null) { - Logger.startScope("invoking local " + invoke.methodName); + if (DEBUG) { + Logger.startScope("invoking local " + invoke.methodName); + } result = method.invoke(invoke.receiver); } else { - if (Logger.ENABLED) { + if (Logger.ENABLED && DEBUG) { StringBuilder str = new StringBuilder(); str.append("invoking local " + invoke.methodName + "("); for (int i = 0; i < invoke.args.length; i++) { @@ -151,7 +243,9 @@ e.getCause().printStackTrace(); result = e.getCause(); } finally { - Logger.endScope(""); + if (DEBUG) { + Logger.endScope(""); + } } output.writeObject(result); output.flush(); @@ -159,9 +253,11 @@ } } + /** + * Sends a result without invoking a method, used by CompilationServer startup code. + */ public void sendResult(Object obj) throws IOException { output.writeObject(new Result(obj)); output.flush(); } - }