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();
     }
-
 }